/* copyright (c) 2018 jones http://www.apache.org/licenses/LICENSE-2.0 开源项目 https://github.com/jones2000/HQChart jones_2000@163.com 分析家语法编译器 */ //日志 import { JSConsole } from "./umychart.console.wechat.js" import { JSCommonData } from "./umychart.data.wechat.js"; //行情数据结构体 及涉及到的行情算法(复权,周期等) //配色资源 import { JSCommonResource_Global_JSChartResource as g_JSChartResource, JSCommonResource_JSCHART_LANGUAGE_ID as JSCHART_LANGUAGE_ID, JSCommonResource_Global_JSChartLocalization as g_JSChartLocalization, } from './umychart.resource.wechat.js' import { JSCommonSplit_IFrameSplitOperator as IFrameSplitOperator, } from './umychart.framesplit.wechat.js' var g_JSComplierResource= { Domain : "https://opensource.zealink.com", //API域名 CacheDomain : "https://opensourcecache.zealink.com", //缓存域名 CustomFunction: //定制函数 { Data:new Map() //自定义函数 key=函数名, Value:{ID:函数名, Callback: } }, CustomVariant: //自定义变量 { Data:new Map() //自定义函数 key=变量名, Value:{ Name:变量名, Description:描述信息 } }, IsCustomFunction:function(name) { if (g_JSComplierResource.CustomFunction.Data.has(name)) return true; return false; }, IsCustomVariant:function(name) { if (g_JSComplierResource.CustomVariant.Data.has(name)) return true; return false; } } var Messages = { BadGetterArity: 'Getter must not have any formal parameters', BadSetterArity: 'Setter must have exactly one formal parameter', BadSetterRestParameter: 'Setter function argument must not be a rest parameter', ConstructorIsAsync: 'Class constructor may not be an async method', ConstructorSpecialMethod: 'Class constructor may not be an accessor', DeclarationMissingInitializer: 'Missing initializer in %0 declaration', DefaultRestParameter: 'Unexpected token =', DuplicateBinding: 'Duplicate binding %0', DuplicateConstructor: 'A class may only have one constructor', DuplicateProtoProperty: 'Duplicate __proto__ fields are not allowed in object literals', ForInOfLoopInitializer: '%0 loop variable declaration may not have an initializer', GeneratorInLegacyContext: 'Generator declarations are not allowed in legacy contexts', IllegalBreak: 'Illegal break statement', IllegalContinue: 'Illegal continue statement', IllegalExportDeclaration: 'Unexpected token', IllegalImportDeclaration: 'Unexpected token', IllegalLanguageModeDirective: 'Illegal \'use strict\' directive in function with non-simple parameter list', IllegalReturn: 'Illegal return statement', InvalidEscapedReservedWord: 'Keyword must not contain escaped characters', InvalidHexEscapeSequence: 'Invalid hexadecimal escape sequence', InvalidLHSInAssignment: 'Invalid left-hand side in assignment', InvalidLHSInForIn: 'Invalid left-hand side in for-in', InvalidLHSInForLoop: 'Invalid left-hand side in for-loop', InvalidModuleSpecifier: 'Unexpected token', InvalidRegExp: 'Invalid regular expression', LetInLexicalBinding: 'let is disallowed as a lexically bound name', MissingFromClause: 'Unexpected token', MultipleDefaultsInSwitch: 'More than one default clause in switch statement', NewlineAfterThrow: 'Illegal newline after throw', NoAsAfterImportNamespace: 'Unexpected token', NoCatchOrFinally: 'Missing catch or finally after try', ParameterAfterRestParameter: 'Rest parameter must be last formal parameter', Redeclaration: '%0 \'%1\' has already been declared', StaticPrototype: 'Classes may not have static property named prototype', StrictCatchVariable: 'Catch variable may not be eval or arguments in strict mode', StrictDelete: 'Delete of an unqualified identifier in strict mode.', StrictFunction: 'In strict mode code, functions can only be declared at top level or inside a block', StrictFunctionName: 'Function name may not be eval or arguments in strict mode', StrictLHSAssignment: 'Assignment to eval or arguments is not allowed in strict mode', StrictLHSPostfix: 'Postfix increment/decrement may not have eval or arguments operand in strict mode', StrictLHSPrefix: 'Prefix increment/decrement may not have eval or arguments operand in strict mode', StrictModeWith: 'Strict mode code may not include a with statement', StrictOctalLiteral: 'Octal literals are not allowed in strict mode.', StrictParamDupe: 'Strict mode function may not have duplicate parameter names', StrictParamName: 'Parameter name eval or arguments is not allowed in strict mode', StrictReservedWord: 'Use of future reserved word in strict mode', StrictVarName: 'Variable name may not be eval or arguments in strict mode', TemplateOctalLiteral: 'Octal literals are not allowed in template strings.', UnexpectedEOS: 'Unexpected end of input', UnexpectedIdentifier: 'Unexpected identifier', UnexpectedNumber: 'Unexpected number', UnexpectedReserved: 'Unexpected reserved word', UnexpectedString: 'Unexpected string', UnexpectedTemplate: 'Unexpected quasi %0', UnexpectedToken: 'Unexpected token %0', UnexpectedTokenIllegal: 'Unexpected token ILLEGAL', UnknownLabel: 'Undefined label \'%0\'', UnterminatedRegExp: 'Invalid regular expression: missing /' }; var Regex = { // Unicode v8.0.0 NonAsciiIdentifierStart: NonAsciiIdentifierStart: /[\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0-\u08B4\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0AF9\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D\u0C58-\u0C5A\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D5F-\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2118-\u211D\u2124\u2126\u2128\u212A-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303C\u3041-\u3096\u309B-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FD5\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA69D\uA6A0-\uA6EF\uA717-\uA71F\uA722-\uA788\uA78B-\uA7AD\uA7B0-\uA7B7\uA7F7-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA8FD\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uA9E0-\uA9E4\uA9E6-\uA9EF\uA9FA-\uA9FE\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA7E-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB65\uAB70-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDD40-\uDD74\uDE80-\uDE9C\uDEA0-\uDED0\uDF00-\uDF1F\uDF30-\uDF4A\uDF50-\uDF75\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF\uDFD1-\uDFD5]|\uD801[\uDC00-\uDC9D\uDD00-\uDD27\uDD30-\uDD63\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC60-\uDC76\uDC80-\uDC9E\uDCE0-\uDCF2\uDCF4\uDCF5\uDD00-\uDD15\uDD20-\uDD39\uDD80-\uDDB7\uDDBE\uDDBF\uDE00\uDE10-\uDE13\uDE15-\uDE17\uDE19-\uDE33\uDE60-\uDE7C\uDE80-\uDE9C\uDEC0-\uDEC7\uDEC9-\uDEE4\uDF00-\uDF35\uDF40-\uDF55\uDF60-\uDF72\uDF80-\uDF91]|\uD803[\uDC00-\uDC48\uDC80-\uDCB2\uDCC0-\uDCF2]|\uD804[\uDC03-\uDC37\uDC83-\uDCAF\uDCD0-\uDCE8\uDD03-\uDD26\uDD50-\uDD72\uDD76\uDD83-\uDDB2\uDDC1-\uDDC4\uDDDA\uDDDC\uDE00-\uDE11\uDE13-\uDE2B\uDE80-\uDE86\uDE88\uDE8A-\uDE8D\uDE8F-\uDE9D\uDE9F-\uDEA8\uDEB0-\uDEDE\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3D\uDF50\uDF5D-\uDF61]|\uD805[\uDC80-\uDCAF\uDCC4\uDCC5\uDCC7\uDD80-\uDDAE\uDDD8-\uDDDB\uDE00-\uDE2F\uDE44\uDE80-\uDEAA\uDF00-\uDF19]|\uD806[\uDCA0-\uDCDF\uDCFF\uDEC0-\uDEF8]|\uD808[\uDC00-\uDF99]|\uD809[\uDC00-\uDC6E\uDC80-\uDD43]|[\uD80C\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD811[\uDC00-\uDE46]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDED0-\uDEED\uDF00-\uDF2F\uDF40-\uDF43\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDF00-\uDF44\uDF50\uDF93-\uDF9F]|\uD82C[\uDC00\uDC01]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB]|\uD83A[\uDC00-\uDCC4]|\uD83B[\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1]|\uD87E[\uDC00-\uDE1D]/, // Unicode v8.0.0 NonAsciiIdentifierPart: NonAsciiIdentifierPart: /[\xAA\xB5\xB7\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0300-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u0483-\u0487\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u05D0-\u05EA\u05F0-\u05F2\u0610-\u061A\u0620-\u0669\u066E-\u06D3\u06D5-\u06DC\u06DF-\u06E8\u06EA-\u06FC\u06FF\u0710-\u074A\u074D-\u07B1\u07C0-\u07F5\u07FA\u0800-\u082D\u0840-\u085B\u08A0-\u08B4\u08E3-\u0963\u0966-\u096F\u0971-\u0983\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BC-\u09C4\u09C7\u09C8\u09CB-\u09CE\u09D7\u09DC\u09DD\u09DF-\u09E3\u09E6-\u09F1\u0A01-\u0A03\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A3C\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A59-\u0A5C\u0A5E\u0A66-\u0A75\u0A81-\u0A83\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABC-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0AD0\u0AE0-\u0AE3\u0AE6-\u0AEF\u0AF9\u0B01-\u0B03\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3C-\u0B44\u0B47\u0B48\u0B4B-\u0B4D\u0B56\u0B57\u0B5C\u0B5D\u0B5F-\u0B63\u0B66-\u0B6F\u0B71\u0B82\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD0\u0BD7\u0BE6-\u0BEF\u0C00-\u0C03\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C58-\u0C5A\u0C60-\u0C63\u0C66-\u0C6F\u0C81-\u0C83\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBC-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5\u0CD6\u0CDE\u0CE0-\u0CE3\u0CE6-\u0CEF\u0CF1\u0CF2\u0D01-\u0D03\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D-\u0D44\u0D46-\u0D48\u0D4A-\u0D4E\u0D57\u0D5F-\u0D63\u0D66-\u0D6F\u0D7A-\u0D7F\u0D82\u0D83\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0DCA\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DE6-\u0DEF\u0DF2\u0DF3\u0E01-\u0E3A\u0E40-\u0E4E\u0E50-\u0E59\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB9\u0EBB-\u0EBD\u0EC0-\u0EC4\u0EC6\u0EC8-\u0ECD\u0ED0-\u0ED9\u0EDC-\u0EDF\u0F00\u0F18\u0F19\u0F20-\u0F29\u0F35\u0F37\u0F39\u0F3E-\u0F47\u0F49-\u0F6C\u0F71-\u0F84\u0F86-\u0F97\u0F99-\u0FBC\u0FC6\u1000-\u1049\u1050-\u109D\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u135D-\u135F\u1369-\u1371\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1714\u1720-\u1734\u1740-\u1753\u1760-\u176C\u176E-\u1770\u1772\u1773\u1780-\u17D3\u17D7\u17DC\u17DD\u17E0-\u17E9\u180B-\u180D\u1810-\u1819\u1820-\u1877\u1880-\u18AA\u18B0-\u18F5\u1900-\u191E\u1920-\u192B\u1930-\u193B\u1946-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u19D0-\u19DA\u1A00-\u1A1B\u1A20-\u1A5E\u1A60-\u1A7C\u1A7F-\u1A89\u1A90-\u1A99\u1AA7\u1AB0-\u1ABD\u1B00-\u1B4B\u1B50-\u1B59\u1B6B-\u1B73\u1B80-\u1BF3\u1C00-\u1C37\u1C40-\u1C49\u1C4D-\u1C7D\u1CD0-\u1CD2\u1CD4-\u1CF6\u1CF8\u1CF9\u1D00-\u1DF5\u1DFC-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u200C\u200D\u203F\u2040\u2054\u2071\u207F\u2090-\u209C\u20D0-\u20DC\u20E1\u20E5-\u20F0\u2102\u2107\u210A-\u2113\u2115\u2118-\u211D\u2124\u2126\u2128\u212A-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D7F-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2DE0-\u2DFF\u3005-\u3007\u3021-\u302F\u3031-\u3035\u3038-\u303C\u3041-\u3096\u3099-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FD5\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA62B\uA640-\uA66F\uA674-\uA67D\uA67F-\uA6F1\uA717-\uA71F\uA722-\uA788\uA78B-\uA7AD\uA7B0-\uA7B7\uA7F7-\uA827\uA840-\uA873\uA880-\uA8C4\uA8D0-\uA8D9\uA8E0-\uA8F7\uA8FB\uA8FD\uA900-\uA92D\uA930-\uA953\uA960-\uA97C\uA980-\uA9C0\uA9CF-\uA9D9\uA9E0-\uA9FE\uAA00-\uAA36\uAA40-\uAA4D\uAA50-\uAA59\uAA60-\uAA76\uAA7A-\uAAC2\uAADB-\uAADD\uAAE0-\uAAEF\uAAF2-\uAAF6\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB65\uAB70-\uABEA\uABEC\uABED\uABF0-\uABF9\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE00-\uFE0F\uFE20-\uFE2F\uFE33\uFE34\uFE4D-\uFE4F\uFE70-\uFE74\uFE76-\uFEFC\uFF10-\uFF19\uFF21-\uFF3A\uFF3F\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDD40-\uDD74\uDDFD\uDE80-\uDE9C\uDEA0-\uDED0\uDEE0\uDF00-\uDF1F\uDF30-\uDF4A\uDF50-\uDF7A\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF\uDFD1-\uDFD5]|\uD801[\uDC00-\uDC9D\uDCA0-\uDCA9\uDD00-\uDD27\uDD30-\uDD63\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC60-\uDC76\uDC80-\uDC9E\uDCE0-\uDCF2\uDCF4\uDCF5\uDD00-\uDD15\uDD20-\uDD39\uDD80-\uDDB7\uDDBE\uDDBF\uDE00-\uDE03\uDE05\uDE06\uDE0C-\uDE13\uDE15-\uDE17\uDE19-\uDE33\uDE38-\uDE3A\uDE3F\uDE60-\uDE7C\uDE80-\uDE9C\uDEC0-\uDEC7\uDEC9-\uDEE6\uDF00-\uDF35\uDF40-\uDF55\uDF60-\uDF72\uDF80-\uDF91]|\uD803[\uDC00-\uDC48\uDC80-\uDCB2\uDCC0-\uDCF2]|\uD804[\uDC00-\uDC46\uDC66-\uDC6F\uDC7F-\uDCBA\uDCD0-\uDCE8\uDCF0-\uDCF9\uDD00-\uDD34\uDD36-\uDD3F\uDD50-\uDD73\uDD76\uDD80-\uDDC4\uDDCA-\uDDCC\uDDD0-\uDDDA\uDDDC\uDE00-\uDE11\uDE13-\uDE37\uDE80-\uDE86\uDE88\uDE8A-\uDE8D\uDE8F-\uDE9D\uDE9F-\uDEA8\uDEB0-\uDEEA\uDEF0-\uDEF9\uDF00-\uDF03\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3C-\uDF44\uDF47\uDF48\uDF4B-\uDF4D\uDF50\uDF57\uDF5D-\uDF63\uDF66-\uDF6C\uDF70-\uDF74]|\uD805[\uDC80-\uDCC5\uDCC7\uDCD0-\uDCD9\uDD80-\uDDB5\uDDB8-\uDDC0\uDDD8-\uDDDD\uDE00-\uDE40\uDE44\uDE50-\uDE59\uDE80-\uDEB7\uDEC0-\uDEC9\uDF00-\uDF19\uDF1D-\uDF2B\uDF30-\uDF39]|\uD806[\uDCA0-\uDCE9\uDCFF\uDEC0-\uDEF8]|\uD808[\uDC00-\uDF99]|\uD809[\uDC00-\uDC6E\uDC80-\uDD43]|[\uD80C\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD811[\uDC00-\uDE46]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDE60-\uDE69\uDED0-\uDEED\uDEF0-\uDEF4\uDF00-\uDF36\uDF40-\uDF43\uDF50-\uDF59\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDF00-\uDF44\uDF50-\uDF7E\uDF8F-\uDF9F]|\uD82C[\uDC00\uDC01]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99\uDC9D\uDC9E]|\uD834[\uDD65-\uDD69\uDD6D-\uDD72\uDD7B-\uDD82\uDD85-\uDD8B\uDDAA-\uDDAD\uDE42-\uDE44]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB\uDFCE-\uDFFF]|\uD836[\uDE00-\uDE36\uDE3B-\uDE6C\uDE75\uDE84\uDE9B-\uDE9F\uDEA1-\uDEAF]|\uD83A[\uDC00-\uDCC4\uDCD0-\uDCD6]|\uD83B[\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1]|\uD87E[\uDC00-\uDE1D]|\uDB40[\uDD00-\uDDEF]/ } var Character = { FromCodePoint: function (cp) { return (cp < 0x10000) ? String.fromCharCode(cp) : String.fromCharCode(0xD800 + ((cp - 0x10000) >> 10)) + String.fromCharCode(0xDC00 + ((cp - 0x10000) & 1023)); }, //是否是空格 https://tc39.github.io/ecma262/#sec-white-space IsWhiteSpace:function(cp) { return (cp === 0x20) || (cp === 0x09) || (cp === 0x0B) || (cp === 0x0C) || (cp === 0xA0) || (cp >= 0x1680 && [0x1680, 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, 0x2007, 0x2008, 0x2009, 0x200A, 0x202F, 0x205F, 0x3000, 0xFEFF].indexOf(cp) >= 0); }, //是否换行 https://tc39.github.io/ecma262/#sec-line-terminators IsLineTerminator:function(cp) { return (cp === 0x0A) || (cp === 0x0D) || (cp === 0x2028) || (cp === 0x2029); }, // https://tc39.github.io/ecma262/#sec-names-and-keywords IsIdentifierStart:function(cp) { return (cp === 0x24) || (cp === 0x5F) || (cp >= 0x41 && cp <= 0x5A) || (cp >= 0x61 && cp <= 0x7A) || (cp === 0x5C) || //【】 (cp===0x3010 || cp===0x3011) || ((cp >= 0x80) && Regex.NonAsciiIdentifierStart.test(Character.FromCodePoint(cp))); }, IsIdentifierPart: function (cp) { return (cp === 0x24) || (cp === 0x5F) || (cp >= 0x41 && cp <= 0x5A) || (cp >= 0x61 && cp <= 0x7A) || (cp >= 0x30 && cp <= 0x39) || (cp === 0x5C) || //【】 (cp===0x3010 || cp===0x3011) || ((cp >= 0x80) && Regex.NonAsciiIdentifierPart.test(Character.FromCodePoint(cp))); }, // https://tc39.github.io/ecma262/#sec-literals-numeric-literals IsDecimalDigit: function (cp) { return (cp >= 0x30 && cp <= 0x39); // 0..9 }, IsHexDigit: function (cp) { return (cp >= 0x30 && cp <= 0x39) || (cp >= 0x41 && cp <= 0x46) || (cp >= 0x61 && cp <= 0x66); // a..f }, isOctalDigit: function (cp) { return (cp >= 0x30 && cp <= 0x37); // 0..7 } } var TOKEN_NAME={}; TOKEN_NAME[1 /* BooleanLiteral */] = 'Boolean'; TOKEN_NAME[2 /* EOF */] = ''; TOKEN_NAME[3 /* Identifier */] = 'Identifier'; TOKEN_NAME[4 /* Keyword */] = 'Keyword'; TOKEN_NAME[5 /* NullLiteral */] = 'Null'; TOKEN_NAME[6 /* NumericLiteral */] = 'Numeric'; TOKEN_NAME[7 /* Punctuator */] = 'Punctuator'; TOKEN_NAME[8 /* StringLiteral */] = 'String'; TOKEN_NAME[9 /* RegularExpression */] = 'RegularExpression'; TOKEN_NAME[10 /* Template */] = 'Template'; //编译异常, 错误类 function ErrorHandler() { this.Error=[]; this.RecordError=function(error) { this.Error.push(error); } this.ConstructError=function(msg,column) { let error=new Error(msg); //通过自己抛异常并自己截获 来获取调用堆栈信息 try { throw error; } catch(base) { if (Object.create && Object.defineProperties) { error=Object.create(base); error.Column=column; } } return error; } this.CreateError=function(index, line, col, description) { let msg='Line ' + line + ': ' + description; let error=this.ConstructError(msg,col); error.Index=index; error.LineNumber=line; error.Description=description; return error; } this.ThrowError=function(index, line, col, description) { let error=this.CreateError(index,line,col,description); throw error; } } //扫描类 function Scanner(code, ErrorHandler) { this.Source=code; this.ErrorHandler=ErrorHandler; this.Length=code.length; this.Index=0; this.LineNumber=(code.length>0)?1:0; this.LineStart=0; this.CurlyStack=[]; this.SaveState=function() //保存当前扫描状态 { return { Index:this.Index, LineNumber:this.LineNumber, LineStart:this.LineStart }; } this.RestoreState=function(state) //还原扫描状态 { this.Index=state.Index; this.LineNumber=state.LineNumber; this.LineStart=state.LineStart; } this.IsEOF=function() //否是已经结束 { return this.Index>=this.Length; } this.IsKeyword=function(id) { return false; } this.CodePointAt = function (i) { let cp = this.Source.charCodeAt(i); if (cp >= 0xD800 && cp <= 0xDBFF) { let second = this.Source.charCodeAt(i + 1); if (second >= 0xDC00 && second <= 0xDFFF) { var first = cp; cp = (first - 0xD800) * 0x400 + second - 0xDC00 + 0x10000; } } return cp; } this.Lex=function() { if (this.IsEOF()) return { Type:2/*EOF*/, Value:'', LineNumber:this.LineNumber, LineStart:this.LineStart, Start:this.Index, End:this.Index }; let cp=this.Source.charCodeAt(this.Index); //变量名 或 关键字 if (Character.IsIdentifierStart(cp)) return this.ScanIdentifier(); //( ) ; 开头 操作符扫描 if (cp === 0x28 || cp === 0x29 || cp === 0x3B) return this.ScanPunctuator(); //' " 开头 字符串扫描 if (cp === 0x27 || cp === 0x22) return this.ScanStringLiteral(); //. 开头 浮点型 if (cp==0x2E) { if (Character.IsDecimalDigit(this.Source.charCodeAt(this.Index + 1))) return this.ScanNumericLiteral(); return this.ScanPunctuator(); } //数字 if (Character.IsDecimalDigit(cp)) return this.ScanNumericLiteral(); if (cp >= 0xD800 && cp < 0xDFFF) { if (Character.IsIdentifierStart(this.CodePointAt(this.Index))) return this.ScanIdentifier(); } return this.ScanPunctuator(); } //关键字 变量名 https://tc39.github.io/ecma262/#sec-names-and-keywords this.ScanIdentifier=function() { let type; let start=this.Index; //0x5C 反斜杠 let id=(this.Source.charCodeAt(start)=== 0x5C) ? this.GetComplexIdentifier() : this.GetIdentifier(); if (id.length) type=3; //Identifier else if (this.IsKeyword(id)) type=4; //Keyword else if (id==null) type=5; //NullLiteral else if (id=='true' || id=='false') type=1; //BooleanLiteral else type=3; //Identifier if (type!=3 && (start+id.length!=this.Index)) { let restore=this.Index; this.Index=start; throw Messages.InvalidEscapedReservedWord; this.Index=restore; } if (id=='AND' || id=='OR') type=7 /*Punctuator*/; return { Type:type, Value:id, LineNumber:this.LineNumber, LineStart:this.LineStart, Start:start, End:this.Index}; } this.GetIdentifier=function() { let start=this.Index++; //start 保存进来的位置 while(!this.IsEOF()) { let ch=this.Source.charCodeAt(this.Index); if (ch==0x5C) { this.Index=start; return this.GetComplexIdentifier(); } else if (ch >= 0xD800 && ch < 0xDFFF) { this.Index=start; return this.GetComplexIdentifier(); } if (Character.IsIdentifierPart(ch)) ++this.Index; else break; } return this.Source.slice(start,this.Index); } //操作符 https://tc39.github.io/ecma262/#sec-punctuators this.ScanPunctuator=function() { let start=this.Index; let str=this.Source[this.Index]; switch(str) { case '(': ++this.Index; break; case ')': case ';': case ',': ++this.Index; break; case '.': ++this.Index; /*if (this.Source[this.Index] === '.' && this.Source[this.Index + 1] === '.') { //Spread operator: ... this.Index += 2; str = '...'; } */ break; default: str=this.Source.substr(this.Index,3); if (str=='AND') { this.Index+=3; } else { str = this.Source.substr(this.Index, 2); if (str === '&&' || str === '||' || str === '==' || str === '!=' || str === '<>' || str === '<=' || str === '>=' || str === '=>' || str==':=' || str=='OR') { this.Index += 2; } else { str=this.Source[this.Index]; if ('<>=!+-*%&|^/:'.indexOf(str) >= 0) ++this.Index; } } } if (this.Index==start) this.ThrowUnecpectedToken(); return { Type:7/*Punctuator*/, Value:str, LineNumber:this.LineNumber, LineStart:this.LineStart, Start:start, End:this.Index }; } //字符串 https://tc39.github.io/ecma262/#sec-literals-string-literals this.ScanStringLiteral=function() { let start=this.Index; let quote=this.Source[this.Index]; ++this.Index; var octal=false; let str=''; while(!this.IsEOF()) { let ch=this.Source[this.Index++]; if (ch==quote) { quote=''; break; } else if (ch=='\\') //字符串转义 { throw "not complete"; } else if (Character.IsLineTerminator(ch.charCodeAt(0))) { break; } else { str+=ch; } } if (quote!='') { this.Index=start; this.ThrowUnecpectedToken(); } return {Type:8/*StringLiteral*/, Value:str, LineNumber:this.LineNumber, LineStart:this.LineStart, Start:start, End:this.Index}; } this.ScanNumericLiteral=function() { let start=this.Index; let ch=this.Source[this.Index]; let num=''; if (ch!='.') { num=this.Source[this.Index++]; ch=this.Source[this.Index]; // Hex number starts with '0x'. 16进制 if (num=='0') { if (ch=='x' || ch=='X') { ++this.Index; return this.ScanHexLiteral(start); } } while(Character.IsDecimalDigit(this.Source.charCodeAt(this.Index))) { num+=this.Source[this.Index++]; } ch=this.Source[this.Index]; } if (ch=='.') { num+=this.Source[this.Index++]; while(Character.IsDecimalDigit(this.Source.charCodeAt(this.Index))) { num+=this.Source[this.Index++]; } ch=this.Source[this.Index]; } //科学计数法 if (ch=='e' || ch=='E') { num+=this.Source[this.Index++]; ch=this.Source[this.Index]; if (ch=='+' || ch=='-') num+=this.Source[this.Index]; if (Character.IsDecimalDigit(this.Source.charCodeAt(this.Index))) { while(Character.IsDecimalDigit(this.Source.charCodeAt(this.Index))) { num+=this.Source[this.Index++]; } } else { this.ThrowUnecpectedToken(); } } if (Character.IsIdentifierStart(this.Source.charCodeAt(this.Index))) { this.ThrowUnecpectedToken(); } return { Type:6/*NumericLiteral*/, Value:parseFloat(num), LineNumber:this.LineNumber, LineStart:this.LineStart, Start:start, End:this.Index }; } //空格 或 注释 this.ScanComments=function() { let comments; let start=(this.Index==0); while(!this.IsEOF()) { let ch=this.Source.charCodeAt(this.Index); if (Character.IsWhiteSpace(ch)) //过滤掉空格 { ++this.Index; } else if (Character.IsLineTerminator(ch)) { ++this.Index; if (ch==0x0D && this.Source.charCodeAt(this.Index)==0x0A) ++this.Index; //回车+换行 ++this.LineNumber; this.LineStart=this.Index; start=true; } else if (ch==0x2F) // //注释 { ch=this.Source.charCodeAt(this.Index+1); if (ch==0x2F) { this.Index+=2; let comment=this.SkipSingleLineComment(2); start=true; } else { break; } } else if (ch == 0x7B) //{ } 注释 { this.Index += 1; let comment = this.SkipMultiLineComment(); } else { break; } } return comments; } this.SkipMultiLineComment = function () { var comments = []; while (!this.IsEOF()) { var ch = this.Source.charCodeAt(this.Index); if (Character.IsLineTerminator(ch)) { ++this.LineNumber; ++this.Index; this.LineStart = this.Index; } else if (ch == 0x7D) { this.Index += 1; return comments; } else { ++this.Index; } } return comments; } //单行注释 https://tc39.github.io/ecma262/#sec-comments this.SkipSingleLineComment=function(offset) { let comments=[]; while(!this.IsEOF()) { let ch=this.Source.charCodeAt(this.Index); ++this.Index; if (Character.IsLineTerminator(ch)) { if (ch === 13 && this.Source.charCodeAt(this.Index) === 10) ++this.Index; ++this.LineNumber; this.LineStart=this.Index; return comments; } } return comments; } this.ThrowUnecpectedToken=function(message) { if (!message) message = Messages.UnexpectedTokenIllegal; return this.ErrorHandler.ThrowError(this.Index, this.LineNumber, this.Index - this.LineStart + 1, message); } } function Tokenizer(code) { this.ErrorHandler=new ErrorHandler(); //错误信息处理类 this.Scanner=new Scanner(code,this.ErrorHandler); this.Buffer=[]; this.GetNextToken=function() { if (this.Buffer.length==0) { let comments=this.Scanner.ScanComments(); if (!this.Scanner.IsEOF()) { let token=this.Scanner.Lex(); let entry={ Type:TOKEN_NAME[token.Type], Value:this.Scanner.Source.slice(token.Start, token.End)}; this.Buffer.push(entry); } } return this.Buffer.shift(); } } var Syntax = { AssignmentExpression: 'AssignmentExpression', AssignmentPattern: 'AssignmentPattern', ArrayExpression: 'ArrayExpression', ArrayPattern: 'ArrayPattern', ArrowFunctionExpression: 'ArrowFunctionExpression', AwaitExpression: 'AwaitExpression', BlockStatement: 'BlockStatement', BinaryExpression: 'BinaryExpression', BreakStatement: 'BreakStatement', CallExpression: 'CallExpression', CatchClause: 'CatchClause', ClassBody: 'ClassBody', ClassDeclaration: 'ClassDeclaration', ClassExpression: 'ClassExpression', ConditionalExpression: 'ConditionalExpression', ContinueStatement: 'ContinueStatement', DoWhileStatement: 'DoWhileStatement', DebuggerStatement: 'DebuggerStatement', EmptyStatement: 'EmptyStatement', ExportAllDeclaration: 'ExportAllDeclaration', ExportDefaultDeclaration: 'ExportDefaultDeclaration', ExportNamedDeclaration: 'ExportNamedDeclaration', ExportSpecifier: 'ExportSpecifier', ExpressionStatement: 'ExpressionStatement', ForStatement: 'ForStatement', ForOfStatement: 'ForOfStatement', ForInStatement: 'ForInStatement', FunctionDeclaration: 'FunctionDeclaration', FunctionExpression: 'FunctionExpression', Identifier: 'Identifier', IfStatement: 'IfStatement', ImportDeclaration: 'ImportDeclaration', ImportDefaultSpecifier: 'ImportDefaultSpecifier', ImportNamespaceSpecifier: 'ImportNamespaceSpecifier', ImportSpecifier: 'ImportSpecifier', Literal: 'Literal', LabeledStatement: 'LabeledStatement', LogicalExpression: 'LogicalExpression', MemberExpression: 'MemberExpression', MetaProperty: 'MetaProperty', MethodDefinition: 'MethodDefinition', NewExpression: 'NewExpression', ObjectExpression: 'ObjectExpression', ObjectPattern: 'ObjectPattern', Program: 'Program', Property: 'Property', RestElement: 'RestElement', ReturnStatement: 'ReturnStatement', SequenceExpression: 'SequenceExpression', SpreadElement: 'SpreadElement', Super: 'Super', SwitchCase: 'SwitchCase', SwitchStatement: 'SwitchStatement', TaggedTemplateExpression: 'TaggedTemplateExpression', TemplateElement: 'TemplateElement', TemplateLiteral: 'TemplateLiteral', ThisExpression: 'ThisExpression', ThrowStatement: 'ThrowStatement', TryStatement: 'TryStatement', UnaryExpression: 'UnaryExpression', UpdateExpression: 'UpdateExpression', VariableDeclaration: 'VariableDeclaration', VariableDeclarator: 'VariableDeclarator', WhileStatement: 'WhileStatement', WithStatement: 'WithStatement', YieldExpression: 'YieldExpression' }; function Node() { this.IsNeedIndexData=false; //是否需要大盘数据 this.IsNeedLatestData=false; //是否需要最新的个股行情数据 this.IsNeedSymbolData=false; //是否需要下载股票数据 this.IsNeedMarginData = new Set(); this.IsNeedNewsAnalysisData = new Set(); //新闻统计数据 this.IsNeedBlockIncreaseData = new Set(); //是否需要市场涨跌股票数据统计 this.IsNeedSymbolExData = new Set(); //下载股票行情的其他数据 this.FunctionData=[]; //{ID:, Args:, FunctionName: } //FINVALUE(ID),FINONE(ID,Y,MMDD), FINANCE(ID) this.IsAPIData = [] //加载API数据 this.GetDataJobList=function() //下载数据任务列表 { let jobs=[]; if (this.IsNeedSymbolData) jobs.push({ID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SYMBOL_DATA}); if (this.IsNeedIndexData) jobs.push({ID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_INDEX_DATA}); if (this.IsNeedLatestData) jobs.push({ID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SYMBOL_LATEST_DATA}); //涨跌停家数统计 for (var blockSymbol of this.IsNeedBlockIncreaseData) { jobs.push({ ID: JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_INDEX_INCREASE_DATA, Symbol: blockSymbol }); } //加载融资融券 for (var jobID of this.IsNeedMarginData) { jobs.push({ID:jobID}); } //加载新闻统计 for (var jobID of this.IsNeedNewsAnalysisData) { jobs.push({ID:jobID}); } for (var i in this.IsAPIData) { var item = this.IsAPIData[i]; jobs.push(item); } //行情其他数据 for (var jobID of this.IsNeedSymbolExData) { jobs.push({ ID:jobID }); } for(var i in this.FunctionData) { var item=this.FunctionData[i]; jobs.push(item); } return jobs; } this.VerifySymbolVariable = function (varName, token) { let setIndexName = new Set(['INDEXA', 'INDEXC', 'INDEXH', 'INDEXL', "INDEXO", "INDEXV", 'INDEXDEC', 'INDEXADV']); if (setIndexName.has(varName)) { this.IsNeedIndexData=true; return; } let setSymbolDataName=new Set(['CLOSE','C','VOL','V','OPEN','O','HIGH','H','LOW','L','AMOUNT']); if (setSymbolDataName.has(varName)) { this.IsNeedSymbolData=true; return; } if (varName === 'VOLR') { if (!this.IsNeedSymbolExData.has(JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_VOLR_DATA)) this.IsNeedSymbolExData.add(JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_VOLR_DATA); return; } //CAPITAL流通股本(手), EXCHANGE 换手率, TOTALCAPITAL 总股本(手) let setVariantName=new Set( [ "CAPITAL","TOTALCAPITAL","EXCHANGE", "HYBLOCK","DYBLOCK","GNBLOCK","FGBLOCK","ZSBLOCK","ZHBLOCK","ZDBLOCK","HYZSCODE", "GNBLOCKNUM","FGBLOCKNUM","ZSBLOCKNUM","ZHBLOCKNUM","ZDBLOCKNUM", "HYSYL","HYSJL" ]); if (setVariantName.has(varName)) { var item={ ID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_VARIANT, VariantName:varName }; if (token) item.Token={ Index:token.Start, Line:token.LineNumber }; this.FunctionData.push(item); return; } if (g_JSComplierResource.IsCustomVariant(varName)) //自定义函数 { var item={ VariantName:varName, ID:JS_EXECUTE_JOB_ID.JOB_CUSTOM_VARIANT_DATA }; if (token) item.Token={ Index:token.Start, Line:token.LineNumber }; this.FunctionData.push(item); return; } } this.VerifySymbolFunction = function (callee, args, token) { //自定义函数 可以覆盖系统内置函数 if (g_JSComplierResource.IsCustomFunction(callee.Name)) { var item={FunctionName:callee.Name, ID:JS_EXECUTE_JOB_ID.JOB_CUSTOM_FUNCTION_DATA, Args:args} if (token) item.Token={ Index:token.Start, Line:token.LineNumber}; this.FunctionData.push(item); return; } if (callee.Name=='DYNAINFO') { this.IsNeedLatestData=true; return; } //财务函数 if (callee.Name=='FINANCE') { var item={ ID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_FINANCE, Args:args, FunctionName:callee.Name }; if (token) item.Token={ Index:token.Start, Line:token.LineNumber }; this.FunctionData.push(item); return; } if (callee.Name=="FINVALUE") { var item={ ID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_FINVALUE, Args:args, FunctionName:callee.Name }; if (token) item.Token={ Index:token.Start, Line:token.LineNumber }; this.FunctionData.push(item); return; } if (callee.Name=="FINONE") { var item={ ID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_FINONE, Args:args, FunctionName:callee.Name }; if (token) item.Token={ Index:token.Start, Line:token.LineNumber }; this.FunctionData.push(item); return; } if (callee.Name=='GPJYVALUE') { var item={ ID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_GPJYVALUE, Args:args, FunctionName:callee.Name }; if (token) item.Token={ Index:token.Start, Line:token.LineNumber }; this.FunctionData.push(item); return; } if (callee.Name === 'MARGIN') { let jobID = JS_EXECUTE_JOB_ID.GetMarginJobID(args[0].Value); if (jobID && !this.IsNeedMarginData.has(jobID)) this.IsNeedMarginData.add(jobID); return; } if (callee.Name === 'NEWS') { let jobID = JS_EXECUTE_JOB_ID.GetNewsAnalysisID(args[0].Value); if (jobID && !this.IsNeedNewsAnalysisData.has(jobID)) this.IsNeedNewsAnalysisData.add(jobID); return; } if (callee.Name == 'COST' || callee.Name == 'WINNER') //筹码都需要换手率 { //下载流通股 var item={ ID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_FINANCE, Args:[7], FunctionName:"FINANCE", FunctionName2:callee.Name }; if (token) item.Token={ Index:token.Start, Line:token.LineNumber }; this.FunctionData.push(item); return; } if (callee.Name=="INBLOCK") { var item={ ID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_VARIANT, VariantName:"INBLOCK" }; //下载所有板块 if (token) item.Token={ Index:token.Start, Line:token.LineNumber }; this.FunctionData.push(item); return; } if (callee.Name === 'BETA') //beta需要下载上证指数 { this.IsNeedIndexData = true; return; } if (callee.Name == 'UPCOUNT' || callee.Name == 'DOWNCOUNT') //上涨下跌个数 { var blockSymbol = args[0].Value; if (!this.IsNeedBlockIncreaseData.has(blockSymbol)) this.IsNeedBlockIncreaseData.add(blockSymbol); return; } if (callee.Name == "LOADAPIDATA") //加载API数据 { var item = { Name: callee.Name, ID: JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_CUSTOM_API_DATA, Args: args }; if (token) item.Token = { Index: token.Start, Line: token.LineNumber }; this.IsAPIData.push(item); return; } } this.ExpressionStatement=function(expression) { return { Type:Syntax.ExpressionStatement, Expression:expression }; } this.Script=function(body) { return {Type:Syntax.Program, Body:body, SourceType:'通达信脚本' }; } this.SequenceExpression=function(expression) { return {Type:Syntax.SequenceExpression, Expression:expression }; } this.BinaryExpression=function(operator, left, right) { let logical = (operator === '||' || operator === '&&' || operator=='AND' || operator=='OR'); let type = logical ? Syntax.LogicalExpression : Syntax.BinaryExpression; return { Type:type, Operator:operator, Left:left, Right:right }; } this.Literal=function(value,raw) { return { Type:Syntax.Literal, Value:value, Raw:raw }; } this.Identifier = function (name, token) { this.VerifySymbolVariable(name, token); return { Type:Syntax.Identifier, Name:name}; } this.AssignmentExpression=function (operator, left, right) { return { Type:Syntax.AssignmentExpression, Operator:operator, Left:left, Right:right }; } this.UnaryExpression=function(operator, argument) { return { Type:Syntax.UnaryExpression, Operator:operator, Argument:argument, Prefix:true }; } this.EmptyStatement=function() { return { Type:Syntax.EmptyStatement }; } this.CallExpression = function (callee, args, token) { this.VerifySymbolFunction(callee, args, token); return { Type:Syntax.CallExpression, Callee:callee, Arguments:args }; } this.StaticMemberExpression = function (object, property) { return { Type: Syntax.MemberExpression, Computed: false, Object: object, Property: property }; } } function JSParser(code) { this.ErrorHandler=new ErrorHandler(); this.Scanner=new Scanner(code, this.ErrorHandler); this.Node=new Node(); //节点创建 this.LookAhead={Type:2, Value:'', LineNumber:this.Scanner.LineNumber, LineStart:0, Start:0, End:0 }; this.HasLineTerminator=false; this.Context = { IsModule: false, await: false, allowIn: true, allowStrictDirective: true, allowYield: true, FirstCoverInitializedNameError: null, IsAssignmentTarget: false, IsBindingElement: false, InFunctionBody: false, inIteration: false, inSwitch: false, labelSet: {}, Strict: false }; this.PeratorPrecedence = { ')': 0, ';': 0, ',': 0, ']': 0, '||': 1, 'OR':1, '&&': 2, 'AND':2, '|': 3, '^': 4, '&': 5, '=': 6, '==': 6, '!=': 6, '<>': 6, '===': 6, '!==': 6, '<': 7, '>': 7, '<=': 7, '>=': 7, '<<': 8, '>>': 8, '>>>': 8, '+': 9, '-': 9, '*': 11, '/': 11, '%': 11 }; this.StartMarker={Index:0, Line: this.Scanner.LineNumber, Column:0 }; this.LastMarker={Index:0, Line: this.Scanner.LineNumber, Column:0 }; this.Initialize=function() { this.NextToken(); this.LastMarker={ Index:this.Scanner.Index, Line:this.Scanner.LineNumber, Column:this.Scanner.Index-this.Scanner.LineStart }; } this.CreateNode=function() { return { Index:this.StartMarker.Index, Line:this.StartMarker.Line, Column:this.StartMarker.Column }; } this.StartNode=function(token, lastLineStart) { if (lastLineStart==void 0) { lastLineStart=0; } let column = token.Start - token.LineStart; let line = token.LineNumber; if (column < 0) { column += lastLineStart; line--; } return { Index: token.Start, Line: line, Column: column }; } this.Match=function(value) { return this.LookAhead.Type==7 /*Punctuator*/ && this.LookAhead.Value==value; } this.Expect=function(value) { let token=this.NextToken(); if (token.Type!=7 /*Punctuator*/ || token.Value!=value) this.ThrowUnexpectedToken(token); } //是否是赋值操作符 this.MatchAssign=function() { if (this.LookAhead.Type!=7 /*Punctuator*/) return false; let op=this.LookAhead.Value; return op==':' || op==':='; } this.GetTokenRaw=function(token) { return this.Scanner.Source.slice(token.Start, token.End); } this.NextToken=function() { let token=this.LookAhead; this.LastMarker.Index=this.Scanner.Index; this.LastMarker.Line=this.Scanner.LineNumber; this.LastMarker.Column=this.Scanner.Index-this.Scanner.LineStart; this.CollectComments(); //过滤注释 空格 if (this.Scanner.Index !== this.StartMarker.Index) { this.StartMarker.Index = this.Scanner.Index; this.StartMarker.Line = this.Scanner.LineNumber; this.StartMarker.Column = this.Scanner.Index - this.Scanner.LineStart; } let next=this.Scanner.Lex(); this.HasLineTerminator=(token.LineNumber!=next.LineNumber); if (next && this.Context.Strict && next.Type==3/*Identifier */) { //TODO: } this.LookAhead=next; return token; } this.CollectComments=function() { this.Scanner.ScanComments(); } this.ParseScript=function() { let node=this.CreateNode(); let body=this.ParseDirectivePrologues(); while(this.LookAhead.Type!=2 /*EOF*/) { body.push(this.ParseStatementListItem()) } return this.Finalize(node,this.Node.Script(body)); } //https://tc39.github.io/ecma262/#sec-directive-prologues-and-the-use-strict-directive this.ParseDirective=function() { let token=this.LookAhead; let node=this.CreateNode(); let expr=this.ParseExpression(); } this.ParseDirectivePrologues=function() { let firstRestricted=null; let body=[]; while(true) { let token=this.LookAhead; if (token.Type!=8 /*StringLiteral*/) break; let statement=this.ParseDirective(); body.push(statement); } return body; } // https://tc39.github.io/ecma262/#sec-block this.ParseStatementListItem=function() { let statement; this.Context.IsAssignmentTarget=true; this.Context.IsBindingElement=true; if (this.LookAhead.Type==4 /*Keyword*/) { } else { statement=this.ParseStatement(); } return statement; } // https://tc39.github.io/ecma262/#sec-ecmascript-language-statements-and-declarations this.ParseStatement=function() { let statement; switch(this.LookAhead.Type) { case 1 /* BooleanLiteral */: case 5 /* NullLiteral */: case 6 /* NumericLiteral */: case 8 /* StringLiteral */: case 10 /* Template */: case 9 /* RegularExpression */: statement = this.ParseExpressionStatement(); break; case 7 /* Punctuator */: let value = this.LookAhead.Value; if (value === '(') statement = this.ParseExpressionStatement(); else if (value === ';') statement = this.ParseEmptyStatement(); else statement = this.ParseExpressionStatement(); break; case 3 /* Identifier */: statement = this.ParseLabelledStatement(); break; case 4 /* Keyword */: break; default: statement="error"; } return statement; } // https://tc39.github.io/ecma262/#sec-empty-statement this.ParseEmptyStatement=function() { let node=this.CreateNode(); this.Expect(';'); return this.Finalize(node, this.Node.EmptyStatement()); } //https://tc39.github.io/ecma262/#sec-labelled-statements this.ParseLabelledStatement=function() { let node=this.CreateNode(); let expr=this.ParseExpression(); this.ConsumeSemicolon(); let statement = new this.Node.ExpressionStatement(expr); return this.Finalize(node, statement); } // https://tc39.github.io/ecma262/#sec-comma-operator this.ParseExpression=function() { let startToken=this.LookAhead; let expr=this.IsolateCoverGrammar(this.ParseAssignmentExpression); if (this.Match(',')) { let expressions=[]; expressions.push(expr); while(this.LookAhead.Type!=2 /*EOF*/) { if (!this.Match(',')) break; this.NextToken(); expressions.push(this.IsolateCoverGrammar(this.ParseAssignmentExpression)); } expr=this.Finalize(this.StartNode(startToken),this.Node.SequenceExpression(expressions)); } return expr; } this.ParseAssignmentExpression=function() { let expr; let startToken=this.LookAhead; let token=startToken; expr=this.ParseConditionalExpression(); if (this.MatchAssign()) { if (!this.Context.IsAssignmentTarget) { let marker=expr.Marker; this.ThrowUnexpectedError(marker.Index,marker.Line,marker.Column,Messages.InvalidLHSInAssignment); } if (!this.Match('=') && !this.Match(':')) { this.Context.IsAssignmentTarget=false; this.Context.IsBindingElement=false; } else { this.ReinterpretExpressionAsPattern(expr); } token=this.NextToken(); let operator=token.Value; let right=this.IsolateCoverGrammar(this.ParseAssignmentExpression); expr=this.Finalize(this.StartNode(startToken), this.Node.AssignmentExpression(operator, expr, right)); this.Context.FirstCoverInitializedNameError=null; } return expr; } this.ParseConditionalExpression=function() { let startToken=this.LookAhead; let expr=this.InheritCoverGrammar(this.ParseBinaryExpression); return expr; } this.ParseBinaryExpression=function() { let startToken=this.LookAhead; let expr=this.InheritCoverGrammar(this.ParseExponentiationExpression); let token=this.LookAhead; var prec=this.BinaryPrecedence(token); if (prec>0) { this.NextToken(); this.Context.IsAssignmentTarget=false; this.Context.IsBindingElement=false; let markers=[startToken,this.LookAhead]; let left=expr; let right=this.IsolateCoverGrammar(this.ParseExponentiationExpression); let stack=[left,token.Value,right]; let precedences = [prec]; while(true) { prec=this.BinaryPrecedence(this.LookAhead); if (prec<=0) break; while(stack.length>2 && prec<=precedences[precedences.length-1]) { right=stack.pop(); let operator=stack.pop(); precedences.pop(); left=stack.pop(); markers.pop(); let node=this.StartNode(markers[markers.length - 1]); stack.push(this.Finalize(node, this.Node.BinaryExpression(operator, left, right))); } //Shift stack.push(this.NextToken().Value); precedences.push(prec); markers.push(this.LookAhead); stack.push(this.IsolateCoverGrammar(this.ParseExponentiationExpression)); } let i=stack.length-1; expr=stack[i]; let lastMarker=markers.pop(); while(i>1) { let marker=markers.pop(); let lastLineStart=lastMarker && lastMarker.LineStart; let node=this.StartNode(marker, lastLineStart); let operator=stack[i-1]; expr=this.Finalize(node, this.Node.BinaryExpression(operator, stack[i - 2], expr)); i-=2; lastMarker=marker; } } return expr; } this.ParseExponentiationExpression=function() { let startToken=this.LookAhead; let expr=this.InheritCoverGrammar(this.ParseUnaryExpression); return expr; } this.ParseUnaryExpression=function() { let expr; if (this.Match('+') || this.Match('-')) { let node=this.StartNode(this.LookAhead); let token=this.NextToken(); expr=this.InheritCoverGrammar(this.ParseUnaryExpression); expr=this.Finalize(node, this.Node.UnaryExpression(token.Value, expr)); this.Context.IsAssignmentTarget=false; this.Context.IsBindingElement=false; } else { expr=this.ParseUpdateExpression(); } return expr; } // https://tc39.github.io/ecma262/#sec-update-expressions this.ParseUpdateExpression=function() { let expr; let startToken=this.LookAhead; expr=this.InheritCoverGrammar(this.ParseLeftHandSideExpressionAllowCall); return expr; } this.ParseLeftHandSideExpressionAllowCall=function() { let startToken=this.LookAhead; let expr; expr=this.InheritCoverGrammar(this.ParsePrimaryExpression); while(true) { if (this.Match('.')) { this.Context.IsBindingElement = false; this.Context.IsAssignmentTarget = true; this.Expect('.'); const property = this.ParseIdentifierName(); expr = this.Finalize(this.StartNode(startToken), this.Node.StaticMemberExpression(expr, property)); } else if (this.Match('(')) { this.Context.IsBindingElement=false; this.Context.IsAssignmentTarget=false; var args=this.ParseArguments(); //解析 调用参数 expr = this.Finalize(this.StartNode(startToken), this.Node.CallExpression(expr, args, startToken)); } else { break; } } return expr; } /* BooleanLiteral = 1, EOF=2, Identifier=3, Keyword=4, NullLiteral=5, NumericLiteral=6, Punctuator=7, StringLiteral=9, RegularExpression=9, Template=10 */ this.IsIdentifierName = function (token) { return token.Type === 3 //Identifier || token.Type === 4 //Keyword || token.Type === 1 //BooleanLiteral || token.Type === 5;//NullLiteral; } this.ParseIdentifierName = function () { const node = this.CreateNode(); const token = this.NextToken(); if (!this.IsIdentifierName(token)) { this.ThrowUnexpectedToken(token); } return this.Finalize(node, this.Node.Identifier(token.Value, token)); } // https://tc39.github.io/ecma262/#sec-left-hand-side-expressions this.ParseArguments=function() { this.Expect('('); var args=[]; if (!this.Match(')')) { while(true) { let expr=this.IsolateCoverGrammar(this.ParseAssignmentExpression); args.push(expr); if (this.Match(')')) break; this.ExpectCommaSeparator(); if (this.Match(')')) break; } } this.Expect(')'); return args; } // Quietly expect a comma when in tolerant mode, otherwise delegates to expect(). this.ExpectCommaSeparator=function() { this.Expect(','); } // https://tc39.github.io/ecma262/#sec-primary-expression this.ParsePrimaryExpression=function() { let node=this.CreateNode(); let expr; var token, raw; switch(this.LookAhead.Type) { case 3:/* Identifier */ token = this.NextToken(); expr = this.Finalize(node, this.Node.Identifier(token.Value, token)); break; case 6:/* NumericLiteral */ case 8:/* StringLiteral */ this.Context.IsAssignmentTarget=false; this.Context.IsBindingElement=false; token=this.NextToken(); raw=this.GetTokenRaw(token); expr=this.Finalize(node, this.Node.Literal(token.Value,raw)); break; case 7:/* Punctuator */ switch(this.LookAhead.Value) { case '(': this.Context.IsBindingElement=false; expr=this.InheritCoverGrammar(this.ParseGroupExpression); break; default: expr=this.ThrowUnexpectedToken(this.NextToken()) } break; default: expr = this.ThrowUnexpectedToken(this.NextToken()); } return expr; } this.ParseGroupExpression=function() { let expr; this.Expect('('); if (this.Match(')')) { this.NextToken(); } else { let startToken=this.LookAhead; let params=[]; let arrow=false; this.Context.IsBindingElement=true; expr=this.InheritCoverGrammar(this.ParseAssignmentExpression); if (this.Match(',')) { let expressions=[]; this.Context.IsAssignmentTarget=false; expressions.push(expr); while(this.LookAhead.Type!=2 /* EOF */) { if (!this.Match(',')) break; this.NextToken(); if (this.Match(')')) { } } } if (!arrow) { this.Expect(')'); this.Context.IsBindingElement=false; } } return expr; } // https://tc39.github.io/ecma262/#sec-expression-statement this.ParseExpressionStatement=function() { let node=this.CreateNode(); let expr=this.ParseExpression(); this.ConsumeSemicolon(); return this.Finalize(node,this.Node.ExpressionStatement(expr)); } this.ConsumeSemicolon=function() { if (this.Match(';')) { this.NextToken(); } else if (!this.HasLineTerminator) { //if (this.LookAhead.Type!=2/*EOF*/ && !this.Match('}')) this.LastMarker.Index=this.StartMarker.Index; this.LastMarker.Line=this.StartMarker.Line; this.LastMarker.Column=this.StartMarker.Column; } } this.ReinterpretExpressionAsPattern=function(expr) { switch(expr.Type) { case Syntax.Identifier: case Syntax.MemberExpression: case Syntax.AssignmentExpression: break; default: break; } } this.Finalize=function(marker,node) { node.Marker={ Line:marker.Line, Column:marker.Column, Index:marker.Index }; return node; } this.BinaryPrecedence = function (token) { let op = token.Value; let precedence; if (token.Type === 7 /* Punctuator */) precedence = this.PeratorPrecedence[op] || 0; else precedence = 0; return precedence; }; this.IsolateCoverGrammar=function(parseFunction) { let previousIsBindingElement=this.Context.IsBindingElement; let previousIsAssignmentTarget=this.Context.IsAssignmentTarget; let previousFirstCoverInitializedNameError=this.Context.FirstCoverInitializedNameError; this.Context.IsBindingElement=true; this.Context.IsAssignmentTarget=true; this.Context.FirstCoverInitializedNameError=null; let result=parseFunction.call(this); if (this.Context.FirstCoverInitializedNameError!=null) { //错误 this.throwUnexpectedToken(this.context.firstCoverInitializedNameError); } this.Context.IsBindingElement=previousIsBindingElement; this.Context.IsAssignmentTarget=previousIsAssignmentTarget; this.Context.FirstCoverInitializedNameError=previousFirstCoverInitializedNameError; return result; } this.InheritCoverGrammar = function (parseFunction) { let previousIsBindingElement = this.Context.IsBindingElement; let previousIsAssignmentTarget = this.Context.IsAssignmentTarget; let previousFirstCoverInitializedNameError = this.Context.FirstCoverInitializedNameError; this.Context.IsBindingElement = true; this.Context.IsAssignmentTarget = true; this.Context.FirstCoverInitializedNameError = null; let result = parseFunction.call(this); this.Context.IsBindingElement = this.Context.IsBindingElement && previousIsBindingElement; this.Context.IsAssignmentTarget = this.Context.IsAssignmentTarget && previousIsAssignmentTarget; this.Context.FirstCoverInitializedNameError = previousFirstCoverInitializedNameError || this.Context.FirstCoverInitializedNameError; return result; }; this.ThrowUnexpectedToken=function(token,message) { throw this.UnexpectedTokenError(token,message); } this.ThrowUnexpectedError=function(index,line,column,message) { let msg=message || "执行异常"; return this.ErrorHandler.ThrowError(index,line,column,msg); } this.UnexpectedTokenError=function(token,message) { let msg=message || Messages.UnexpectedToken; let value='ILLEGAL'; if (token) { if (!message) { } value=token.Value; } msg=msg.replace("%0",value); if (token && typeof(token.LineNumber)=='number') { let index=token.Start; let line=token.LineNumber; let lastMarkerLineStart=this.LastMarker.Index-this.LastMarker.Column; let column=token.Start-lastMarkerLineStart+1; return this.ErrorHandler.CreateError(index,line,column,msg); } else { let index=this.LastMarker.Index; let line=this.LastMarker.Line; let column=this.LastMarker.Column+1; return this.ErrorHandler.CreateError(index,line,column,msg); } } } /* 算法类 */ function JSAlgorithm(errorHandler, symbolData) { this.ErrorHandler=errorHandler; this.SymbolData = symbolData; //股票数据 //相加 this.Add=function(data,data2) { let isNumber=typeof(data)=='number'; let isNumber2=typeof(data2)=='number'; //单数值相加 if (isNumber && isNumber2) return data+data2; //都是数组相加 let result=[]; if (!isNumber && !isNumber2) { let count=Math.max(data.length, data2.length); for(let i=0;idata2 ? 1 : 0); //都是数组比较 let result=[]; if (!isNumber && !isNumber2) { let count=Math.max(data.length, data2.length); for(let i=0;idata2[i] ? 1:0); } } return result; } if (isNumber) //单数据-数组 { for(let i in data2) { result[i]=null; if ( !isNaN(data) && !isNaN(data2[i]) ) result[i]=(data>data2[i] ? 1 : 0); } } else //数组-单数据 { for(let i in data) { result[i]=null; if ( !isNaN(data[i]) && !isNaN(data2) ) result[i]=(data[i]>data2 ? 1 : 0); } } return result; } //大于等于 this.GTE=function(data,data2) { let isNumber=typeof(data)=='number'; let isNumber2=typeof(data2)=='number'; //单数值比较 if (isNumber && isNumber2) return (data>=data2 ? 1 : 0); //都是数组比较 let result=[]; if (!isNumber && !isNumber2) { let count=Math.max(data.length, data2.length); for(let i=0;i=data2[i] ? 1:0); } } return result; } if (isNumber) //单数据-数组 { for(let i in data2) { result[i]=null; if ( !isNaN(data) && !isNaN(data2[i]) ) result[i]=(data>=data2[i] ? 1 : 0); } } else //数组-单数据 { for(let i in data) { result[i]=null; if ( !isNaN(data[i]) && !isNaN(data2) ) result[i]=(data[i]>=data2 ? 1 : 0); } } return result; } //小于 this.LT=function(data,data2) { let isNumber=typeof(data)=='number'; let isNumber2=typeof(data2)=='number'; //单数值比较 if (isNumber && isNumber2) return (data=data2 ? 1 : 0); //都是数组比较 let result=[]; if (!isNumber && !isNumber2) { let count=Math.max(data.length, data2.length); for(let i=0;iOPEN,HIGH,LOW)表示该周期收阴则返回最高值,否则返回最低值 */ this.IFN=function(data,trueData,falseData) { return this.IF(data,falseData,trueData); } //指标函数 函数名全部大写 this.REF=function(data,n) { let result=[]; if (typeof(n)=='number') { if (data.length<=0) return result; if (n>=data.length) return result; result=data.slice(0,data.length-n); for(let i=0;i=n.length) continue; var value=n[i]; if (value>0 && value<=i) result[i]=data[i-value]; else if (i) result[i]=result[i-1]; else result[i]=data[i]; } } return result; } //引用若干周期前的数据(未作平滑处理). //用法: REFV(X,A),引用A周期前的X值.A可以是变量. //平滑处理:当引用不到数据时进行的操作. //例如: REFV(CLOSE,BARSCOUNT(C)-1)表示第二根K线的收盘价. this.REFV=function(data,n) { let result=[]; if (typeof(n)=='number') { if (data.length<=0) return result; if (n>=data.length) return result; result=data.slice(0,data.length-n); for(let i=0;i=n.length) continue; var value=n[i]; if (value>=0 && value<=i) result[i]=data[i-value]; } } return result; } //属于未来函数,引用若干周期后的数据(平滑处理). //用法: REFX(X,A),引用A周期后的X值.A可以是变量. //平滑处理:当引用不到数据时进行的操作.此函数中,平滑时使用上一个周期的引用值. //例如: TT:=IF(C>O,1,2); // REFX(CLOSE,TT);表示阳线引用下一周期的收盘价,阴线引用日后第二周期的收盘价. this.REFX=function(data,n) { let result=[]; if (typeof(n)=='number') { if (data.length<=0) return result; if (n>=data.length) return result; result=data.slice(n,data.length); //平滑处理 var lastData=data[data.length-1]; for(let i=0;i=n.length) continue; var value=n[i]; if (value>=0 && value+i=data.length) return result; result=data.slice(n,data.length); //平滑处理 for(let i=0;i=n.length) continue; var value=n[i]; if (value>=0 && value+i= 0; --j) { var value = data[i - j]; if (!this.IsNumber(value)) { value = preValue; //空数据就取上一个数据 data[i - j] = value; } else { preValue = value; } sum += value; } result[i] = sum / dayCount; } return result; } //指数平均数指标 EMA(close,10) this.EMA=function(data,dayCount) { var result = []; var offset=0; if (offset>=data.length) return result; //取首个有效数据 for(;offset= 0 && j < data.length) { if (this.IsNumber(data[j])) { sum += data[j]; ++count; } } } if (count != 0) result[i] = (sum / count); else result[i] = null; sum = 0; count = 0; } return result; } /* SMA 移动平均 返回移动平均。 用法: SMA(X,N,M) X的M日移动平均,M为权重,如Y=(X*M+Y'*(N-M))/N */ this.SMA=function(data,n,m) { var result = []; var i=0; var lastData=null; for(;i= 0; --j) { var value = data[i - j]; if (!this.IsNumber(value)) { value = preValue; data[i - j] = value; } else preValue = value; count += dayCount - j; sum += value * (dayCount - j); } result[i] = sum / count; } return result; } /* 返回平滑移动平均 用法:MEMA(X,N):X的N日平滑移动平均,如Y=(X+Y'*(N-1))/N MEMA(X,N)相当于SMA(X,N,1) */ this.MEMA = function (data, dayCount) { let result = []; if (!data || !data.length) return result; var i = 0, j = 0; for (j = 0; j < data.length && !this.IsNumber(data[j]); ++j) { result[j] = null; } i = j; if (dayCount < 1 || i + dayCount >= data.length) return result; var sum = 0; var data = data.slice(0); for (; i < j + dayCount; ++i) { result[i] = null; if (!this.IsNumber(data[i]) && i - 1 >= 0) data[i] = data[i - 1]; sum += data[i]; } result[i - 1] = sum / dayCount; for (; i < data.length; ++i) { if (this.IsNumber(result[i - 1]) && this.IsNumber(data[i])) result[i] = (data[i] + result[i - 1] * (dayCount - 1)) / dayCount; else if (i - 1 > -1 && this.IsNumber(result[i - 1])) result[i] = result[i - 1]; else result[i] = null; } return result; } /* 加权移动平均 返回加权移动平均 用法:EXPMA(X,M):X的M日加权移动平均 EXPMA[i]=buffer[i]*para+(1-para)*EXPMA[i-1] para=2/(1+__para) */ this.EXPMA=function(data,dayCount) { let result=[]; if (dayCount>=data.length) return result; let i=dayCount; for(;i=data.length) return result; var index=0; for(;index= start; --i) { for (j = i, total = 0; j >= start && total < data2[i]; --j) total += data[j]; if (j < start) result[i] = null; else result[i] = i - j; } for (i = start + 1; i < data.length; ++i) { if (result[i] == null) result[i] = result[i - 1]; } return result; } /* 求相反数. 用法:REVERSE(X)返回-X. 例如:REVERSE(CLOSE)返回-CLOSE */ this.REVERSE = function (data) { var result = []; var i = 0; for (; i < data.length && !this.isNumber(data[i]); ++i) { result[i] = null; } for (; i < data.length; ++i) { if (!this.isNumber(data[i])) result[i] = null; else result[i] = 0 - data[i]; } return result; } this.COUNT=function(data,n) { if (Array.isArray(n)) { var start=null; var dataCount=data.length; for(var i=0;i=0 && k= n.length) continue; max = null; var count = n[i]; if (count > 0 && count <= i) { for (j = i - count; j <= i; ++j) { if (max == null || max < data[j]) max = data[j]; } } else { count = i; for (j = 0; j <= i; ++j) { if (max == null || max < data[j]) max = data[j]; } } result[i] = max; } } else { if (n > data.length) return result; if (n <= 0) n = data.length - 1; var nMax = 0; for (nMax = 0; nMax < data.length; ++nMax) { if (this.IsNumber(data[nMax])) break; } if (nMax < data.length) result[nMax] = data[nMax]; for (var i = nMax + 1, j = 2; i < data.length && j < n; ++i, ++j) { if (data[i] >= data[nMax]) nMax = i; result[i] = data[nMax]; } for (; i < data.length; ++i) { if (i - nMax < n) { nMax = data[i] < data[nMax] ? nMax : i; } else { for (j = nMax = (i - n + 1); j <= i; ++j) { nMax = data[j] < data[nMax] ? nMax : j; } } result[i] = data[nMax]; } } return result; } /* LLV 最低值 求最低值。 用法: LLV(X,N) 求N周期内X最低值,N=0则从第一个有效值开始。 例如: LLV(LOW,0) 表示求历史最低价。 */ this.LLV=function(data,n) { var result = []; if (Array.isArray(n)) { for (var i = 0; i < data.length; ++i) { result[i] = null; if (i >= n.length) continue; var min = null; var count = n[i]; if (count > 0 && count <= i) { for (var j = i - count; j <= i; ++j) { if (min == null || min > data[j]) min = data[j]; } } else { count = i; for (var j = 0; j <= i; ++j) { if (min == null || min > data[j]) min = data[j]; } } result[i] = min; } } else { if (n>data.length) return result; if (n<=0) n=data.length-1; var nMin=0; for(nMin=0;nMindata[nMin]?nMin:i; } else { for(j=nMin=(i-n+1);j<=i;++j) { nMin=data[j]>data[nMin]?nMin:j; } } result[i]=data[nMin]; } } return result; } this.STD=function(data,n) { var result=[]; var total=0; var averageData=[]; //平均值 for(var i=n-1;i data2[index] && data[index - 1] < data2[index - 1]) ? 1 : 0; } } else if (Array.isArray(data) && typeof (data2) == 'number') { var index = 0; for (; index < data.length; ++index) { if (this.IsNumber(data[index])) break; } for (++index; index < data.length; ++index) { result[index] = (data[index] > data2 && data[index - 1] < data2) ? 1 : 0; } } else if (typeof (data) == 'number' && Array.isArray(data2)) { var index = 0; for (; index < data2.length; ++index) { if (this.IsNumber(data2[index])) break; } for (++index; index < data2.length; ++index) { result[index] = (data2[index] < data && data2[index - 1] > data) ? 1 : 0; } } return result; } //累乘 this.MULAR=function(data,n) { var result=[]; if(data.lengthdatanum) return result; for(E=0; i < datanum && j < num; ++i,++j) E += data[i]/num; if (j == num) { DEV = 0; for(i--; k < num; k++) DEV += (data[i-k]-E) * (data[i-k]-E); result[i] = DEV; i++; } for(; i < datanum; ++i) { E += (data[i] - data[i-num]) / num; for(DEV=0, k = 0; k < num; ++k) DEV += (data[i-k]-E) * (data[i-k]-E); result[i] = DEV; } return result; } //NOT 取反 //求逻辑非。 //用法: NOT(X) 返回非X,即当X=0时返回1,否则返回0。 //例如: NOT(ISUP) 表示平盘或收阴。 this.NOT=function(data) { let isNumber=typeof(data)=='number'; if (isNumber) return data? 0:1; let result=[]; for(let i in data) { result[i]=null; if (this.IsNumber(data[i])) result[i]=data[i]?0:1; } return result; } //FORCAST 线性回归预测值 //FORCAST(X,N)  返回线性回归预测值。 this.FORCAST=function(data,n) { var result=[]; if (typeof(n)!='number') n=parseInt(n); //字符串的转成数值型 var num = n; var datanum = data.length; if (num < 1 || num >= datanum) return result; var Ex = 0, Ey = 0, Sxy = 0, Sxx = 0, Const, Slope; var i, j,x; for(j = 0; j < datanum && !this.IsNumber(data[j]); ++j) { result[j] = null; } for(i = j+num-1; i < datanum; ++i) { Ex = Ey = Sxy = Sxx = 0; for (j = 0, x = num; j < num && j <= i; ++j,--x) { Ex +=x; Ey += data[i - j]; } Ex /= num; Ey /= num; for (j = 0, x = num; j < num && j <= i; ++j, --x) { Sxy += (x-Ex)*(data[i-j]-Ey); Sxx += (x-Ex)*(x-Ex); } Slope = Sxy / Sxx; Const = Ey - Ex*Slope; result[i] = Slope * num + Const; } return result; } //SLOPE 线性回归斜率 //SLOPE(X,N)  返回线性回归斜率。 this.SLOPE=function(data,n) { let result=[]; if (typeof(n)!='number') n=parseInt(n); //字符串的转成数值型 if (n<1 || !data.length) return result; if (n>=data.length) return result; let start=0; for(let i=0;i= datanum) return result; var i = 0, j = 0; for(i = 0; i < datanum && !this.isNumber(data[i]); ++i) { result[i] = null; } var SigmaPowerX = 0, SigmaX = 0, MidResult; for (; i < datanum && j < num; ++i, ++j) { SigmaPowerX += data[i] * data[i]; SigmaX += data[i]; } if (j == num) { MidResult = num*SigmaPowerX - SigmaX*SigmaX; result[i-1] = Math.sqrt(MidResult) / num; } for(; i < datanum; ++i) { SigmaPowerX += data[i]*data[i] - data[i-num]*data[i-num]; SigmaX += data[i] - data[i-num]; MidResult = num*SigmaPowerX - SigmaX*SigmaX; result[i] = Math.sqrt(MidResult) / num; } } //VAR 估算样本方差 //VAR(X,N)  返回估算样本方差。 this.VAR=function(data,n) { var result=[]; if (typeof(n)!='number') n=parseInt(n); //字符串的转成数值型 var num = n; var datanum = data.length; if (num <= 1 || num >= datanum) return result; var i, j; for (i = 0; i < datanum && !this.IsNumber(data[i]); ++i) { result[i] = null; } var SigmaPowerX, SigmaX; for (j = 0, i = i+num-1; i < datanum; ++i) { SigmaPowerX = SigmaX = 0; for(j=0; j < num && j <= i; ++j) { SigmaPowerX += data[i-j] * data[i-j]; SigmaX += data[i-j]; } result[i] = (num*SigmaPowerX - SigmaX*SigmaX) / num * (num -1); } return result; } //VARP 总体样本方差 //VARP(X,N)  返回总体样本方差 。 this.VARP=function(data,n) { var result=[]; if (typeof(n)!='number') n=parseInt(n); //字符串的转成数值型 var num = n; var datanum = data.length; if (num < 1 || num >= datanum) return result; var i = 0, j = 0; for (i = 0; i < datanum && !this.IsNumber(data[i]); ++i) { result[i] = null; } var SigmaPowerX = 0, SigmaX = 0; for (; i < datanum && j < num; ++i, ++j) { SigmaPowerX += data[i] * data[i]; SigmaX += data[i]; } if (j == num) result[i-1] = (num*SigmaPowerX - SigmaX*SigmaX) / (num*num); for(; i < datanum; ++i) { SigmaPowerX += data[i]*data[i] - data[i-num]*data[i-num]; SigmaX += data[i] - data[i-num]; result[i] = (num*SigmaPowerX - SigmaX*SigmaX) / (num*num); } return result; } //RANGE(A,B,C)表示A>B AND AMath.min(range,range2) && data=range.length) continue; rangeValue=range[i]; } else { rangeValue=range; } if (!this.IsNumber(rangeValue)) continue; if (!isNumber3) { if (i>=range2.length) continue; rangeValue2=range2[i]; } else { rangeValue2=range2; } if (!this.IsNumber(rangeValue2)) continue; result[i]= (value>Math.min(rangeValue,rangeValue2) && value0) latestID==i; if (i-latestIDOPEN,5)查找阳线,5天内再次出现的阳线不被记录在内 */ this.FILTER = function (data, n) { var result = []; for (let i = 0, j = 0; i < data.length; ++i) { if (data[i]) { result[i] = 1; for (j = 0; j < n && j + i + 1 < data.length; ++j) { result[j + i + 1] = 0; } i += n; } else { result[i] = 0; } } return result; } this.BARSLAST=function(data) { var result=[]; if (!data) return result; let day=null; for(let i=0;i0) day=0; else if (day!=null) ++day; if (day!=null) result[i]=day; } return result; } /* N周期内第一个条件成立到当前的周期数. 用法: BARSSINCEN(X,N):N周期内第一次X不为0到现在的天数,N为常量 例如: BARSSINCEN(HIGH>10,10)表示10个周期内股价超过10元时到当前的周期数 */ this.BARSSINCEN = function (data, n) { var result=[]; if (this.IsNumber(n) && Array.isArray(data)) { var nPeriod=n; if (nPeriod<1) nPeriod=data.length; var i=this.GetFirstVaildIndex(data); if (i>=data.length) return result; var j=0; if (i <= nPeriod - 1) j = nPeriod - 1; else j = i; result[j] = j - i; for (; j < data.length; ++j) { if (this.IsNumber(result[j - 1])) { if (result[j - 1] + 1 < nPeriod) { result[j] = result[j - 1] + 1; } else { for (var k = j - nPeriod+1; k <= j; ++k) { if (!(Math.abs(data[k]) < 0.000001)) { result[j] = j - k; break; } } } } else { if (!(Math.abs(data[j]) < 0.000001)) result[j] = 0; } } } return result; } /* 第一个条件成立到当前的周期数. 用法: BARSSINCE(X):第一次X不为0到现在的天数 例如: BARSSINCE(HIGH>10)表示股价超过10元时到当前的周期数 */ this.BARSSINCE = function (data) { var result = []; var day = null; for (let i = 0; i < data.length; ++i) { result[i] = null; if (day == null) { if (data[i]) day = 0; } else { ++day; } if (day) result[i] = day; } return result; } /*三角函数调用 func 三角函数 反正切值. 用法: ATAN(X)返回X的反正切值 余弦值. 用法: COS(X)返回X的余弦值 正弦值. 用法: SIN(X)返回X的正弦值 正切值. 用法: TAN(X)返回X的正切值 求自然对数. 用法: LN(X)以e为底的对数 例如: LN(CLOSE)求收盘价的对数 求10为底的对数. 用法: LOG(X)取得X的对数 例如: LOG(100)等于2 指数. 用法: EXP(X)为e的X次幂 例如: EXP(CLOSE)返回e的CLOSE次幂 开平方. 用法: SQRT(X)为X的平方根 例如: SQRT(CLOSE)收盘价的平方根 */ this.Trigonometric = function (data, func) { if (!Array.isArray(data)) { if (this.IsNumber(data)) return func(data); return null; } else { var result = []; for (let i in data) { var item = data[i]; if (this.IsNumber(item)) result[i] = func(item); else result[i] = null; } return result; } } //反正弦值. 用法: ASIN(X)返回X的反正弦值 this.ASIN = function (data) { if (!Array.isArray(data)) { if (this.IsNumber(data)) return Math.acos(data); return null; } else { var result = []; for (let i in data) { var item = data[i]; result[i] = null; if (this.IsNumber(item)) { if (item >= -1 && item <= 1) { result[i] = Math.asin(item); } else if (i - 1 >= 0) { var preItem = result[i - 1]; if (this.IsNumber(preItem)) result[i] = preItem; } } } return result; } } //反余弦值. 用法: ACOS(X)返回X的反余弦值 this.ACOS = function (data) { if (!Array.isArray(data)) { if (this.IsNumber(data)) return Math.acos(data); return null; } else { var result = []; for (let i in data) { var item = data[i]; result[i] = null; if (this.IsNumber(item)) { if (item >= -1 && item <= 1) { result[i] = Math.acos(item); } else if (i - 1 >= 0) //超出范围使用上一个数值 { var preItem = result[i - 1]; if (this.IsNumber(preItem)) result[i] = preItem; } } } return result; } } /* LAST(X,A,B):持续存在. 用法: LAST(CLOSE>OPEN,10,5) 表示从前10日到前5日内一直阳线 若A为0,表示从第一天开始,B为0,表示到最后日止 */ this.LAST = function (data, n, n2) { var result = []; if (n2 <= 0) n2 = data.length - 1; if (n2 > n) return result; var day = 0; for (let i = 0, j = 0; i < data.length; ++i) { result[i] = 0; day = 0; var start = i - n; var end = i - n2; if (start < 0 || end < 0) continue; for (j = start; j < data.length && j <= end; ++j, ++day) { if (!data[j]) break; } if (day == end - start + 1) //[start,end] result[i] = 1; } return result; } /* 属于未来函数,之字转向. 用法: ZIG(K,N),当价格变化量超过N%时转向,K表示0:开盘价,1:最高价,2:最低价,3:收盘价,其余:数组信息 例如: ZIG(3,5)表示收盘价的5%的ZIG转向 */ this.ZIG=function(data,n) { var hisData=this.SymbolData.Data; var result=[]; if (typeof(data)=='number') { switch(data) { case 0: data=hisData.GetOpen(); break; case 1: data=hisData.GetHigh(); break; case 2: data=hisData.GetLow(); break; case 3: data=hisData.GetClose(); break; default: return result; } } return this.ZIG_Calculate(data,n); } this.ZIG_Calculate=function(data,dRate) { var dest=[]; var nDataCount=data.length; var m=this.GetFirstVaildIndex(data); var i = 0, lLastPos = 0, lState = 0, j = 0; var dif = 0; for (i = m + 1, lLastPos = lState = m; i= dRate*data[m] ? (data[i]>data[m] ? i : -i) : m; } for (; i= data[i - 1] && data[i] >= data[i + 1]) { if (lState<0) { if ((data[i] - data[-lState]) * 100= lLastPos; j--) dest[j]=data[-lState] + (-lState - j)*dif; lLastPos = -lState; lState = i; } } else if (data[i]>data[lState]) lState = i; } else if (data[i] <= data[i - 1] && data[i] <= data[i + 1]) { if (lState>0) { if ((data[lState] - data[i]) * 100= nDataCount - 2) { if (lState>0 && data[nDataCount - 1] >= data[lState]) lState = nDataCount - 1; if (lState<0 && data[nDataCount - 1] <= data[-lState]) lState = 1 - nDataCount; } if (lState>0) { dif = (data[lState] - data[j = lLastPos]) / (lState - lLastPos ); dest[j++]=data[lLastPos]; for (; j <= lState; ++j) dest[j]=data[lLastPos] + (j - lLastPos)*dif; } else { dif = (data[lLastPos] - data[j = -lState]) / (-lState - lLastPos); dest[j--]=data[-lState]; for (; j >= lLastPos; j--) dest[j]=(data[-lState] + (-lState - j)*dif); } if ((lState = Math.abs(lState))= data[lState]) { dif = (data[nDataCount - 1] - data[j = lState]) / (nDataCount - lState); dest[j++]=(data[lState]); for (; j= lState; j--) dest[j]=(data[nDataCount - 1] + (nDataCount - j)*dif); } } return dest; } this.GetFirstVaildIndex=function(data) { for (var i = 0; i subItem) findData = { ID: i, Value: subItem }; } } secondData.Value = findData.Value; secondData.ID = findData.ID; var lineCache = { Start: { ID: firstData.ID, Value: firstData.Value }, End: { ID: secondData.ID, Value: secondData.Value } }; var lineData = this.JSDraw.CalculateDrawLine(lineCache);//计算2个点的线上 其他点的数值 for (var i in lineData) { var lineItem = lineData[i]; result[lineItem.ID] = lineItem.Value; } if (thridData.ID == data.length - 1) //最后一组数据 { //最后2个点的数据连成线 lineCache = { Start: { ID: secondData.ID, Value: secondData.Value }, End: { ID: thridData.ID, Value: thridData.Value } }; lineData = this.JSDraw.CalculateDrawLine(lineCache);//计算2个点的线上 其他点的数值 for (var i in lineData) { var lineItem = lineData[i]; result[lineItem.ID] = lineItem.Value; } } else { firstData.ID = secondData.ID; firstData.Value = secondData.Value; secondData.ID = thridData.ID; secondData.Value = thridData.Value; secondData.Up = firstData.Value < secondData.Value; } } /* 属于未来函数,前M个ZIG转向波谷到当前距离. 用法: TROUGHBARS(K,N,M)表示之字转向ZIG(K,N)的前M个波谷到当前的周期数,M必须大于等于1 例如: TROUGHBARS(2,5,2)表示%5最低价ZIG转向的前2个波谷到当前的周期数 */ this.TROUGHBARS=function(data,n,n2) { var zigData=this.ZIG(data,n); //计算ZIG var dest=[]; var lEnd =n2; if (lEnd<1) return dest; var nDataCount = zigData.length; var trough = []; for(var i=0;izigData[i - 1]; ++i); for (; izigData[i-1]; ++i); for(; izigData[i - 1]; ++i); for (peak[0] = --i; izigData[i + 1]) { if (lFlag) { if (lEnd) { var tempPeak=peak.slice(0); for(var j=0;jzigData[i - 1]; ++i); for (peak[0] = --i; izigData[i + 1]) { if (lFlag) { if (lEnd) { var tempPeak=peak.slice(0); for(var j=0;jOPEN,N) 表示N日内一直阳线(N应大于0,小于总周期数,N支持变量) */ this.EVERY = function (data, n) { var result = []; if (n < 1) return result; var i = 0; for (; i < data.length; ++i) { result[i] = null; if (this.IsNumber(data[i])) break; } var flag = 0; for (; i < data.length; ++i) { if (data[i]) flag += 1; else flag = 0; if (flag == n) { result[i] = 1; --flag; } else { result[i] = 0; } } return result; } /* 成本分布情况. 用法: COST(10),表示10%获利盘的价格是多少,即有10%的持仓量在该价格以下,其余90%在该价格以上,为套牢盘 该函数仅对日线分析周期有效 */ this.COST = function (data, node) { var result=[]; var rate=data/100; if(rate<0.000001 || rate>1) return result; var kData=this.SymbolData.Data.Data; if (!kData || kData.length<=0) return result; var aryCapital=this.SymbolData.GetStockCacheData({ FunctionName:"FINANCE", Args:[7], ArgCount:1, Node:node } ); //流通股本 var dMaxPrice=kData[0].High,dMinPrice=kData[0].Low; for(var i=0;i 2000 || dMinPrice < 0 || dMaxPrice>2000 || dMinPrice < 0) this.ThrowUnexpectedNode(node,'COST() 历史K线最大最小值错误, 超出(0,1000)范围'); var lMaxPrice = parseInt(dMaxPrice * 100 + 1); var lMinPrice = parseInt(dMinPrice * 100 - 1); var lLow = 0, lHigh = 0, lClose = 0; //去掉小数 dMaxPrice = lMaxPrice / 100.0; dMinPrice = lMinPrice / 100.0; var lSpeed = lMaxPrice - lMinPrice + 1; if (lSpeed < 1) return result; var aryVolPrice=[],aryPerVol=[]; for(var i=0;i= aryCapital.length) continue; if (aryCapital[i]>1) { var kItem=kData[i] dHSL = kItem.Vol/aryCapital[i]; for( var j=0;j=dTotalVol*rate) { dCost=(dMaxPrice-dMinPrice)*j/lSpeed+dMinPrice; break; } } } result[i]=dCost; } return result; } /* 获利盘比例. 用法: WINNER(CLOSE),表示以当前收市价卖出的获利盘比例,例如返回0.1表示10%获利盘;WINNER(10.5)表示10.5元价格的获利盘比例 该函数仅对日线分析周期有效 !!!!计算比较耗时间 */ this.WINNER = function (data,node) { var result=[]; var kData=this.SymbolData.Data.Data; if (!kData || kData.length<=0) return result; var aryCapital=this.SymbolData.GetStockCacheData({ FunctionName:"FINANCE", Args:[7], ArgCount:1, Node:node } ); //流通股本 var dMaxPrice=kData[0].High,dMinPrice=kData[0].Low; for(var i=0;i 1000 || dMinPrice < 0 || dMaxPrice>1000 || dMinPrice < 0) this.ThrowUnexpectedNode(node,'WINNER() 历史K线最大最小值错误, 超出(0,1000)范围'); var lMaxPrice = parseInt(dMaxPrice * 100 + 1); var lMinPrice = parseInt(dMinPrice * 100 - 1); var lLow = 0, lHigh = 0, lClose = 0; //去掉小数 dMaxPrice = lMaxPrice / 100.0; dMinPrice = lMinPrice / 100.0; var lSpeed = lMaxPrice - lMinPrice + 1; if (lSpeed < 1) return result; var aryVolPrice=[],aryPerVol=[]; for(var i=0;i= aryCapital.length) continue; if (!(aryCapital[i]>1)) continue; var kItem=kData[i] dHSL = kItem.Vol/aryCapital[i]; for( var j=0;j 0) result[i]=dVol / dTotalVol; else if (i - 1 >= 0) result[i] = result[i - 1]; } return result; } //计算截至到某一天的历史所有筹码 this.CalculateChip = function (index, exchangeData, hisData, dRate) { var result = { Min: null, Max: null, Data: [] }; var seed = 1;//筹码历史衰减换手系数 var max = null, min = null; for (let i = index; i >= 0; --i) { let item = {}; //Vol:量 High:最高 Low:最低 var kData = hisData[i]; if (i == index) item.Vol = kData.Vol * exchangeData[i]; else item.Vol = kData.Vol * seed; item.Date = kData.Date; item.High = kData.High; item.Low = kData.Low; if (max == null) max = item.High; else if (max < item.High) max = item.High; if (min == null) min = item.Low; else if (min < item.Low) min = item.Low; result.Data[i] = item; seed *= (1 - (exchangeData[i] / 100) * dRate); //换手率累乘 } result.Max = max; result.Min = min; return result; } /* 返回是否连涨周期数. 用法: UPNDAY(CLOSE,M) 表示连涨M个周期,M为常量 */ this.UPNDAY = function (data, n) { var result = []; if (n < 1) return result; if (data == null || n > data.length) return result; var days = 0; for (let i = 0; i < data.length; ++i) { result[i] = 0; if (i - 1 < 0) continue; if (!this.IsNumber(data[i]) || !this.IsNumber(data[i - 1])) //无效数都不算连涨 { days = 0; continue; } if (data[i] > data[i - 1])++days; else days = 0; if (days == n) { result[i] = 1; --days; } } return result; } /* 返回是否连跌周期. 用法: DOWNNDAY(CLOSE,M) 表示连跌M个周期,M为常量 */ this.DOWNNDAY = function (data, n) { var result = []; if (n < 1) return result; if (data == null || n > data.length) return result; var days = 0; for (let i = 0; i < data.length; ++i) { result[i] = 0; if (i - 1 < 0) continue; if (!this.IsNumber(data[i]) || !this.IsNumber(data[i - 1])) //无效数都不算连涨 { days = 0; continue; } if (data[i] < data[i - 1])++days; else days = 0; if (days == n) { result[i] = 1; --days; } } return result; } /* 返回是否持续存在X>Y 用法: NDAY(CLOSE,OPEN,3) 表示连续3日收阳线 */ this.NDAY = function (data, data2, n) { var result = []; if (n < 1) return result; if (!Array.isArray(data) && !Array.isArray(data2)) return result; if (data == null || data2 == null) return result; if (Array.isArray(data) && Array.isArray(data2)) { if (n >= data.length || n >= data2.length) return result; var count = Math.max(data.length, data2.length); var days = 0; for (let i = 0; i < count; ++i) { result[i] = 0; if (i >= data.length || i >= data2.length) continue; if (!this.IsNumber(data[i]) || !this.IsNumber(data2[i])) { days = 0; continue; } if (data[i] > data2[i])++days; else days = 0; if (days == n) { result[i] = 1; --days; } } } else if (Array.isArray(data) && !Array.isArray(data2)) { if (n >= data.length || !this.IsNumber(data2)) return; var days = 0; for (let i in data) { result[i] = 0; if (!this.IsNumber(data[i])) { days = 0; continue; } if (data[i] > data2)++days; else days = 0; if (days == n) { result[i] = 1; --days; } } } else if (!Array.isArray(data) && Array.isArray(data2)) { if (n >= data2.length || !this.IsNumber(data)) return; var days = 0; for (let i in data2) { result[i] = 0; if (!this.IsNumber(data2[i])) { days = 0; continue; } if (data > data2[i])++days; else days = 0; if (days == n) { result[i] = 1; --days; } } } return result; } /* 两条线维持一定周期后交叉. 用法:LONGCROSS(A,B,N)表示A在N周期内都小于B,本周期从下方向上穿过B时返回1,否则返回0 */ this.LONGCROSS = function (data, data2, n) { var result = []; var count = Math.max(data.length, data2.length); for (let i = 0; i < count; ++i) { result[i] = 0; if (i - 1 < 0) continue; if (i >= data.length || i >= data2.length) continue; if (!this.IsNumber(data[i]) || !this.IsNumber(data2[i]) || !this.IsNumber(data[i - 1]) || !this.IsNumber(data2[i - 1])) continue; if (data[i] > data2[i] && data[i - 1] < data2[i - 1]) result[i] = 1; } for (let i = 0, j = 0; i < count; ++i) { if (!result[i]) continue; for (j = 1; j <= n && i - j >= 0; ++j) { if (data[i - j] >= data2[i - j]) { result[i] = 0; break; } } } return result; } /* EXISTR(X,A,B):是否存在(前几日到前几日间). 例如: EXISTR(CLOSE>OPEN,10,5) 表示从前10日内到前5日内存在着阳线 若A为0,表示从第一天开始,B为0,表示到最后日止 */ this.EXISTR = function (data, n, n2) { var result = []; if (!Array.isArray(data)) return result; n = parseInt(n); n2 = parseInt(n2); if (n <= 0) n = data.length; if (n2 <= 0) n2 = 1; if (n2 > n) return result; var result = []; var value; for (let i = 0, j = 0; i < data.length; ++i) { result[i] = null; if (i - n < 0 || i - n2 < 0) continue; result[i] = 0; for (j = n; j >= n2; --j) { var value = data[i - j]; if (this.IsNumber(value) && value) { result[i] = 1; break; } } } return result; } /* RELATE(X,Y,N) 返回X和Y的N周期的相关系数 RELATE(X,Y,N)=(∑[(Xi-Avg(X))(Yi-Avg(y))])/N ÷ √((∑(Xi-Avg(X))^2)/N * (∑(Yi-Avg(Y))^2)/N) 其中 avg(x)表示x的N周期均值: avg(X) = (∑Xi)/N √(...)表示开平方 */ this.RELATE = function (data, data2, n) { var result = []; if (n < 1) n = 1; if (!Array.isArray(data) || !Array.isArray(data2)) return result; var dataAverage = this.CalculateAverage(data, n); var data2Average = this.CalculateAverage(data2, n); var count = Math.max(data.length, data2.length); for (let i = 0, j = 0; i < count; ++i) { result[i] = null; if (i >= data.length || i >= data2.length || i >= dataAverage.length || i >= data2Average.length) continue; var average = dataAverage[i]; var average2 = data2Average[i]; var total = 0, total2 = 0, total3 = 0; for (j = i - n + 1; j <= i; ++j) { total += (data[j] - average) * (data2[j] - average2); //∑[(Xi-Avg(X))(Yi-Avg(y))]) total2 += Math.pow(data[j] - average, 2); //∑(Xi-Avg(X))^2 total3 += Math.pow(data2[j] - average2, 2); //∑(Yi-Avg(Y))^2) } result[i] = (total / n) / (Math.sqrt(total2 / n) * Math.sqrt(total3 / n)); } return result; } //计算数组n周期内的均值 this.CalculateAverage = function (data, n) { var result = []; if (n < 1) return result; var total = 0; for (var i = 0; i < data.length; ++i) //去掉开始的无效数 { if (this.IsNumber(data[i])) break; } for (; i < data.length && i < n; ++i) //计算第1个周期的数据 { result[i] = null; var value = data[i]; if (!this.IsNumber(value)) continue; total += value; } result[i - 1] = total / n; for (; i < data.length; ++i) //计算后面的周期数据 { var value = data[i]; var preValue = data[i - n]; //上一个周期的第1个数据 if (!this.IsNumber(value)) value = 0; if (!this.IsNumber(preValue)) preValue = 0; total = total - preValue + value; //当前周期的数据 等于上一个周期数据 去掉上一个周期的第1个数据 加上这个周期的最后1个数据 result[i] = total / n; } return result; } /* COVAR(X,Y,N) 返回X和Y的N周期的协方差 */ this.COVAR = function (data, data2, n) { var result = []; if (n < 1) n = 1; if (!Array.isArray(data) || !Array.isArray(data2)) return result; var dataAverage = this.CalculateAverage(data, n); var data2Average = this.CalculateAverage(data2, n); var count = Math.max(data.length, data2.length); var count = Math.max(data.length, data2.length); for (let i = 0, j = 0; i < count; ++i) { result[i] = null; if (i >= data.length || i >= data2.length || i >= dataAverage.length || i >= data2Average.length) continue; var average = dataAverage[i]; var average2 = data2Average[i]; var total = 0; for (j = i - n + 1; j <= i; ++j) { total += (data[j] - average) * (data2[j] - average2); } result[i] = (total / n); } return result; } /* 求上一高点到当前的周期数. 用法: HHVBARS(X,N):求N周期内X最高值到当前周期数,N=0表示从第一个有效值开始统计 例如: HHVBARS(HIGH,0)求得历史新高到到当前的周期数 */ this.HHVBARS = function (data, n) { var result = []; if (!Array.isArray(data)) return result; if (Array.isArray(n)) { for(var i=0;i=data[nMax]) nMax=j; } if (nMax!=null) result[i]=(i-nMax); } } else { if (n < 1) n = data.length; var nMax = null; //最大值索引 for (var i = 0; i < data.length; ++i) { result[i] = null; if (this.IsNumber(data[i])) { nMax = i; break; } } var j = 0; for (i = nMax + 1; i < data.length && j < n; ++i, ++j) //求第1个最大值 { if (data[i] >= data[nMax]) nMax = i; if (n == data.length) result[i] = (i - nMax); } for (; i < data.length; ++i) { if (i - nMax < n) { if (data[i] >= data[nMax]) nMax = i; } else { nMax = i - n + 1; for (j = nMax; j <= i; ++j) //计算区间最大值 { if (data[j] >= data[nMax]) nMax = j; } } result[i] = i - nMax; } } return result; } /* 求上一低点到当前的周期数. 用法: LLVBARS(X,N):求N周期内X最低值到当前周期数,N=0表示从第一个有效值开始统计 例如: LLVBARS(HIGH,20)求得20日最低点到当前的周期数 */ this.LLVBARS = function (data, n) { var result = []; if (!Array.isArray(data)) return result; if (Array.isArray(n)) { for(var i=0;i 0 && stockItem.YClose > 0) stockProfit[i] = (stockItem.Close - stockItem.YClose) / stockItem.YClose; if (indexItem.Close > 0 && indexItem.YClose > 0) indexProfit[i] = (indexItem.Close - indexItem.YClose) / indexItem.YClose; } //计算均值数组 var averageStockProfit = this.CalculateAverage(stockProfit, n); var averageIndexProfit = this.CalculateAverage(indexProfit, n); for (var i = 0, j = 0; i < stockData.Data.length; ++i) { result[i] = null; if (i >= stockProfit.length || i >= indexProfit.length || i >= averageStockProfit.length || i >= averageIndexProfit.length) continue; var averageStock = averageStockProfit[i]; var averageIndex = averageIndexProfit[i]; var covariance = 0; //协方差 var variance = 0; //方差 for (j = i - n + 1; j <= i; ++j) { var value = (indexProfit[j] - averageIndex); var value2 = (stockProfit[j] - averageStock); covariance += value * value2; variance += value * value; } if (this.IsDivideNumber(variance) && this.IsNumber(covariance)) result[i] = covariance / variance; //(covariance/n)/(variance/n)=covariance/variance; } return result; } /* 用法:BETA2(X,Y,N)为X与Y的N周期相关放大系数,表示Y变化1%,则X将变化N% 例如:BETA2(CLOSE,INDEXC,10)表示收盘价与大盘指数之间的10周期相关放大率 */ this.BETA2 = function (x, y, n) { var result = []; if (n <= 0) n = 1; var xProfit = [null]; //x数据的涨幅 var yProfit = [null]; //y数据的涨幅 var count = Math.max(x.length, y.length); var lastItem = { X: x[0], Y: y[0] }; for (var i = 1; i < count; ++i) { xProfit[i] = 0; yProfit[i] = 0; var xItem = x[i]; var yItem = y[i]; if (lastItem.X > 0) xProfit[i] = (xItem - lastItem.X) / lastItem.X; if (lastItem.Y > 0) yProfit[i] = (yItem - lastItem.Y) / lastItem.Y; lastItem = { X: xItem, Y: yItem }; } //计算均值数组 var averageXProfit = this.CalculateAverage(xProfit, n); var averageYProfit = this.CalculateAverage(yProfit, n); for (var i = 0, j = 0; i < count; ++i) { result[i] = null; if (i >= xProfit.length || i >= yProfit.length || i >= averageXProfit.length || i >= averageYProfit.length) continue; var averageX = averageXProfit[i]; var averageY = averageYProfit[i]; var covariance = 0; //协方差 var variance = 0; //方差 for (j = i - n + 1; j <= i; ++j) { var value = (xProfit[j] - averageX); var value2 = (yProfit[j] - averageY); covariance += value * value2; variance += value * value; } if (this.IsDivideNumber(variance) && this.IsNumber(covariance)) result[i] = covariance / variance; //(covariance/n)/(variance/n)=covariance/variance; } return result; } /* 抛物转向. 用法: SAR(N,S,M),N为计算周期,S为步长,M为极值 例如: SAR(10,2,20)表示计算10日抛物转向,步长为2%,极限值为20% */ this.SAR = function (n, step, exValue) { var result = []; var stockData = this.SymbolData.Data; if (n >= stockData.Data.length) return result; var high = null, low = null; for (var i = 0; i < n; ++i) { var item = stockData.Data[i]; if (high == null) high = item.High; else if (high < item.High) high = item = high; if (low == null) low = item.Low; else if (low > item.Low) low = item.Low; } const SAR_LONG = 0, SAR_SHORT = 1; var position = SAR_LONG; result[n - 1] = low; var nextSar = low, sip = stockData.Data[0].High, af = exValue / 100; for (var i = n; i < stockData.Data.length; ++i) { var ysip = sip; var item = stockData.Data[i]; var yitem = stockData.Data[i - 1]; if (position == SAR_LONG) { if (item.Low < result[i - 1]) { position = SAR_SHORT; sip = item.Low; af = step / 100; nextSar = Math.max(item.High, yitem.High); nextSar = Math.max(nextSar, ysip + af * (sip - ysip)); } else { position = SAR_LONG; if (item.High > ysip) { sip = item.High; af = Math.min(af + step / 100, exValue / 100); } nextSar = Math.min(item.Low, yitem.Low); nextSar = Math.min(nextSar, result[i - 1] + af * (sip - result[i - 1])); } } else if (position == SAR_SHORT) { if (item.High > result[i - 1]) { position = SAR_LONG; sip = item.High; af = step / 100; nextSar = Math.min(item.Low, yitem.Low); nextSar = Math.min(nextSar, result[i - 1] + af * (sip - ysip)); } else { position = SAR_SHORT; if (item.Low < ysip) { sip = item.Low; af = Math.min(af + step / 100, exValue / 100); } nextSar = Math.max(item.High, yitem.High); nextSar = Math.max(nextSar, result[i - 1] + af * (sip - result[i - 1])); } } result[i] = nextSar; } return result; } /* 抛物转向点. 用法: SARTURN(N,S,M),N为计算周期,S为步长,M为极值,若发生向上转向则返回1,若发生向下转向则返回-1,否则为0 其用法与SAR函数相同 */ this.SARTURN = function (n, step, exValue) { var result = []; var sar = this.SAR(n, step, exValue); var stockData = this.SymbolData.Data; var index = 0; for (index = 0; index < sar.length; ++index) { if (this.IsNumber(sar[index])) break; } var flag = 0; if (index < stockData.Data.length) flag = stockData.Data[index].Close > sar[index]; for (var i = index + 1; i < stockData.Data.length; ++i) { var item = stockData.Data[i]; if (item.Close < sar[i] && flag) result[i] = -1; else result[i] = (item.Close > sar[i] && !flag) ? 1 : 0; flag = item.Close > sar[i]; } return result; } /* 属于未来函数,将当前位置到若干周期前的数据设为1. 用法: BACKSET(X,N),若X非0,则将当前位置到N周期前的数值设为1. 例如: BACKSET(CLOSE>OPEN,2)若收阳则将该周期及前一周期数值设为1,否则为0 */ this.BACKSET = function (condition, n) { var result = []; if (!condition) return result; var dataCount = condition.length; if (!this.IsNumber(dataCount) || dataCount <= 0) return result; if (Array.isArray(n)) { for(var i=0;i=0 && k= 0; --i) { var value = condition[i]; if (this.IsNumber(value) && value) { for (j = i; j > i - num; --j) { result[j] = 1; } } } if (condition[i]) { for (j = i; j >= pos; --j) result[j] = 1; } } return result; } //STRCAT(A,B):将两个字符串A,B(非序列化)相加成一个字符串C. //用法: STRCAT('多头','开仓')将两个字符串'多头','开仓'相加成一个字符串'多头开仓' this.STRCAT = function (str1, str2) { var result=[]; if (this.IsString(str1) && this.IsString(str2)) result=str1+str2; return result; } //VARCAT(A,B):将两个字符串A,B相加成一个字符串C. //用法: DRAWTEXT(CLOSE>OPEN,LOW,VARCAT('多头',VAR2STR(C,2))) 将两个字符串相加成一个字符串并按条件显示出来 this.VARCAT=function(data,data2) { var result=[]; if (Array.isArray(data) && Array.isArray(data2)) { var nCount=Math.max(data.length, data2.length); var strValue=""; for(var i=0;i= 0; --i) { var item = data[i]; if (this.IsNumber(item)) { result = item.toFixed(n); return result; } } } else { if (this.IsNumber(data)) result = data.toFixed(n); } return result; } //VAR2STR(A,N):取A的每一个值转为字符串,小数位数N. //用法: VAR2STR(C,3)表示取收盘价,以3位小数转为字符串 this.VAR2STR=function(data,n) { var result=[]; if (Array.isArray(data)) { for(var i=0;iOPEN)表示统计连续收阳的周期数 */ this.BARSLASTCOUNT=function(data) { var result=null; if (Array.isArray(data)) { result=[]; if (data.length>0) { var count=0; for(var i=data.length-1;i>=0;--i) { count=0; for(var j=i;j>=0;--j) { if (data[j]) ++count; else break; } result[i]=count; } } } else { if (data) result=1; else result=0; } return result; } //取整. //用法: INTPART(A)返回沿A绝对值减小方向最接近的整数 //例如:INTPART(12.3)求得12,INTPART(-3.5)求得-3 this.INTPART=function(data) { var result=null; if (Array.isArray(data)) { result=[]; for(var i in data) { var item=data[i]; if (this.IsNumber(item)) result[i]=parseInt(item); else result[i]=null; } } else if (this.IsNumber(data)) { result=parseInt(data); } return result; } //函数调用 this.CallFunction=function(name,args,node) { switch(name) { case 'MAX': return this.MAX(args[0], args[1]); case 'MIN': return this.MIN(args[0], args[1]); case 'REF': return this.REF(args[0], args[1]); case "REFV": return this.REFV(args[0], args[1]); case 'REFX': return this.REFX(args[0], args[1]); case "REFXV": return this.REFXV(args[0], args[1]); case 'ABS': return this.ABS(args[0]); case 'MA': return this.MA(args[0], args[1]); case "EMA": return this.EMA(args[0], args[1]); case "SMA": return this.SMA(args[0], args[1],args[2]); case "DMA": return this.DMA(args[0], args[1]); case "XMA": return this.XMA(args[0], args[1]); case 'EXPMA': return this.EXPMA(args[0], args[1]); case 'EXPMEMA': return this.EXPMEMA(args[0], args[1]); case 'COUNT': return this.COUNT(args[0], args[1]); case 'LLV': return this.LLV(args[0], args[1]); case 'LLVBARS': return this.LLVBARS(args[0], args[1]); case 'HHV': return this.HHV(args[0], args[1]); case 'HHVBARS': return this.HHVBARS(args[0], args[1]); case 'MULAR': return this.MULAR(args[0], args[1]); case 'CROSS': return this.CROSS(args[0], args[1]); case 'LONGCROSS': return this.LONGCROSS(args[0], args[1], args[2]); case 'AVEDEV': return this.AVEDEV(args[0], args[1]); case 'STD': return this.STD(args[0], args[1]); case 'IF': case 'IFF': return this.IF(args[0], args[1], args[2]); case 'IFN': return this.IFN(args[0], args[1], args[2]); case 'NOT': return this.NOT(args[0]); case 'SUM': return this.SUM(args[0], args[1]); case 'RANGE': return this.RANGE(args[0],args[1],args[2]); case 'EXIST': return this.EXIST(args[0],args[1]); case 'EXISTR': return this.EXISTR(args[0], args[1], args[2]); case 'FILTER': return this.FILTER(args[0], args[1]); case 'TFILTER': return this.TFILTER(args[0],args[1],args[2]); case 'SLOPE': return this.SLOPE(args[0],args[1]); case 'BARSLAST': return this.BARSLAST(args[0]); case 'BARSCOUNT': return this.BARSCOUNT(args[0]); case 'BARSSINCEN': return this.BARSSINCEN(args[0], args[1]); case 'BARSSINCE': return this.BARSSINCE(args[0]); case 'LAST': return this.LAST(args[0], args[1], args[2]); case 'EVERY': return this.EVERY(args[0], args[1]); case 'ZIG': return this.ZIG(args[0], args[1]); case 'TROUGHBARS': return this.TROUGHBARS(args[0], args[1], args[2]); case "TROUGH": return this.TROUGH(args[0],args[1],args[2]); case 'PEAKBARS': return this.PEAKBARS(args[0], args[1], args[2]); case 'PEAK': return this.PEAK(args[0],args[1],args[2]); case 'COST': return this.COST(args[0], node); case 'WINNER': return this.WINNER(args[0], node); case 'UPNDAY': return this.UPNDAY(args[0], args[1]); case 'DOWNNDAY': return this.DOWNNDAY(args[0], args[1]); case 'NDAY': return this.NDAY(args[0], args[1], args[2]); case 'DEVSQ': return this.DEVSQ(args[0], args[1]); case 'FORCAST': return this.FORCAST(args[0], args[1]); case 'STDP': return this.STDP(args[0], args[1]); case 'VAR': return this.VAR(args[0], args[1]); case 'VARP': return this.VARP(args[0], args[1]); case 'RELATE': return this.RELATE(args[0], args[1], args[2]); case 'COVAR': return this.COVAR(args[0], args[1], args[2]); case 'BETA': return this.BETA(args[0]); case 'BETA2': return this.BETA2(args[0], args[1], args[2]); case 'WMA': return this.WMA(args[0], args[1]); case 'MEMA': return this.MEMA(args[0], args[1]); case 'SUMBARS': return this.SUMBARS(args[0], args[1]); case 'REVERSE': return this.REVERSE(args[0]); case 'SAR': return this.SAR(args[0], args[1], args[2]); case 'SARTURN': return this.SARTURN(args[0], args[1], args[2]); case 'BACKSET': return this.BACKSET(args[0], args[1]); case 'STRCAT': return this.STRCAT(args[0], args[1]); case "VARCAT": return this.VARCAT(args[0], args[1]); case "VAR2STR": return this.VAR2STR(args[0], args[1]); case 'CON2STR': return this.CON2STR(args[0], args[1]); case "STRSPACE": return this.STRSPACE(args[0]); case 'DTPRICE': return this.DTPRICE(args[0], args[1]); case 'ZTPRICE': return this.ZTPRICE(args[0], args[1]); case 'FRACPART': return this.FRACPART(args[0]); case 'BARSLASTCOUNT': return this.BARSLASTCOUNT(args[0]); case 'INTPART': return this.INTPART(args[0]); //三角函数 case 'ATAN': return this.Trigonometric(args[0], Math.atan); case 'ACOS': return this.ACOS(args[0]); case 'ASIN': return this.ASIN(args[0]); case 'COS': return this.Trigonometric(args[0], Math.cos); case 'SIN': return this.Trigonometric(args[0], Math.sin); case 'TAN': return this.Trigonometric(args[0], Math.tan); case 'LN': return this.Trigonometric(args[0], Math.log); case 'LOG': return this.Trigonometric(args[0], Math.log10); case 'EXP': return this.Trigonometric(args[0], Math.exp); case 'SQRT': return this.Trigonometric(args[0], Math.sqrt); default: this.ThrowUnexpectedNode(node,'函数'+name+'不存在'); } } //调用自定义函数 返回数据格式{Out:输出数据, Draw:绘图数据(可选)} this.CallCustomFunction=function(name, args, symbolData, node) { var functionInfo=g_JSComplierResource.CustomFunction.Data.get(name); var dwonloadData=symbolData.GetStockCacheData({ CustomName:name, Node:node }); if (!functionInfo.Invoke) return { Out: dwonloadData } JSConsole.Complier.Log('[JSAlgorithm::CallCustomFunction] call custom function functionInfo=',functionInfo); var self=this; var obj= { Name:name, Args:args, Symbol:symbolData.Symbol, Period:symbolData.Period, Right:symbolData.Right, KData:symbolData.Data, //K线数据 DownloadData:dwonloadData, ThrowError:function(error) { self.ThrowUnexpectedNode(node, error); } }; return functionInfo.Invoke(obj); } this.ThrowUnexpectedNode=function(node,message) { let marker=node.Marker; let msg=message || "执行异常"; return this.ErrorHandler.ThrowError(marker.Index,marker.Line,marker.Column,msg); } } //是否有是有效的数字 JSAlgorithm.prototype.IsNumber=function(value) { if (value==null) return false; if (isNaN(value)) return false; return true; } //是否是整形 JSAlgorithm.prototype.IsInteger=function(x) { return (typeof x === 'number') && (x % 1 === 0); } //是否有是有效的除数 JSAlgorithm.prototype.IsDivideNumber=function(value) { if (value==null) return false; if (isNaN(value)) return false; if (value==0) return false; return true; } //是否是字符串 JSAlgorithm.prototype.IsString=function(value) { if (value && typeof(value)=='string') return true; return false; } /* 绘图函数 */ function JSDraw(errorHandler, symbolData) { this.ErrorHandler=errorHandler; this.SymbolData = symbolData; this.DRAWTEXT=function(condition,price,text) { let drawData=[]; let result={DrawData:drawData, DrawType:'DRAWTEXT',Text:text}; if (Array.isArray(condition)) { var IsNumber=this.IsNumber(price); for(var i in condition) { drawData[i]=null; if (isNaN(condition[i]) || !condition[i]) continue; if (IsNumber) { drawData[i]=price; } else { if (this.IsNumber(price[i])) drawData[i]=price[i]; } } } else if (this.IsNumber(condition) && condition) { var IsNumber=this.IsNumber(price); for(var i=0;i=HHV(HIGH,20),HIGH,LOW<=LLV(LOW,20),LOW,1) 表示在创20天新高与创20天新低之间画直线并且向右延长。 */ this.DRAWLINE=function(condition,data,condition2,data2,expand) { let drawData=[]; let result={DrawData:drawData, DrawType:'DRAWLINE', Expand:expand}; if(condition.length<=0) return result; let count=Math.max(condition.length,condition2.length); let bFirstPoint=false; let bSecondPont=false; let lineCache={Start:{ },End:{ }, List:new Array()}; for(let i=0;i=0;--i) { if (this.IsNumber(drawData[i])) { x2=i; break; } } //y3=(y1-y2)*(x3-x1)/(x2-x1) if (x2!=null && x2-1>=0) { var x1=x2-1; for(var i=x2+1;iVAL2时,在VAL1和VAL2之间填充COLOR1;当VAL1=HHV(HIGH,20),HIGH)表示在创20天新高点之间画折线。 */ this.POLYLINE = function (condition, data) { let drawData = []; let result = { DrawData: drawData, DrawType: 'POLYLINE' }; let isNumber = typeof (data) == 'number'; let bFirstPoint = false; let bSecondPont = false; if (isNumber) { for (let i in condition) { drawData[i] = null; if (bFirstPoint == false) { if (!condition[i]) continue; drawData[i] = data; bFirstPoint = true; } else { drawData[i] = data; } } } else { let lineCache = { Start: {}, End: {}, List: new Array() }; for (let i in condition) { drawData[i] = null; if (bFirstPoint == false && bSecondPont == false) { if (condition[i] == null || !condition[i]) continue; if (i >= data.length || !this.IsNumber(data[i])) continue; bFirstPoint = true; lineCache.Start = { ID: parseInt(i), Value: data[i] }; //第1个点 } else if (bFirstPoint == true && bSecondPont == false) { if (condition[i] == null || !condition[i]) continue; if (i >= data.length || !this.IsNumber(data[i])) continue; lineCache.End = { ID: parseInt(i), Value: data[i] }; //第2个点 //根据起始点和结束点 计算中间各个点的数据 let lineData = this.CalculateDrawLine(lineCache); //计算2个点的线上 其他点的数值 for (let j in lineData) { let item = lineData[j]; drawData[item.ID] = item.Value; } let start = { ID: lineCache.End.ID, Value: lineCache.End.Value }; lineCache = { Start: start, End: {} }; } } } return result } /* 画出数字. 用法: DRAWNUMBER(COND,PRICE,NUMBER),当COND条件满足时,在PRICE位置书写数字NUMBER. 例如: DRAWNUMBER(CLOSE/OPEN>1.08,LOW,C)表示当日实体阳线大于8%时在最低价位置显示收盘价. */ this.DRAWNUMBER = function (condition, data, data2) { let drawData = { Value: new Array(), Text: new Array() }; let result = { DrawData: drawData, DrawType: 'DRAWNUMBER' }; var isArrayData=Array.isArray(data); let isNumber = typeof (data2) == 'number'; let text; if (isNumber) { if (this.IsInteger(data2)) text=data2.toString(); else text=data2.toFixed(2); } for (let i in condition) { drawData.Value[i] = null; if (!condition[i]) continue; if (isArrayData) { if (i >= data.length || !this.IsNumber(data[i])) continue; if (isNumber) { drawData.Value[i] = data[i]; drawData.Text[i] = text; } else { if (i >= data2.length || !data2[i]) continue; drawData.Value[i] = data[i]; if (typeof(data2[i])=='number') drawData.Text[i] = data2[i].toFixed(2); else drawData.Text[i] = data2[i].toString(); } } else if (this.IsNumber(data)) { if (isNumber) { drawData.Value[i]=data; drawData.Text[i]=text; } else { if (i>=data2.length || !data2[i]) continue; drawData.Value[i]=data; if (this.IsNumber(data2[i])) drawData.Text[i] = data2[i].toFixed(2); else drawData.Text[i] = data2[i].toString(); } } } return result; } /* 在图形上绘制小图标. 用法: DRAWICON(COND,PRICE,TYPE),当COND条件满足时,在PRICE位置画TYPE号图标(TYPE为1--41). 例如: DRAWICON(CLOSE>OPEN,LOW,1)表示当收阳时在最低价位置画1号图标. */ this.DRAWICON = function (condition, data, type) { //图标对应的字符代码 let mapIcon = new Map([ [1, { Symbol: '↑', Color: 'rgb(238,44,44)' }], [2, { Symbol: '↓', Color: 'rgb(0,139,69)' }], [3, { Symbol: '😧' }], [4, { Symbol: '😨' }], [5, { Symbol: '😁' }], [6, { Symbol: '😱' }], [7, { Symbol: '◼', Color: 'rgb(238,44,44)' }], [8, { Symbol: '◆', Color: 'rgb(0,139,69)' }], [9, { Symbol: '💰' }], [10, { Symbol: '📪' }], [11, { Symbol: '👆' }], [12, { Symbol: '👇' }], [13, { Symbol: 'B', Color: 'rgb(178,34,34)' },], [14, { Symbol: 'S', Color: 'rgb(0,139,69)' }], [36, { Symbol: 'Χ', Color: 'rgb(238,44,44)' }], [37, { Symbol: 'X', Color: 'rgb(0,139,69)' }], [38, { Symbol: '▲', Color: 'rgb(238,44,44)' }], [39, { Symbol: '▼', Color: 'rgb(0,139,69)' }], ]); let icon = mapIcon.get(type); if (!icon) icon = { Symbol: '●', Color: 'rgb(0,139,69)'}; let drawData = []; let result = { DrawData: drawData, DrawType: 'DRAWICON', Icon: icon }; if (condition.length <= 0) return result; var IsNumber = typeof (data) == "number"; if (typeof (condition) == 'number') { if (!condition) return result; for (var i = 0; i < this.SymbolData.Data.Data.length; ++i) { if (IsNumber) { drawData[i] = data; } else { if (i < data.length && this.IsNumber(data[i])) drawData[i] = data[i]; else drawData[i] = null; } } return result; } for (var i in condition) { drawData[i] = null; if (!condition[i]) continue; if (IsNumber) { drawData[i] = data; } else { if (this.IsNumber(data[i])) drawData[i] = data[i]; } } return result; } // 相对位置上画矩形. //用法: DRAWRECTREL(LEFT,TOP,RIGHT,BOTTOM,COLOR),以图形窗口(LEFT,TOP)为左上角,(RIGHT,BOTTOM)为右下角绘制矩形,坐标单位是窗口沿水平和垂直方向的1/1000,取值范围是0—999,超出范围则可能显示在图形窗口外,矩形中间填充颜色COLOR,COLOR为0表示不填充. //例如: DRAWRECTREL(0,0,500,500,RGB(255,255,0))表示在图形最左上部1/4位置用黄色绘制矩形 this.DRAWRECTREL = function (left, top, right, bottom, color) { let drawData = { Rect: { Left: Math.min(left,right), Top: Math.min(top,bottom), Right: Math.max(left,right), Bottom: Math.max(top,bottom) }, Color: color }; if (color == 0) drawData.Color = null; let result = { DrawData: drawData, DrawType: 'DRAWRECTREL' }; return result; } //填充背景. //用法: DRAWGBK(COND,COLOR1,COLOR2,colorAngle) colorAngle=渐近色角度 //例如: DRAWGBK(O>C,RGB(0,255,0),RGB(255,0,0),0); this.DRAWGBK=function(condition, color, color2, colorAngle) { let drawData={ Color:[], Angle:colorAngle }; if (color) drawData.Color.push(color); if (color2) drawData.Color.push(color2); let result={DrawData:null, DrawType:'DRAWGBK'}; if (Array.isArray(condition)) { for(var i in condition) { var item=condition[i]; if (item) { result.DrawData=drawData; break; } } } else { if (condition) result.DrawData=drawData; } return result; } this.DRAWGBK2=function(condition, color, color2, colorAngle) { let drawData={ Color:[], Angle:colorAngle }; if (color) drawData.Color.push(color); if (color2) drawData.Color.push(color2); let result={DrawData:null, DrawType:'DRAWGBK2'}; if (Array.isArray(condition)) { drawData.Data=[]; for(var i in condition) { var item=condition[i]; drawData.Data[i]=item ? 1:0; } result.DrawData=drawData; } else { if (condition) { result.DrawData=drawData; result.DrawType="DRAWGBK"; } } return result; } this.RGB = function (r, g, b) { var rgb = `rgb(${r},${g},${b})`; return rgb; } this.RGBA = function (r, g, b, a) { var rgba = `rgba(${r},${g},${b},${a})`; return rgba; } } JSDraw.prototype.CalculateDrawLine=function(lineCache) { lineCache.List=[]; for(let i=lineCache.Start.ID; i<=lineCache.End.ID; ++i) lineCache.List.push(i); let height=Math.abs(lineCache.Start.Value-lineCache.End.Value); let width=lineCache.List.length-1; var result=[]; result.push({ID:lineCache.Start.ID, Value:lineCache.Start.Value}); //第1个点 if (lineCache.Start.Value>lineCache.End.Value) { for(let i=1;i0) this.MaxReqeustDataCount=option.MaxReqeustDataCount; if (option.MaxRequestMinuteDayCount>0) this.MaxRequestMinuteDayCount=option.MaxRequestMinuteDayCount; if (option.KLineApiUrl) this.KLineApiUrl=option.KLineApiUrl; if (option.NetworkFilter) this.NetworkFilter = option.NetworkFilter; } //最新行情 this.GetLatestData=function() { if (this.LatestData) return this.Execute.RunNextJob(); var self=this; wx.request({ url: self.RealtimeApiUrl, data: { "field": ["name","symbol","yclose","open","price","high","low","vol","amount","date","time","increase","exchangerate","amplitude"], "symbol": [this.Symbol] }, method:"POST", dataType: "json", success: function (recvData) { self.RecvLatestData(recvData); self.Execute.RunNextJob(); }, error: function(request) { self.RecvError(request); } }); } this.RecvLatestData = function (recvData) { let data=recvData.data; if (!data.stock || data.stock.length!=1) return; let stock=data.stock[0]; this.LatestData={ Symbol:stock.symbol, Name:stock.name, Date:stock.date, Time:stock.time, YClose:stock.yclose,Price:stock.price, Open:stock.open, High:stock.high, Low:stock.low, Vol:stock.vol, Amount:stock.amount, Increase:stock.increase, Exchangerate:stock.exchangerate, Amplitude:stock.amplitude}; JSConsole.Complier.Log('[JSSymbolData::RecvLatestData]', this.LatestData); } this.GetLatestCacheData=function(dataname) { if (!this.LatestData) return null; switch(dataname) { case DYNAINFO_ARGUMENT_ID.YCLOSE: return this.LatestData.YClose; case DYNAINFO_ARGUMENT_ID.OPEN: return this.LatestData.Open; case DYNAINFO_ARGUMENT_ID.HIGH: return this.LatestData.High; case DYNAINFO_ARGUMENT_ID.LOW: return this.LatestData.Low; case DYNAINFO_ARGUMENT_ID.VOL: return this.LatestData.Vol; case DYNAINFO_ARGUMENT_ID.AMOUNT: return this.LatestData.Amount; case DYNAINFO_ARGUMENT_ID.INCREASE: return this.LatestData.Increase; case DYNAINFO_ARGUMENT_ID.EXCHANGERATE: return this.LatestData.Exchangerate; case DYNAINFO_ARGUMENT_ID.AMPLITUDE: return this.LatestData.Amplitude; case DYNAINFO_ARGUMENT_ID.CLOSE: return this.LatestData.Price; default: return null; } } this.GetVolRateData = function (job, node) { var volrKey = job.ID.toString() + '-VolRate-' + this.Symbol; if (this.ExtendData.has(volrKey)) return this.Execute.RunNextJob(); var self = this; wx.request({ url: self.RealtimeApiUrl, data: { "field": ["name", "symbol", "avgvol5", 'date'], "symbol": [this.Symbol] }, method: "POST", dataType: "json", async: true, success: function (recvData) { self.RecvVolRateData(recvData, volrKey); self.Execute.RunNextJob(); }, error: function (request) { self.RecvError(request); } }); } this.RecvVolRateData = function (recvData, key) { var data=recvData.data; if (!data.stock || data.stock.length != 1) return; var avgVol5 = data.stock[0].avgvol5; var date = data.stock[0].date; var item = { AvgVol5: avgVol5, Date: date }; this.ExtendData.set(key, item); JSConsole.Complier.Log('[JSSymbolData::RecvVolRateData]', item); } this.GetVolRateCacheData = function (node) { var key = JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_VOLR_DATA.toString() + '-VolRate-' + this.Symbol; if (!key || !this.ExtendData.has(key)) this.Execute.ThrowUnexpectedNode(node, '不支持VOLR'); var result = []; var value = this.ExtendData.get(key); var avgVol5 = value.AvgVol5 / 241; var totalVol = 0; //5日成交总量只取了最新一天的,历史的暂时没有取,所以数据计算的时候只计算最新的一天, 其他都空 for (var i = 0, j = 0; i < this.Data.Data.length; ++i) { result[i] = null; var item = this.Data.Data[i]; var dateTime = item.DateTime; //日期加时间 if (!dateTime) continue; var aryValue = dateTime.split(' '); if (aryValue.length != 2) continue; var date = parseInt(aryValue[0]); if (date != value.Date) continue; totalVol += item.Vol; if (avgVol5 > 0) result[i] = totalVol / (j + 1) / avgVol5 * 100; ++j; } return result; } //获取大盘指数数据 this.GetIndexData=function() { if (this.IndexData) return this.Execute.RunNextJob(); var self=this; if (JSCommonData.ChartData.IsDayPeriod(this.Period,true)) //请求日线数据 { wx.request({ url: self.KLineApiUrl, data: { "field": ["name", "symbol", "yclose", "open", "price", "high", "low", "vol", 'up', 'down', 'stop', 'unchanged'], "symbol": '000001.sh', "start": -1, "count": self.MaxReqeustDataCount+500 //多请求2年的数据 确保股票剔除停牌日期以后可以对上 }, method: 'POST', dataType: "json", success: function (recvData) { self.RecvIndexHistroyData(recvData); self.Execute.RunNextJob(); }, error: function(request) { self.RecvError(request); } }); } else if (JSCommonData.ChartData.IsMinutePeriod(this.Period, true)) //请求分钟数据 { wx.request({ url: self.MinuteKLineApiUrl, data: { "field": ["name","symbol","yclose","open","price","high","low","vol"], "symbol": '000001.sh', "start": -1, "count": self.MaxRequestMinuteDayCount+5 }, method: 'POST', dataType: "json", success: function (data) { self.RecvIndexMinuteHistroyData(data); self.Execute.RunNextJob(); }, error: function(request) { self.RecvError(request); } }); } } this.RecvIndexHistroyData=function(recvData) { let data = recvData.data; JSConsole.Complier.Log('[JSSymbolData::RecvIndexHistroyData] recv data' , data); let hisData=this.JsonDataToHistoryData(data); this.IndexData = new JSCommonData.ChartData(); this.IndexData.DataType=0; /*日线数据 */ this.IndexData.Data=hisData; var aryOverlayData = this.SourceData.GetOverlayData(this.IndexData.Data); //和主图数据拟合以后的数据 this.IndexData.Data=aryOverlayData; if (JSCommonData.ChartData.IsDayPeriod(this.Period, false)) //周期数据 { let periodData=this.IndexData.GetPeriodData(this.Period); this.IndexData.Data=periodData; } } this.RecvIndexMinuteHistroyData = function (recvData) { let data = recvData.data; JSConsole.Complier.Log('[JSSymbolData::RecvIndexMinuteHistroyData] recv data' , data); let hisData=this.JsonDataToMinuteHistoryData(data); this.IndexData = new JSCommonData.ChartData(); this.IndexData.DataType=1; /*分钟线数据 */ this.IndexData.Data=hisData; if (JSCommonData.ChartData.IsMinutePeriod(this.Period, false)) //周期数据 { let periodData=this.IndexData.GetPeriodData(this.Period); this.IndexData.Data=periodData; } } //获取大盘指数缓存数据 this.GetIndexCacheData=function(dataName) { if (!this.IndexData) return new Array(); switch(dataName) { case 'INDEXA': return this.IndexData.GetAmount(); case 'INDEXC': return this.IndexData.GetClose(); case 'INDEXH': return this.IndexData.GetHigh(); case 'INDEXL': return this.IndexData.GetLow(); case 'INDEXO': return this.IndexData.GetOpen(); case 'INDEXV': return this.IndexData.GetVol(); case 'INDEXADV': return this.IndexData.GetUp(); case 'INDEXDEC': return this.IndexData.GetDown(); } } //分钟涨幅股票个数统计数据下载 this.GetIndexIncreaseData = function (job) { var upKey = job.ID.toString() + '-UpCount-' + job.Symbol; var downKey = job.ID.toString() + '-DownCount-' + job.Symbol; if (this.ExtendData.has(upKey) && this.ExtendData.has(downKey)) return this.Execute.RunNextJob(); var symbol = job.Symbol; symbol = symbol.replace('.CI', '.ci'); var self = this; var apiUrl = g_JSComplierResource.CacheDomain + '/cache/analyze/increaseanalyze/' + symbol + '.json'; JSConsole.Complier.Log('[JSSymbolData::GetIndexIncreaseData] Get url=', apiUrl); wx.request({ url: apiUrl, method: "GET", dataType: "json", success: function (data) { self.RecvMinuteIncreaseData(data, { UpKey: upKey, DownKey: downKey }); self.Execute.RunNextJob(); }, error: function (request) { self.RecvError(request); } }); } this.RecvMinuteIncreaseData = function (recvData, key) { JSConsole.Complier.Log('[JSSymbolData::RecvMinuteIncreaseData] recv data', recvData); var data=recvData.data; if (!data.minute) return; var minuteData = data.minute; if (!minuteData.time || !minuteData.up || !minuteData.down) return; var upData = [], downData = []; for (var i = 0; i < minuteData.time.length; ++i) { upData[i] = minuteData.up[i]; downData[i] = minuteData.down[i]; } this.ExtendData.set(key.UpKey, upData); this.ExtendData.set(key.DownKey, downData); } //分钟涨幅股票个数统计数据 this.GetIndexIncreaseCacheData = function (funcName, symbol, node) { var key; if (funcName == 'UPCOUNT') key = JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_INDEX_INCREASE_DATA.toString() + '-UpCount-' + symbol; else if (funcName == 'DOWNCOUNT') key = JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_INDEX_INCREASE_DATA.toString() + '-DownCount-' + symbol; if (!key || !this.ExtendData.has(key)) this.Execute.ThrowUnexpectedNode(node, '不支持函数' + funcName + '(' + symbol + ')'); return this.ExtendData.get(key); } this.GetSymbolData=function() { if (this.Data) return this.Execute.RunNextJob(); let self=this; if (this.DataType === 2) //当天分钟数据 { wx.request({ url: self.RealtimeApiUrl, data: { "field": ["name", "symbol", "yclose", "open", "price", "high", "low", "vol", "amount", "date", "minute", "time", "minutecount"], "symbol": [self.Symbol], "start": -1 }, method: 'POST', dataType: "json", async: true, success: function (recvData) { self.RecvMinuteData(recvData); self.Execute.RunNextJob(); } }); return; } if (JSCommonData.ChartData.IsDayPeriod(this.Period,true)) //请求日线数据 { wx.request({ url: self.KLineApiUrl, data: { "field": [ "name", "symbol","yclose","open","price","high","low","vol"], "symbol": self.Symbol, "start": -1, "count": self.MaxReqeustDataCount }, method: 'POST', dataType: "json", async:true, success: function (recvData) { self.RecvHistroyData(recvData); self.Execute.RunNextJob(); }, error: function(request) { self.RecvError(request); } }); } else if (JSCommonData.ChartData.IsMinutePeriod(this.Period, true)) //请求分钟数据 { wx.request({ url: this.MinuteKLineApiUrl, data: { "field": ["name","symbol","yclose","open","price","high","low","vol"], "symbol": self.Symbol, "start": -1, "count": self.MaxRequestMinuteDayCount }, method: 'POST', dataType: "json", async:true, success: function (data) { self.RecvMinuteHistroyData(data); self.Execute.RunNextJob(); }, error: function(request) { self.RecvError(request); } }); } } this.RecvHistroyData=function(recvData) { let data=recvData.data; JSConsole.Complier.Log('[JSSymbolData::RecvHistroyData] recv data' , data); let hisData=this.JsonDataToHistoryData(data); this.Data=new JSCommonData.ChartData(); this.Data.DataType=0; /*日线数据 */ this.Data.Data=hisData; this.SourceData = new JSCommonData.ChartData; this.SourceData.Data = hisData; if (this.Right>0) //复权 { let rightData=this.Data.GetRightDate(this.Right); this.Data.Data=rightData; } if (JSCommonData.ChartData.IsDayPeriod(this.Period, false)) //周期数据 { let periodData=this.Data.GetPeriodData(this.Period); this.Data.Data=periodData; } this.Name = data.name; } this.RecvMinuteHistroyData = function (recvData) { let data = recvData.data; JSConsole.Complier.Log('[JSSymbolData::RecvMinuteHistroyData] recv data' , data); let hisData=this.JsonDataToMinuteHistoryData(data); this.Data = new JSCommonData.ChartData(); this.Data.DataType=1; /*分钟线数据 */ this.Data.Data=hisData; this.SourceData = new JSCommonData.ChartData; this.SourceData.Data = hisData; if (JSCommonData.ChartData.IsMinutePeriod(this.Period, false)) //周期数据 { let periodData=this.Data.GetPeriodData(this.Period); this.Data.Data=periodData; } this.Name = data.name; } //最新的分钟数据走势图 this.RecvMinuteData = function (recvData) { let data = recvData.data; JSConsole.Complier.Log('[JSSymbolData::RecvMinuteData] recv data', data); var aryMinuteData = this.JsonDataToMinuteData(data); this.Data = new JSCommonData.ChartData(); this.Data.DataType = 2; /*分钟走势图数据 */ this.Data.Data = aryMinuteData; this.Name = data.stock[0].name; } this.GetSymbolCacheData=function(dataName) { if (!this.Data) return new Array(); switch(dataName) { case 'CLOSE': case 'C': return this.Data.GetClose(); case 'VOL': case 'V': return this.Data.GetVol(); case 'OPEN': case 'O': return this.Data.GetOpen(); case 'HIGH': case 'H': return this.Data.GetHigh(); case 'LOW': case 'L': return this.Data.GetLow(); case 'AMOUNT': case 'AMO': return this.Data.GetAmount(); case 'VOLINSTK': return this.Data.GetPosition(); } } this.GetCurrBarsCount=function() { if (!this.Data || !this.Data.Data || !this.Data.Data.length) return new Array(); let lCount=this.Data.Data.length; let result=[]; for(let i=lCount-1;i>=0;--i) result.push(i); return result; } this.GetIsLastBar = function () { let result = []; if (!this.Data || !this.Data.Data || !this.Data.Data.length) return result let lCount = this.Data.Data.length; for (let i = 0; i < lCount; ++i) { if (i == lCount - 1) result.push(1); else result.push(0); } return result; } //融资融券函数 this.GetMarginCacheData = function (id, node) { let jobID = JS_EXECUTE_JOB_ID.GetMarginJobID(id); if (!jobID) this.Execute.ThrowUnexpectedNode(node, '不支持MARGIN(' + id + ')'); if (this.MarginData.has(jobID)) return this.MarginData.get(jobID); return []; } //下融资融券 this.GetMarginData = function (jobID) { if (this.MarginData.has(jobID)) return this.Execute.RunNextJob(); JSConsole.Complier.Log('[JSSymbolData::GetMarginData] jobID=', jobID); var self = this; let fieldList = ["name", "date", "symbol"]; switch (jobID) { case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BALANCE: //融资融券余额 fieldList.push("margin.balance"); break; case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_RATE: //融资占比 fieldList.push("margin.rate"); break; case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BUY_BALANCE: //买入信息-融资余额 case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BUY_AMOUNT: //买入信息-买入额 case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BUY_REPAY: //买入信息-偿还额 case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BUY_NET: //买入信息-融资净买入 fieldList.push("margin.buy"); break; case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_SELL_BALANCE: //卖出信息-融券余量 case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_SELL_VOLUME: //卖出信息-卖出量 case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_SELL_REPAY: //卖出信息-偿还量 case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_SELL_NET: //卖出信息-融券净卖出 fieldList.push("margin.sell"); break; } //请求数据 wx.request({ url: this.StockHistoryDayApiUrl, data: { "field": fieldList, "symbol": [this.Symbol], "orderfield": "date" }, method: 'POST', dataType: "json", async: true, success: function (recvData) { self.RecvMarginData(recvData, jobID); self.Execute.RunNextJob(); } }); } this.RecvMarginData = function (recvData, jobID) { var data = recvData.data; //JSConsole.Complier.Log(data); if (!data.stock || data.stock.length != 1) return; let stock = data.stock[0]; var aryData = new Array(); var aryData2 = [], aryData3 = [], aryData4 = []; //其他3个数据 for (let i in stock.stockday) { var item = stock.stockday[i]; var marginData = item.margin; if (!marginData) continue; let indexData = new JSCommonData.SingleData(); indexData.Date = item.date; switch (jobID) { case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BALANCE: if (!this.IsNumber(marginData.balance)) continue; indexData.Value = marginData.balance; //融资融券余额 aryData.push(indexData); break; case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_RATE: if (!this.IsNumber(marginData.rate)) continue; indexData.Value = marginData.rate; //融资占比 aryData.push(indexData); break; case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BUY_BALANCE: //买入信息-融资余额 case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BUY_AMOUNT: //买入信息-买入额 case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BUY_REPAY: //买入信息-偿还额 case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BUY_NET: //买入信息-融资净买入 var buyData = marginData.buy; if (!buyData) continue; if (!this.IsNumber(buyData.balance) || !this.IsNumber(buyData.amount) || !this.IsNumber(buyData.repay) || !this.IsNumber(buyData.net)) continue; indexData.Value = buyData.balance; var indexData2 = new JSCommonData.SingleData(); indexData2.Date = item.date; indexData2.Value = buyData.amount; var indexData3 = new JSCommonData.SingleData(); indexData3.Date = item.date; indexData3.Value = buyData.repay; var indexData4 = new JSCommonData.SingleData(); indexData4.Date = item.date; indexData4.Value = buyData.net; aryData.push(indexData); aryData2.push(indexData2); aryData3.push(indexData3); aryData4.push(indexData4); break; case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_SELL_BALANCE: //卖出信息-融券余量 case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_SELL_VOLUME: //卖出信息-卖出量 case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_SELL_REPAY: //卖出信息-偿还量 case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_SELL_NET: //卖出信息-融券净卖出 var sellData = marginData.sell; if (!sellData) continue; if (!this.IsNumber(sellData.balance) || !this.IsNumber(sellData.volume) || !this.IsNumber(sellData.repay) || !this.IsNumber(sellData.net)) continue; indexData.Value = buyData.balance; var indexData2 = new JSCommonData.SingleData(); indexData2.Date = item.date; indexData2.Value = buyData.volume; var indexData3 = new JSCommonData.SingleData(); indexData3.Date = item.date; indexData3.Value = buyData.repay; var indexData4 = new JSCommonData.SingleData(); indexData4.Date = item.date; indexData4.Value = buyData.net; aryData.push(indexData); aryData2.push(indexData2); aryData3.push(indexData3); aryData4.push(indexData4); break; default: continue; } } var allData = []; if (jobID === JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BALANCE || jobID === JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_RATE) { allData.push({ JobID: jobID, Data: aryData }); } else if (jobID === JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BUY_BALANCE || jobID === JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BUY_AMOUNT || jobID === JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BUY_REPAY || jobID === JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BUY_NET) { allData.push({ JobID: JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BUY_BALANCE, Data: aryData }); allData.push({ JobID: JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BUY_AMOUNT, Data: aryData2 }); allData.push({ JobID: JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BUY_REPAY, Data: aryData3 }); allData.push({ JobID: JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BUY_NET, Data: aryData4 }); } else if (jobID === JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_SELL_BALANCE || jobID === JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_SELL_VOLUME || jobID === JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_SELL_REPAY || jobID === JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_SELL_NET) { allData.push({ JobID: JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_SELL_BALANCE, Data: aryData }); allData.push({ JobID: JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_SELL_VOLUME, Data: aryData2 }); allData.push({ JobID: JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_SELL_REPAY, Data: aryData3 }); allData.push({ JobID: JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_SELL_NET, Data: aryData4 }); } for (let i in allData) { let aryFixedData = this.Data.GetFittingData(allData[i].Data); var bindData = new JSCommonData.ChartData(); bindData.Data = aryFixedData; bindData.Period = this.Period; //周期 if (bindData.Period > 0) //周期数据 { var periodData = bindData.GetPeriodSingleData(bindData.Period); bindData.Data = periodData; } let data = bindData.GetValue(); this.MarginData.set(allData[i].JobID, data); } } this.GetNewsAnalysisCacheData = function (id, node) { let jobID = JS_EXECUTE_JOB_ID.GetNewsAnalysisID(id); if (!jobID) this.Execute.ThrowUnexpectedNode(node, '不支持NEWS(' + id + ')'); if (this.NewsAnalysisData.has(jobID)) return this.NewsAnalysisData.get(jobID); return []; } //下载新闻统计 this.GetNewsAnalysisData = function (jobID) { if (this.NewsAnalysisData.has(jobID)) return this.Execute.RunNextJob(); var self = this; var mapFolder = new Map([ [JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_NEGATIVE, "negative"], [JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_RESEARCH, 'research'], [JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_INTERACT, 'interact'], [JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_HOLDERCHANGE, 'holderchange'], //NEWS(4) 股东增持 [JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_HOLDERCHANGE2, 'holderchange'], //NEWS(5) 股东减持 [JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_TRUSTHOLDER, 'trustholder'], //NEWS(6) 信托持股 [JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_BLOCKTRADING, 'Blocktrading'], //NEWS(7) 大宗交易 [JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_COMPANYNEWS, 'companynews'], //NEWS(8) 官网新闻 [JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_TOPMANAGERS, 'topmanagers'], //NEWS(9) 高管要闻 [JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_PLEDGE, 'Pledge'], //NEWS(10) 股权质押 ]); if (!mapFolder.has(jobID)) { this.Execute.RunNextJob(); return; } var folderName = mapFolder.get(jobID); var url = this.StockNewsAnalysisApiUrl + '/' + folderName + '/' + this.Symbol + '.json'; //请求数据 wx.request({ url: url, method: 'GET', dataType: "json", async: true, success: function (recvData) { if (recvData.statusCode==200) self.RecvNewsAnalysisData(recvData, jobID); else self.RecvNewsAnalysisDataError(recvData, jobID); self.Execute.RunNextJob(); }, fail: function (request, textStatus) { //self.RecvNewsAnalysisDataError(request, textStatus, jobID); self.Execute.RunNextJob(); } }); } this.RecvNewsAnalysisDataError = function (recvData, jobID) { JSConsole.Complier.Log('[JSSymbolData::RecvNewsAnalysisDataError] request error.', recvData.statusCode); //没有新闻使用0数据填充 var aryData = []; for (var i = 0; i < this.Data.Data.length; ++i) { var item = new JSCommonData.SingleData(); item.Date = this.Data.Data[i].Date; item.Value = 0 aryData.push(item); } var bindData = new JSCommonData.ChartData(); bindData.Data = aryData; this.NewsAnalysisData.set(jobID, bindData.GetValue()); } this.RecvNewsAnalysisData = function (recvData, jobID) { var data=recvData.data; if (!data.data || !data.date) return; if (data.data.length <= 0 || data.data.length != data.date.length) return; JSConsole.Complier.Log('[JSSymbolData::RecvNewsAnalysisData] jobID', jobID, data.update); if (jobID == JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_HOLDERCHANGE || jobID == JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_HOLDERCHANGE2) { var aryData = [], aryData2 = []; for (var i = 0; i < data.data.length; ++i) { var item = new JSCommonData.SingleData(); item.Date = data.date[i]; item.Value = data.data[i]; if (this.IsNumber(item.Value)) aryData.push(item); if (i < data.data2.length) { item = new JSCommonData.SingleData(); item.Date = data.date[i]; item.Value = data.data2[i]; if (this.IsNumber(item.Value)) aryData2.push(item); } } let aryFixedData = this.Data.GetFittingData2(aryData, 0); var bindData = new JSCommonData.ChartData(); bindData.Data = aryFixedData; this.NewsAnalysisData.set(JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_HOLDERCHANGE, bindData.GetValue()); aryFixedData = this.Data.GetFittingData2(aryData2, 0); bindData = new JSCommonData.ChartData(); bindData.Data = aryFixedData; this.NewsAnalysisData.set(JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_HOLDERCHANGE2, bindData.GetValue()); } else { var aryData = []; for (var i = 0; i < data.data.length; ++i) { var item = new JSCommonData.SingleData(); item.Date = data.date[i]; item.Value = data.data[i]; aryData.push(item); } let aryFixedData = this.Data.GetFittingData2(aryData, 0); var bindData = new JSCommonData.ChartData(); bindData.Data = aryFixedData; this.NewsAnalysisData.set(jobID, bindData.GetValue()); } } this.GetStockDataKey=function(jobItem, aryArgs) { var key=jobItem.FunctionName; if (aryArgs.length>0) { key+="("; for(var i=0;i0) key+=","; key+=aryArgs[i].toString(); } key+=")"; } return key; } this.GetFinOne=function(jobItem) { var aryArgs=this.JobArgumentsToArray(jobItem, 3); var key=this.GetStockDataKey(jobItem,aryArgs); if (this.StockData.has(key)) return this.Execute.RunNextJob(); var self=this; if (this.NetworkFilter) { var dateRange=this.Data.GetDateRange(); var obj= { Name:'JSSymbolData::GetFinOne', //类名:: Explain:'财务数据FINONE(ID,Y,MMDD)', JobID:jobItem.ID, Request:{ Url:self.StockHistoryDayApiUrl, Type:'POST', Data:{ Args:aryArgs, symbol: this.Symbol, daterange:dateRange } }, Self:this, PreventDefault:false }; this.NetworkFilter(obj, function(recvData) { self.RecvStockValue(recvData,jobItem,key,1); self.Execute.RunNextJob(); }); if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求 } var apiDownload=new DownloadFinOneData( { Job:jobItem, Symbol:this.Symbol, Url:this.StockHistoryDayApiUrl, Args:aryArgs, DataKey:key, Callback:function(recvData, jobItem, key) { self.RecvStockValue(recvData, jobItem, key,1); self.Execute.RunNextJob(); }, ErrorCallback:function(strError) { self.AddStockValueError(key,strError); } }); apiDownload.Download(); } this.GetFinValue=function(jobItem) { var aryArgs=this.JobArgumentsToArray(jobItem, 1); var lID=aryArgs[0]; var key=this.GetStockDataKey(jobItem,aryArgs); if (this.StockData.has(key)) return this.Execute.RunNextJob(); var self=this; if (this.NetworkFilter) { var dateRange=this.Data.GetDateRange(); var obj= { Name:'JSSymbolData::GetFinValue', //类名:: Explain:'财务数据FINVALUE(ID)', JobID:jobItem.ID, Request:{ Url:self.StockHistoryDayApiUrl, Type:'POST', Data:{ id:lID, symbol: this.Symbol, daterange:dateRange } }, Self:this, PreventDefault:false }; this.NetworkFilter(obj, function(recvData) { self.RecvStockValue(recvData,jobItem,key,0); self.Execute.RunNextJob(); }); if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求 } var apiDownload=new DownloadFinValueData( { Job:jobItem, Symbol:this.Symbol, Url:this.StockHistoryDayApiUrl, Args:aryArgs, DataKey:key, Callback:function(recvData, jobItem, key) { self.RecvStockValue(recvData, jobItem, key,0); self.Execute.RunNextJob(); }, ErrorCallback:function(strError) { self.AddStockValueError(key,strError); } }); apiDownload.Download(); } this.GetFinance=function(jobItem) { var aryArgs=this.JobArgumentsToArray(jobItem, 1); var lID=aryArgs[0]; var key=this.GetStockDataKey(jobItem,aryArgs); if (this.StockData.has(key)) return this.Execute.RunNextJob(); var self=this; if (this.NetworkFilter) { var dateRange=this.Data.GetDateRange(); var obj= { Name:'JSSymbolData::GetFinance', //类名:: Explain:'财务数据FINANCE(ID)', JobID:jobItem.ID, Request:{ Url:self.RealtimeApiUrl, Type:'POST', Data:{ id:lID, symbol: this.Symbol, daterange:dateRange } }, Self:this, PreventDefault:false }; this.NetworkFilter(obj, function(recvData) { self.RecvStockValue(recvData,jobItem,key,0); self.Execute.RunNextJob(); }); if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求 } var apiDownload=new DownloadFinanceData( { Job:jobItem, Symbol:this.Symbol, Url:this.StockHistoryDayApiUrl, RealtimeUrl:this.RealtimeApiUrl, Args:aryArgs, DataKey:key, Callback:function(recvData, jobItem, key) { self.RecvStockValue(recvData, jobItem, key,0); self.Execute.RunNextJob(); }, ErrorCallback:function(strError) { self.AddStockValueError(key,strError); } }); apiDownload.Download(); } this.GetVariantData=function(jobItem) { var key=jobItem.VariantName; if (this.StockData.has(key)) return this.Execute.RunNextJob(); var self=this; if (this.NetworkFilter) { var dateRange=this.Data.GetDateRange(); var obj= { Name:'JSSymbolData::GetVariantData', //类名:: Explain:'变量数据下载', JobID:jobItem.ID, Request:{ Url:"www.121287.com", Type:'POST', Data:{ VariantName:jobItem.VariantName, symbol: this.Symbol, daterange:dateRange } }, Self:this, PreventDefault:false }; this.NetworkFilter(obj, function(recvData) { if (recvData.Error) { self.AddStockValueError(key,recvData.Error); } else { var dataType=0; if (IFrameSplitOperator.IsNumber(recvData.DataType)) dataType=recvData.DataType; self.RecvStockValue(recvData.Data,jobItem,key,dataType); } self.Execute.RunNextJob(); }); if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求 } var errorCallback=function(strError) { self.AddStockValueError(key,strError); }; var apiDownload; if (jobItem.VariantName=="CAPITAL" || jobItem.VariantName=="TOTALCAPITAL" || jobItem.VariantName=="EXCHANGE") { var callback=function(recvData, jobItem, key) { self.RecvStockValue(recvData, jobItem, key,0); self.Execute.RunNextJob(); }; apiDownload=new DownloadFinanceData( { Job:jobItem, Symbol:this.Symbol, Url:this.StockHistoryDayApiUrl, RealtimeUrl:this.RealtimeApiUrl, Args:[jobItem.VariantName], DataKey:key, Callback:callback, ErrorCallback:errorCallback }); } else if (jobItem.VariantName=="HYBLOCK" || jobItem.VariantName=="DYBLOCK" || jobItem.VariantName=="GNBLOCK") { var callback=function(recvData, jobItem, key, dataType) { self.RecvStockValue(recvData, jobItem, key, dataType); self.Execute.RunNextJob(); }; apiDownload=new DownloadGroupData( { Job:jobItem, Symbol:this.Symbol, Url:this.StockHistoryDayApiUrl, RealtimeUrl:this.RealtimeApiUrl, Args:[jobItem.VariantName], DataKey:key, Callback:callback, ErrorCallback:errorCallback }); } else if (jobItem.VariantName=="INBLOCK") { var errorMessage=`${jobItem.VariantName}, 请对接外部数据.`; this.AddStockValueError(key,errorMessage); this.Execute.RunNextJob(); return; } else { var errorMessage=`不支持变量${jobItem.VariantName}, 请对接外部数据.`; this.AddStockValueError(key,errorMessage); this.Execute.RunNextJob(); return; } apiDownload.Download(); } this.GetGPJYValue=function(jobItem) { var aryArgs=this.JobArgumentsToArray(jobItem, 3); var key=this.GetStockDataKey(jobItem,aryArgs); if (this.StockData.has(key)) return this.Execute.RunNextJob(); var self=this; //TYPE:为1表示做平滑处理,没有数据的周期返回上一周期的值;为0表示不做平滑处理 var dataType=aryArgs[2]==1?0:2; if (this.NetworkFilter) { var dateRange=this.Data.GetDateRange(); var obj= { Name:'JSSymbolData::GetGPJYValue', //类名:: Explain:'股票交易类数据GPJYVALUE(ID,N,TYPE)', JobID:jobItem.ID, Request:{ Url:self.StockHistoryDayApiUrl, Type:'POST', Data:{ Args:aryArgs, symbol: this.Symbol, daterange:dateRange } }, Self:this, PreventDefault:false }; this.NetworkFilter(obj, function(recvData) { self.RecvStockValue(recvData,jobItem,key,dataType); self.Execute.RunNextJob(); }); if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求 } var apiDownload=new DownloadGPJYValue( { Job:jobItem, Symbol:this.Symbol, Url:this.StockHistoryDayApiUrl, Args:aryArgs, DataKey:key, Callback:function(recvData, jobItem, key) { self.RecvStockValue(recvData, jobItem, key,dataType); self.Execute.RunNextJob(); }, ErrorCallback:function(strError) { self.AddStockValueError(key,strError); } }); apiDownload.Download(); } //自定义变量数据下载 this.GetCustomVariantData=function(jobItem) { var key=jobItem.VariantName; if (this.StockData.has(key)) return this.Execute.RunNextJob(); var variantInfo=g_JSComplierResource.CustomVariant.Data.get(key); var self=this; if (this.NetworkFilter) { var dateRange=this.Data.GetDateRange(); var obj= { Name:'JSSymbolData::GetCustomVariantData', //类名::函数名 Explain:'自定义变量数据下载', JobID:jobItem.ID, Request:{ Url:"www.121287.com", Type:'POST', Data:{ VariantName:jobItem.VariantName, symbol: this.Symbol, daterange:dateRange } }, Self:this, VariantInfo:variantInfo, PreventDefault:false }; this.NetworkFilter(obj, function(recvData) { if (recvData.Error) self.AddStockValueError(key,recvData.Error); else self.RecvStockValue(recvData.Data,jobItem,key,recvData.DataType); self.Execute.RunNextJob(); }); } else { this.AddStockValueError(key, `自定义变量${key}下载失败`); this.Execute.RunNextJob(); } } this.GetCustomFunctionData=function(jobItem) { var key=jobItem.FunctionName; var functionInfo=g_JSComplierResource.CustomFunction.Data.get(key); if (!functionInfo.IsDownload) return this.Execute.RunNextJob(); if (this.StockData.has(key)) return this.Execute.RunNextJob(); //一个函数只能缓存一个数据, 保存多个外部自己保存 var self=this; if (this.NetworkFilter) { var dateRange=this.Data.GetDateRange(); var obj= { Name:'JSSymbolData::GetCustomFunctionData', //类名::函数名 Explain:'自定义函数数据下载', JobID:jobItem.ID, Request: { Url:"www.121287.com", Type:'POST', Data: { FunctionName:jobItem.FunctionName, symbol: this.Symbol, daterange:dateRange, JobItem:jobItem //函数编译信息 } }, Self:this, FunctionInfo:functionInfo, PreventDefault:false }; this.NetworkFilter(obj, function(recvData) { if (recvData.Error) self.AddStockValueError(key,recvData.Error); else self.RecvStockValue(recvData.Data,jobItem,key,recvData.DataType); self.Execute.RunNextJob(); }); } else { this.AddStockValueError(key, `自定义函数${key}下载失败`); this.Execute.RunNextJob(); } } this.RecvStockValue=function(recvData,jobItem,key,dataType) { if (!recvData) { //JSConsole.Complier.Log(`[JSSymbolData::RecvStockValue] key=${key} data is null`); return; } if (dataType==0) { if (Array.isArray(recvData)) { var kdata=this.Data; //K线 var aryFittingData; if (JSCommonData.ChartData.IsDayPeriod(this.Period,true)) aryFittingData=kdata.GetFittingFinanceData(recvData); //数据和主图K线拟合 else if (JSCommonData.ChartData.IsMinutePeriod(this.Period,true)) aryFittingData=kdata.GetMinuteFittingFinanceData(recvData); //数据和主图K线拟合 else return; var bindData=new JSCommonData.ChartData(); bindData.Data=aryFittingData; var result=bindData.GetValue(); if (key=="EXCHANGE") //计算换手率=成交量/流通股本*100 { for(var i in result) { var kitem=kdata.Data[i]; if (result[i]>0) result[i]=kitem.Vol/result[i] * 100; } } this.StockData.set(key,{ Data:result }); } else { this.StockData.set(key,{ Data:recvData.Value }); } } else if (dataType==1) //单数值 { this.StockData.set(key,{ Data:recvData.Value }); } else if (dataType==2) //数据不做平滑处理 { var kdata=this.Data; //K线 var aryFittingData; if (JSCommonData.ChartData.IsDayPeriod(this.Period,true)) aryFittingData=kdata.GetFittingTradeData(recvData, 0, false); //数据和主图K线拟合 else if (JSCommonData.ChartData.IsMinutePeriod(this.Period,true)) aryFittingData=kdata.GetMinuteFittingTradeData(recvData, 0, false); //数据和主图K线拟合 else return; var bindData=new JSCommonData.ChartData(); bindData.Data=aryFittingData; var result=bindData.GetValue(); this.StockData.set(key,{ Data:result }); } } this.AddStockValueError=function(key, message) { this.StockData.set(key,{ Error:message }); } this.GetStockCacheData=function(obj) { var key; if (obj.FunctionName) key=this.GetStockDataKey({FunctionName:obj.FunctionName}, obj.Args); else if (obj.VariantName) key=obj.VariantName; else if (obj.CustomName) key=obj.CustomName; //自定义名字 else return null; if (!this.StockData.has(key)) return null; var data=this.StockData.get(key); if (data.Error) this.Execute.ThrowUnexpectedNode(obj.Node, data.Error); return data.Data; } this.IsInBlock=function(blockName, node) { var data=this.GetStockCacheData({ VariantName:"INBLOCK", Node:node }); if (!data) return 0; var aryBlock=data.split('|'); for(var i=0; i up) item.Up = list[i][up]; if (list[i].length > down) item.Down = list[i][down]; if (list[i].length > stop) item.Stop = list[i][stop]; if (list[i].length > unchanged) item.Unchanged = list[i][unchanged]; aryDayData.push(item); } return aryDayData; } this.JsonDataToMinuteHistoryData=function(data) { var list = data.data; var aryDayData=new Array(); var date = 0, yclose = 1, open = 2, high = 3, low = 4, close = 5, vol = 6, amount = 7, time = 8; for (var i = 0; i < list.length; ++i) { let item = new JSCommonData.HistoryData(); item.Date = list[i][date]; item.Open = list[i][open]; item.YClose = list[i][yclose]; item.Close = list[i][close]; item.High = list[i][high]; item.Low = list[i][low]; item.Vol = list[i][vol]; //原始单位股 item.Amount = list[i][amount]; item.Time=list[i][time]; // if (isNaN(item.Open) || item.Open<=0) continue; //停牌的数据剔除 aryDayData.push(item); } // 无效数据处理 for(let i = 0; i < aryDayData.length; ++i) { var minData = aryDayData[i]; if (minData == null) coninue; if (isNaN(minData.Open) || minData.Open <= 0 || isNaN(minData.High) || minData.High <= 0 || isNaN(minData.Low) || minData.Low <= 0 || isNaN(minData.Close) || minData.Close <= 0 || isNaN(minData.YClose) || minData.YClose <= 0) { if (i == 0) { if (minData.YClose > 0) { minData.Open = minData.YClose; minData.High = minData.YClose; minData.Low = minData.YClose; minData.Close = minData.YClose; } } else // 用前一个有效数据填充 { for(let j = i-1; j >= 0; --j) { var minData2 = aryDayData[j]; if (minData2 == null) coninue; if (minData2.Open > 0 && minData2.High > 0 && minData2.Low > 0 && minData2.Close > 0) { if (minData.YClose <= 0) minData.YClose = minData2.Close; minData.Open = minData2.Open; minData.High = minData2.High; minData.Low = minData2.Low; minData.Close = minData2.Close; break; } } } } } return aryDayData; } //API 返回数据 转化为array[] this.JsonDataToMinuteData = function (data) { var aryMinuteData = new Array(); for (var i in data.stock[0].minute) { var jsData = data.stock[0].minute[i]; var item = new JSCommonData.MinuteData(); item.Close = jsData.price; item.Open = jsData.open; item.High = jsData.high; item.Low = jsData.low; item.Vol = jsData.vol; //股 item.Amount = jsData.amount; if (i == 0) //第1个数据 写死9:25 item.DateTime = data.stock[0].date.toString() + " 0925"; else item.DateTime = data.stock[0].date.toString() + " " + jsData.time.toString(); item.Date = data.stock[0].date; item.Time = jsData.time; item.Increate = jsData.increate; item.Risefall = jsData.risefall; item.AvPrice = jsData.avprice; aryMinuteData[i] = item; } return aryMinuteData; } //CODELIKE 模糊股票代码 this.CODELIKE=function(value) { if (this.Symbol.indexOf(value)==0) return 1; return 0; } this.NAMELIKE = function (value) { if (this.Name && this.Name.indexOf(value) == 0) return 1; return 0; } /* SETCODE 市场类型 0:深圳 1:上海,47:中金所期货 28:郑州商品 29:大连商品 30:上海商品,27:香港指数 31:香港主板,48:香港创业板... */ this.SETCODE=function() { if (this.Symbol.indexOf('.sh')) return 1; if (this.Symbol.indexOf('.sz')) return 0; return 0; } this.GetSymbol = function () { return this.Symbol; } this.GetName = function () { return this.Name; } this.TIME=function() { var result = []; if (!this.Data || !this.Data.Data || !this.Data.Data.length) return result; for(let i in this.Data.Data) { var item=this.Data.Data[i]; if (this.IsNumber(item.Time)) result[i]=item.Time; else result[i]=0; } return result; } this.DATE = function () { var result = []; if (!this.Data || !this.Data.Data || !this.Data.Data.length) return result; for (let i in this.Data.Data) { var item = this.Data.Data[i]; result[i] = item.Date - 19000000;; } return result; } this.YEAR = function () { var result = []; if (!this.Data || !this.Data.Data || !this.Data.Data.length) return result; for (let i in this.Data.Data) { var item = this.Data.Data[i]; if (this.IsNumber(item.Date)) result[i] = parseInt(item.Date / 10000); else result[i] = null; } return result; } this.MONTH = function () { var result = []; if (!this.Data || !this.Data.Data || !this.Data.Data.length) return result; for (let i in this.Data.Data) { var item = this.Data.Data[i]; if (this.IsNumber(item.Date)) result[i] = parseInt(item.Date % 10000 / 100); else result[i] = null; } return result; } //星期 1-7 this.WEEK = function () { var result = []; if (!this.Data || !this.Data.Data || !this.Data.Data.length) return result; var tempDate = new Date(); for (let i in this.Data.Data) { var item = this.Data.Data[i]; result[i] = null; if (!this.IsNumber(item.Date)) continue; var year = parseInt(item.Date / 10000); var month = parseInt(item.Date % 10000 / 100); var day = item.Date % 100; tempDate.setFullYear(year); tempDate.setMonth(month - 1); tempDate.setDate(day); result[i] = tempDate.getDay(); } return result; } this.REFDATE = function (data, date) { var result = null; var findDate=null; if (Array.isArray(date)) { if (date.length>0) findDate=date[date.length-1]; } else if (this.IsNumber(date)) { findDate=date; } if (findDate==null) return null; if (findDate<5000000) findDate+=19000000; var index = null; for (let i in this.Data.Data) //查找日期对应的索引 { if (this.Data.Data[i].Date == findDate) { index = parseInt(i); break; } } if (index == null || index >= data.length) return null; return data[index]; } //用法:结果从0到11,依次分别是1/5/15/30/60分钟,日/周/月,多分钟,多日,季,年 this.PERIOD=function() { //Period周期 0=日线 1=周线 2=月线 3=年线 9=季线 4=1分钟 5=5分钟 6=15分钟 7=30分钟 8=60分钟 const PERIOD_MAP=[5,6,7,11, 0,1,2,3,4,5, 9]; if (this.Period >= 0 && this.Period <= PERIOD_MAP.length - 1) return PERIOD_MAP[this.Period]; return this.Period; } this.GetDrawNull = function () { var result = []; if (!this.Data || !this.Data.Data || !this.Data.Data.length) return result; for (let i in this.Data.Data) { result[i] = null; } return result; } } //是否有是有效的数字 JSSymbolData.prototype.IsNumber = function (value) { if (value == null) return false; if (isNaN(value)) return false; return true; } JSSymbolData.prototype.IsDivideNumber = function (value) { if (value == null) return false; if (isNaN(value)) return false; if (value == 0) return false; return true; } JSSymbolData.prototype.JsonDataToFinance = function (data) { var financeData; for (let i = 1; i <= 4; ++i) { switch (i) { case 1: var finance = data.finance1; var announcement = data.announcement1; break; case 2: var finance = data.finance2; var announcement = data.announcement2; break; case 3: var finance = data.finance3; var announcement = data.announcement3; break; case 4: var finance = data.finance4; var announcement = data.announcement4; break; default: break; } if (!finance || !announcement || !this.IsNumber(announcement.year) || !this.IsNumber(announcement.quarter)) continue; if (financeData) //如果存在1天公布多个报告期数据 只取最新的一个公告期数据 { if (financeData.Announcement.year < announcement.year) financeData = { Date: item.date, Finance: finance, Announcement: announcement }; } else { financeData = { Date: data.date, Finance: finance, Announcement: announcement }; } } return financeData; } var JS_EXECUTE_DEBUG_LOG=false; var JS_EXECUTE_JOB_ID= { JOB_DOWNLOAD_SYMBOL_DATA:1, //下载股票的K线数据 JOB_DOWNLOAD_INDEX_DATA:2, //下载大盘的K线数据 JOB_DOWNLOAD_SYMBOL_LATEST_DATA:3, //最新的股票行情数据 JOB_DOWNLOAD_INDEX_INCREASE_DATA: 4, //涨跌股票个数统计数据 JOB_DOWNLOAD_VOLR_DATA: 5, //5日量比均量下载量比数据 JOB_DOWNLOAD_FINVALUE:301, //引用专业财务数据 FINVALUE(ID),ID为数据编号 JOB_DOWNLOAD_FINONE:302, //引用指定年和月日的某类型的财务数据 FINONE(ID,Y,MMDD),ID为数据编号,Y和MMDD表示年和月日. JOB_DOWNLOAD_FINANCE:303, //FINANCE(ID) 基础财务数据 JOB_DOWNLOAD_GPJYVALUE:304, //引用股票交易类数据 GPJYVALUE(ID,N,TYPE),ID为数据编号,N表示第几个数据,TYPE:为1表示做平滑处理,没有数据的周期返回上一周期的值;为0表示不做平滑处理 JOB_DOWNLOAD_VARIANT:305, //CAPITAL , TOTALCAPITAL, EXCHANGE JOB_CUSTOM_FUNCTION_DATA:6000, //自定义函数 JOB_CUSTOM_VARIANT_DATA:6001, //自定义变量 JOB_DOWNLOAD_MARGIN_BALANCE: 1000, //融资融券余额 JOB_DOWNLOAD_MARGIN_RATE: 1001, //融资占比 JOB_DOWNLOAD_MARGIN_BUY_BALANCE: 1010, //买入信息-融资余额 JOB_DOWNLOAD_MARGIN_BUY_AMOUNT: 1011, //买入信息-买入额 JOB_DOWNLOAD_MARGIN_BUY_REPAY: 1012, //买入信息-偿还额 JOB_DOWNLOAD_MARGIN_BUY_NET: 1013, //买入信息-融资净买入 JOB_DOWNLOAD_MARGIN_SELL_BALANCE: 1020, //卖出信息-融券余量 JOB_DOWNLOAD_MARGIN_SELL_VOLUME: 1021, //卖出信息-卖出量 JOB_DOWNLOAD_MARGIN_SELL_REPAY: 1022, //卖出信息-偿还量 JOB_DOWNLOAD_MARGIN_SELL_NET: 1023, //卖出信息-融券净卖出 JOB_DOWNLOAD_NEWS_ANALYSIS_NEGATIVE: 2000, //负面新闻统计 JOB_DOWNLOAD_NEWS_ANALYSIS_RESEARCH: 2001, //机构调研 JOB_DOWNLOAD_NEWS_ANALYSIS_INTERACT: 2002, //互动易 JOB_DOWNLOAD_NEWS_ANALYSIS_HOLDERCHANGE: 2003, //股东增持 JOB_DOWNLOAD_NEWS_ANALYSIS_HOLDERCHANGE2: 2004, //股东减持 JOB_DOWNLOAD_NEWS_ANALYSIS_TRUSTHOLDER: 2005, //信托持股 JOB_DOWNLOAD_NEWS_ANALYSIS_BLOCKTRADING: 2006, //大宗交易 JOB_DOWNLOAD_NEWS_ANALYSIS_COMPANYNEWS: 2007, //官网新闻 JOB_DOWNLOAD_NEWS_ANALYSIS_TOPMANAGERS: 2008, //高管要闻 JOB_DOWNLOAD_NEWS_ANALYSIS_PLEDGE: 2009, //股权质押 JOB_CUSTOM_FUNCTION_DATA: 6000, //自定义函数 JOB_CUSTOM_VARIANT_DATA: 6001, //自定义变量 JOB_DOWNLOAD_CUSTOM_API_DATA: 30000, //自定义数据 JOB_RUN_SCRIPT:10000, //执行脚本 //融资融券 GetMarginJobID: function (value) { let dataMap = new Map([ [1, JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BALANCE], //MARGIN(1) 融资融券余额 [2, JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_RATE], //MARGIN(2) 融资占比 [3, JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BUY_BALANCE], //MARGIN(3) 买入信息-融资余额 [4, JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BUY_AMOUNT], //MARGIN(4) 买入信息-买入额 [5, JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BUY_REPAY], //MARGIN(5) 买入信息-偿还额 [6, JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BUY_NET], //MARGIN(6) 买入信息-融资净买入 [7, JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_SELL_BALANCE], //MARGIN(7) 卖出信息-融券余量 [8, JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_SELL_VOLUME], //MARGIN(8) 卖出信息-卖出量 [9, JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_SELL_REPAY], //MARGIN(9) 卖出信息-偿还量 [10, JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_SELL_NET], //MARGIN(10) 卖出信息-融券净卖出 ]); if (dataMap.has(value)) return dataMap.get(value); return null; }, GetNewsAnalysisID: function (value) { let dataMap = new Map([ [1, JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_NEGATIVE], //NEWS(1) 负面新闻统计 [2, JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_RESEARCH], //NEWS(2) 机构调研统计 [3, JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_INTERACT], //NEWS(3) 互动易 [4, JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_HOLDERCHANGE], //NEWS(4) 股东增持 [5, JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_HOLDERCHANGE2], //NEWS(5) 股东减持 [6, JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_TRUSTHOLDER], //NEWS(6) 信托持股 [7, JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_BLOCKTRADING], //NEWS(7) 大宗交易 [8, JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_COMPANYNEWS], //NEWS(8) 官网新闻 [9, JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_TOPMANAGERS], //NEWS(9) 高管要闻 [10, JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_PLEDGE], //NEWS(10) 股权质押 ]); if (dataMap.has(value)) return dataMap.get(value); return null; } }; function JSExecute(ast,option) { this.AST=ast; //语法树 this.ErrorHandler=new ErrorHandler(); this.VarTable=new Map(); //变量表 this.OutVarTable=new Array(); //输出变量 this.Arguments=[]; //脚本自动变量表, 只读 this.ConstVarTable=new Map([ //个股数据 ['CLOSE', null], ['VOL', null], ['OPEN', null], ['HIGH', null], ['LOW', null], ['AMOUNT', null], ['AMO', null], ['VOLINSTK',null], ['C', null], ['V', null], ['O', null], ['H', null], ['L', null], ['VOLR', null], //日期类 ['DATE', null], ['YEAR', null], ['MONTH', null], ['PERIOD', null], ['WEEK', null],["TIME",null], //大盘数据 ['INDEXA',null],['INDEXC',null],['INDEXH',null],['INDEXL',null],['INDEXO',null],['INDEXV',null], ['INDEXADV', null], ['INDEXDEC', null], ['CURRBARSCOUNT', null], //到最后交易日的周期数 ['ISLASTBAR', null], //判断是否为最后一个周期 ["TOTALCAPITAL",null], //总股本 ['CAPITAL', null], //流通股本(手) ['EXCHANGE', null], //换手率 ['SETCODE', null], //市场类型 ['CODE', null], //品种代码 ['STKNAME', null], //品种名称 ['HYBLOCK', null], //所属行业板块 ['DYBLOCK', null], //所属地域板块 ['GNBLOCK', null], //所属概念 ["FGBLOCK",null], //所属风格板块 ["ZSBLOCK",null], //所属指数板块 ["ZHBLOCK",null], //所属组合板块 ["ZDBLOCK",null], //所属自定义板块 ["HYZSCODE",null], ["GNBLOCKNUM",null], //所属概念板块的个数 ["FGBLOCKNUM",null], //所属风格板块的个数 ["ZSBLOCKNUM",null], //所属指数板块的个数 ["ZHBLOCKNUM",null], //所属组合板块的个数 ["ZDBLOCKNUM",null], //所属自定义板块的个数 ["HYSYL",null], //指数市盈率或个股所属行业的市盈率 ["HYSJL",null], //指数市净率或个股所属行业的市净率 ['DRAWNULL', null] ]); this.SymbolData=new JSSymbolData(this.AST,option,this); this.Algorithm = new JSAlgorithm(this.ErrorHandler, this.SymbolData); this.Draw = new JSDraw(this.ErrorHandler, this.SymbolData); this.JobList=[]; //执行的任务队列 this.UpdateUICallback=null; //回调 this.CallbackParam=null; if (option) { if (option.Callback) this.UpdateUICallback=option.Callback; if (option.CallbackParam) this.CallbackParam=option.CallbackParam; if (option.Arguments) this.Arguments=option.Arguments; } this.Execute=function() { JSConsole.Complier.Log('[JSExecute::Execute] JobList', this.JobList); this.RunNextJob(); } this.RunNextJob=function() { if (this.JobList.length<=0) return; var jobItem=this.JobList.shift(); switch (jobItem.ID) { case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SYMBOL_DATA: return this.SymbolData.GetSymbolData(); case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_INDEX_DATA: return this.SymbolData.GetIndexData(); case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_INDEX_INCREASE_DATA: return this.SymbolData.GetIndexIncreaseData(jobItem); case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SYMBOL_LATEST_DATA: return this.SymbolData.GetLatestData(); case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_VOLR_DATA: //量比 return this.SymbolData.GetVolRateData(jobItem); case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_FINONE: return this.SymbolData.GetFinOne(jobItem); case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_FINVALUE: return this.SymbolData.GetFinValue(jobItem); case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_FINANCE: return this.SymbolData.GetFinance(jobItem); case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_GPJYVALUE: return this.SymbolData.GetGPJYValue(jobItem); case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_VARIANT: //CAPITAL, TOTALCAPITAL return this.SymbolData.GetVariantData(jobItem); case JS_EXECUTE_JOB_ID.JOB_CUSTOM_VARIANT_DATA: return this.SymbolData.GetCustomVariantData(jobItem); case JS_EXECUTE_JOB_ID.JOB_CUSTOM_FUNCTION_DATA: return this.SymbolData.GetCustomFunctionData(jobItem); case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BALANCE: case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_RATE: case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BUY_BALANCE: //买入信息-融资余额 case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BUY_AMOUNT: //买入信息-买入额 case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BUY_REPAY: //买入信息-偿还额 case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BUY_NET: //买入信息-融资净买入 case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_SELL_BALANCE: //卖出信息-融券余量 case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_SELL_VOLUME: //卖出信息-卖出量 case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_SELL_REPAY: //卖出信息-偿还量 case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_SELL_NET: //卖出信息-融券净卖出 return this.SymbolData.GetMarginData(jobItem.ID); case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_NEGATIVE: //负面新闻 case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_RESEARCH: //机构调研 case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_INTERACT: //互动易 case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_HOLDERCHANGE: //股东增持 case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_HOLDERCHANGE2: //股东减持 case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_TRUSTHOLDER: //信托持股 case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_BLOCKTRADING: //大宗交易 case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_COMPANYNEWS: //官网新闻 case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_TOPMANAGERS: //高管要闻 case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_PLEDGE: //股权质押 return this.SymbolData.GetNewsAnalysisData(jobItem.ID); case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_CUSTOM_API_DATA: return this.SymbolData.DownloadCustomAPIData(jobItem); case JS_EXECUTE_JOB_ID.JOB_RUN_SCRIPT: return this.Run(); } } this.ReadSymbolData=function(name,node) { switch(name) { case 'CLOSE': case 'C': case 'VOL': case 'V': case 'OPEN': case 'O': case 'HIGH': case 'H': case 'LOW': case 'L': case 'AMOUNT': case 'VOLINSTK': return this.SymbolData.GetSymbolCacheData(name); case 'VOLR': return this.SymbolData.GetVolRateCacheData(node); //大盘数据 case 'INDEXA': case 'INDEXC': case 'INDEXH': case 'INDEXO': case 'INDEXV': case 'INDEXL': case 'INDEXADV': case 'INDEXDEC': return this.SymbolData.GetIndexCacheData(name); case 'CURRBARSCOUNT': return this.SymbolData.GetCurrBarsCount(); case 'ISLASTBAR': return this.SymbolData.GetIsLastBar(); case "TOTALCAPITAL": case 'CAPITAL': case 'EXCHANGE': case "HYBLOCK": case "DYBLOCK": case "GNBLOCK": case "FGBLOCK": case "ZSBLOCK": case "ZHBLOCK": case "ZDBLOCK": case "HYZSCODE": case "GNBLOCKNUM": case "FGBLOCKNUM": case "ZSBLOCKNUM": case "ZHBLOCKNUM": case "ZDBLOCKNUM": case "HYSYL": case "HYSJL": return this.SymbolData.GetStockCacheData({ VariantName:name, Node:node }); case 'SETCODE': return this.SymbolData.SETCODE(); case 'CODE': return this.SymbolData.GetSymbol(); case 'STKNAME': return this.SymbolData.GetName(); case 'TIME': return this.SymbolData.TIME(); case 'DATE': return this.SymbolData.DATE(); case 'YEAR': return this.SymbolData.YEAR(); case 'MONTH': return this.SymbolData.MONTH(); case 'WEEK': return this.SymbolData.WEEK(); case 'PERIOD': return this.SymbolData.PERIOD(); case 'DRAWNULL': return this.SymbolData.GetDrawNull(); } } this.ReadCustomVariant=function(name,node) { return this.SymbolData.GetStockCacheData({ VariantName:name, Node:node }); } //读取变量 this.ReadVariable=function(name,node) { if (this.ConstVarTable.has(name)) { let data=this.ConstVarTable.get(name); if (data==null) //动态加载,用到再加载 { data=this.ReadSymbolData(name,node); this.ConstVarTable.set(name,data); } return data; } if (g_JSComplierResource.IsCustomVariant(name)) return this.ReadCustomVariant(name,node); //读取自定义变量 if (this.VarTable.has(name)) return this.VarTable.get(name); this.ThrowUnexpectedNode(node, '变量'+name+'不存在'); return null; } this.ReadMemberVariable = function (node) { var obj = node.Object; var member = node.Property; let maiObj; if (obj.Type == Syntax.BinaryExpression || obj.Type == Syntax.LogicalExpression) maiObj = this.VisitBinaryExpression(obj); else if (obj.Type == Syntax.CallExpression) maiObj = this.VisitCallExpression(obj); else maiObj = this.GetNodeValue(obj); if (!maiObj) return null; var value = maiObj[member.Name]; if (value) return value; return null; } //单数据转成数组 个数和历史数据一致 this.SingleDataToArrayData = function (value) { let count = this.SymbolData.Data.Data.length; let result = []; for (let i = 0; i < count; ++i) { result[i] = value; } return result; } this.RunAST=function() { //预定义的变量 for(let i in this.Arguments) { let item =this.Arguments[i]; this.VarTable.set(item.Name,item.Value); } if (!this.AST) this.ThrowError(); if (!this.AST.Body) this.ThrowError(); for(let i in this.AST.Body) { let item =this.AST.Body[i]; this.VisitNode(item); //输出变量 if (item.Type==Syntax.ExpressionStatement && item.Expression) { if (item.Expression.Type==Syntax.AssignmentExpression && item.Expression.Operator==':' && item.Expression.Left) { let assignmentItem=item.Expression; let varName=assignmentItem.Left.Name; let outVar=this.VarTable.get(varName); var type=0; if (!Array.isArray(outVar)) { if (typeof (outVar) == 'string') { var floatValue=parseFloat(outVar); if (IFrameSplitOperator.IsNumber(floatValue)) { outVar=this.SingleDataToArrayData(floatValue); } else { outVar=this.SingleDataToArrayData(outVar); type=1001; } } else outVar = this.SingleDataToArrayData(outVar); } this.OutVarTable.push({Name:varName, Data:outVar,Type:type}); } else if (item.Expression.Type==Syntax.CallExpression) { let callItem=item.Expression; if (this.Draw.IsDrawFunction(callItem.Callee.Name)) { let draw=callItem.Draw; draw.Name=callItem.Callee.Name; this.OutVarTable.push({Name:draw.Name, Draw:draw, Type:1}); } else { let outVar=callItem.Out; varName=`__temp_c_${callItem.Callee.Name}_${i}__`; var type=0; if (!Array.isArray(outVar)) outVar=this.SingleDataToArrayData(outVar); this.OutVarTable.push({Name:varName, Data:outVar,Type:type,NoneName:true}); } } else if (item.Expression.Type==Syntax.Identifier) { let varName=item.Expression.Name; let outVar=this.ReadVariable(varName,item.Expression); var type=0; if (!Array.isArray(outVar)) { if (typeof(outVar)=='string') outVar=this.SingleDataToArrayData(parseFloat(outVar)); else outVar=this.SingleDataToArrayData(outVar); } varName="__temp_i_"+i+"__"; this.OutVarTable.push({Name:varName, Data:outVar, Type:type, NoneName:true}); } else if (item.Expression.Type==Syntax.BinaryExpression) { var varName="__temp_b_"+i+"__"; let outVar=item.Expression.Out; var type=0; if (!Array.isArray(outVar)) outVar=this.SingleDataToArrayData(outVar); this.OutVarTable.push({Name:varName, Data:outVar,Type:type, NoneName:true}); } else if (item.Expression.Type==Syntax.LogicalExpression) //逻辑语句 如 T1 AND T2 { var varName="__temp_l_"+i+"__"; let outVar=item.Expression.Out; var type=0; if (!Array.isArray(outVar)) outVar=this.SingleDataToArrayData(outVar); this.OutVarTable.push({Name:varName, Data:outVar,Type:type, NoneName:true}); } else if (item.Expression.Type==Syntax.SequenceExpression) { let varName; let draw; let color; let lineWidth; let colorStick=false; let pointDot=false; let circleDot=false; let lineStick=false; let stick=false; let volStick=false; let isShow = true; let isExData = false; let isDotLine = false; let isOverlayLine = false; //叠加线 let isNoneName=false; var isShowTitle=true; //显示在位置之上,对于DRAWTEXT和DRAWNUMBER等函数有用,放在语句的最后面(不能与LINETHICK等函数共用),比如: //DRAWNUMBER(CLOSE>OPEN,HIGH,CLOSE),DRAWABOVE; var isDrawAbove=false; for(let j in item.Expression.Expression) { let itemExpression=item.Expression.Expression[j]; if (itemExpression.Type==Syntax.AssignmentExpression && itemExpression.Operator==':' && itemExpression.Left) { varName = itemExpression.Left.Name; let varValue = this.VarTable.get(varName); if (!Array.isArray(varValue)) { varValue = this.SingleDataToArrayData(varValue); this.VarTable.set(varName, varValue); //把常量放到变量表里 } } else if (itemExpression.Type==Syntax.Identifier) { let value=itemExpression.Name; if (value==='COLORSTICK') colorStick=true; else if (value==='POINTDOT') pointDot=true; else if (value==='CIRCLEDOT') circleDot=true; else if (value == 'DOTLINE') isDotLine = true; else if (value==='LINESTICK') lineStick=true; else if (value==='STICK') stick=true; else if (value==='VOLSTICK') volStick=true; else if (value==="DRAWABOVE") isDrawAbove=true; else if (value.indexOf('COLOR')==0) color=value; else if (value.indexOf('LINETHICK')==0) lineWidth=value; else if (value.indexOf('NODRAW') == 0) isShow = false; else if (value.indexOf('EXDATA') == 0) isExData = true; //扩展数据, 不显示再图形里面 else if (value.indexOf('LINEOVERLAY') == 0) isOverlayLine = true; else if (value.indexOf("NOTEXT")==0 || value.indexOf("NOTITLE")==0) isShowTitle=false; //标题不显示 else { varName=itemExpression.Name; let varValue=this.ReadVariable(varName,itemExpression); if (!Array.isArray(varValue)) varValue=this.SingleDataToArrayData(varValue); varName="__temp_si_"+i+"__"; isNoneName=true; this.VarTable.set(varName,varValue); //放到变量表里 } } else if (itemExpression.Type == Syntax.Literal) //常量 { let aryValue = this.SingleDataToArrayData(itemExpression.Value); varName = itemExpression.Value.toString(); this.VarTable.set(varName, aryValue); //把常量放到变量表里 } else if (itemExpression.Type==Syntax.CallExpression) { if (this.Draw.IsDrawFunction(itemExpression.Callee.Name)) { draw=itemExpression.Draw; draw.Name=itemExpression.Callee.Name; } else { let varValue=itemExpression.Out; varName=`__temp_sc_${itemExpression.Callee.Name}_${i}__`; isNoneName=true; this.VarTable.set(varName,varValue); } } else if (itemExpression.Type==Syntax.BinaryExpression) { varName="__temp_sb_"+i+"__"; let aryValue=itemExpression.Out; isNoneName=true; this.VarTable.set(varName,aryValue); } } if (pointDot && varName) //圆点 { let outVar=this.VarTable.get(varName); let value={Name:varName, Data:outVar, Radius:g_JSChartResource.POINTDOT.Radius, Type:3}; if (color) value.Color=color; if (lineWidth) value.LineWidth = lineWidth; this.OutVarTable.push(value); } else if (circleDot && varName) //圆点 { let outVar=this.VarTable.get(varName); let value={Name:varName, Data:outVar, Radius:g_JSChartResource.CIRCLEDOT.Radius, Type:3}; if (color) value.Color=color; if (lineWidth) value.LineWidth = lineWidth; this.OutVarTable.push(value); } else if (lineStick && varName) //LINESTICK 同时画出柱状线和指标线 { let outVar=this.VarTable.get(varName); let value={Name:varName, Data:outVar, Type:4}; if (color) value.Color=color; if (lineWidth) value.LineWidth=lineWidth; this.OutVarTable.push(value); } else if (stick && varName) //STICK 画柱状线 { let outVar=this.VarTable.get(varName); let value={Name:varName, Data:outVar, Type:5}; if (color) value.Color=color; if (lineWidth) value.LineWidth=lineWidth; this.OutVarTable.push(value); } else if (volStick && varName) //VOLSTICK 画彩色柱状线 { let outVar=this.VarTable.get(varName); let value={Name:varName, Data:outVar, Type:6}; if (color) value.Color=color; this.OutVarTable.push(value); } else if (colorStick && varName) //CYW: SUM(VAR4,10)/10000, COLORSTICK; 画上下柱子 { let outVar=this.VarTable.get(varName); let value={Name:varName, Data:outVar, Color:color, Type:2}; if (lineWidth) value.LineWidth=lineWidth; if (color) value.Color=color; this.OutVarTable.push(value); } else if (varName && color) { let outVar=this.VarTable.get(varName); let value={Name:varName, Data:outVar, Color:color, Type:0}; if (lineWidth) value.LineWidth=lineWidth; if (isShow == false) value.IsShow = false; if (isExData == true) value.IsExData = true; if (isDotLine == true) value.IsDotLine = true; if (isOverlayLine == true) value.IsOverlayLine = true; if (isNoneName==true) value.NoneName=true; if (isShowTitle==false) value.IsShowTitle=false; this.OutVarTable.push(value); } else if (draw) { var outVar = { Name: draw.Name, Draw: draw, Type: 1 }; if (color) outVar.Color = color; if (lineWidth) outVar.LineWidth = lineWidth; if (isDrawAbove) outVar.IsDrawAbove=true; this.OutVarTable.push(outVar); } else if (varName) { let outVar = this.VarTable.get(varName); let value = { Name: varName, Data: outVar, Type: 0 }; if (color) value.Color = color; if (lineWidth) value.LineWidth = lineWidth; if (isShow == false) value.IsShow = false; if (isExData == true) value.IsExData = true; if (isDotLine == true) value.IsDotLine = true; if (isOverlayLine == true) value.IsOverlayLine = true; if (isShowTitle==false) value.IsShowTitle=false; this.OutVarTable.push(value); } } } } JSConsole.Complier.Log('[JSExecute::Run]', this.VarTable); return this.OutVarTable; } this.Run=function() { let data=this.RunAST();//执行脚本 JSConsole.Complier.Log('[JSComplier.Run] execute finish', data); if (this.UpdateUICallback) { JSConsole.Complier.Log('[JSComplier.Run] invoke UpdateUICallback.'); this.UpdateUICallback(data,this.CallbackParam); } } this.VisitNode=function(node) { switch(node.Type) { case Syntax.SequenceExpression: this.VisitSequenceExpression(node); break; case Syntax.ExpressionStatement: this.VisitNode(node.Expression); break; case Syntax.AssignmentExpression: this.VisitAssignmentExpression(node); break; case Syntax.BinaryExpression: case Syntax.LogicalExpression: this.VisitBinaryExpression(node); break; case Syntax.CallExpression: this.VisitCallExpression(node); break; } } this.VisitSequenceExpression=function(node) { for(let i in node.Expression) { let item =node.Expression[i]; this.VisitNode(item); } } //函数调用 this.VisitCallExpression=function(node) { let funcName=node.Callee.Name; let args=[]; for(let i in node.Arguments) { let item=node.Arguments[i]; let value; if (item.Type==Syntax.BinaryExpression || item.Type==Syntax.LogicalExpression) value=this.VisitBinaryExpression(item); else if (item.Type==Syntax.CallExpression) value=this.VisitCallExpression(item); else value=this.GetNodeValue(item); args.push(value); } //if (JS_EXECUTE_DEBUG_LOG) JSConsole.Complier.Log('[JSExecute::VisitCallExpression]' , funcName, '(', args.toString() ,')'); if (g_JSComplierResource.IsCustomFunction(funcName)) //自定义函数 { var data=this.Algorithm.CallCustomFunction(funcName, args, this.SymbolData, node); node.Out=[]; node.Draw=null; if (data) { if (data.Out) node.Out=data.Out; if (data.Draw) node.Draw=data.Draw; } return node.Out; } switch(funcName) { case 'DYNAINFO': //行情最新数据 node.Out=this.SymbolData.GetLatestCacheData(args[0]); break; case 'STICKLINE': node.Draw=this.Draw.STICKLINE(args[0],args[1],args[2],args[3],args[4]); node.Out=[]; break; case 'DRAWTEXT': node.Draw=this.Draw.DRAWTEXT(args[0],args[1],args[2]); node.Out=[]; break; case 'SUPERDRAWTEXT': node.Draw = this.Draw.SUPERDRAWTEXT(args[0], args[1], args[2], args[3], args[4]); node.Out = []; break; case 'DRAWTEXT_FIX': node.Draw=this.Draw.DRAWTEXT_FIX(args[0],args[1],args[2],args[3],args[4]); node.Out=[]; break; case 'DRAWICON': node.Draw = this.Draw.DRAWICON(args[0], args[1], args[2]); node.Out = []; break; case 'DRAWLINE': node.Draw=this.Draw.DRAWLINE(args[0],args[1],args[2],args[3],args[4]); node.Out=node.Draw.DrawData; break; case 'DRAWBAND': node.Draw=this.Draw.DRAWBAND(args[0],args[1],args[2],args[3]); node.Out=[]; break; case 'DRAWKLINE': node.Draw = this.Draw.DRAWKLINE(args[0], args[1], args[2], args[3]); node.Out = []; break; case 'DRAWKLINE_IF': node.Draw = this.Draw.DRAWKLINE_IF(args[0], args[1], args[2], args[3], args[4]); node.Out = []; break; case 'PLOYLINE': case 'POLYLINE': node.Draw = this.Draw.POLYLINE(args[0], args[1]); node.Out = node.Draw.DrawData; break; case 'DRAWNUMBER': node.Draw = this.Draw.DRAWNUMBER(args[0], args[1], args[2]); node.Out = node.Draw.DrawData.Value; break; case 'RGB': node.Out = this.Draw.RGB(args[0], args[1], args[2]); break; case 'RGBA': node.Out = this.Draw.RGBA(args[0], args[1], args[2],args[3]); break; case 'DRAWRECTREL': node.Draw = this.Draw.DRAWRECTREL(args[0], args[1], args[2], args[3], args[4]); node.Out = []; break; case 'DRAWGBK': node.Draw=this.Draw.DRAWGBK(args[0],args[1],args[2],args[3]); node.Out=[]; break; case 'DRAWGBK2': node.Draw=this.Draw.DRAWGBK2(args[0],args[1],args[2],args[3]); node.Out=[]; break; case 'CODELIKE': node.Out=this.SymbolData.CODELIKE(args[0]); break; case 'NAMELIKE': node.Out = this.SymbolData.NAMELIKE(args[1]); break; case 'REFDATE': node.Out = this.SymbolData.REFDATE(args[0], args[1]); break; case 'FINANCE': node.Out=this.SymbolData.GetStockCacheData( {FunctionName:funcName, Args:args, ArgCount:1, Node:node } ); break; case "FINVALUE": node.Out=this.SymbolData.GetStockCacheData( {FunctionName:funcName, Args:args, ArgCount:1, Node:node } ); break; case "FINONE": node.Out=this.SymbolData.GetStockCacheData( {FunctionName:funcName, Args:args, ArgCount:3, Node:node } ); break; case "GPJYVALUE": node.Out=this.SymbolData.GetStockCacheData( {FunctionName:funcName, Args:args, ArgCount:3, Node:node } ); break; case "MARGIN": node.Out = this.SymbolData.GetMarginCacheData(args[0], node); break; case "NEWS": node.Out = this.SymbolData.GetNewsAnalysisCacheData(args[0], node); break; case 'UPCOUNT': case 'DOWNCOUNT': node.Out = this.SymbolData.GetIndexIncreaseCacheData(funcName, args[0], node); break; case 'LOADAPIDATA': node.Out = this.SymbolData.GetCustomApiData(args); break; case "INBLOCK": node.Out=this.SymbolData.IsInBlock(args[0],node); break; default: node.Out=this.Algorithm.CallFunction(funcName, args,node); break; } return node.Out; } //赋值 this.VisitAssignmentExpression=function(node) { let left=node.Left; if (left.Type!=Syntax.Identifier) this.ThrowUnexpectedNode(node); let varName=left.Name; let right=node.Right; let value=null; if (right.Type==Syntax.BinaryExpression || right.Type==Syntax.LogicalExpression) value=this.VisitBinaryExpression(right); else if (right.Type==Syntax.CallExpression) value=this.VisitCallExpression(right); else if (right.Type==Syntax.Literal) value=right.Value; else if (right.Type==Syntax.Identifier) //右值是变量 value=this.ReadVariable(right.Name,right); else if (right.Type == Syntax.MemberExpression) value = this.ReadMemberVariable(right); if (JS_EXECUTE_DEBUG_LOG) JSConsole.Complier.Log('[JSExecute::VisitAssignmentExpression]' , varName, ' = ',value); this.VarTable.set(varName,value); } //逻辑运算 this.VisitBinaryExpression=function(node) { let stack=[]; stack.push(node); let temp=null; while(stack.length!=0) { temp=stack[stack.length-1]; if (temp.Left && node!=temp.Left && node!=temp.Right) { stack.push(temp.Left); } else if (temp.Right && node!=temp.Right) { stack.push(temp.Right); } else { let value=stack.pop(); if (value.Type==Syntax.BinaryExpression) //只遍历操作符就可以 { let leftValue=this.GetNodeValue(value.Left); let rightValue=this.GetNodeValue(value.Right); if (JS_EXECUTE_DEBUG_LOG) JSConsole.Complier.Log('[JSExecute::VisitBinaryExpression] BinaryExpression',value , leftValue, rightValue); value.Out=null; //保存中间值 switch(value.Operator) { case '-': value.Out=this.Algorithm.Subtract(leftValue,rightValue); break; case '*': value.Out=this.Algorithm.Multiply(leftValue,rightValue); break; case '/': value.Out=this.Algorithm.Divide(leftValue,rightValue) break; case '+': value.Out=this.Algorithm.Add(leftValue,rightValue); break; case '>': value.Out=this.Algorithm.GT(leftValue,rightValue); break; case '>=': value.Out=this.Algorithm.GTE(leftValue,rightValue); break; case '<': value.Out=this.Algorithm.LT(leftValue,rightValue); break; case '<=': value.Out=this.Algorithm.LTE(leftValue,rightValue); break; case '==': case '=': value.Out=this.Algorithm.EQ(leftValue,rightValue); break; case '!=': case '<>': value.Out = this.Algorithm.NEQ(leftValue, rightValue); break; } if (JS_EXECUTE_DEBUG_LOG) JSConsole.Complier.Log('[JSExecute::VisitBinaryExpression] BinaryExpression',value); } else if (value.Type==Syntax.LogicalExpression) { let leftValue=this.GetNodeValue(value.Left); let rightValue=this.GetNodeValue(value.Right); if (JS_EXECUTE_DEBUG_LOG) JSConsole.Complier.Log('[JSExecute::VisitBinaryExpression] LogicalExpression',value , leftValue, rightValue); value.Out=null; //保存中间值 switch(value.Operator) { case '&&': case 'AND': value.Out=this.Algorithm.And(leftValue,rightValue); break; case '||': case 'OR': value.Out=this.Algorithm.Or(leftValue,rightValue); break; } if (JS_EXECUTE_DEBUG_LOG) JSConsole.Complier.Log('[JSExecute::VisitBinaryExpression] LogicalExpression',value); } node=temp; } } return node.Out; } this.GetNodeValue=function(node) { switch(node.Type) { case Syntax.Literal: //数字 return node.Value; case Syntax.UnaryExpression: if (node.Operator=='-') { let value=this.GetNodeValue(node.Argument); return this.Algorithm.Subtract(0,value); } return node.Argument.Value; case Syntax.Identifier: let value=this.ReadVariable(node.Name,node); return value; case Syntax.BinaryExpression: case Syntax.LogicalExpression: return node.Out; case Syntax.CallExpression: return this.VisitCallExpression(node); default: this.ThrowUnexpectedNode(node); } } this.ThrowUnexpectedNode=function(node,message) { let marker=node.Marker; let msg=message || "执行异常"; return this.ErrorHandler.ThrowError(marker.Index,marker.Line,marker.Column,msg); } this.ThrowError=function() { } } //对外导出类 function JSComplier() { } //词法分析 JSComplier.Tokenize=function(code) { JSConsole.Complier.Log('[JSComplier.Tokenize]', code); let tokenizer=new Tokenizer(code); let tokens=[]; try { while(true) { let token=tokenizer.GetNextToken(); if (!token) break; tokens.push(token); } } catch(e) { } return tokens; } //语法解析 生成抽象语法树(Abstract Syntax Tree) JSComplier.Parse=function(code) { JSConsole.Complier.Log('[JSComplier.Parse]',code); let parser=new JSParser(code); parser.Initialize(); let program=parser.ParseScript(); let ast=program; return ast; } /* 执行 option.Symbol=股票代码 option.Name=股票名称 option.Data=这个股票的ChartData option.Right=复权 option.MaxReqeustDataCount=请求数据的最大个数 */ function timeout(ms) { return new Promise((resolve) => { setTimeout(resolve, ms); }); } JSComplier.Execute=function(code,option,errorCallback) { //异步调用 var asyncExecute= function() { try { JSConsole.Complier.Log('[JSComplier.Execute] code ',code); JSConsole.Complier.Log('[JSComplier.Execute] parser .....'); let parser=new JSParser(code); parser.Initialize(); let program=parser.ParseScript(); let ast=program; JSConsole.Complier.Log('[JSComplier.Execute] parser finish.', ast); JSConsole.Complier.Log('[JSComplier.Execute] execute .....'); let execute=new JSExecute(ast,option); execute.JobList=parser.Node.GetDataJobList(); execute.JobList.push({ID:JS_EXECUTE_JOB_ID.JOB_RUN_SCRIPT}); let result=execute.Execute(); }catch(error) { JSConsole.Complier.Log(error); if (errorCallback) errorCallback(error); } } asyncExecute(); JSConsole.Complier.Log('[JSComplier.Execute] async execute.'); } JSComplier.SetDomain = function (domain, cacheDomain) { if (domain) g_JSComplierResource.Domain = domain; if (cacheDomain) g_JSComplierResource.CacheDomain = cacheDomain; } JSComplier.AddFunction=function(obj) //添加函数 { Name:函数名, Description:描述信息, IsDownload:是否需要下载数据, Invoke:函数执行(可选) } { if (!obj || !obj.Name) return; var ID=obj.Name.toUpperCase(); g_JSComplierResource.CustomFunction.Data.set(ID, obj); } JSComplier.AddVariant=function(obj) //{ Name:变量名, Description:描述信息 } { if (!obj || !obj.Name) return; var ID=obj.Name.toUpperCase(); g_JSComplierResource.CustomVariant.Data.set(ID, obj); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////// // //数据下载 function DownloadFinanceData(obj) { this.Url=obj.Url; this.RealtimeUrl=obj.RealtimeUrl; this.Job=obj.Job; this.Symbol=obj.Symbol; this.Args=obj.Args; this.DataKey=obj.DataKey; this.RecvCallback=obj.Callback; this.ErrorCallback=obj.ErrorCallback; this.Download=function() { var id=this.Args[0]; switch(id) { case 1: //FINANCE(1) 总股本(随时间可能有变化) 股 case 7: //FINANCE(7) 流通股本(随时间可能有变化) 股 case "EXCHANGE": //换手率 this.DownloadHistoryData(id); break; case 9: //FINANCE(9) 资产负债率 case 18: //FINANCE(18) 每股公积金 case 30: //FINANCE(30) 净利润 case 32: //FINANCE(32) 每股未分配利润 case 33: //FINANCE(33) 每股收益(折算为全年收益),对于沪深品种有效 case 34: //FINANCE(34) 每股净资产 case 38: //FINANCE(38) 每股收益(最近一期季报) case 40: //FINANCE(40) 流通市值 case 41: //FINANCE(41) 总市值 case 42: //FINANCE(42) 上市的天数 case 43: //FINANCE(43) 利润同比 case "CAPITAL": case "TOTALCAPITAL": //定制 case 100: //股东人数 this.DownloadRealtimeData(id); break; default: this.DownloadRealtimeData(id); break; } } //最新一期数据 this.DownloadRealtimeData=function(id) { var self=this; var fieldList=this.GetFieldList(); if (!fieldList) { if (this.Job.FunctionName2) message=`${this.Job.FunctionName2} can't support.`; else if (this.Job.FunctionName) message=`${this.Job.FunctionName}(${this.Args[0]}) can't support.`; else message=`${this.Args[0]} can't support.`; this.ErrorCallback(message); self.RecvCallback(null, self.Job, self.DataKey); return; } //请求数据 wx.request({ url: this.RealtimeUrl, data: { "field": fieldList, "symbol": [this.Symbol], "condition":[ ] , "start": 0, "end": 10 }, method: 'POST', dataType: "json", async:true, success: function (recvData) { var data=self.RealtimeDataToHQChartData(recvData.data); self.RecvCallback(data, self.Job, self.DataKey); } }); } //历史数据 this.DownloadHistoryData=function(id) { var self=this; var fieldList=this.GetFieldList(); if (!fieldList) { message=`${this.Job.FunctionName}(${this.Args[0]}) can't support.`; this.ErrorCallback(message); self.RecvCallback(null, self.Job, self.DataKey); return; } //请求数据 wx.request({ url: this.Url, data: { "field": fieldList, "symbol": [this.Symbol], "condition":[ ] , "start": 0, "end": 200 }, method: 'POST', dataType: "json", async:true, success: function (recvData) { var data=self.ToHQChartData(recvData.data); if (data) //排序 data.sort(function (a, b) { return (a.Date - b.Date) }); self.RecvCallback(data, self.Job, self.DataKey); } }); } this.GetFieldList=function() { var id=this.Args[0]; switch(id) { case 1: return ["capital.total", "capital.date"]; case 7: return ["capital.a", "capital.date"]; case "EXCHANGE": return ["capital.a", "capital.date"]; case 9: return ["finance.peruprofit","symbol","date"]; case 18: return ["finance.percreserve","symbol","date"]; case 30: return ["finance.nprofit","symbol","date"]; case 32: return ["finance.peruprofit","symbol","date"]; case 33: return ["finance.persearning","symbol","date"]; case 34: return ["finance.pernetasset","symbol","date"]; case 38: return ["finance.persearning","symbol","date"]; case 40: return ["capital.a", "capital.date","symbol","date", "price"]; case 41: return ["capital.total", "capital.date","symbol","date","price"]; case "CAPITAL": return ["capital.a", "capital.date","symbol","date"]; case "TOTALCAPITAL": return ["capital.total", "capital.date","symbol","date"]; case 42: return ["company.releasedate","symbol","date"]; case 43: return ["dividendyield","symbol","date"]; case 100: return ["shareholder","symbol","date"] default: return null; } } //最新报告期数据 this.RealtimeDataToHQChartData=function(recvData,id) { if (!recvData.stock || recvData.stock.length!=1) return null; var stock=recvData.stock[0]; var id=this.Args[0]; var date=stock.date; switch(id) { case 9: if (!stock.finance) return null; return { Date:date, Value:stock.finance.peruprofit }; case 18: if (!stock.finance) return null; return { Date:date, Value:stock.finance.percreserve }; case 30: if (!stock.finance) return null; return { Date:date, Value:stock.finance.nprofit }; case 32: if (!stock.finance) return null; return { Date:date, Value:stock.finance.peruprofit }; case 33: if (!stock.finance) return null; return { Date:date, Value:stock.finance.persearning }; case 34: if (!stock.finance) return null; return { Date:date, Value:stock.finance.pernetasset }; case 38: if (!stock.finance) return null; return { Date:date, Value:stock.finance.persearning }; case 40: //FINANCE(40) 流通市值 if (!stock.capital) return null; return { Date:date, Value:stock.capital.a*stock.price }; //流通股*最新价格 case 41: //FINANCE(41) 总市值 if (!stock.capital) return null; return { Date:date, Value:stock.capital.total*stock.price }; //总股本*最新价格 case 42: //FINANCE(42) 上市的天数 if (!stock.company) return null; { var releaseDate=stock.company.releasedate; var year=parseInt(releaseDate/10000); var month=parseInt((releaseDate%10000)/100); var day=releaseDate%100; var firstDate=new Date(year, month-1, day); var nowDate=new Date(); var days=parseInt((nowDate.getTime()-firstDate.getTime())/(1000 * 60 * 60 * 24)); return { Date:date, Value:days+1 }; } case 43: if (!stock.dividendyield) return null; return { Date:date, Value:stock.dividendyield.quarter4 }; case 100: if (!stock.shareholder) return null; return { Date:date, Value:stock.shareholder.count }; case "CAPITAL": if (!stock.capital) return null; return { Date:date, Value:stock.capital.a/100 }; //当前流通股本 手 case "TOTALCAPITAL": if (!stock.capital) return null; return { Date:date, Value:stock.capital.total/100 }; //当前流通股本 手 } } //历史数据转 this.ToHQChartData=function(recvData) { if (!recvData.stock || recvData.stock.length!=1) return null; var aryData=[]; var setDate=new Set(); //有重复数据 去掉 var stock=recvData.stock[0]; var id=this.Args[0]; for(var i in stock.stockday) { var item=stock.stockday[i]; var hqchartItem=this.ToHQChartItemData(item,id); if (hqchartItem && !setDate.has(hqchartItem.Date)) { aryData.push(hqchartItem); setDate.add(hqchartItem.Date); } } return aryData; } this.ToHQChartItemData=function(item, id) { if (!item) return null; var date=item.date; switch(id) { case 1: if (!item.capital) return null; return { Date:date, Value:item.capital.total }; case 7: case "EXCHANGE": //换手率 历史流通股本 if (!item.capital) return null; return { Date:date, Value:item.capital.a }; default: return null; } } } ////////////////////////////////////////////////////////////////////////////////////////////// //内置财务数据下载 // function DownloadFinValueData(obj) { this.Url=obj.Url; this.Job=obj.Job; this.Symbol=obj.Symbol; this.Args=obj.Args; this.DataKey=obj.DataKey; this.RecvCallback=obj.Callback; this.ErrorCallback=obj.ErrorCallback; this.Download=function() { var self=this; var fieldList=this.GetFieldList(); if (!fieldList) { message=`${this.Job.FunctionName}(${this.Args[0]}) can't support.`; this.ErrorCallback(message); self.RecvCallback(null, self.Job, self.DataKey); return; } //请求数据 wx.request({ url: this.Url, data: { "field": fieldList, "symbol": [this.Symbol], "condition":[ {"item":["finance","doc","exists","true"]}] , "start": 0, "end": 200 }, method: 'POST', dataType: "json", async:true, success: function (recvData) { var data=self.ToHQChartData(recvData.data); if (data) //排序 data.sort(function (a, b) { return (a.Date - b.Date) }); self.RecvCallback(data, self.Job, self.DataKey); } }); } this.ToHQChartData=function(recvData) { if (!recvData.stock || recvData.stock.length!=1) return null; var aryData=[]; var setDate=new Set(); //有重复数据 去掉 var stock=recvData.stock[0]; for(var i in stock.stockday) { var item=stock.stockday[i]; if (item.announcement1) { var hqchartItem=this.ToHQChartItemData(item.announcement1, item.finance1, item); if (hqchartItem && !setDate.has(hqchartItem.Date)) { aryData.push(hqchartItem); setDate.add(hqchartItem.Date); } } if (item.announcement2) { var hqchartItem=this.ToHQChartItemData(item.announcement2, item.finance2, item); if (hqchartItem && !setDate.has(hqchartItem.Date)) { aryData.push(hqchartItem); setDate.add(hqchartItem.Date); } } if (item.announcement3) { var hqchartItem=this.ToHQChartItemData(item.announcement3, item.finance3, item); if (hqchartItem && !setDate.has(hqchartItem.Date)) { aryData.push(hqchartItem); setDate.add(hqchartItem.Date); } } if (item.announcement4) { var hqchartItem=this.ToHQChartItemData(item.announcement4, item.finance4, item); if (hqchartItem && !setDate.has(hqchartItem.Date)) { aryData.push(hqchartItem); setDate.add(hqchartItem.Date); } } } return aryData; } //{ Date:日期 , Value:数值 } this.ToHQChartItemData=function(announcement, finance, sourceItem) { var id=this.Args[0]; var date=announcement.year*10000; var quarter=announcement.quarter; switch(quarter) { case 1: date+=331; break; case 2: date+=630; break; case 3: date+=930; break; case 4: date+=1231; break; default: return null; } var result={ Date:date, Value:0 }; switch(id) { case 0: result.Value=date%1000000; //0--返回报告期(YYMMDD格式),150930表示为2015年第三季 break; case 1: result.Value=finance.persearning; break; case 3: result.Value=finance.peruprofit; break; case 4: result.Value=finance.pernetasset; break; case 5: result.Value=finance.percreserve; break; case 6: result.Value=finance.woewa; break; case 7: result.Value=finance.perccfo; break; case 8: result.Value=finance.monetaryfunds; break; case 11: result.Value=finance.areceivable; break; } return result; } this.GetFieldList=function() { var id=this.Args[0]; switch(id) { case 0: return ["finance.date"]; case 1: //persearning 每股收益 return ["finance.persearning"]; case 3: //peruprofit 每股未分配利润 return ["finance.peruprofit"]; case 4: //pernetasset 每股净资产 return ["finance.pernetasset"]; case 5: //percreserve 每股资本公积金 return ["finance.percreserve"]; case 6: //woewa 加权平均净资产收益 return ["finance.woewa"]; case 7: //perccfo 每股经营性现金流 return ["finance.perccfo"]; case 8: //monetaryfunds 货币资金 return ["finance.monetaryfunds"]; case 11: //areceivable 应收账款 return ["finance.areceivable"]; default: return null; } } } ///////////////////////////////////////////////////////// // 内置财务数据下载 某一期的数据 // function DownloadFinOneData(obj) { this.newMethod=DownloadFinValueData; //派生 this.newMethod(obj); delete this.newMethod; this.Download=function() { var self=this; var fieldList=this.GetFieldList(); if (!fieldList) { message=`${this.Job.FunctionName}(${this.Args[0]}, ${this.Args[1]}, ${this.Args[2]}) can't support.`; this.ErrorCallback(message); self.RecvCallback(null, self.Job, self.DataKey); return; } var aryCondition=[ {"item":["finance","doc","exists","true"] } ]; var year=this.Args[1]; var month=this.Args[2]; var dataIndex=0; var dataEnd=3; var preYear=null; if (year==0 && month==0) //如果Y和MMDD都为0,表示最新的财报; { } else if (year==0 && month<300) //如果Y为0,MMDD为小于300的数字,表示最近一期向前推MMDD期的数据,如果是331,630,930,1231这些,表示最近一期的对应季报的数据; { dataIndex=month; dataEnd=200; } else if (month==0 && year<1000) //如果Y为0,MMDD为小于300的数字,表示最近一期向前推MMDD期的数据,如果是331,630,930,1231这些,表示最近一期的对应季报的数据; { preYear=year; } else if (year>1909) { if (month==331) { aryCondition= [ {"item":["announcement1.year","int32","eq",year]}, {"item":["finance1","doc","exists","true"]} ]; fieldList.push("announcement1.year"); fieldList.push("announcement1.quarter"); } else if (month==630) { aryCondition= [ {"item":["announcement2.year","int32","eq",year]}, {"item":["finance2","doc","exists","true"]} ]; fieldList.push("announcement2.year"); fieldList.push("announcement2.quarter"); } else if (month==930) { aryCondition= [ {"item":["announcement3.year","int32","eq",year]}, {"item":["finance3","doc","exists","true"]} ]; fieldList.push("announcement4.year"); fieldList.push("announcement4.quarter"); } else { aryCondition= [ {"item":["announcement4.year","int32","eq",year]}, {"item":["finance4","doc","exists","true"]} ]; fieldList.push("announcement4.year"); fieldList.push("announcement4.quarter"); } } //请求数据 wx.request({ url: this.Url, data: { "field": fieldList, "symbol": [this.Symbol], "condition":aryCondition, "start": 0, "end": dataEnd }, method: 'POST', dataType: "json", async:true, success: function (recvData) { var data=self.ToHQChartData(recvData.data); var result=null; if (data && data.length>0) { data.sort(function (a, b) { return (b.Date-a.Date) }); if (preYear==null) result=data[dataIndex]; //返回一个数据 else result=self.GetPreYearData(data, preYear); } self.RecvCallback(result, self.Job, self.DataKey); } }); } this.GetPreYearData=function(data, preYear) { //331,630,930,1231这些,表示最近一期的对应季报的数据; if (preYear==331 || preYear==630|| preYear==930 || preYear==1231) { for(var i in data) { var item=data[i]; if (item.Date%10000==preYear) return item; } } else { //如果MMDD为0,Y为一数字,表示最近一期向前推Y年的同期数据; var month=data[0].Date%1000; for(var i=1, j=0; i0) { data.sort(function (a, b) { return (a.Date-b.Date) }); } self.RecvCallback(data, self.Job, self.DataKey); } }); } this.GetFieldList=function() { var id=this.Args[0]; switch(id) { case 1: //1--股东人数 股东户数(户) return ["shareholder", "date", "symbol"]; case 2: //2--龙虎榜 买入总计(万元) 卖出总计(万元) return ["tradedetail.buy","tradedetail.sell", "date", "symbol"]; case 3: //3--融资融券1 融资余额(万元) 融券余量(股) return ["margin","date", "symbol"]; case 4: //4--大宗交易 成交均价(元) 成交额(万元) return ["blocktrading.amount","blocktrading.price","date", "symbol"] default: return null; } } this.ToHQChartData=function(recvData) { if (!recvData.stock || recvData.stock.length!=1) return null; var aryData=[]; var setDate=new Set(); //有重复数据 去掉 var stock=recvData.stock[0]; var id=this.Args[0]; var subID=this.Args[1]; for(var i in stock.stockday) { var item=stock.stockday[i]; var hqchartItem=this.ToHQChartItemData(item,id,subID); if (hqchartItem && !setDate.has(hqchartItem.Date)) { aryData.push(hqchartItem); setDate.add(hqchartItem.Date); } } return aryData; } this.ToHQChartItemData=function(item, id, subID) { if (!item) return null; var date=item.date; switch(id) { case 1: if (!item.shareholder) return null; return { Date:date, Value:item.shareholder.count }; case 2: if (!item.tradedetail && item.tradedetail[0]) return null; if (subID==0) return { Date:date, Value:item.tradedetail[0].buy }; else return { Date:date, Value:item.tradedetail[0].sell }; case 3: if (!item.margin) return null; if (subID==0) { if (item.margin.buy) return { Date:date, Value:item.margin.buy.balance }; } else { if (item.margin.sell) return { Date:date, Value:item.margin.sell.balance }; } return null; case 4: if (!item.blocktrading) return null; if (subID==0) return { Date:date, Value:item.blocktrading.price }; else return { Date:date, Value:item.blocktrading.amount }; default: return null; } } } function DownloadGroupData(obj) { this.Url=obj.Url; this.RealtimeUrl=obj.RealtimeUrl; this.Job=obj.Job; this.Symbol=obj.Symbol; this.Args=obj.Args; this.DataKey=obj.DataKey; this.RecvCallback=obj.Callback; this.ErrorCallback=obj.ErrorCallback; this.Download=function() { var varName=this.Args[0]; switch(varName) { case "HYBLOCK": case "DYBLOCK": case "GNBLOCK": this.DownloadGroupName(varName); break; } } this.DownloadGroupName=function(blockType) { var self=this; var field=["name","symbol"]; if (blockType=="HYBLOCK") field.push("industry"); else if (blockType=="DYBLOCK") field.push("region"); else if (blockType=="GNBLOCK") field.push("concept"); wx.request({ url: self.RealtimeUrl, data: { "field": field, "symbol": [this.Symbol] }, method:"post", dataType: "json", async:true, success: function (recvData) { var data=self.RecvGroupName(recvData.data); self.RecvCallback(data, self.Job, self.DataKey, 1); }, error: function(request) { self.ErrorCallback(request); } }); } this.RecvGroupName=function(recvData) { if (!recvData.stock || recvData.stock.length!=1) return null; var stock=recvData.stock[0]; var varName=this.Args[0]; var value=null; if (varName=="HYBLOCK") { var industry=stock.industry; if (!industry) return null; var value; for(var i in industry) { var item=industry[i]; value=item.name; } } else if (varName=="DYBLOCK") { var region=stock.region; if (!region) return null; for(var i in region) { var item=region[i]; value=item.name; } } else if (varName=="GNBLOCK") { var concept=stock.concept; if (!concept) return null; value=""; for(var i in concept) { var item=concept[i]; if (value.length>0) value+=' '; value+=item.name; } } return { Value:value }; } } /* 测试例子 var code1='VARHIGH:IF(VAR1<=REF(HH,-1),REF(H,BARSLAST(VAR1>=REF(HH,1))),DRAWNULL),COLORYELLOW;'; var code2='VAR1=((SMA(MAX((CLOSE - LC),0),3,1) / SMA(ABS((CLOSE - LC)),3,1)) * 100);'; var code3='mm1=1-2*-9+20;'; JSConsole.Complier.Log(code1+code2) var tokens=JSComplier.Tokenize(code1+code2); var ast=JSComplier.Parse(code2+code1); JSConsole.Complier.Log(ast); */ module.exports = { JSCommonComplier: { JSComplier: JSComplier, }, //单个类导出 JSCommonComplier_ErrorHandler: ErrorHandler, JSCommonComplier_JSComplier:JSComplier, JSCommonComplier_JSParser:JSParser, JSCommonComplier_Syntax:Syntax, JS_EXECUTE_JOB_ID:JS_EXECUTE_JOB_ID, g_JSComplierResource:g_JSComplierResource, };