You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1120 lines
56 KiB

  1. /*
  2. copyright (c) 2018 jones
  3. http://www.apache.org/licenses/LICENSE-2.0
  4. 开源项目 https://github.com/jones2000/HQChart
  5. jones_2000@163.com
  6. 分析家脚本翻译器
  7. */
  8. import { JSConsole } from "./umychart.console.wechat.js"
  9. import {
  10. ErrorHandler,
  11. JSComplier,
  12. JSParser,
  13. Syntax,
  14. JS_EXECUTE_JOB_ID,
  15. g_JSComplierResource,
  16. } from "./umychart.complier.wechat";
  17. import
  18. {
  19. IFrameSplitOperator,
  20. } from './umychart.framesplit.wechat.js'
  21. //脚本说明
  22. function JSExplainer(ast,option)
  23. {
  24. this.AST=ast;
  25. this.ErrorHandler=new ErrorHandler();
  26. this.ErrorCallback; //执行错误回调
  27. this.UpdateUICallback;
  28. this.CallbackParam;
  29. this.JobList=[]; //执行的任务队列
  30. this.VarTable=new Map(); //变量表
  31. this.OutVarTable=[]; //输出变量
  32. this.MaxValueLength=100; //最长的字符
  33. //脚本自动变量表, 只读
  34. this.ConstVarTable=new Map(
  35. [
  36. //个股数据
  37. ['CLOSE',"收盘价"],['VOL',"成交量"],['OPEN',"开盘价"],['HIGH',"最高价"],['LOW',"最低价"],['AMOUNT',"成交量"],
  38. ['C',"收盘价"],['V',"成交量"],['O',"开盘价"],['H',"最高价"],['L',"最低价"],['AMO',"成交量"],
  39. ['VOLR',"量比"], ['VOLINSTK',"持仓量"], ["OPI","持仓量"], ["ZSTJJ","均价"], ["QHJSJ","结算价"], ["SETTLE", "结算价"],
  40. //日期类
  41. ['DATE',"日期"],['YEAR',"年份"],['MONTH',"月份"],['PERIOD', "周期"],['WEEK',"星期"],["TIME","时间"],
  42. //大盘数据
  43. ['INDEXA',"大盘成交额"],['INDEXC',"大盘收盘价"],['INDEXH',"大盘最高价"],['INDEXL',"大盘最低价"],['INDEXO',"大盘开盘价"],['INDEXV',"大盘成交量"],
  44. ['INDEXADV',"大盘上涨家数"],['INDEXDEC',"´大盘下跌家数"],
  45. ["ADVANCE","上涨家数"], ['DECLINE', "下跌家数"],
  46. ['FROMOPEN',"当前离开盘分钟数"],
  47. ['TOTALFZNUM', "总分钟数"],
  48. ['CURRBARSCOUNT',"到最后交易的周期"], //到最后交易日的周期数
  49. ['TOTALBARSCOUNT',"总的周期数"],
  50. ['ISLASTBAR',"是否是最后一个周期"], //判断是否为最后一个周期
  51. ['BARSTATUS',"数据位置状态"], //BARSTATUS返回数据位置信息,1表示第一根K线,2表示最后一个数据,0表示中间位置.
  52. ['CAPITAL',"当前流通股本(手)"], ["TOTALCAPITAL","当前总股本(手)"],
  53. ['EXCHANGE',"换手率"], //换手率
  54. ['SETCODE', "市场类型"], //市场类型
  55. ['CODE',"品种代码"], //品种代码
  56. ['STKNAME',"品种名称"], //品种名称
  57. ["TQFLAG","当前复权状态"], //TQFLAG 当前的复权状态,0:无复权 1:前复权 2:后复权
  58. ['HYBLOCK',"所属行业"], //所属行业板块
  59. ['DYBLOCK',"所属地域"], //所属地域板块
  60. ['GNBLOCK',"所属概念"], //所属概念
  61. ["FGBLOCK","所属风格板块"],
  62. ["ZSBLOCK","所属指数板块"],
  63. ["ZHBLOCK",'所属组合板块'],
  64. ["ZDBLOCK",'所属自定义板块'],
  65. ["HYZSCODE","所属行业的板块指数代码"],
  66. ["GNBLOCKNUM","所属概念板块的个数"],
  67. ["FGBLOCKNUM","所属风格板块的个数"],
  68. ["ZSBLOCKNUM","所属指数板块的个数"],
  69. ["ZHBLOCKNUM","所属组合板块的个数"],
  70. ["ZDBLOCKNUM","所属自定义板块的个数"],
  71. ["HYSYL","指数市盈率或个股所属行业的市盈率"],
  72. ["HYSJL","指数市净率或个股所属行业的市净率"],
  73. ['DRAWNULL',"无效数据"],
  74. ["LARGEINTRDVOL","逐笔买入大单成交量"],
  75. ["LARGEOUTTRDVOL","逐笔卖出大单成交量"],
  76. ["TRADENUM", "逐笔成交总单数"],
  77. ["TRADEINNUM", "逐笔买入成交单数"],
  78. ["TRADEOUTNUM", "逐笔卖出成交单数"],
  79. ["LARGETRDINNUM", "逐笔买入大单成交单数"],
  80. ["LARGETRDOUTNUM", "逐笔卖出大单成交单数"],
  81. ["CUR_BUYORDER", "总委买量"],
  82. ["CUR_SELLORDER", "总委卖量"],
  83. ["ACTINVOL", "主动买成交量"],
  84. ["ACTOUTVOL", "主动卖成交量"],
  85. ["BIDORDERVOL", "累计总有效委买量"],
  86. ["BIDCANCELVOL", "累计总有效撤买量"],
  87. ["AVGBIDPX", "最新委买均价"],
  88. ["OFFERORDERVOL", "累计总有效委卖量"],
  89. ["OFFERCANCELVOL", "累计总有效撤卖量"],
  90. ["AVGOFFERPX", "最新委卖均价"],
  91. ]);
  92. if (option)
  93. {
  94. if (option.Callback) this.UpdateUICallback=option.Callback;
  95. if (option.CallbackParam) this.CallbackParam=option.CallbackParam;
  96. if (option.Arguments) this.Arguments=option.Arguments;
  97. }
  98. this.Run=function()
  99. {
  100. try
  101. {
  102. this.OutVarTable=[];
  103. this.VarTable=new Map();
  104. JSConsole.Complier.Log('[JSExecute::JSExplainer] Load Arguments', this.Arguments);
  105. for(let i in this.Arguments) //预定义的变量
  106. {
  107. let item =this.Arguments[i];
  108. this.VarTable.set(item.Name,item.Value);
  109. }
  110. let data=this.RunAST();//执行脚本
  111. JSConsole.Complier.Log('[JSExplainer.Run] explain finish', data);
  112. if (this.UpdateUICallback) //回调发送结果, 可以支持异步
  113. {
  114. JSConsole.Complier.Log('[JSExplainer.Run] invoke UpdateUICallback.');
  115. this.UpdateUICallback(data);
  116. }
  117. }
  118. catch(error)
  119. {
  120. JSConsole.Complier.Log('[JSExplainer.Run] throw error ', error);
  121. if (this.ErrorCallback)
  122. {
  123. this.ErrorCallback(error, this.OutVarTable);
  124. }
  125. }
  126. }
  127. this.RunAST=function()
  128. {
  129. if (!this.AST) this.ThrowError();
  130. if (!this.AST.Body) this.ThrowError();
  131. for(let i=0; i<this.AST.Body.length; ++i)
  132. {
  133. let item =this.AST.Body[i];
  134. this.VisitNode(item);
  135. //输出变量
  136. if (item.Type==Syntax.ExpressionStatement && item.Expression)
  137. {
  138. if (item.Expression.Type==Syntax.AssignmentExpression)
  139. {
  140. if (item.Expression.Operator==':' && item.Expression.Left)
  141. {
  142. let assignmentItem=item.Expression;
  143. let varName=assignmentItem.Left.Name;
  144. let outVar=`输出${varName}: ${this.VarTable.get(varName)}`;
  145. this.OutVarTable.push({ Name:varName, Data:outVar,Type:0});
  146. }
  147. else if (item.Expression.Operator==':=' && item.Expression.Left)
  148. {
  149. let assignmentItem=item.Expression;
  150. let varName=assignmentItem.Left.Name;
  151. let outVar=`赋值${varName}: ${this.VarTable.get(varName)}`;
  152. this.OutVarTable.push({ Name:varName, Data:outVar,Type:0, IsOut:false });
  153. }
  154. }
  155. else if (item.Expression.Type==Syntax.CallExpression)
  156. {
  157. let callItem=item.Expression;
  158. if (this.IsDrawFunction(callItem.Callee.Name))
  159. {
  160. let outVar=callItem.Out;
  161. var drawName=callItem.Callee.Name;
  162. this.OutVarTable.push({Name:drawName, Draw:`输出: ${outVar}`, Type:1});
  163. }
  164. else
  165. {
  166. let outVar=callItem.Out;
  167. varName=`__temp_c_${callItem.Callee.Name}_${i}__`;
  168. this.OutVarTable.push({Name:varName, Data:`输出: ${outVar}`,Type:0, NoneName:true});
  169. }
  170. }
  171. else if (item.Expression.Type==Syntax.Identifier)
  172. {
  173. let varName=item.Expression.Name;
  174. let outVar=this.ReadVariable(varName,item.Expression);
  175. varName="__temp_i_"+i+"__";
  176. this.OutVarTable.push({Name:varName, Data:`输出: ${outVar}`, Type:0, NoneName:true});
  177. }
  178. else if (item.Expression.Type==Syntax.Literal) //常量
  179. {
  180. let outVar=item.Expression.Value;
  181. if (IFrameSplitOperator.IsString(outVar) && outVar.indexOf("$")>0)
  182. outVar=this.GetOtherSymbolExplain({ Literal:outVar }, item);
  183. varName="__temp_li_"+i+"__";
  184. var type=0;
  185. this.OutVarTable.push({Name:varName, Data:`输出: ${outVar}`, Type:0, NoneName:true});
  186. }
  187. else if (item.Expression.Type==Syntax.BinaryExpression) // CLOSE+OPEN;
  188. {
  189. var varName="__temp_b_"+i+"__";
  190. let outVar=item.Expression.Out;
  191. this.OutVarTable.push({Name:varName, Data:`输出: ${outVar}`,Type:0, NoneName:true});
  192. }
  193. else if (item.Expression.Type==Syntax.LogicalExpression) //逻辑语句 如 T1 AND T2
  194. {
  195. var varName="__temp_l_"+i+"__";
  196. let outVar=item.Expression.Out;
  197. this.OutVarTable.push({Name:varName, Data:`输出: ${outVar}`,Type:0, NoneName:true});
  198. }
  199. else if (item.Expression.Type==Syntax.SequenceExpression)
  200. {
  201. let varName;
  202. let drawName;
  203. let draw;
  204. let color;
  205. let lineWidth;
  206. let colorStick=false;
  207. let pointDot=false;
  208. let circleDot=false;
  209. let lineStick=false;
  210. let stick=false;
  211. let volStick=false;
  212. let isShow=true;
  213. let isExData=false;
  214. let isDotLine=false;
  215. let isOverlayLine=false; //叠加线
  216. var isNoneName=false;
  217. //显示在位置之上,对于DRAWTEXT和DRAWNUMBER等函数有用,放在语句的最后面(不能与LINETHICK等函数共用),比如:
  218. //DRAWNUMBER(CLOSE>OPEN,HIGH,CLOSE),DRAWABOVE;
  219. var isDrawAbove=false;
  220. for(let j in item.Expression.Expression)
  221. {
  222. let itemExpression=item.Expression.Expression[j];
  223. if (itemExpression.Type==Syntax.AssignmentExpression && itemExpression.Operator==':' && itemExpression.Left)
  224. {
  225. varName=itemExpression.Left.Name;
  226. let varValue=this.VarTable.get(varName);
  227. this.VarTable.set(varName,this.ConvertToShortValue(varValue)); //把常量放到变量表里
  228. }
  229. else if (itemExpression.Type==Syntax.Identifier)
  230. {
  231. let value=itemExpression.Name;
  232. if (value==='COLORSTICK') colorStick=true;
  233. else if (value==='POINTDOT') pointDot=true;
  234. else if (value==='CIRCLEDOT') circleDot=true;
  235. else if (value==='DOTLINE') isDotLine=true;
  236. else if (value==='LINESTICK') lineStick=true;
  237. else if (value==='STICK') stick=true;
  238. else if (value==='VOLSTICK') volStick=true;
  239. else if (value==="DRAWABOVE") isDrawAbove=true;
  240. else if (value.indexOf('COLOR')==0) color=value;
  241. else if (value.indexOf('LINETHICK')==0) lineWidth=value;
  242. else if (value.indexOf('NODRAW')==0) isShow=false;
  243. else if (value.indexOf('EXDATA')==0) isExData=true; //扩展数据, 不显示再图形里面
  244. else if (value.indexOf('LINEOVERLAY')==0) isOverlayLine=true;
  245. else
  246. {
  247. varName=itemExpression.Name;
  248. let varValue=this.ReadVariable(varName,itemExpression);
  249. varName="__temp_si_"+i+"__";
  250. isNoneName=true;
  251. this.VarTable.set(varName,this.ConvertToShortValue(varValue)); //放到变量表里
  252. }
  253. }
  254. else if(itemExpression.Type==Syntax.Literal) //常量
  255. {
  256. let aryValue=itemExpression.Value;
  257. varName=itemExpression.Value.toString();
  258. isNoneName=true;
  259. this.VarTable.set(varName,aryValue); //把常量放到变量表里
  260. }
  261. else if (itemExpression.Type==Syntax.CallExpression)
  262. {
  263. if (this.IsDrawFunction(itemExpression.Callee.Name))
  264. {
  265. draw=itemExpression.Out;
  266. drawName=itemExpression.Callee.Name;
  267. }
  268. else
  269. {
  270. let varValue=itemExpression.Out;
  271. varName=`__temp_sc_${itemExpression.Callee.Name}_${i}__`;
  272. isNoneName=true;
  273. this.VarTable.set(varName,varValue);
  274. }
  275. }
  276. else if (itemExpression.Type==Syntax.BinaryExpression)
  277. {
  278. varName="__temp_sb_"+i+"__";
  279. let aryValue=itemExpression.Out;
  280. isNoneName=true;
  281. this.VarTable.set(varName,aryValue);
  282. }
  283. }
  284. var outValue;
  285. if (draw) outValue=`输出: ${draw}`;
  286. else if (isNoneName) outValue=`输出: ${this.VarTable.get(varName)}`;
  287. else outValue=`输出${varName}: ${this.VarTable.get(varName)}`;
  288. if (color) outValue+=`,颜色${this.GetColorExplain(color)}`;
  289. if (lineWidth) outValue+=`,线段粗细${this.GetLineWidthExplain(lineWidth)}`;
  290. if (isShow==false) outValue+=",不显示";
  291. if (isDotLine==true) outValue+=",画虚线";
  292. if (isDrawAbove==true) outValue+=',显示在位置之上';
  293. if (pointDot && varName) //圆点
  294. {
  295. outValue+=",画小圆点线";
  296. let value={Name:varName, Data:outValue, Radius:g_JSChartResource.POINTDOT.Radius, Type:3};
  297. this.OutVarTable.push(value);
  298. }
  299. else if (circleDot && varName) //圆点
  300. {
  301. outValue+=",画小圆圈线";
  302. let value={Name:varName, Data:outValue, Radius:g_JSChartResource.CIRCLEDOT.Radius, Type:3};
  303. this.OutVarTable.push(value);
  304. }
  305. else if (lineStick && varName) //LINESTICK 同时画出柱状线和指标线
  306. {
  307. outValue+=",画出柱状线和指标线";
  308. let value={Name:varName, Data:outValue, Type:4};
  309. this.OutVarTable.push(value);
  310. }
  311. else if (stick && varName) //STICK 画柱状线
  312. {
  313. outValue+=",画柱状线";
  314. let value={Name:varName, Data:outValue, Type:5};
  315. this.OutVarTable.push(value);
  316. }
  317. else if (volStick && varName) //VOLSTICK 画彩色柱状线
  318. {
  319. outValue+=",画成交量柱状线";
  320. let value={Name:varName, Data:outValue, Type:6};
  321. this.OutVarTable.push(value);
  322. }
  323. else if (varName && color)
  324. {
  325. let value={Name:varName, Data:outValue, Color:color, Type:0};
  326. this.OutVarTable.push(value);
  327. }
  328. else if (draw) //画图函数
  329. {
  330. var outVar={ Name:drawName, Data:outValue, Type:1 };
  331. this.OutVarTable.push(outVar);
  332. }
  333. else if (colorStick && varName) //CYW: SUM(VAR4,10)/10000, COLORSTICK; 画上下柱子
  334. {
  335. outValue+=",画彩色柱状线";
  336. let value={Name:varName, Data:outValue, Color:color, Type:2};
  337. this.OutVarTable.push(value);
  338. }
  339. else if (varName)
  340. {
  341. let value={Name:varName, Data:outValue,Type:0};
  342. this.OutVarTable.push(value);
  343. }
  344. }
  345. }
  346. }
  347. JSConsole.Complier.Log('[JSExplainer::Run]', this.VarTable);
  348. return this.OutVarTable;
  349. }
  350. this.VisitNode=function(node)
  351. {
  352. switch(node.Type)
  353. {
  354. case Syntax.SequenceExpression:
  355. this.VisitSequenceExpression(node);
  356. break;
  357. case Syntax.ExpressionStatement:
  358. this.VisitNode(node.Expression);
  359. break;
  360. case Syntax.AssignmentExpression:
  361. this.VisitAssignmentExpression(node);
  362. break;
  363. case Syntax.BinaryExpression:
  364. case Syntax.LogicalExpression:
  365. this.VisitBinaryExpression(node);
  366. break;
  367. case Syntax.CallExpression:
  368. this.VisitCallExpression(node);
  369. break;
  370. }
  371. }
  372. this.VisitSequenceExpression=function(node)
  373. {
  374. for(let i in node.Expression)
  375. {
  376. let item =node.Expression[i];
  377. this.VisitNode(item);
  378. }
  379. }
  380. //函数调用
  381. this.VisitCallExpression=function(node)
  382. {
  383. let funcName=node.Callee.Name;
  384. let args=[];
  385. for(let i in node.Arguments)
  386. {
  387. let item=node.Arguments[i];
  388. let value;
  389. if (item.Type==Syntax.BinaryExpression || item.Type==Syntax.LogicalExpression)
  390. value=this.VisitBinaryExpression(item);
  391. else if (item.Type==Syntax.CallExpression)
  392. value=this.VisitCallExpression(item);
  393. else
  394. value=this.GetNodeValue(item);
  395. args.push(value);
  396. }
  397. JSConsole.Complier.Log('[JSExplainer::VisitCallExpression]' , funcName, '(', args.toString() ,')');
  398. if (g_JSComplierResource.IsCustomFunction(funcName))
  399. {
  400. var data=this.Algorithm.CallCustomFunction(funcName, args, this.SymbolData, node);
  401. node.Out=[];
  402. node.Draw=null;
  403. if (data)
  404. {
  405. if (data.Out) node.Out=data.Out;
  406. if (data.Draw) node.Draw=data.Draw;
  407. }
  408. return node.Out;
  409. }
  410. node.Out=this.CallFunctionExplain(funcName, args, node);
  411. return node.Out;
  412. }
  413. this.FUNCTION_INFO_LIST=new Map(
  414. [
  415. ["REF", { Name:"REF", Param:{ Count:2 }, ToString:function(args) { return `${args[1]}日前的${args[0]}`; } } ],
  416. ["REFX", { Name:"REFX", Param:{ Count:2 }, ToString:function(args) { return `${args[1]}日后的${args[0]}`; } } ],
  417. ["REFV", { Name:"REFV", Param:{ Count:2 }, ToString:function(args) { return `${args[1]}日前的(未作平滑处理)${args[0]}`; } } ],
  418. ["REFXV", { Name:"REFXV", Param:{ Count:2 }, ToString:function(args) { return `${args[1]}日后的(未作平滑处理)${args[0]}`; } } ],
  419. ["REFDATE", { Name:"REFDATE", Param:{ Count:2 }, ToString:function(args) { return `${args[1]}${args[0]}`; } } ],
  420. ["COUNT", { Name:"COUNT", Param:{ Count:2 }, ToString:function(args) { return `统计${args[1]}日中满足${args[0]}的天数`; } } ],
  421. ["BARSLASTCOUNT", { Name:"BARSLASTCOUNT", Param:{ Count:1 }, ToString:function(args) { return `条件${args[0]}连续成立次数`; } } ],
  422. ["BARSCOUNT", { Name:"BARSCOUNT", Param:{ Count:1 }, ToString:function(args) { return `${args[0]}有效数据周期数`; } } ],
  423. ["BARSLAST", { Name:"BARSLAST", Param:{ Count:1 }, ToString:function(args) { return `上次${args[0]}不为0距今天数`; } } ],
  424. ["BARSNEXT", { Name:"BARSNEXT", Param:{ Count:1 }, ToString:function(args) { return `下次${args[0]}不为0距今天数`; } } ],
  425. ["BARSSINCEN", { Name:"BARSSINCEN", Param:{ Count:2 }, ToString:function(args) { return `${args[1]}周期内首次${args[0]}距今天数`; } } ],
  426. ["BARSSINCE", { Name:"BARSSINCE", Param:{ Count:1 }, ToString:function(args) { return `首次${args[0]}距今天数`; } } ],
  427. ["HHV", { Name:"HHV", Param:{ Count:2 }, ToString:function(args) { return `${args[1]}日内${args[0]}的最高值`; } } ],
  428. ["LLV", { Name:"LLV", Param:{ Count:2 }, ToString:function(args) { return `${args[1]}日内${args[0]}的最低值`; } } ],
  429. ["ZTPRICE", { Name:"ZTPRICE", Param:{ Count:2 }, ToString:function(args) { return '计算涨停价'; } } ],
  430. ["DTPRICE", { Name:"DTPRICE", Param:{ Count:2 }, ToString:function(args) { return '计算跌停价'; } } ],
  431. ["BACKSET", { Name:"BACKSET", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}则将最近${args[1]}周期置为1`; } } ],
  432. ["HOD", { Name:"HOD", Param:{ Count:2 }, ToString:function(args) { return `${args[1]}日内${args[0]}的高值名次`; } } ],
  433. ["LOD", { Name:"LOD", Param:{ Count:2 }, ToString:function(args) { return `${args[1]}日内${args[0]}的低值名次`; } } ],
  434. ["REVERSE", { Name:"REVERSE", Param:{ Count:1 }, ToString:function(args) { return `${args[0]}的相反数`; } } ],
  435. ["FILTER", { Name:"FILTER", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}${args[1]}日过滤`; } } ],
  436. ["FILTERX", { Name:"FILTERX", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}${args[1]}日反向过滤`; } } ],
  437. ["TFILTER", { Name:"TFILTER", Param:{Count:3}, ToString:function(args) { return `信号过滤(多头)`; } }],
  438. ["SUMBARS", { Name:"SUMBARS", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}累加至${args[1]}的天数`; } } ],
  439. ["MA", { Name:"MA", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}${args[1]}日简单移动平均`; } } ],
  440. ["SMA", { Name:"SMA", Param:{ Count:3 }, ToString:function(args) { return `${args[0]}${args[1]}日[${args[2]}日权重]移动平均`; } } ],
  441. ["MEMA", { Name:"MEMA", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}${args[1]}日平滑移动平均`; } } ],
  442. ["EMA", { Name:"EMA", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}${args[1]}日指数移动平均`; } } ],
  443. ["EXPMA", { Name:"EXPMA", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}${args[1]}日指数移动平均`; } } ],
  444. ["WMA", { Name:"WMA", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}${args[1]}日加权移动平均`; } } ],
  445. ["DMA", { Name:"DMA", Param:{ Count:2 }, ToString:function(args) { return `${args[1]}为权重${args[0]}的动态移动平均`; } } ],
  446. ["XMA", { Name:"XMA", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}${args[1]}日偏移移动平均`; } } ],
  447. ["RANGE", { Name:"RANGE", Param:{ Count:3 }, ToString:function(args) { return `${args[0]}位于${args[1]}${args[2]}之间`; } } ],
  448. ["CONST", { Name:"CONST", Param:{ Count:1 }, ToString:function(args) { return `${args[0]}的最后一日值`; } } ],
  449. ["TOPRANGE", { Name:"TOPRANGE", Param:{ Count:1 }, ToString:function(args) { return `当前值是近${args[0]}周期的最大值`; } } ],
  450. ["LOWRANGE", { Name:"LOWRANGE", Param:{ Count:1 }, ToString:function(args) { return `当前值是近${args[0]}周期的最小值`; } } ],
  451. ["FINDHIGH", { Name:"FINDHIGH", Param:{ Count:4 }, ToString:function(args) { return `${args[0]}${args[1]}日前的${args[2]}天内第${args[3]}个最高价`; } } ],
  452. ["FINDHIGHBARS", { Name:"FINDHIGHBARS", Param:{ Count:4 }, ToString:function(args) { return `${args[0]}${args[1]}日前的${args[2]}天内第${args[3]}个最高价到当前周期的周期数`; } } ],
  453. ["FINDLOW", { Name:"FINDLOW", Param:{ Count:4 }, ToString:function(args) { return `${args[0]}${args[1]}日前的${args[2]}天内第${args[3]}个最低价`; } } ],
  454. ["FINDLOWBARS", { Name:"FINDLOWBARS", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}${args[1]}日前的${args[2]}天内第${args[3]}个最低价到当前周期的周期数`; } } ],
  455. ["SUM", { Name:"SUM", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}${args[1]}日累加`; } } ],
  456. ["MULAR", { Name:"MULAR", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}${args[1]}日累乘`; } } ],
  457. ["AMA", { Name:"AMA", Param:{ Count:2 }, ToString:function(args) { return `${args[1]}为权重${args[0]}的自适应均线`; } } ],
  458. ["TMA", { Name:"TMA", Param:{ Count:3 }, ToString:function(args) { return `${args[0]}${args[1]}日[${args[2]}日权重]移动平均`; } } ],
  459. ["CROSS", { Name:"CROSS", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}上穿${args[1]}`; } } ],
  460. ["LONGCROSS", { Name:"LONGCROSS", Param:{ Count:3 }, ToString:function(args) { return `${args[0]}小于${args[1]}保持${args[2]}个交易日后交叉上穿`; } } ],
  461. ["UPNDAY", { Name:"UPNDAY", Param:{ Count:2 }, ToString:function(args) { return `最近${args[1]}${args[0]}连涨`; } } ],
  462. ["DOWNNDAY", { Name:"DOWNNDAY", Param:{ Count:2 }, ToString:function(args) { return `最近${args[1]}${args[0]}连跌`; } } ],
  463. ["NDAY", { Name:"NDAY", Param:{ Count:3 }, ToString:function(args) { return `最近${args[2]}${args[0]}一直大于${args[1]}`; } } ],
  464. ["EXIST", { Name:"EXIST", Param:{ Count:2 }, ToString:function(args) { return `最近${args[1]}日存在${args[0]}`; } } ],
  465. ["EXISTR", { Name:"EXISTR", Param:{ Count:3 }, ToString:function(args) { return `从前${args[1]}日到前${args[2]}日存在${args[0]}`; } } ],
  466. ["EVERY", { Name:"EVERY", Param:{ Count:2 }, ToString:function(args) { return `最近${args[1]}日一直存在${args[0]}`; } } ],
  467. ["LAST", { Name:"LAST", Param:{ Count:3 }, ToString:function(args) { return `从前${args[1]}日到前${args[2]}日持续${args[0]}`; } } ],
  468. ["NOT", { Name:"NOT", Param:{ Count:1 }, ToString:function(args) { return `${args[0]}取反`; } } ],
  469. ["IF", { Name:"IF", Param:{ Count:3 }, ToString:function(args) { return `如果${args[0]},返回${args[1]},否则返回${args[2]}`; } } ],
  470. ["IFF", { Name:"IFF", Param:{ Count:3 }, ToString:function(args) { return `如果${args[0]},返回${args[1]},否则返回${args[2]}`; } } ],
  471. ["IFN", { Name:"IFN", Param:{ Count:3 }, ToString:function(args) { return `如果${args[0]},返回${args[1]},否则返回${args[2]}`; } } ],
  472. ["IFC", { Name:"IFC", Param:{ Count:3 }, ToString:function(args) { return `如果${args[0]},返回${args[1]},否则返回${args[2]}`; } } ],
  473. ["TESTSKIP", { Name:"TESTSKIP", Param:{ Count:1 }, ToString:function(args) { return `如果满足条件${args[0]},公式返回`; } } ],
  474. ["VALUEWHEN", { Name:"VALUEWHEN", Param:{ Count:2 }, ToString:function(args) { return `如果${args[0]},返回${args[1]},否则返回上个输出值 `; } } ],
  475. ["MAX", { Name:"MAX", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}${args[1]}的较大值`; } } ],
  476. ["MIN", { Name:"MIN", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}${args[1]}的较小值`; } } ],
  477. ["ACOS", { Name:"ACOS", Param:{ Count:1 }, ToString:function(args) { return `${args[0]}的反余弦`; } } ],
  478. ["ASIN", { Name:"ASIN", Param:{ Count:1 }, ToString:function(args) { return `${args[0]}的反正弦`; } } ],
  479. ["ATAN", { Name:"ATAN", Param:{ Count:1 }, ToString:function(args) { return `${args[0]}的反正切`; } } ],
  480. ["COS", { Name:"COS", Param:{ Count:1 }, ToString:function(args) { return `${args[0]}的余弦`; } } ],
  481. ["SIN", { Name:"SIN", Param:{ Count:1 }, ToString:function(args) { return `${args[0]}的正弦`; } } ],
  482. ["TAN", { Name:"TAN", Param:{ Count:1 }, ToString:function(args) { return `${args[0]}的正切`; } } ],
  483. ["EXP", { Name:"EXP", Param:{ Count:1 }, ToString:function(args) { return `${args[0]}的指数`; } } ],
  484. ["LN", { Name:"LN", Param:{ Count:1 }, ToString:function(args) { return `${args[0]}的自然对数`; } } ],
  485. ["LOG", { Name:"LOG", Param:{ Count:1 }, ToString:function(args) { return `${args[0]}的对数`; } } ],
  486. ["SQRT", { Name:"SQRT", Param:{ Count:1 }, ToString:function(args) { return `${args[0]}的开方`; } } ],
  487. ["ABS", { Name:"ABS", Param:{ Count:1 }, ToString:function(args) { return `${args[0]}的绝对值`; } } ],
  488. ["POW", { Name:"POW", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}${args[1]}乘幂`; } } ],
  489. ["CEILING", { Name:"CEILING", Param:{ Count:1 }, ToString:function(args) { return `${args[0]}的向上舍入`; } } ],
  490. ["FLOOR", { Name:"FLOOR", Param:{ Count:1 }, ToString:function(args) { return `${args[0]}的向上舍入`; } } ],
  491. ["INTPART", { Name:"INTPART", Param:{ Count:1 }, ToString:function(args) { return `${args[0]}的整数部分`; } } ],
  492. ["BETWEEN", { Name:"BETWEEN", Param:{ Count:3 }, ToString:function(args) { return `${args[0]}位于${args[1]}${args[2]}之间`; } } ],
  493. ["FRACPART", { Name:"FRACPART", Param:{ Count:1 }, ToString:function(args) { return `${args[0]}的小数部分`; } } ],
  494. ["ROUND", { Name:"ROUND", Param:{ Count:1 }, ToString:function(args) { return `${args[0]}(进行)四舍五入`; } } ],
  495. ["ROUND2", { Name:"ROUND2", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}(进行)四舍五入`; } } ],
  496. ["SIGN", { Name:"SIGN", Param:{ Count:1 }, ToString:function(args) { return `${args[0]}的符号`; } } ],
  497. ["MOD", { Name:"MOD", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}关于${args[1]}的模`; } } ],
  498. ["RAND", { Name:"RAND", Param:{ Count:1 }, ToString:function(args) { return `随机正整数`; } } ],
  499. ["AVEDEV", { Name:"AVEDEV", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}${args[1]}日平均绝对偏差`; } } ],
  500. ["DEVSQ", { Name:"DEVSQ", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}${args[1]}日数据偏差平方和`; } } ],
  501. ["FORCAST", { Name:"FORCAST", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}${args[1]}日线性回归预测值`; } } ],
  502. ["TSMA", { Name:"TSMA", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}${args[1]}个周期内的时间序列三角移动平均`; } } ],
  503. ["SLOPE", { Name:"SLOPE", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}${args[1]}日线性回归斜率`; } } ],
  504. ["STD", { Name:"STD", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}${args[1]}日估算标准差`; } } ],
  505. ["STDP", { Name:"STDP", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}${args[1]}日总体标准差`; } } ],
  506. ["STDDEV", { Name:"STDDEV", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}${args[1]}日标准偏差`; } } ],
  507. ["VAR", { Name:"VAR", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}${args[1]}日估算样本方差`; } } ],
  508. ["VARP", { Name:"VARP", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}${args[1]}日总体样本方差`; } } ],
  509. ["COVAR", { Name:"COVAR", Param:{ Count:3 }, ToString:function(args) { return `${args[0]}${args[1]}${args[2]}周期的协方差`; } } ],
  510. ["RELATE", { Name:"RELATE", Param:{ Count:3 }, ToString:function(args) { return `${args[0]}${args[1]}${args[0]}周期的相关系数`; } } ],
  511. ["BETA", { Name:"BETA", Param:{ Count:1 }, ToString:function(args) { return `β(Beta)系数`; } } ],
  512. ["BETAEX", { Name:"BETAEX", Param:{ Count:3 }, ToString:function(args) { return `${args[0]}${args[1]}${args[2]}周期的相关放大系数`; } } ],
  513. ["COST", { Name:"COST", Param:{ Count:1 }, ToString:function(args) { return `获利盘为${args[0]}%的成本分布`; } } ],
  514. ["WINNER", { Name:"WINNER", Param:{ Count:1 }, ToString:function(args) { return `${args[0]}计算的获利盘比例`; } } ],
  515. ["LWINNER", { Name:"LWINNER", Param:{ Count:2 }, ToString:function(args) { return `最近${args[0]}日那部分成本以${args[1]}价格卖出的获利盘比例`; } } ],
  516. ["PWINNER", { Name:"PWINNER", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}日前那部分成本以${args[1]}价格卖出的获利盘比例`; } } ],
  517. ["COSTEX", { Name:"COSTEX", Param:{ Count:2 }, ToString:function(args) { return `位于价格${args[0]}${args[1]}间的成本`; } } ],
  518. ["PPART", { Name:"PPART", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}日前那部分成本占总成本的比例`; } } ],
  519. ["SAR", { Name:"SAR", Param:{ Count:3 }, ToString:function(args) { return `步长为${args[1]}极限值为${args[0]}${args[2]}日抛物转向`; } } ],
  520. ["SARTURN", { Name:"SARTURN", Param:{ Count:3 }, ToString:function(args) { return `步长为${args[1]}极限值为${args[0]}${args[2]}日抛物转向点`; } } ],
  521. //字符串函数
  522. ["CON2STR", { Name:"CON2STR", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}转为字符串`; } } ],
  523. ["VAR2STR", { Name:"VAR2STR", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}转为字符串`; } } ],
  524. ["STR2CON", { Name:"STR2CON", Param:{ Count:1 }, ToString:function(args) { return `${args[0]}转为数字`; } } ],
  525. ["STRLEN", { Name:"STRLEN", Param:{ Count:1 }, ToString:function(args) { return `得到${args[0]}字符串长度`; } } ],
  526. ["STRCAT", { Name:"STRCAT", Param:{ Count:2 }, ToString:function(args) { return `字符串相加`; } } ],
  527. ["VARCAT", { Name:"VARCAT", Param:{ Count:2 }, ToString:function(args) { return `字符串相加`; } } ],
  528. ["STRSPACE", { Name:"STRSPACE", Param:{ Count:1 }, ToString:function(args) { return `字符串${args[0]}加一空格`; } } ],
  529. ["SUBSTR", { Name:"SUBSTR", Param:{ Count:3 }, ToString:function(args) { return `字符串${args[0]}中取一部分`; } } ],
  530. ["STRCMP", { Name:"STRCMP", Param:{ Count:2 }, ToString:function(args) { return `字符串${args[0]}和字符串${args[1]}比较`; } } ],
  531. ["FINDSTR", { Name:"FINDSTR", Param:{ Count:2 }, ToString:function(args) { return `字符串${args[0]}中查找字符串${args[1]}`; } } ],
  532. ["NAMEINCLUD", { Name:"NAMEINCLUD", Param:{ Count:1 }, ToString:function(args) { return `查找品种名称中包含${args[0]}`; } } ],
  533. ["CODELIKE", { Name:"CODELIKE", Param:{ Count:1 }, ToString:function(args) { return `查找品种名称中包含${args[0]}`; } } ],
  534. ["INBLOCK", { Name:"AVEDEV", Param:{ Count:1 }, ToString:function(args) { return `属于${args[0]}板块`; } } ],
  535. ["STKINDI",{ Name:"STKINDI", Param:{ Dynamic:true }, ToString:function(args) { return "指标引用"; } }],
  536. [
  537. "HHVBARS",
  538. {
  539. Name:"HHVBARS", Param:{ Count:2 },
  540. ToString:function(args)
  541. {
  542. if (args[1]==0) return `历史${args[0]}新高距今天数`;
  543. return `${args[1]}日内${args[0]}新高距今天数`;
  544. }
  545. }
  546. ],
  547. [
  548. "LLVBARS",
  549. {
  550. Name:"LLVBARS", Param:{ Count:2 },
  551. ToString:function(args)
  552. {
  553. if (args[1]==0) return `历史${args[0]}新低距今天数`;
  554. return `${args[1]}日内${args[0]}新低距今天数`;
  555. }
  556. }
  557. ],
  558. ["L2_VOLNUM", { Name:"L2_VOLNUM", Param:{ Count:2 }, ToString:function(args) { return `单数分档`; } }],
  559. ["L2_VOL", { Name:"L2_VOL", Param:{ Count:2 }, ToString:function(args) { return `成交量分档`; } }],
  560. ["L2_AMO", { Name:"L2_AMO", Param:{ Count:2 }, ToString:function(args) { return `成交额分档`; } }],
  561. ]
  562. );
  563. this.CallFunctionExplain=function(funcName, args, node)
  564. {
  565. if (this.FUNCTION_INFO_LIST.has(funcName))
  566. {
  567. var item=this.FUNCTION_INFO_LIST.get(funcName);
  568. if (item.Param.Dynamic===true) //动态参数
  569. {
  570. }
  571. else
  572. {
  573. if (item.Param.Count!=args.length)
  574. this.ThrowUnexpectedNode(node,`函数${funcName}参数个数不正确. 需要${item.Param.Count}个参数`);
  575. }
  576. return item.ToString(args);
  577. }
  578. switch(funcName)
  579. {
  580. case "CALCSTOCKINDEX":
  581. return `引用${args[0]}${args[1]}指标第${args[2]}个输出值`;
  582. case "PEAK":
  583. case "PEAKBARS":
  584. case "ZIG":
  585. case "ZIGA":
  586. case "TROUGH":
  587. case "TROUGHBARS":
  588. return this.GetZIGExplain(funcName,args);
  589. case "FINANCE":
  590. return this.GetFinanceExplain(args);
  591. case "DYNAINFO":
  592. return this.GetDynainfoExplain(args);
  593. case 'CLOSE':
  594. case 'C':
  595. case 'VOL':
  596. case 'V':
  597. case 'OPEN':
  598. case 'O':
  599. case 'HIGH':
  600. case 'H':
  601. case 'LOW':
  602. case 'L':
  603. case 'AMOUNT':
  604. case 'AMO':
  605. return this.GetOtherSymbolExplain( {FunctionName:funcName, Args:args} ,node);
  606. //绘图函数
  607. case "PLOYLINE":
  608. return `当满足条件${args[0]}时以${args[1]}位置为顶点画折线连接`;
  609. case "DRAWLINE":
  610. return `当满足条件${args[0]}时,在${args[1]}位置画直线起点,当满足条件${args[2]}时,在${args[3]}位置画直线终点,${args[4]}表示是否延长`;
  611. case "DRAWSL":
  612. return `当满足条件${args[0]}时,在${args[1]}位置画斜线线性回归,${args[2]}斜率,${args[3]}长度,${args[4]}方向`;
  613. case "DRAWKLINE":
  614. return 'K线';
  615. case "DRAWICON":
  616. return `当满足条件${args[0]}时,在${args[1]}位置画${args[2]}号图标`;
  617. case "DRAWTEXT":
  618. return `当满足条件${args[0]}时,在${args[1]}位置书写文字`;
  619. case "DRAWTEXT_FIX":
  620. return `当满足条件${args[0]}时,在横轴${args[1]}纵轴${args[2]}位置书写文字`;
  621. case "DRAWNUMBER":
  622. return `当满足条件${args[0]}时,在${args[1]}位置书写数字`;
  623. case "DRAWNUMBER_FIX":
  624. return `当满足条件${args[0]}时,在横轴${args[1]}纵轴${args[2]}位置书写数字`;
  625. case "RGB":
  626. return `自定色[${args[0]},${args[1]},${args[2]}]`;
  627. case "DRAWBAND":
  628. return '画带状线';
  629. case "DRAWRECTREL":
  630. return "相对位置上画矩形.";
  631. case "DRAWGBK":
  632. return "填充背景";
  633. case "STICKLINE":
  634. var barType="";
  635. if (args[4]==-1) barType="虚线空心柱";
  636. else if (args[4]==0) barType="实心柱";
  637. else barType="实线空心柱";
  638. return `当满足条件${args[0]}时, 在${args[1]}${args[2]}位置之间画柱状线,宽度为${args[3]},${barType}`;
  639. case "UPCOLOR":
  640. return `上涨颜色${args[0]}`;
  641. case "DOWNCOLOR":
  642. return `下跌颜色${args[0]}`;
  643. case "STICKTYPE":
  644. case "FIRSTDRAW":
  645. return "";
  646. default:
  647. this.ThrowUnexpectedNode(node,`函数${funcName}不存在`);
  648. }
  649. }
  650. this.GetDynainfoExplain=function(args)
  651. {
  652. const DATA_NAME_MAP=new Map(
  653. [
  654. [3,"前收盘价"], [4,"开盘价"], [5,"最高价"], [6,"最低价"], [7,"现价"], [8,'总量'], [9,"现量"],
  655. [10,"总金额"], [11,"均价"], [12,"日涨跌"], [13,"振幅"], [14,"涨幅"], [15,"开盘时的成交金额"],
  656. [16,"前5日每分钟均量"], [17,"量比"], [18,"上涨家数"], [19,"下跌家数"]
  657. ]);
  658. var id=args[0];
  659. if (DATA_NAME_MAP.has(id)) return DATA_NAME_MAP.get(id);
  660. return `即时行情[${id}]`;
  661. }
  662. this.GetFinanceExplain=function(args)
  663. {
  664. const DATA_NAME_MAP=new Map(
  665. [
  666. [1,"总股本"], [2,"市场类型"], [3,"沪深品种类型"], [4,"沪深行业代码"], [5,"B股"], [6,"H股"], [7,"流通股本[股]"], [8,"股东人数[户]"], [9,"资产负债率%"],
  667. [10,"总资产"], [11,"流动资产"], [12,"固定资产"], [13,"无形资产"], [15,"流动负债"], [16,"少数股东权益"]
  668. ]);
  669. var id=args[0];
  670. if (DATA_NAME_MAP.has(id)) return DATA_NAME_MAP.get(id);
  671. return `财务数据[${id}]`;
  672. }
  673. this.GetZIGExplain=function(funcName,args)
  674. {
  675. var value=args[0];
  676. if (value==0) value="开盘价";
  677. else if (value==1) value="最高价";
  678. else if (value==2) value="最低价";
  679. else if (value==3) value="收盘价";
  680. switch(funcName)
  681. {
  682. case "PEAK":
  683. return `${value}${args[1]}%之字转向的前${args[2]}个波峰值`;
  684. case "PEAKBARS":
  685. return `${value}${args[1]}5%之字转向的前${args[2]}个波峰位置`;
  686. case "ZIG":
  687. return `${value}${args[1]}的之字转向`;
  688. case "ZIGA":
  689. return `${value}变化${args[1]}的之字转向`;
  690. case "TROUGH":
  691. return `${value}${args[1]}%之字转向的前${args[2]}个波谷值`;
  692. case "TROUGHBARS":
  693. return `${value}${args[1]}%之字转向的前${args[2]}个波谷位置`;
  694. }
  695. }
  696. this.GetColorExplain=function(colorName)
  697. {
  698. const COLOR_MAP=new Map(
  699. [
  700. ['COLORBLACK','黑色'],['COLORBLUE','蓝色'],['COLORGREEN','绿色'],['COLORCYAN','青色'],['COLORRED','红色'],
  701. ['COLORMAGENTA','洋红色'],['COLORBROWN','棕色'],['COLORLIGRAY','淡灰色'],['COLORGRAY','深灰色'],['COLORLIBLUE','淡蓝色'],
  702. ['COLORLIGREEN','淡绿色'],['COLORLICYAN','淡青色'],['COLORLIRED','淡红色'],['COLORLIMAGENTA','淡洋红色'],['COLORWHITE','白色'],['COLORYELLOW','黄色']
  703. ]);
  704. if (COLOR_MAP.has(colorName)) return COLOR_MAP.get(colorName);
  705. //COLOR 自定义色
  706. //格式为COLOR+“RRGGBB”:RR、GG、BB表示红色、绿色和蓝色的分量,每种颜色的取值范围是00-FF,采用了16进制。
  707. //例如:MA5:MA(CLOSE,5),COLOR00FFFF 表示纯红色与纯绿色的混合色:COLOR808000表示淡蓝色和淡绿色的混合色。
  708. if (colorName.indexOf('COLOR')==0) return '#'+colorName.substr(5);
  709. return 'rgb(30,144,255)';
  710. }
  711. this.GetLineWidthExplain=function(lineWidth)
  712. {
  713. var width=parseInt(lineWidth.replace("LINETHICK",""));
  714. if (IFrameSplitOperator.IsPlusNumber(width)) return width;
  715. return 1;
  716. }
  717. this.SymbolPeriodExplain=function(valueName,period)
  718. {
  719. const mapStockDataName=new Map(
  720. [
  721. ['CLOSE',"收盘价"],["C","收盘价"],['VOL',"成交量"],['V',"成交量"], ['OPEN',"开盘价"], ['O',"开盘价"],
  722. ['HIGH',"最高价"],['H',"最高价"], ['LOW',"最低价"],['L',"最低价"],['AMOUNT',"成交金额"],['AMO',"成交金额"],
  723. ['VOLINSTK',"持仓量"]
  724. ]);
  725. //MIN1,MIN5,MIN15,MIN30,MIN60,DAY,WEEK,MONTH,SEASON,YEAR
  726. const mapPeriodName=new Map(
  727. [
  728. ["MIN1","1分钟"], ["MIN5", "5分钟"], ["MIN15", "15分钟"], ["MIN30","30分钟"],["MIN60","60分钟"],
  729. ["DAY","日"],["WEEK","周"], ["MONTH", "月"], ['SEASON',"季"], ["YEAR", "年"],["WEEK2","双周"], ["HALFYEAR", "半年"]
  730. ]);
  731. var dataName=valueName;
  732. if (mapStockDataName.has(valueName)) dataName=mapStockDataName.get(valueName);
  733. var periodName=period;
  734. if (mapPeriodName.has(period)) periodName=mapPeriodName.get(period);
  735. return `${dataName}[取${periodName}数据]`;
  736. }
  737. this.GetOtherSymbolExplain=function(obj, node)
  738. {
  739. const mapStockDataName=new Map(
  740. [
  741. ['CLOSE',"收盘价"],["C","收盘价"],['VOL',"成交量"],['V',"成交量"], ['OPEN',"开盘价"], ['O',"开盘价"],
  742. ['HIGH',"最高价"],['H',"最高价"], ['LOW',"最低价"],['L',"最低价"],['AMOUNT',"成交金额"],['AMO',"成交金额"],
  743. ['VOLINSTK',"持仓量"]
  744. ]);
  745. if (obj.FunctionName)
  746. {
  747. var args=obj.Args;
  748. var dataName=mapStockDataName.get(obj.FunctionName);
  749. return `[${args[0]}]${dataName}`;
  750. }
  751. else if (obj.Literal)
  752. {
  753. var value=obj.Literal.toUpperCase();
  754. var args=value.split("$");
  755. if (!mapStockDataName.has(args[1])) return "";
  756. var symbol=args[0];
  757. var dataName=mapStockDataName.get(args[1]);
  758. return `[${symbol}]${dataName}`;
  759. }
  760. }
  761. this.IsDrawFunction=function(name)
  762. {
  763. let setFunctionName=new Set(
  764. [
  765. "STICKLINE","DRAWTEXT",'SUPERDRAWTEXT','DRAWLINE','DRAWBAND','DRAWKLINE','DRAWKLINE_IF','PLOYLINE',
  766. 'POLYLINE','DRAWNUMBER',"DRAWNUMBER_FIX",'DRAWICON','DRAWCHANNEL','PARTLINE','DRAWTEXT_FIX','DRAWGBK','DRAWTEXT_LINE','DRAWRECTREL',"DRAWTEXTABS",
  767. 'DRAWOVERLAYLINE',"FILLRGN", "FILLRGN2","FILLTOPRGN", "FILLBOTTOMRGN", "FILLVERTICALRGN","FLOATRGN","DRAWSL", "DRAWGBK2"
  768. ]);
  769. if (setFunctionName.has(name)) return true;
  770. return false;
  771. }
  772. //赋值
  773. this.VisitAssignmentExpression=function(node)
  774. {
  775. let left=node.Left;
  776. if (left.Type!=Syntax.Identifier) this.ThrowUnexpectedNode(node);
  777. let varName=left.Name;
  778. let right=node.Right;
  779. let value=null;
  780. if (right.Type==Syntax.BinaryExpression || right.Type==Syntax.LogicalExpression)
  781. value=this.VisitBinaryExpression(right);
  782. else if (right.Type==Syntax.CallExpression)
  783. value=this.VisitCallExpression(right);
  784. else if (right.Type==Syntax.Literal)
  785. {
  786. value=right.Value;
  787. if (IFrameSplitOperator.IsString(value) && right.Value.indexOf("$")>0)
  788. value=this.GetOtherSymbolExplain({ Literal:value }, node);
  789. }
  790. else if (right.Type==Syntax.Identifier) //右值是变量
  791. value=this.ReadVariable(right.Name,right);
  792. else if (right.Type==Syntax.MemberExpression)
  793. value=this.ReadMemberVariable(right);
  794. else if (right.Type==Syntax.UnaryExpression)
  795. {
  796. if (right.Operator=='-')
  797. {
  798. var tempValue=this.GetNodeValue(right.Argument);
  799. value='-'+tempValue;
  800. }
  801. else
  802. {
  803. value=right.Argument.Value;
  804. }
  805. }
  806. JSConsole.Complier.Log('[JSExplainer::VisitAssignmentExpression]' , varName, ' = ',value);
  807. this.VarTable.set(varName,this.ConvertToShortValue(value));
  808. }
  809. this.ConvertToShortValue=function(value)
  810. {
  811. var maxLength=this.MaxValueLength;
  812. if (value && value.length>=maxLength)
  813. {
  814. var shortValue=value.slice(0, maxLength-10);
  815. shortValue+="......";
  816. return shortValue;
  817. }
  818. return value;
  819. }
  820. this.ReadMemberVariable=function(node)
  821. {
  822. var obj=node.Object;
  823. var member=node.Property;
  824. let maiObj;
  825. if (obj.Type==Syntax.BinaryExpression || obj.Type==Syntax.LogicalExpression )
  826. maiObj=this.VisitBinaryExpression(obj);
  827. else if (obj.Type==Syntax.CallExpression)
  828. maiObj=this.VisitCallExpression(obj);
  829. else
  830. {
  831. if (member.Name.indexOf('#')>0)
  832. {
  833. var aryValue=member.Name.split("#");
  834. var value=`${obj.Name}${aryValue[0]}[周期${aryValue[1]}]`;
  835. }
  836. else
  837. {
  838. var value=`${obj.Name}${member.Name}`;
  839. }
  840. return value;
  841. }
  842. if (!maiObj) return null;
  843. var value=maiObj[member.Name];
  844. if (value) return value;
  845. return null;
  846. }
  847. //逻辑运算
  848. this.VisitBinaryExpression=function(node)
  849. {
  850. let stack=[];
  851. stack.push(node);
  852. let temp=null;
  853. while(stack.length!=0)
  854. {
  855. temp=stack[stack.length-1];
  856. if (temp.Left && node!=temp.Left && node!=temp.Right)
  857. {
  858. stack.push(temp.Left);
  859. }
  860. else if (temp.Right && node!=temp.Right)
  861. {
  862. stack.push(temp.Right);
  863. }
  864. else
  865. {
  866. let value=stack.pop();
  867. if (value.Type==Syntax.BinaryExpression) //只遍历操作符就可以
  868. {
  869. let leftValue=this.GetNodeValue(value.Left);
  870. let rightValue=this.GetNodeValue(value.Right);
  871. JSConsole.Complier.Log('[JSExplainer::VisitBinaryExpression] BinaryExpression',value , leftValue, rightValue);
  872. value.Out=null; //保存中间值
  873. value.Out=`(${leftValue} ${value.Operator} ${rightValue})`;
  874. if (leftValue=="收盘价" && rightValue=="开盘价")
  875. {
  876. if (value.Operator==">") value.Out='(收阳线)';
  877. else if (value.Operator=="<") value.Out='(收阴线)';
  878. else if (value.Operator=="=") value.Out='(平盘)';
  879. }
  880. else if (leftValue=="开盘价" && rightValue=="收盘价")
  881. {
  882. if (value.Operator=="<") value.Out='(收阳线)';
  883. else if (value.Operator==">") value.Out='(收阴线)';
  884. else if (value.Operator=="=") value.Out='(平盘)';
  885. }
  886. JSConsole.Complier.Log('[JSExplainer::VisitBinaryExpression] BinaryExpression',value);
  887. }
  888. else if (value.Type==Syntax.LogicalExpression)
  889. {
  890. let leftValue=this.GetNodeValue(value.Left);
  891. let rightValue=this.GetNodeValue(value.Right);
  892. JSConsole.Complier.Log('[JSExecute::VisitBinaryExpression] LogicalExpression',value , leftValue, rightValue);
  893. value.Out=null; //保存中间值
  894. switch(value.Operator)
  895. {
  896. case '&&':
  897. case 'AND':
  898. value.Out=`(${leftValue} 并且 ${rightValue})`;
  899. break;
  900. case '||':
  901. case 'OR':
  902. value.Out=`(${leftValue} 或者 ${rightValue})`;
  903. break;
  904. }
  905. JSConsole.Complier.Log('[JSExplainer::VisitBinaryExpression] LogicalExpression',value);
  906. }
  907. node=temp;
  908. }
  909. }
  910. return node.Out;
  911. }
  912. this.GetNodeValue=function(node)
  913. {
  914. switch(node.Type)
  915. {
  916. case Syntax.Literal: //数字
  917. return node.Value;
  918. case Syntax.UnaryExpression:
  919. if (node.Operator=='-')
  920. {
  921. let value=this.GetNodeValue(node.Argument);
  922. return '-'+value;
  923. }
  924. return node.Argument.Value;
  925. case Syntax.Identifier:
  926. let value=this.ReadVariable(node.Name,node);
  927. return value;
  928. case Syntax.BinaryExpression:
  929. case Syntax.LogicalExpression:
  930. return node.Out;
  931. case Syntax.CallExpression:
  932. return this.VisitCallExpression(node);
  933. default:
  934. this.ThrowUnexpectedNode(node);
  935. }
  936. }
  937. //读取变量
  938. this.ReadVariable=function(name,node)
  939. {
  940. if (this.ConstVarTable.has(name))
  941. {
  942. let data=this.ConstVarTable.get(name);
  943. return data;
  944. }
  945. if (g_JSComplierResource.IsCustomVariant(name)) return this.ReadCustomVariant(name,node); //读取自定义变量
  946. if (this.VarTable.has(name)) return this.VarTable.get(name);
  947. if (name.indexOf('#')>0)
  948. {
  949. var aryPeriod=name.split('#');
  950. return this.SymbolPeriodExplain(aryPeriod[0],aryPeriod[1]);
  951. }
  952. this.ThrowUnexpectedNode(node, '变量'+name+'不存在');
  953. return name;
  954. }
  955. this.ThrowUnexpectedNode=function(node,message)
  956. {
  957. let marker=node.Marker;
  958. let msg=message || "执行异常";
  959. return this.ErrorHandler.ThrowError(marker.Index,marker.Line,marker.Column,msg);
  960. }
  961. this.ThrowError=function()
  962. {
  963. }
  964. }
  965. JSComplier.Explain=function(code,option, errorCallback)
  966. {
  967. //异步调用
  968. //var asyncExecute= async function() es5不能执行 去掉异步
  969. var asyncExplain= function()
  970. {
  971. try
  972. {
  973. JSConsole.Complier.Log('[JSComplier.Explain]',code,option);
  974. JSConsole.Complier.Log('[JSComplier.Explain] parser .....');
  975. let parser=new JSParser(code);
  976. parser.Initialize();
  977. let program=parser.ParseScript();
  978. let ast=program;
  979. JSConsole.Complier.Log('[JSComplier.Explain] parser finish.', ast);
  980. JSConsole.Complier.Log('[JSComplier.Explain] explain .....');
  981. let execute=new JSExplainer(ast,option);
  982. execute.ErrorCallback=errorCallback; //执行错误回调
  983. execute.JobList=parser.Node.GetDataJobList();
  984. execute.JobList.push({ID:JS_EXECUTE_JOB_ID.JOB_RUN_SCRIPT});
  985. let result=execute.Run();
  986. }catch(error)
  987. {
  988. JSConsole.Complier.Log(error);
  989. if (errorCallback) errorCallback(error, option.CallbackParam);
  990. }
  991. }
  992. asyncExplain();
  993. JSConsole.Complier.Log('[JSComplier.Explain] async explain.');
  994. }