def __init__(self, ast, option=None) : self.AST=ast # 语法树 self.ErrorHandler=ErrorHandler() self.VarTable={} # 变量表 self.OutVarTable=[] # 输出变量 self.Arguments=[] # 脚本自动变量表, 只读 self.ConstVarTable={ # 个股数据 'CLOSE':None, 'VOL':None, 'OPEN':None, 'HIGH':None, 'LOW':None, 'AMOUNT':None, 'C':None, 'V':None, 'O':None, 'H':None, 'L':None, 'VOLR':None, # 日期类 'DATE':None, 'YEAR':None, 'MONTH':None, 'PERIOD':None, 'WEEK':None, # 大盘数据 'INDEXA':None, 'INDEXC':None, 'INDEXH':None, 'INDEXL':None, 'INDEXO':None, 'INDEXV':None, 'INDEXADV':None, 'INDEXDEC':None, # 到最后交易日的周期数 'CURRBARSCOUNT':None, # 流通股本(手) 'CAPITAL':None, # 换手率 'EXCHANGE':None, 'SETCODE':None } if option and option.ProcCreateSymbolData: self.SymbolData=option.ProcCreateSymbolData(ast=ast,option=option, procThrow=self.ThrowUnexpectedNode) else : self.SymbolData=JSSymbolData(ast=ast,option=option, procThrow=self.ThrowUnexpectedNode) self.Algorithm=JSAlgorithm(errorHandler=self.ErrorHandler,symbolData=self.SymbolData) self.Draw=JSDraw(errorHandler=self.ErrorHandler,symbolData=self.SymbolData) self.JobList=[] # 执行的任务队列 if option and option.Arguments: self.Arguments=option.Arguments
class JSExecute: def __init__(self, ast, option=None): self.AST = ast # 语法树 self.ErrorHandler = ErrorHandler() self.VarTable = {} # 变量表 self.OutVarTable = [] # 输出变量 self.Arguments = [] # 脚本自动变量表, 只读 self.ConstVarTable = { # 个股数据 'CLOSE': None, 'VOL': None, 'OPEN': None, 'HIGH': None, 'LOW': None, 'AMOUNT': None, 'C': None, 'V': None, 'O': None, 'H': None, 'L': None, 'VOLR': None, # 日期类 'DATE': None, 'YEAR': None, 'MONTH': None, 'PERIOD': None, 'WEEK': None, # 大盘数据 'INDEXA': None, 'INDEXC': None, 'INDEXH': None, 'INDEXL': None, 'INDEXO': None, 'INDEXV': None, 'INDEXADV': None, 'INDEXDEC': None, # 到最后交易日的周期数 'CURRBARSCOUNT': None, # 流通股本(手) 'CAPITAL': None, # 换手率 'EXCHANGE': None, 'SETCODE': None } self.SymbolData = JSSymbolData(ast=ast, option=option, procThrow=self.ThrowUnexpectedNode) self.Algorithm = JSAlgorithm(errorHandler=self.ErrorHandler, symbolData=self.SymbolData) self.Draw = JSDraw(errorHandler=self.ErrorHandler, symbolData=self.SymbolData) self.JobList = [] # 执行的任务队列 if option and option.Arguments: self.Arguments = option.Arguments def Execute(self): self.SymbolData.RunDownloadJob(self.JobList) # 准备数据 outVar = self.RunAST() return outVar def ReadSymbolData(self, name, node): if name in ('CLOSE', 'C', 'VOL', 'V', 'OPEN', 'O', 'HIGH', 'H', 'LOW', 'L', 'AMOUNT'): return self.SymbolData.GetSymbolCacheData(name) elif name == 'VOLR': # 量比 pass # return self.SymbolData.GetVolRateCacheData(node) elif name in ('INDEXA', 'INDEXC', 'INDEXH', 'INDEXO', 'INDEXV', 'INDEXL', 'INDEXADV', 'INDEXDEC'): # 大盘数据 return self.SymbolData.GetIndexCacheData(name) elif name == 'CURRBARSCOUNT': pass # return self.SymbolData.GetCurrBarsCount() elif name == 'CAPITAL': return self.SymbolData.GetFinanceCacheData( JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_CAPITAL_DATA, node=node) elif name == 'EXCHANGE': return self.SymbolData.GetFinanceCacheData( JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_EXCHANGE_DATA, node=node) elif name == 'SETCODE': return self.SymbolData.SETCODE() elif name == 'DATE': return self.SymbolData.DATE() elif name == 'YEAR': return self.SymbolData.YEAR() elif name == 'MONTH': return self.SymbolData.MONTH() elif name == 'WEEK': return self.SymbolData.WEEK() elif name == 'PERIOD': return self.SymbolData.PERIOD() # 读取变量 def ReadVariable(self, name, node): if name in self.ConstVarTable: data = self.ConstVarTable[name] if not data: # 动态加载,用到再加载 data = self.ReadSymbolData(name, node) self.ConstVarTable[name] = data return data if name in self.VarTable: return self.VarTable[name] self.ThrowUnexpectedNode(node, '变量' + name + '不存在') return None # 单数据转成数组 个数和历史数据一致 def SingleDataToArrayData(self, value): count = len(self.SymbolData.Data.Data) result = [value] * count return result def RunAST(self): # 预定义的变量 for item in self.Arguments: self.VarTable[item.Name] = item.Value if not self.AST or not self.AST.Body: self.ThrowError() for item in self.AST.Body: self.VisitNode(item) if item.Type == Syntax.ExpressionStatement and item.Expression: if item.Expression.Type == Syntax.AssignmentExpression and item.Expression.Operator == ':' and item.Expression.Left: assignmentItem = item.Expression varName = assignmentItem.Left.Name outVar = self.VarTable[varName] if not isinstance(outVar, list): outVar = self.SingleDataToArrayData(outVar) self.OutVarTable.append( OutVariable(name=varName, data=outVar, type=0)) elif (item.Expression.Type == Syntax.CallExpression): callItem = item.Expression if (JSDraw.IsDrawFunction(callItem.Callee.Name)): draw = callItem.Draw draw.Name = callItem.Callee.Name self.OutVarTable.append( OutVariable(name=draw.Name, draw=draw, type=1)) elif (item.Expression.Type == Syntax.SequenceExpression): varName = None draw = None color = None lineWidth = None colorStick = False pointDot = False circleDot = False lineStick = False stick = False volStick = False isShow = True isExData = False for itemExpression in item.Expression.Expression: if (itemExpression.Type == Syntax.AssignmentExpression and itemExpression.Operator == ':' and itemExpression.Left): varName = itemExpression.Left.Name varValue = self.VarTable[varName] if not JSComplierHelper.IsArray(varValue): varValue = self.SingleDataToArrayData(varValue) self.VarTable[ varName] = varValue # 把单数值转化成数组放到变量表里 elif (itemExpression.Type == Syntax.Identifier): value = itemExpression.Name if (value == 'COLORSTICK'): colorStick = True elif (value == 'POINTDOT'): pointDot = True elif (value == 'CIRCLEDOT'): circleDot = True elif (value == 'LINESTICK'): lineStick = True elif (value == 'STICK'): stick = True elif (value == 'VOLSTICK'): volStick = True elif (value.find('COLOR') == 0): color = value elif (value.find('LINETHICK') == 0): lineWidth = value elif (value.find('NODRAW') == 0): isShow = False elif (value.find('EXDATA') == 0): isExData = True # 扩展数据, 不显示再图形里面 elif (itemExpression.Type == Syntax.Literal): #常量 aryValue = self.SingleDataToArrayData( itemExpression.Value) varName = str(itemExpression.Value) self.VarTable[varName, aryValue] # 把常量放到变量表里 elif (itemExpression.Type == Syntax.CallExpression and JSDraw.IsDrawFunction( itemExpression.Callee.Name)): draw = itemExpression.Draw draw.Name = itemExpression.Callee.Name if (pointDot and varName): # 圆点 outVar = self.VarTable[varName] if (not JSComplierHelper.IsArray(outVar)): outVar = self.SingleDataToArrayData(outVar) value = OutVariable(name=varName, data=outVar, type=3) value.Radius = 2 if color: value.Color = color if lineWidth: value.LineWidth = lineWidth self.OutVarTable.append(value) elif (circleDot and varName): # 圆点 outVar = self.VarTable[varName] if not JSComplierHelper.IsArray(outVar): outVar = self.SingleDataToArrayData(outVar) value = OutVariable(name=varName, data=outVar, type=3) value.Radius = 1.3 if color: value.Color = color if lineWidth: value.LineWidth = lineWidth self.OutVarTable.append(value) elif (lineStick and varName): # LINESTICK 同时画出柱状线和指标线 outVar = self.VarTable[varName] value = OutVariable(name=varName, data=outVar, type=4) if color: value.Color = color if lineWidth: value.LineWidth = lineWidth self.OutVarTable.append(value) elif (stick and varName): # STICK 画柱状线 outVar = self.VarTable[varName] value = OutVariable(name=varName, data=outVar, type=5) if color: value.Color = color if lineWidth: value.LineWidth = lineWidth self.OutVarTable.append(value) elif (volStick and varName): # VOLSTICK 画彩色柱状线 outVar = self.VarTable[varName] value = OutVariable(name=varName, data=outVar, type=6) if color: value.Color = color self.OutVarTable.append(value) elif (varName and color): outVar = self.VarTable[varName] if not JSComplierHelper.IsArray(outVar): outVar = self.SingleDataToArrayData(outVar) value = OutVariable(name=varName, data=outVar, type=0) value.Color = color if (lineWidth): value.LineWidth = lineWidth if (isShow == False): value.IsShow = False if (isExData == True): value.IsExData = True self.OutVarTable.append(value) elif (draw and color): value = OutVariable(name=draw.Name, data=draw, type=1) value.Color = color self.OutVarTable.append(value) elif (colorStick and varName ): # CYW: SUM(VAR4,10)/10000, COLORSTICK; 画上下柱子 outVar = self.VarTable[varName] value = OutVariable(name=varName, data=outVar, type=2) value.Color = color self.OutVarTable.append(value) elif (varName): outVar = self.VarTable[varName] value = OutVariable(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 self.OutVarTable.append(value) return self.OutVarTable def VisitNode(self, node): if node.Type == Syntax.SequenceExpression: self.VisitSequenceExpression(node) elif node.Type == Syntax.ExpressionStatement: self.VisitNode(node.Expression) elif node.Type == Syntax.AssignmentExpression: self.VisitAssignmentExpression(node) elif node.Type in (Syntax.BinaryExpression, Syntax.LogicalExpression): self.VisitBinaryExpression(node) elif node.Type == Syntax.CallExpression: self.VisitCallExpression(node) def VisitSequenceExpression(self, node): for item in node.Expression: self.VisitNode(item) # 函数调用 def VisitCallExpression(self, node): funcName = node.Callee.Name args = [] for item in node.Arguments: if item.Type == Syntax.BinaryExpression or item.Type == Syntax.LogicalExpression: value = self.VisitBinaryExpression(item) elif item.Type == Syntax.CallExpression: value = self.VisitCallExpression(item) else: value = self.GetNodeValue(item) args.append(value) # console.log('[JSExecute::VisitCallExpression]' , funcName, '(', args.toString() ,')'); if funcName == 'DYNAINFO': # 行情最新数据 node.Out = self.SymbolData.GetLatestCacheData(int(args[0])) elif funcName == 'STICKLINE': node.Draw = self.Draw.STICKLINE(args[0], args[1], args[2], args[3], args[4]) node.Out = [] elif funcName == 'DRAWTEXT': node.Draw = self.Draw.DRAWTEXT(args[0], args[1], args[2]) node.Out = [] elif funcName == 'SUPERDRAWTEXT': node.Draw = self.Draw.SUPERDRAWTEXT(args[0], args[1], args[2], args[3], args[4]) node.Out = [] elif funcName == 'DRAWICON': node.Draw = self.Draw.DRAWICON(args[0], args[1], int(args[2])) node.Out = [] elif funcName == 'DRAWLINE': node.Draw = self.Draw.DRAWLINE(args[0], args[1], args[2], args[3], int(args[4])) node.Out = node.Draw.DrawData elif funcName == 'DRAWBAND': node.Draw = self.Draw.DRAWBAND(args[0], args[1], args[2], args[3]) node.Out = [] elif funcName == 'DRAWKLINE': node.Draw = self.Draw.DRAWKLINE(args[0], args[1], args[2], args[3]) node.Out = [] elif funcName == 'DRAWKLINE_IF': node.Draw = self.Draw.DRAWKLINE_IF(args[0], args[1], args[2], args[3], args[4]) node.Out = [] elif funcName in ('PLOYLINE', 'POLYLINE'): node.Draw = self.Draw.POLYLINE(args[0], args[1]) node.Out = node.Draw.DrawData elif funcName == 'DRAWNUMBER': node.Draw = self.Draw.DRAWNUMBER(args[0], args[1], args[2]) node.Out = node.Draw.DrawData.Value elif funcName == "DRAWCHANNEL": node.Draw = self.Draw.DRAWCHANNEL(args[0], args[1], args[2], args[3], int(args[4]), args[5], args[6]) node.Out = [] elif funcName == 'CODELIKE': node.Out = self.SymbolData.CODELIKE(args[0]) elif funcName == 'NAMELIKE': node.Out = self.SymbolData.NAMELIKE(args[0]) elif funcName == 'REFDATE': node.Out = self.SymbolData.REFDATE(args[0], args[1]) elif funcName == 'FINANCE': node.Out = self.SymbolData.GetFinanceCacheData(args[0], node) elif funcName == "MARGIN": node.Out = self.SymbolData.GetMarginCacheData(int(args[0]), node) elif funcName == "HK2SHSZ": node.Out = self.SymbolData.GetHKToSHSZCacheData(args[0], node) elif funcName == "NEWS": node.Out = self.SymbolData.GetNewsAnalysisCacheData(args[0], node) elif funcName in ('UPCOUNT', 'DOWNCOUNT'): node.Out = self.SymbolData.GetIndexIncreaseCacheData( funcName, args[0], node) else: node.Out = self.Algorithm.CallFunction(funcName, args, node) return node.Out # 赋值 def VisitAssignmentExpression(self, node): left = node.Left if left.Type != Syntax.Identifier: self.ThrowUnexpectedNode(node) varName = left.Name right = node.Right value = None if right.Type == Syntax.BinaryExpression or right.Type == Syntax.LogicalExpression: value = self.VisitBinaryExpression(right) elif right.Type == Syntax.CallExpression: value = self.VisitCallExpression(right) elif right.Type == Syntax.Literal: value = right.Value elif right.Type == Syntax.Identifier: # 右值是变量 value = self.ReadVariable(right.Name, right) # console.log('[JSExecute::VisitAssignmentExpression]' , varName, ' = ',value); self.VarTable[varName] = value # 逻辑运算 def VisitBinaryExpression(self, node): stack = [] stack.append(node) temp = None while len(stack) != 0: temp = stack[-1] if isinstance( temp, (BinaryExpression, AssignmentExpression )) and temp.Left and node != temp.Left and node != temp.Right: stack.append(temp.Left) elif isinstance( temp, (BinaryExpression, AssignmentExpression)) and temp.Right and node != temp.Right: stack.append(temp.Right) else: value = stack.pop() if value.Type == Syntax.BinaryExpression: # 只遍历操作符就可以 leftValue = self.GetNodeValue(value.Left) rightValue = self.GetNodeValue(value.Right) # console.log('[JSExecute::VisitBinaryExpression] BinaryExpression',value , leftValue, rightValue); value.Out = None # 保存中间值 if value.Operator == '-': value.Out = self.Algorithm.Subtract( leftValue, rightValue) elif value.Operator == '*': value.Out = self.Algorithm.Multiply( leftValue, rightValue) elif value.Operator == '/': value.Out = self.Algorithm.Divide( leftValue, rightValue) elif value.Operator == '+': value.Out = self.Algorithm.Add(leftValue, rightValue) elif value.Operator == '>': value.Out = self.Algorithm.GT(leftValue, rightValue) elif value.Operator == '>=': value.Out = self.Algorithm.GTE(leftValue, rightValue) elif value.Operator == '<': value.Out = self.Algorithm.LT(leftValue, rightValue) elif value.Operator == '<=': value.Out = self.Algorithm.LTE(leftValue, rightValue) elif value.Operator in ('=', '=='): value.Out = self.Algorithm.EQ(leftValue, rightValue) elif value.Operator in ('!=', '<>'): value.Out = self.Algorithm.NEQ(leftValue, rightValue) # console.log('[JSExecute::VisitBinaryExpression] BinaryExpression',value); elif value.Type == Syntax.LogicalExpression: leftValue = self.GetNodeValue(value.Left) rightValue = self.GetNodeValue(value.Right) # console.log('[JSExecute::VisitBinaryExpression] LogicalExpression',value , leftValue, rightValue); value.Out = None # 保存中间值 if value.Operator in ('&&', 'AND'): value.Out = self.Algorithm.And(leftValue, rightValue) elif value.Operator in ('||', 'OR'): value.Out = self.Algorithm.Or(leftValue, rightValue) # console.log('[JSExecute::VisitBinaryExpression] LogicalExpression',value); node = temp return node.Out def GetNodeValue(self, node): if node.Type == Syntax.Literal: #数字 return node.Value elif node.Type == Syntax.UnaryExpression: if node.Operator == '-': value = self.GetNodeValue(node.Argument) return self.Algorithm.Subtract(0, value) return node.Argument.Value elif node.Type == Syntax.Identifier: value = self.ReadVariable(node.Name, node) return value elif node.Type in (Syntax.BinaryExpression, Syntax.LogicalExpression): return node.Out elif node.Type == Syntax.CallExpression: return self.VisitCallExpression(node) else: self.ThrowUnexpectedNode(node) def ThrowUnexpectedNode(self, node, message="执行异常"): marker = node.Marker msg = message return self.ErrorHandler.ThrowError(marker.Index, marker.Line, marker.Column, msg) def ThrowError(self): pass
def RunAST(self): # 预定义的变量 for item in self.Arguments: self.VarTable[item.Name] = item.Value if not self.AST or not self.AST.Body: self.ThrowError() for item in self.AST.Body: self.VisitNode(item) if item.Type == Syntax.ExpressionStatement and item.Expression: if item.Expression.Type == Syntax.AssignmentExpression and item.Expression.Operator == ':' and item.Expression.Left: assignmentItem = item.Expression varName = assignmentItem.Left.Name outVar = self.VarTable[varName] if not isinstance(outVar, list): outVar = self.SingleDataToArrayData(outVar) self.OutVarTable.append( OutVariable(name=varName, data=outVar, type=0)) elif (item.Expression.Type == Syntax.CallExpression): callItem = item.Expression if (JSDraw.IsDrawFunction(callItem.Callee.Name)): draw = callItem.Draw draw.Name = callItem.Callee.Name self.OutVarTable.append( OutVariable(name=draw.Name, draw=draw, type=1)) elif (item.Expression.Type == Syntax.SequenceExpression): varName = None draw = None color = None lineWidth = None colorStick = False pointDot = False circleDot = False lineStick = False stick = False volStick = False isShow = True isExData = False for itemExpression in item.Expression.Expression: if (itemExpression.Type == Syntax.AssignmentExpression and itemExpression.Operator == ':' and itemExpression.Left): varName = itemExpression.Left.Name varValue = self.VarTable[varName] if not JSComplierHelper.IsArray(varValue): varValue = self.SingleDataToArrayData(varValue) self.VarTable[ varName] = varValue # 把单数值转化成数组放到变量表里 elif (itemExpression.Type == Syntax.Identifier): value = itemExpression.Name if (value == 'COLORSTICK'): colorStick = True elif (value == 'POINTDOT'): pointDot = True elif (value == 'CIRCLEDOT'): circleDot = True elif (value == 'LINESTICK'): lineStick = True elif (value == 'STICK'): stick = True elif (value == 'VOLSTICK'): volStick = True elif (value.find('COLOR') == 0): color = value elif (value.find('LINETHICK') == 0): lineWidth = value elif (value.find('NODRAW') == 0): isShow = False elif (value.find('EXDATA') == 0): isExData = True # 扩展数据, 不显示再图形里面 elif (itemExpression.Type == Syntax.Literal): #常量 aryValue = self.SingleDataToArrayData( itemExpression.Value) varName = str(itemExpression.Value) self.VarTable[varName, aryValue] # 把常量放到变量表里 elif (itemExpression.Type == Syntax.CallExpression and JSDraw.IsDrawFunction( itemExpression.Callee.Name)): draw = itemExpression.Draw draw.Name = itemExpression.Callee.Name if (pointDot and varName): # 圆点 outVar = self.VarTable[varName] if (not JSComplierHelper.IsArray(outVar)): outVar = self.SingleDataToArrayData(outVar) value = OutVariable(name=varName, data=outVar, type=3) value.Radius = 2 if color: value.Color = color if lineWidth: value.LineWidth = lineWidth self.OutVarTable.append(value) elif (circleDot and varName): # 圆点 outVar = self.VarTable[varName] if not JSComplierHelper.IsArray(outVar): outVar = self.SingleDataToArrayData(outVar) value = OutVariable(name=varName, data=outVar, type=3) value.Radius = 1.3 if color: value.Color = color if lineWidth: value.LineWidth = lineWidth self.OutVarTable.append(value) elif (lineStick and varName): # LINESTICK 同时画出柱状线和指标线 outVar = self.VarTable[varName] value = OutVariable(name=varName, data=outVar, type=4) if color: value.Color = color if lineWidth: value.LineWidth = lineWidth self.OutVarTable.append(value) elif (stick and varName): # STICK 画柱状线 outVar = self.VarTable[varName] value = OutVariable(name=varName, data=outVar, type=5) if color: value.Color = color if lineWidth: value.LineWidth = lineWidth self.OutVarTable.append(value) elif (volStick and varName): # VOLSTICK 画彩色柱状线 outVar = self.VarTable[varName] value = OutVariable(name=varName, data=outVar, type=6) if color: value.Color = color self.OutVarTable.append(value) elif (varName and color): outVar = self.VarTable[varName] if not JSComplierHelper.IsArray(outVar): outVar = self.SingleDataToArrayData(outVar) value = OutVariable(name=varName, data=outVar, type=0) value.Color = color if (lineWidth): value.LineWidth = lineWidth if (isShow == False): value.IsShow = False if (isExData == True): value.IsExData = True self.OutVarTable.append(value) elif (draw and color): value = OutVariable(name=draw.Name, data=draw, type=1) value.Color = color self.OutVarTable.append(value) elif (colorStick and varName ): # CYW: SUM(VAR4,10)/10000, COLORSTICK; 画上下柱子 outVar = self.VarTable[varName] value = OutVariable(name=varName, data=outVar, type=2) value.Color = color self.OutVarTable.append(value) elif (varName): outVar = self.VarTable[varName] value = OutVariable(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 self.OutVarTable.append(value) return self.OutVarTable