/* Copyright (c) 2018 jones http://www.apache.org/licenses/LICENSE-2.0 开源项目 https://github.com/jones2000/HQChart jones_2000@163.com 数据请求分装 可以根据不同的平台 替换网络请求模块 */ function JSNetwork() { } JSNetwork.HttpReqeust=function(obj) //对请求进行封装 { $.ajax( { url: obj.url, data: obj.data, type:obj.type, dataType: obj.dataType,async:obj.async, success: obj.success, error: obj.error, } ); } JSNetwork.HttpRequest=function(obj) //对请求进行封装 { $.ajax( { url: obj.url, data: obj.data, type:obj.type, dataType: obj.dataType,async:obj.async, success: obj.success, error: obj.error, } ); } /* Copyright (c) 2018 jones http://www.apache.org/licenses/LICENSE-2.0 开源项目 https://github.com/jones2000/HQChart jones_2000@163.com 系统指标 (H5版本) */ /* 指标数据脚本 系统内置指标都写在这里 Name:指标名字 Description:指标描述信息 IsMainIndex:是否是主图指标 true=主图指标 false=副图指标 KLineType:K线设置 -1=主图不显示K线(只在主图有效) 0=在副图显示K线 1=在副图显示K线(收盘价线) 2=在副图显示K线(美国线) InstructionType: 1=专家指示 2=五彩K线 FloatPrecision: 小数位数 缺省=2 YSplitScale: Y固定刻度 [1,8,10] YSpecificMaxMin: 固定Y轴最大最小值 { Max: 9, Min: 0, Count: 3 }; StringFormat: 1=带单位万/亿 2=原始格式 Condition: 限制条件 { Symbol:'Index'/'Stock'(只支持指数/股票),Period:[](支持的周期), } */ //周期条件枚举 var CONDITION_PERIOD= { MINUTE_ID:101, //分钟 走势图 MULTIDAY_MINUTE_ID:102, //多日分钟 走势图 HISTORY_MINUTE_ID:103, //历史分钟 走势图 //K线周期 KLINE_DAY_ID:0, KLINE_WEEK_ID:1, KLINE_MONTH_ID:2, KLINE_YEAR_ID:3, KLINE_MINUTE_ID:4, KLINE_5_MINUTE_ID:5, KLINE_15_MINUTE_ID:6, KLINE_30_MINUTE_ID:7, KLINE_60_MINUTE_ID:8 }; //自定义的指标脚本 function CustomIndexScript() { this.DataMap=new Map(); //key=指标id, value=data {ID:, Name:指标名字, Description:指标描述信息 Args:参数 ......} this.Get=function(id) { if (!this.DataMap.has(id)) return null; return this.DataMap.get(id); } this.Add=function(data) { this.DataMap.set(data.ID, data); } } var g_CustomIndex=new CustomIndexScript(); function JSIndexScript() { this.DataMap=new Map( [ ['MA', this.MA],['均线', this.MA],['BOLL', this.BOLL],['BOLL副图', this.BOLL2],['BBI', this.BBI], ['DKX', this.DKX],['MIKE', this.MIKE],['PBX', this.PBX], ['ENE', this.ENE],['MACD', this.MACD],['KDJ', this.KDJ], ['VOL', this.VOL],['RSI', this.RSI],['BRAR', this.BRAR], ['WR', this.WR],['BIAS', this.BIAS],['OBV', this.OBV], ['DMI', this.DMI],['CR', this.CR],['PSY', this.PSY], ['CCI', this.CCI],['DMA', this.DMA],['TRIX', this.TRIX], ['VR', this.VR],['EMV', this.EMV],['ROC', this.ROC], ['MTM', this.MTM],['FSL', this.FSL],['CYR', this.CYR], ['MASS', this.MASS],['WAD', this.WAD],['CHO', this.CHO], ['ADTM', this.ADTM],['HSL', this.HSL],['BIAS36', this.BIAS36], ['BIAS_QL', this.BIAS_QL],['DPO', this.DPO],['OSC', this.OSC], ['ATR', this.ATR],['NVI', this.NVI],['PVI', this.PVI], ['UOS', this.UOS],['CYW', this.CYW],['LON', this.LON], ['NDB', this.NDB],['SKDJ',this.SKDJ],['KD',this.KD],['FKX',this.FKX], ['DKCOL',this.DKCOL],['UDL',this.UDL],['MFI',this.MFI],['LWR',this.LWR], ['MARSI',this.MARSI],['CYD',this.CYD],['CYF',this.CYF],['TAPI',this.TAPI], ['VMACD',this.VMACD],['QACD',this.QACD],['VPT',this.VPT],['WVAD',this.WVAD], ['DBQR',this.DBQR],['JS',this.JS],['CYE',this.CYE],['QR',this.QR],['GDX',this.GDX], ['JLHB',this.JLHB],['PCNT',this.PCNT],['BTX', this.BTX],['AMO',this.AMO], ['VRSI',this.VRSI],['HSCOL',this.HSCOL],['DBQRV',this.DBQRV],['DBLB',this.DBLB], ['ACD',this.ACD],['EXPMA',this.EXPMA],['EXPMA_S',this.EXPMA_S],['HMA',this.HMA], ['LMA',this.LMA],['VMA',this.VMA],['AMV',this.AMV],['BBIBOLL',this.BBIBOLL], ['ALLIGAT',this.ALLIGAT],['ZX',this.ZX],['XS',this.XS],['XS2',this.XS2], ['SG-XDT',this.SG_XDT],['SG-SMX',this.SG_SMX],['SG-LB',this.SG_LB],['SG-PF',this.SG_PF], ['RAD',this.RAD],['SHT',this.SHT],['ZLJC',this.ZLJC],['ZLMM',this.ZLMM],['SLZT',this.SLZT], ['ADVOL',this.ADVOL],['CYC',this.CYC],['CYS',this.CYS],['CYQKL',this.CYQKL], ['SCR',this.SCR],['ASR',this.ASR],['SAR',this.SAR],['TJCJL',this.TJCJL],['量比',this.VOLRate], ['平均K线',this.HeikinAshi], ['EMPTY', this.EMPTY], //什么都不显示的指标 ['飞龙四式', this.Dragon4_Main],['飞龙四式-附图', this.Dragon4_Fig], ['资金分析', this.FundsAnalysis],['融资占比',this.MarginProportion],['负面新闻', this.NewsNegative], ['涨跌趋势', this.UpDownAnalyze],['北上资金', this.HK2SHSZ],['股东人数', this.ShareHolder], ['Zealink-资金吸筹', this.Zealink_Index1], ['Zealink-牛熊区间', this.Zealink_Index2],['Zealink-持仓信号', this.Zealink_Index3], ['Zealink-增减持',this.Zealink_Index4],['Zealink-大宗交易', this.Zealink_Index5], ['Zealink-信托持股', this.Zealink_Index6], ['Zealink-官网新闻', this.Zealink_Index7], ['Zealink-高管要闻', this.Zealink_Index8],['Zealink-股权质押', this.Zealink_Index9], ['Zealink-操盘BS点', this.Zealink_Index10],['Zealink-操盘BS点2', this.Zealink_Index11], //外包指标 ['放心股-操盘BS点',this.FXG_BSPoint], ['放心股-涨停多空线',this.FXG_INDEX], ['放心股-涨停吸筹区',this.FXG_INDEX2], ['放心股-量能黄金点',this.FXG_INDEX3], //五彩K线(函数COLOR_开头) ['五彩K线-十字星',this.COLOR_KSTAR1],['五彩K线-早晨之星',this.COLOR_KSTAR2],['五彩K线-黄昏之星',this.COLOR_KSTAR3],['五彩K线-长十字',this.COLOR_SHI1], ['五彩K线-身怀六甲',this.COLOR_K220],['五彩K线-三个白武士',this.COLOR_K300],['五彩K线-三只乌鸦',this.COLOR_K310],['五彩K线-光头阳线',this.COLOR_K380], ['五彩K线-光脚阴线',this.COLOR_K390],['五彩K线-垂死十字',this.COLOR_K134],['五彩K线-早晨十字星',this.COLOR_K140],['五彩K线-黄昏十字星',this.COLOR_K150], ['五彩K线-射击之星',this.COLOR_K160],['五彩K线-倒转锤头',this.COLOR_K165],['五彩K线-锤头',this.COLOR_K170],['五彩K线-吊颈',this.COLOR_K180], ['五彩K线-穿头破脚',this.COLOR_K190],['五彩K线-出水芙蓉',this.COLOR_CSFR],['五彩K线-乌云盖顶',this.COLOR_WYGD],['五彩K线-曙光初现',this.COLOR_SGCJ], ['五彩K线-十字胎',this.COLOR_SZTAI],['五彩K线-剑',this.COLOR_SWORD],['五彩K线-平顶',this.COLOR_PINGDING],['五彩K线-平底',this.COLOR_PINGDI], ['五彩K线-大阳烛',this.COLOR_DAYANZHU],['五彩K线-大阴烛',this.COLOR_DAYINGZHU], ['五彩K线-好友反攻',this.COLOR_HYFG],['五彩K线-跳空缺口',this.COLOR_TKQK], ['五彩K线-双飞乌鸦',this.COLOR_SFWY],['五彩K线-上升三部曲',this.COLOR_SSSBQ],['五彩K线-下跌三部曲',this.COLOR_XDSBQ],['五彩K线-长下影',this.COLOR_CHXY], ['五彩K线-长上影',this.COLOR_CHSY],['五彩K线-分离',this.COLOR_FENLI], //交易系统 ['交易系统-BIAS',this.TRADE_BIAS],['交易系统-CCI',this.TRADE_CCI],['交易系统-DMI',this.TRADE_DMI],['交易系统-KD',this.TRADE_KD], ['交易系统-BOLL',this.TRADE_BOLL],['交易系统-KDJ',this.TRADE_KDJ],['交易系统-MA',this.TRADE_MA],['交易系统-MACD',this.TRADE_MACD], ['交易系统-MTM',this.TRADE_MTM],['交易系统-PSY',this.TRADE_PSY],['交易系统-ROC',this.TRADE_ROC],['交易系统-RSI',this.TRADE_RSI], ['交易系统-VR',this.TRADE_VR],['交易系统-DPSJ',this.TRADE_DPSJ], ['TEST', this.TEST] //测试用 ]); } JSIndexScript.AddIndex=function(aryIndex) //添加自定义指标 { for(var i in aryIndex) { g_CustomIndex.Add(aryIndex[i]); } } JSIndexScript.prototype.Get=function(id) { var data=g_CustomIndex.Get(id); if (data) return data; var func=this.DataMap.get(id); if (func) return func(); return null; } JSIndexScript.prototype.Search=function(name) { var result=[]; var reg = new RegExp(name,'i'); this.DataMap.forEach(function(value,key) { if (key.indexOf('交易系统-')!=0 && key.indexOf('五彩K线-')!=0 && key.search(reg)>=0) result.push(key); }); return result; } JSIndexScript.prototype.MA=function() { let data= { Name:'MA', Description:'均线', IsMainIndex:true, StringFormat:2, Args:[ { Name:'M1', Value:5}, { Name:'M2', Value:10 }, { Name:'M3', Value:20} ], Script: //脚本 'MA1:MA(CLOSE,M1);\n\ MA2:MA(CLOSE,M2);\n\ MA3:MA(CLOSE,M3);' }; return data; } JSIndexScript.prototype.BOLL=function() { let data= { Name:'BOLL', Description:'布林线', IsMainIndex:true, Args:[ { Name:'M', Value:20} ], Script: //脚本 'BOLL:MA(CLOSE,M);\n\ UB:BOLL+2*STD(CLOSE,M);\n\ LB:BOLL-2*STD(CLOSE,M);' }; return data; } JSIndexScript.prototype.BOLL2=function() { let data= { Name:'BOLL2', Description:'布林线', IsMainIndex:false, KLineType:0, Args:[ { Name:'M', Value:20} ], Script: //脚本 'BOLL:MA(CLOSE,M);\n\ UB:BOLL+2*STD(CLOSE,M);\n\ LB:BOLL-2*STD(CLOSE,M);' }; return data; } JSIndexScript.prototype.BBI=function() { let data= { Name:'BBI', Description:'多空均线', IsMainIndex:true, Args:[ { Name:'M1', Value:3}, { Name:'M2', Value:6}, { Name:'M3', Value:12}, { Name:'M4', Value:24} ], Script: //脚本 'BBI:(MA(CLOSE,M1)+MA(CLOSE,M2)+MA(CLOSE,M3)+MA(CLOSE,M4))/4;' }; return data; } JSIndexScript.prototype.DKX=function() { let data= { Name:'DKX', Description:'多空线', IsMainIndex:false, Args:[ { Name:'M', Value:10} ], Script: //脚本 'MID:=(3*CLOSE+LOW+OPEN+HIGH)/6;\n\ DKX:(20*MID+19*REF(MID,1)+18*REF(MID,2)+17*REF(MID,3)+\n\ 16*REF(MID,4)+15*REF(MID,5)+14*REF(MID,6)+\n\ 13*REF(MID,7)+12*REF(MID,8)+11*REF(MID,9)+\n\ 10*REF(MID,10)+9*REF(MID,11)+8*REF(MID,12)+\n\ 7*REF(MID,13)+6*REF(MID,14)+5*REF(MID,15)+\n\ 4*REF(MID,16)+3*REF(MID,17)+2*REF(MID,18)+REF(MID,20))/210;\n\ MADKX:MA(DKX,M);' }; return data; } JSIndexScript.prototype.MIKE=function() { let data= { Name:'MIKE', Description:'麦克支撑压力', IsMainIndex:true, Args:[ { Name:'N', Value:10} ], Script: //脚本 'HLC:=REF(MA((HIGH+LOW+CLOSE)/3,N),1);\n\ HV:=EMA(HHV(HIGH,N),3);\n\ LV:=EMA(LLV(LOW,N),3);\n\ STOR:EMA(2*HV-LV,3);\n\ MIDR:EMA(HLC+HV-LV,3);\n\ WEKR:EMA(HLC*2-LV,3);\n\ WEKS:EMA(HLC*2-HV,3);\n\ MIDS:EMA(HLC-HV+LV,3);\n\ STOS:EMA(2*LV-HV,3);' }; return data; } JSIndexScript.prototype.PBX=function() { let data= { Name:'PBX', Description:'瀑布线', IsMainIndex:true, Args:[ { Name:'M1', Value:4}, { Name:'M2', Value:6}, { Name:'M3', Value:9}, { Name:'M4', Value:13},{ Name:'M5', Value:18},{ Name:'M6', Value:24} ], Script: //脚本 'PBX1:(EMA(CLOSE,M1)+MA(CLOSE,M1*2)+MA(CLOSE,M1*4))/3;\n\ PBX2:(EMA(CLOSE,M2)+MA(CLOSE,M2*2)+MA(CLOSE,M2*4))/3;\n\ PBX3:(EMA(CLOSE,M3)+MA(CLOSE,M3*2)+MA(CLOSE,M3*4))/3;\n\ PBX4:(EMA(CLOSE,M4)+MA(CLOSE,M4*2)+MA(CLOSE,M4*4))/3;\n\ PBX5:(EMA(CLOSE,M5)+MA(CLOSE,M5*2)+MA(CLOSE,M5*4))/3;\n\ PBX6:(EMA(CLOSE,M6)+MA(CLOSE,M6*2)+MA(CLOSE,M6*4))/3;' }; return data; } JSIndexScript.prototype.ENE=function() { let data= { Name:'ENE', Description:'轨道线', IsMainIndex:true, Args:[ { Name:'N', Value:25}, { Name:'M1', Value:6}, { Name:'M2', Value:6} ], Script: //脚本 'UPPER:(1+M1/100)*MA(CLOSE,N);\n\ LOWER:(1-M2/100)*MA(CLOSE,N);\n\ ENE:(UPPER+LOWER)/2;' }; return data; } JSIndexScript.prototype.MACD=function() { let data= { Name:'MACD', Description:'平滑异同平均', IsMainIndex:false, Args:[ { Name:'SHORT', Value:12}, { Name:'LONG', Value:26}, { Name:'MID', Value:9} ], Script: //脚本 'DIF:EMA(CLOSE,SHORT)-EMA(CLOSE,LONG);\n\ DEA:EMA(DIF,MID);\n\ MACD:(DIF-DEA)*2,COLORSTICK;' }; return data; } JSIndexScript.prototype.KDJ=function() { let data= { Name:'KDJ', Description:'随机指标', IsMainIndex:false, Args:[ { Name:'N', Value:9}, { Name:'M1', Value:3}, { Name:'M2', Value:3} ], Script: //脚本 'RSV:=(CLOSE-LLV(LOW,N))/(HHV(HIGH,N)-LLV(LOW,N))*100;\n\ K:SMA(RSV,M1,1);\n\ D:SMA(K,M2,1);\n\ J:3*K-2*D;' }; return data; } JSIndexScript.prototype.VOL=function() { let data= { Name:'VOL', Description:'成交量', IsMainIndex:false,FloatPrecision:0, Args:[ { Name:'M1', Value:5}, { Name:'M2', Value:10} ], Script: //脚本 'VOL:VOL,VOLSTICK;\n\ MA1:MA(VOL,M1);\n\ MA2:MA(VOL,M2);' }; return data; } JSIndexScript.prototype.RSI=function() { let data= { Name:'RSI', Description:'相对强弱指标', IsMainIndex:false, Args:[ { Name:'N1', Value:6}, { Name:'N2', Value:12}, { Name:'N3', Value:24} ], Script: //脚本 'LC:=REF(CLOSE,1);\n\ RSI1:SMA(MAX(CLOSE-LC,0),N1,1)/SMA(ABS(CLOSE-LC),N1,1)*100;\n\ RSI2:SMA(MAX(CLOSE-LC,0),N2,1)/SMA(ABS(CLOSE-LC),N2,1)*100;\n\ RSI3:SMA(MAX(CLOSE-LC,0),N3,1)/SMA(ABS(CLOSE-LC),N3,1)*100;' }; return data; } JSIndexScript.prototype.BRAR=function() { let data= { Name:'BRAR', Description:'情绪指标', IsMainIndex:false, Args:[ { Name:'N', Value:26} ], Script: //脚本 'BR:SUM(MAX(0,HIGH-REF(CLOSE,1)),N)/SUM(MAX(0,REF(CLOSE,1)-LOW),N)*100;\n\ AR:SUM(HIGH-OPEN,N)/SUM(OPEN-LOW,N)*100;' }; return data; } JSIndexScript.prototype.WR=function() { let data= { Name:'WR', Description:'威廉指标', IsMainIndex:false, Args:[ { Name:'N', Value:10}, { Name:'N1', Value:6} ], Script: //脚本 'WR1:100*(HHV(HIGH,N)-CLOSE)/(HHV(HIGH,N)-LLV(LOW,N));\n\ WR2:100*(HHV(HIGH,N1)-CLOSE)/(HHV(HIGH,N1)-LLV(LOW,N1));' }; return data; } JSIndexScript.prototype.BIAS=function() { let data= { Name:'BIAS', Description:'乖离率', IsMainIndex:false, Args:[ { Name:'N1', Value:6}, { Name:'N2', Value:12}, { Name:'N3', Value:24} ], Script: //脚本 'BIAS1 :(CLOSE-MA(CLOSE,N1))/MA(CLOSE,N1)*100;\n\ BIAS2 :(CLOSE-MA(CLOSE,N2))/MA(CLOSE,N2)*100;\n\ BIAS3 :(CLOSE-MA(CLOSE,N3))/MA(CLOSE,N3)*100;' }; return data; } JSIndexScript.prototype.OBV=function() { let data= { Name:'OBV', Description:'累积能量线', IsMainIndex:false, Args:[ { Name:'M', Value:30} ], Script: //脚本 'VA:=IF(CLOSE>REF(CLOSE,1),VOL,-VOL);\n\ OBV:SUM(IF(CLOSE==REF(CLOSE,1),0,VA),0);\n\ MAOBV:MA(OBV,M);' }; return data; } JSIndexScript.prototype.DMI=function() { let data= { Name:'DMI', Description:'趋向指标', IsMainIndex:false, Args:[ { Name:'N', Value:14}, { Name:'MM', Value:6} ], Script: //脚本 'MTR:=EXPMEMA(MAX(MAX(HIGH-LOW,ABS(HIGH-REF(CLOSE,1))),ABS(REF(CLOSE,1)-LOW)),N);\n\ HD :=HIGH-REF(HIGH,1);\n\ LD :=REF(LOW,1)-LOW;\n\ DMP:=EXPMEMA(IF(HD>0&&HD>LD,HD,0),N);\n\ DMM:=EXPMEMA(IF(LD>0&&LD>HD,LD,0),N);\n\ PDI: DMP*100/MTR;\n\ MDI: DMM*100/MTR;\n\ ADX: EXPMEMA(ABS(MDI-PDI)/(MDI+PDI)*100,MM);\n\ ADXR:EXPMEMA(ADX,MM);' }; return data; } JSIndexScript.prototype.CR=function() { let data= { Name:'CR', Description:'带状能量线', IsMainIndex:false, Args:[ { Name:'N', Value:26}, { Name:'M1', Value:10},{ Name:'M2', Value:20},{ Name:'M3', Value:40},{ Name:'M4', Value:62} ], Script: //脚本 'MID:=REF(HIGH+LOW,1)/2;\n\ CR:SUM(MAX(0,HIGH-MID),N)/SUM(MAX(0,MID-LOW),N)*100;\n\ MA1:REF(MA(CR,M1),M1/2.5+1);\n\ MA2:REF(MA(CR,M2),M2/2.5+1);\n\ MA3:REF(MA(CR,M3),M3/2.5+1);\n\ MA4:REF(MA(CR,M4),M4/2.5+1);' }; return data; } JSIndexScript.prototype.PSY=function() { let data= { Name:'PSY', Description:'心理线', IsMainIndex:false, Args:[ { Name:'N', Value:12}, { Name:'M', Value:6} ], Script: //脚本 'PSY:COUNT(CLOSE>REF(CLOSE,1),N)/N*100;\r\ PSYMA:MA(PSY,M);' }; return data; } JSIndexScript.prototype.CCI=function() { let data= { Name:'CCI', Description:'商品路径指标', IsMainIndex:false, Args:[ { Name:'N', Value:14} ], Script: //脚本 'TYP:=(HIGH+LOW+CLOSE)/3;\n\ CCI:(TYP-MA(TYP,N))/(0.015*AVEDEV(TYP,N));' }; return data; } JSIndexScript.prototype.DMA=function() { let data= { Name:'DMA', Description:'平均差', IsMainIndex:false, Args:[ { Name:'N1', Value:10},{ Name:'N2', Value:50},{ Name:'M', Value:10} ], Script: //脚本 'DIF:MA(CLOSE,N1)-MA(CLOSE,N2);\n\ DIFMA:MA(DIF,M);' }; return data; } JSIndexScript.prototype.TRIX=function() { let data= { Name:'TRIX', Description:'三重指数平均线', IsMainIndex:false, Args:[ { Name:'N', Value:12},{ Name:'M', Value:9} ], Script: //脚本 'MTR:=EMA(EMA(EMA(CLOSE,N),N),N);\n\ TRIX:(MTR-REF(MTR,1))/REF(MTR,1)*100;\n\ MATRIX:MA(TRIX,M) ;' }; return data; } JSIndexScript.prototype.VR=function() { let data= { Name:'VR', Description:'成交量变异率', IsMainIndex:false, Args:[ { Name:'N', Value:26},{ Name:'M', Value:6} ], Script: //脚本 'TH:=SUM(IF(CLOSE>REF(CLOSE,1),VOL,0),N);\n\ TL:=SUM(IF(CLOSEREF(CLOSE,1),MIDA,MIDB),0);\n\ MAWAD:MA(WAD,M);' }; return data; } JSIndexScript.prototype.CHO=function() { let data= { Name:'CHO', Description:'佳庆指标', IsMainIndex:false, Args:[ { Name:'N1', Value:10}, { Name:'N2', Value:20}, { Name:'M', Value:6}], Script: //脚本 'MID:=SUM(VOL*(2*CLOSE-HIGH-LOW)/(HIGH+LOW),0);\n\ CHO:MA(MID,N1)-MA(MID,N2);\n\ MACHO:MA(CHO,M);' }; return data; } JSIndexScript.prototype.ADTM=function() { let data= { Name:'ADTM', Description:'动态买卖气指标', IsMainIndex:false, Args:[ { Name:'N', Value:23}, { Name:'M', Value:8}], Script: //脚本 'DTM:=IF(OPEN<=REF(OPEN,1),0,MAX((HIGH-OPEN),(OPEN-REF(OPEN,1))));\n\ DBM:=IF(OPEN>=REF(OPEN,1),0,MAX((OPEN-LOW),(OPEN-REF(OPEN,1))));\n\ STM:=SUM(DTM,N);\n\ SBM:=SUM(DBM,N);\n\ ADTM:IF(STM>SBM,(STM-SBM)/STM,IF(STM==SBM,0,(STM-SBM)/SBM));\n\ MAADTM:MA(ADTM,M);' }; return data; } JSIndexScript.prototype.HSL=function() { let data= { Name:'HSL', Description:'换手线', IsMainIndex:false, Args:[ { Name:'N', Value:5} ], Script: //脚本 'HSL:IF((SETCODE==0||SETCODE==1),100*VOL,VOL)/(FINANCE(7)/100);\n\ MAHSL:MA(HSL,N);' }; return data; } JSIndexScript.prototype.BIAS36=function() { let data= { Name:'BIAS36', Description:'三六乖离', IsMainIndex:false, Args:[ { Name:'M', Value:6} ], Script: //脚本 'BIAS36:MA(CLOSE,3)-MA(CLOSE,6);\n\ BIAS612:MA(CLOSE,6)-MA(CLOSE,12);\n\ MABIAS:MA(BIAS36,M);' }; return data; } JSIndexScript.prototype.BIAS_QL=function() { let data= { Name:'BIAS_QL', Description:'乖离率-传统版', IsMainIndex:false, Args:[ { Name:'N', Value:6}, { Name:'M', Value:6} ], Script: //脚本 'BIAS :(CLOSE-MA(CLOSE,N))/MA(CLOSE,N)*100;\n\ BIASMA :MA(BIAS,M);' }; return data; } JSIndexScript.prototype.DPO=function() { let data= { Name:'DPO', Description:'区间震荡线', IsMainIndex:false, Args:[ { Name:'N', Value:20}, { Name:'M', Value:6} ], Script: //脚本 'DPO:CLOSE-REF(MA(CLOSE,N),N/2+1);\n\ MADPO:MA(DPO,M);' }; return data; } JSIndexScript.prototype.OSC=function() { let data= { Name:'OSC', Description:'变动速率线', IsMainIndex:false, Args:[ { Name:'N', Value:20}, { Name:'M', Value:6} ], Script: //脚本 'OSC:100*(CLOSE-MA(CLOSE,N));\n\ MAOSC:EXPMEMA(OSC,M);' }; return data; } JSIndexScript.prototype.ATR=function() { let data= { Name:'ATR', Description:'真实波幅', IsMainIndex:false, Args:[ { Name:'N', Value:14}], Script: //脚本 'MTR:MAX(MAX((HIGH-LOW),ABS(REF(CLOSE,1)-HIGH)),ABS(REF(CLOSE,1)-LOW));\n\ ATR:MA(MTR,N);' }; return data; } JSIndexScript.prototype.NVI=function() { let data= { Name:'ATR', Description:'负成交量', IsMainIndex:false, Args:[ { Name:'N', Value:72} ], Script: //脚本 'NVI:100*MULAR(IF(VREF(V,1),C/REF(C,1),1),0);\n\ MANVI:MA(NVI,N);' }; return data; } JSIndexScript.prototype.UOS=function() { let data= { Name:'UOS', Description:'终极指标', IsMainIndex:false, Args:[ { Name:'N1', Value:7} ,{ Name:'N2', Value:14},{ Name:'N3', Value:28},{ Name:'M', Value:6}], Script: //脚本 'TH:=MAX(HIGH,REF(CLOSE,1));\n\ TL:=MIN(LOW,REF(CLOSE,1));\n\ ACC1:=SUM(CLOSE-TL,N1)/SUM(TH-TL,N1);\n\ ACC2:=SUM(CLOSE-TL,N2)/SUM(TH-TL,N2);\n\ ACC3:=SUM(CLOSE-TL,N3)/SUM(TH-TL,N3);\n\ UOS:(ACC1*N2*N3+ACC2*N1*N3+ACC3*N1*N2)*100/(N1*N2+N1*N3+N2*N3);\n\ MAUOS:EXPMEMA(UOS,M);' }; return data; } JSIndexScript.prototype.CYW=function() { let data= { Name:'CYW', Description:'主力控盘', IsMainIndex:false, Args:[ ], Script: //脚本 'VAR1:=CLOSE-LOW;\n\ VAR2:=HIGH-LOW;\n\ VAR3:=CLOSE-HIGH;\n\ VAR4:=IF(HIGH>LOW,(VAR1/VAR2+VAR3/VAR2)*VOL,0);\n\ CYW: SUM(VAR4,10)/10000, COLORSTICK;' }; return data; } JSIndexScript.prototype.LON=function() { let data= { Name:'LON', Description:'龙系长线', IsMainIndex:false, Args:[ { Name:'N', Value:10} ], Script: //脚本 'LC := REF(CLOSE,1);\n\ VID := SUM(VOL,2)/(((HHV(HIGH,2)-LLV(LOW,2)))*100);\n\ RC := (CLOSE-LC)*VID;\n\ LONG := SUM(RC,0);\n\ DIFF := SMA(LONG,10,1);\n\ DEA := SMA(LONG,20,1);\n\ LON : DIFF-DEA;\n\ LONMA : MA(LON,10);\n\ LONT : LON, COLORSTICK;' }; return data; } JSIndexScript.prototype.NDB = function () { let data = { Name: 'NDB', Description: '脑电波', IsMainIndex: false, Args: [{ Name: 'P1', Value: 5 }, { Name: 'P2', Value: 10 }], Script: //脚本 'HH:=IF(C/REF(C,1)>1.098 AND L>REF(H,1),2*C-REF(C,1)-H,2*C-H-L);\n\ V1:= BARSCOUNT(C) - 1;\n\ V2:= 2 * REF(C, V1) - REF(H, V1) - REF(L, V1);\n\ DK: SUM(HH, 0) + V2;\n\ MDK5: MA(DK, P1);\n\ MDK10: MA(DK, P2);' }; return data; } JSIndexScript.prototype.SKDJ = function () { let data = { Name: 'SKDJ', Description: '慢速随机指标', IsMainIndex: false, Args: [{ Name: 'N', Value: 9 }, { Name: 'M', Value: 3 }], Script: //脚本 'LOWV:=LLV(LOW,N);\n\ HIGHV:=HHV(HIGH,N);\n\ RSV:=EMA((CLOSE-LOWV)/(HIGHV-LOWV)*100,M);\n\ K:EMA(RSV,M);\n\ D:MA(K,M);' }; return data; } JSIndexScript.prototype.KD = function () { let data = { Name: 'KD', Description: '随机指标KD', IsMainIndex: false, Args: [{ Name: 'N', Value: 9 }, { Name: 'M1', Value: 3 },{ Name: 'M2', Value: 3 }], Script: //脚本 'RSV:=(CLOSE-LLV(LOW,N))/(HHV(HIGH,N)-LLV(LOW,N))*100;\n\ K:SMA(RSV,M1,1);\n\ D:SMA(K,M2,1);' }; return data; } JSIndexScript.prototype.FKX=function() { let data= { Name:'FKX', Description:'反K线', IsMainIndex:true, Args:[ ], Script: //脚本 'DRAWKLINE(-LOW, -OPEN, -HIGH, -CLOSE);' }; return data; } JSIndexScript.prototype.DKCOL = function () { let data = { Name: 'DKCOL', Description: '多空能量柱(适用于分时主图)', IsMainIndex: true, Args: [{ Name: 'N', Value: 5 }], Script: //脚本 'FF:=(C-REF(C,N))/REF(C,N);\n\ STICKLINE(FF>0,DYNAINFO(3),DYNAINFO(3)*(1+FF),0.5,0),COLORRED;\n\ STICKLINE(FF<0,DYNAINFO(3),DYNAINFO(3)*(1+FF),0.5,0),COLORGREEN;' }; return data; } JSIndexScript.prototype.UDL = function () { let data = { Name: 'UDL', Description: '引力线', IsMainIndex: false, Args: [{ Name: 'N1', Value: 3 },{ Name: 'N2', Value: 5 },{ Name: 'N3', Value: 10 },{ Name: 'N4', Value: 20 },{ Name: 'M', Value: 6 }], Script: //脚本 'UDL:(MA(CLOSE,N1)+MA(CLOSE,N2)+MA(CLOSE,N3)+MA(CLOSE,N4))/4;\n\ MAUDL:MA(UDL,M);' }; return data; } JSIndexScript.prototype.MFI = function () { let data = { Name: 'MFI', Description: '资金流量指标', IsMainIndex: false, Args: [{ Name: 'N', Value: 14 },{ Name: 'N2', Value: 6 }], Script: //脚本 'TYP := (HIGH + LOW + CLOSE)/3;\n\ V1:=SUM(IF(TYP>REF(TYP,1),TYP*VOL,0),N)/SUM(IF(TYP=0,DIF,0);\n\ VD:=IF(DIF<0,-DIF,0);\n\ MAU1:=MEMA(VU,M1);\n\ MAD1:=MEMA(VD,M1);\n\ MAU2:=MEMA(VU,M2);\n\ MAD2:=MEMA(VD,M2);\n\ RSI10:MA(100*MAU1/(MAU1+MAD1),M1);\n\ RSI6:MA(100*MAU2/(MAU2+MAD2),M2);' }; return data; } JSIndexScript.prototype.CYD = function () { let data = { Name: 'CYD', Description: '承接因子', IsMainIndex: false, Args: [{ Name: 'N', Value: 21 }], Script: //脚本 'CYDS:WINNER(CLOSE)/(VOL/CAPITAL);\n\ CYDN:WINNER(CLOSE)/MA(VOL/CAPITAL,N);' }; return data; } JSIndexScript.prototype.CYF = function () { let data = { Name: 'CYF', Description: '市场能量', IsMainIndex: false, Args: [{ Name: 'N', Value: 21 }], Script: //脚本 'CYF:100-100/(1+EMA(HSL,N));' }; return data; } JSIndexScript.prototype.TAPI = function () { let data = { Name: 'TAPI', Description: '加权指数成交值', IsMainIndex: false, Args: [{ Name: 'M', Value: 6 }], Script: //脚本 'TAPI:AMOUNT/INDEXC;\n\ MATAIP:MA(TAPI,M);' }; return data; } JSIndexScript.prototype.VMACD = function () { let data = { Name: 'VMACD', Description: '量平滑异同平均', IsMainIndex: false, Args: [{ Name: 'SHORT', Value: 12 },{ Name: 'LONG', Value: 26 },{ Name: 'MID', Value: 9 }], Script: //脚本 'DIF:EMA(VOL,SHORT)-EMA(VOL,LONG);\n\ DEA:EMA(DIF,MID);\n\ MACD:DIF-DEA,COLORSTICK;' }; return data; } JSIndexScript.prototype.QACD = function () { let data = { Name: 'QACD', Description: '快速异同平均', IsMainIndex: false, Args: [{ Name: 'N1', Value: 12 },{ Name: 'N2', Value: 26 },{ Name: 'M', Value: 9 }], Script: //脚本 'DIF:EMA(CLOSE,N1)-EMA(CLOSE,N2);\n\ MACD:EMA(DIF,M);\n\ DDIF:DIF-MACD;' }; return data; } JSIndexScript.prototype.VPT = function () { let data = { Name: 'VPT', Description: '量价曲线', IsMainIndex: false, Args: [{ Name: 'N', Value: 51 },{ Name: 'M', Value: 6 }], Script: //脚本 'VPT:SUM(VOL*(CLOSE-REF(CLOSE,1))/REF(CLOSE,1),N);\n\ MAVPT:MA(VPT,M);' }; return data; } JSIndexScript.prototype.WVAD = function () { let data = { Name: 'WVAD', Description: '威廉变异离散量', IsMainIndex: false, Args: [{ Name: 'N', Value: 24 },{ Name: 'M', Value: 6 }], Script: //脚本 'WVAD:SUM((CLOSE-OPEN)/(HIGH-LOW)*VOL,N)/10000;\n\ MAWVAD:MA(WVAD,M);' }; return data; } JSIndexScript.prototype.DBQR = function () { let data = { Name: 'WVAD', Description: '对比强弱', IsMainIndex: false, Args: [{ Name: 'N', Value: 5 },{ Name: 'M1', Value: 10 },{ Name: 'M2', Value: 20 },{ Name: 'M3', Value: 60 }], Script: //脚本 'ZS:(INDEXC-REF(INDEXC,N))/REF(INDEXC,N);\n\ GG:(CLOSE-REF(CLOSE,N))/REF(CLOSE,N);\n\ MADBQR1:MA(GG,M1);\n\ MADBQR2:MA(GG,M2);\n\ MADBQR3:MA(GG,M3);' }; return data; } JSIndexScript.prototype.JS = function () { let data = { Name: 'JS', Description: '加速线', IsMainIndex: false, Args: [{ Name: 'N', Value: 5 },{ Name: 'M1', Value: 5 },{ Name: 'M2', Value: 10 },{ Name: 'M3', Value: 20 }], Script: //脚本 'JS:100*(CLOSE-REF(CLOSE,N))/(N*REF(CLOSE,N));\n\ MAJS1:MA(JS,M1);\n\ MAJS2:MA(JS,M2);\n\ MAJS3:MA(JS,M3);' }; return data; } JSIndexScript.prototype.CYE = function () { let data = { Name: 'CYE', Description: '市场趋势', IsMainIndex: false, Args: [ ], Script: //脚本 'MAL:=MA(CLOSE,5);\n\ MAS:=MA(MA(CLOSE,20),5);\n\ CYEL:(MAL-REF(MAL,1))/REF(MAL,1)*100;\n\ CYES:(MAS-REF(MAS,1))/REF(MAS,1)*100;' }; return data; } JSIndexScript.prototype.QR = function () { let data = { Name: 'QR', Description: '强弱指标', IsMainIndex: false, Args: [{ Name: 'N', Value: 21 } ], Script: //脚本 '个股: (CLOSE-REF(CLOSE,N))/REF(CLOSE,N)*100; \n\ 大盘: (INDEXC-REF(INDEXC,N))/REF(INDEXC,N)*100; \n\ 强弱值:EMA(个股-大盘,2),COLORSTICK;' }; return data; } JSIndexScript.prototype.GDX = function () { let data = { Name: 'GDX', Description: '轨道线', IsMainIndex: false, Args: [{ Name: 'N', Value: 30 } ,{ Name: 'M', Value: 9 }], Script: //脚本 'AA:=ABS((2*CLOSE+HIGH+LOW)/4-MA(CLOSE,N))/MA(CLOSE,N); \n\ 轨道:DMA(CLOSE,AA);\n\ 压力线:(1+M/100)*轨道; \n\ 支撑线:(1-M/100)*轨道;' }; return data; } JSIndexScript.prototype.JLHB = function () { let data = { Name: 'JLHB', Description: '绝路航标', IsMainIndex: false, Args: [{ Name: 'N', Value: 7 } ,{ Name: 'M', Value: 5 }], Script: //脚本 'VAR1:=(CLOSE-LLV(LOW,60))/(HHV(HIGH,60)-LLV(LOW,60))*80; \n\ B:SMA(VAR1,N,1); \n\ VAR2:SMA(B,M,1); \n\ 绝路航标:IF(CROSS(B,VAR2) AND B<40,50,0);' }; return data; } JSIndexScript.prototype.PCNT = function () { let data = { Name: 'PCNT', Description: '幅度比', IsMainIndex: false, Args: [{ Name: 'M', Value: 5 }], Script: //脚本 'PCNT:(CLOSE-REF(CLOSE,1))/CLOSE*100;\n\ MAPCNT:EXPMEMA(PCNT,M);' }; return data; } JSIndexScript.prototype.BTX = function () { let data = { Name: 'BTX', Description: '宝塔线', IsMainIndex: false, Args: [], Script: //脚本 'B1:=REF(C,1);\n\ B2:= REF(C, 2);\n\ SS:= IF(C > REF(C, 1) AND REF(C, 1) >= REF(C, 2), 1, IF(C < REF(C, 1) AND REF(C, 1) <= REF(C, 2), -1, IF(C > REF(C, 2) AND REF(C, 2) > REF(C, 1), 2, IF(C < REF(C, 2) AND REF(C, 2) < REF(C, 1), -2, 0))));\n\ SM:= IF(REF(SS, 1) <> 0, REF(SS, 1), IF(REF(SS, 2) <> 0, REF(SS, 2), IF(REF(SS, 3) <> 0, REF(SS, 3), IF(REF(SS, 5) <> 0, REF(SS, 5), IF(REF(SS, 6) <> 0, REF(SS, 6), IF(REF(SS, 7) <> 0, REF(SS, 7), 0))))));\n\ MC:= IF(REF(SS, 1) <> 0, B2, IF(SM > 0, MIN(B1, B2), MAX(B1, B2)));\n\ TOW1:= IF(C > REF(C, 1), C, REF(C, 1));\n\ TOW2:= IF((SS == -1 OR SS == -2) AND SM > 0, B2, TOW1);\n\ TOWER:= IF(TOW1 > TOW2, TOW1, TOW2);\n\ STICKLINE(SS == 1 OR SM >= 1 AND SS == 0, B1, C, 10, 1), COLORRED;\n\ STICKLINE(SS == -1 OR SM <= -1 AND SS == 0, B1, C, 10, 0), COLORCYAN;\n\ STICKLINE(SS == 2, B2, C, 10, 1), COLORRED;\n\ STICKLINE(SS == -2, B2, C, 10, 0), COLORCYAN;\n\ STICKLINE((SS == -1 OR SS == -2) AND SM > 0, B2, B1, 10, 1), COLORRED;\n\ STICKLINE((SS == 1 OR SS == 2) AND SM < 0, B2, B1, 10, 0), COLORCYAN;' }; return data; } JSIndexScript.prototype.AMO = function () { let data = { Name: 'AMO', Description: '成交金额', IsMainIndex: false, Args: [{ Name: 'M1', Value: 5 },{ Name: 'M2', Value: 10 }], Script: //脚本 'AMOW:AMOUNT/10000.0,VOLSTICK;\n\ AMO1:MA(AMOW,M1);\n\ AMO2:MA(AMOW,M2);' }; return data; } JSIndexScript.prototype.VRSI = function () { let data = { Name: 'VRSI', Description: '相对强弱量', IsMainIndex: false, Args: [{ Name: 'N1', Value: 6 },{ Name: 'N2', Value: 12 },{ Name: 'N3', Value: 24 }], Script: //脚本 'LC:=REF(VOL,1);\n\ RSI1:SMA(MAX(VOL-LC,0),N1,1)/SMA(ABS(VOL-LC),N1,1)*100;\n\ RSI2:SMA(MAX(VOL-LC,0),N2,1)/SMA(ABS(VOL-LC),N2,1)*100;\n\ RSI3:SMA(MAX(VOL-LC,0),N3,1)/SMA(ABS(VOL-LC),N3,1)*100;' }; return data; } JSIndexScript.prototype.HSCOL = function () { let data = { Name: 'HSCOL', Description: '换手柱', IsMainIndex: false, Args: [{ Name: 'N', Value: 5 }], Script: //脚本 'HSCOL:IF((SETCODE==0||SETCODE==1),100*VOL,VOL)/(FINANCE(7)/100),VOLSTICK;\n\ MAHSL:MA(HSCOL,N);' }; return data; } JSIndexScript.prototype.DBQRV = function () { let data = { Name: 'DBQRV', Description: '对比强弱量(需下载日线)', IsMainIndex: false, Args: [{ Name: 'N', Value: 5 }], Script: //脚本 'ZS:(INDEXV-REF(INDEXV,N))/REF(INDEXV,N);\n\ GG:(VOL-REF(VOL,N))/REF(VOL,N);' }; return data; } JSIndexScript.prototype.DBLB = function () { let data = { Name: 'DBLB', Description: '对比量比(需下载日线)', IsMainIndex: false, Args: [{ Name: 'N', Value: 5 },{ Name: 'M', Value: 5 }], Script: //脚本 'GG:=VOL/SUM(REF(VOL,1),N);\n\ ZS:=INDEXV/SUM(REF(INDEXV,1),N);\n\ DBLB:GG/ZS;\n\ MADBLB:MA(DBLB,M);' }; return data; } JSIndexScript.prototype.ACD = function () { let data = { Name: 'ACD', Description: '升降线', IsMainIndex: false, Args: [{ Name: 'M', Value: 20 }], Script: //脚本 'LC:=REF(CLOSE,1);\n\ DIF:=CLOSE-IF(CLOSE>LC,MIN(LOW,LC),MAX(HIGH,LC));\n\ ACD:SUM(IF(CLOSE==LC,0,DIF),0);\n\ MAACD:EXPMEMA(ACD,M);' }; return data; } JSIndexScript.prototype.EXPMA = function () { let data = { Name: 'EXPMA', Description: '指数平均线', IsMainIndex: true, Args: [{ Name: 'M1', Value: 12 },{ Name: 'M2', Value: 50 }], Script: //脚本 'EXP1:EMA(CLOSE,M1);\n\ EXP2:EMA(CLOSE,M2);' }; return data; } JSIndexScript.prototype.EXPMA_S = function () { let data = { Name: 'EXPMA_S', Description: '指数平均线-副图', IsMainIndex: false, Args: [{ Name: 'M1', Value: 12 },{ Name: 'M2', Value: 50 }], Script: //脚本 'EXP1:EMA(CLOSE,M1);\n\ EXP2:EMA(CLOSE,M2);' }; return data; } JSIndexScript.prototype.HMA = function () { let data = { Name: 'HMA', Description: '高价平均线', IsMainIndex: true, Args: [{ Name: 'M1', Value: 6 },{ Name: 'M2', Value: 12 },{ Name: 'M3', Value: 30 },{ Name: 'M4', Value: 72 },{ Name: 'M5', Value: 144 }], Script: //脚本 'HMA1:MA(HIGH,M1);\n\ HMA2:MA(HIGH,M2);\n\ HMA3:MA(HIGH,M3);\n\ HMA4:MA(HIGH,M4);\n\ HMA5:MA(HIGH,M5);' }; return data; } JSIndexScript.prototype.LMA = function () { let data = { Name: 'LMA', Description: '低价平均线', IsMainIndex: true, Args: [{ Name: 'M1', Value: 6 },{ Name: 'M2', Value: 12 },{ Name: 'M3', Value: 30 },{ Name: 'M4', Value: 72 },{ Name: 'M5', Value: 144 }], Script: //脚本 'LMA1:MA(LOW,M1);\n\ LMA2:MA(LOW,M2);\n\ LMA3:MA(LOW,M3);\n\ LMA4:MA(LOW,M4);\n\ LMA5:MA(LOW,M5);' }; return data; } JSIndexScript.prototype.VMA = function () { let data = { Name: 'VMA', Description: '变异平均线', IsMainIndex: true, Args: [{ Name: 'M1', Value: 6 },{ Name: 'M2', Value: 12 },{ Name: 'M3', Value: 30 },{ Name: 'M4', Value: 72 },{ Name: 'M5', Value: 144 }], Script: //脚本 'VV:=(HIGH+OPEN+LOW+CLOSE)/4;\n\ VMA1:MA(VV,M1);\n\ VMA2:MA(VV,M2);\n\ VMA3:MA(VV,M3);\n\ VMA4:MA(VV,M4);\n\ VMA5:MA(VV,M5);' }; return data; } JSIndexScript.prototype.AMV = function () { let data = { Name: 'AMV', Description: '成本价均线', IsMainIndex: false, Args: [{ Name: 'M1', Value: 6 },{ Name: 'M2', Value: 12 },{ Name: 'M3', Value: 30 },{ Name: 'M4', Value: 72 },{ Name: 'M5', Value: 144 }], Script: //脚本 'AMOV:=VOL*(OPEN+CLOSE)/2;\n\ AMV1:SUM(AMOV,M1)/SUM(VOL,M1);\n\ AMV2:SUM(AMOV,M2)/SUM(VOL,M2);\n\ AMV3:SUM(AMOV,M3)/SUM(VOL,M3);\n\ AMV4:SUM(AMOV,M4)/SUM(VOL,M4);' }; return data; } JSIndexScript.prototype.BBIBOLL = function () { let data = { Name: 'BBIBOLL', Description: '多空布林线', IsMainIndex: true, Args: [{ Name: 'N', Value: 11 },{ Name: 'M', Value: 6 }], Script: //脚本 'CV:=CLOSE;\n\ BBIBOLL:(MA(CV,3)+MA(CV,6)+MA(CV,12)+MA(CV,24))/4;\n\ UPR:BBIBOLL+M*STD(BBIBOLL,N);\n\ DWN:BBIBOLL-M*STD(BBIBOLL,N);' }; return data; } JSIndexScript.prototype.ALLIGAT = function () { let data = { Name: 'ALLIGAT', Description: '鳄鱼线', IsMainIndex: true, Args: [], Script: //脚本 'NN:=(H+L)/2;\n\ 上唇:REF(MA(NN,5),3),COLOR40FF40;\n\ 牙齿:REF(MA(NN,8),5),COLOR0000C0;\n\ 下颚:REF(MA(NN,13),8),COLORFF4040;' }; return data; } JSIndexScript.prototype.ZX = function () { let data = { Name: 'ZX', Description: '重心线', IsMainIndex: false, Args: [], Script: //脚本 'AV:0.01*AMOUNT/VOL;' }; return data; } JSIndexScript.prototype.XS = function () { let data = { Name: 'XS', Description: '薛斯通道', IsMainIndex: true, Args: [{ Name: 'N', Value: 13 }], Script: //脚本 'VAR2:=CLOSE*VOL;\n\ VAR3:=EMA((EMA(VAR2,3)/EMA(VOL,3)+EMA(VAR2,6)/EMA(VOL,6)+EMA(VAR2,12)/EMA(VOL,12)+EMA(VAR2,24)/EMA(VOL,24))/4,N);\n\ SUP:1.06*VAR3;\n\ SDN:VAR3*0.94;\n\ VAR4:=EMA(CLOSE,9);\n\ LUP:EMA(VAR4*1.14,5);\n\ LDN:EMA(VAR4*0.86,5);' }; return data; } JSIndexScript.prototype.XS2 = function () { let data = { Name: 'XS2', Description: '薛斯通道II', IsMainIndex: true, Args: [{ Name: 'N', Value: 102 },{ Name: 'M', Value: 7 }], Script: //脚本 'AA:=MA((2*CLOSE+HIGH+LOW)/4,5); \n\ 通道1:AA*N/100; \n\ 通道2:AA*(200-N)/100; \n\ CC:=ABS((2*CLOSE+HIGH+LOW)/4-MA(CLOSE,20))/MA(CLOSE,20); \n\ DD:=DMA(CLOSE,CC); \n\ 通道3:(1+M/100)*DD; \n\ 通道4:(1-M/100)*DD;' }; return data; } JSIndexScript.prototype.SG_XDT = function () { let data = { Name: 'SG-XDT', Description: '心电图(需下载日线)', IsMainIndex: false, Args: [{ Name: 'P1', Value: 5 },{ Name: 'P2', Value: 10 }], Script: //脚本 'QR:CLOSE/INDEXC*1000;\n\ MQR1:MA(QR,5);\n\ MQR2:MA(QR,10);' }; return data; } JSIndexScript.prototype.SG_SMX = function () { let data = { Name: 'SG-SMX', Description: '生命线(需下载日线)', IsMainIndex: false, Args: [{ Name: 'N', Value: 50 }], Script: //脚本 'H1:=HHV(HIGH,N);\n\ L1:=LLV(LOW,N);\n\ H2:=HHV(INDEXH,N);\n\ L2:=LLV(INDEXL,N);\n\ ZY:=CLOSE/INDEXC*2000;\n\ ZY1:EMA(ZY,3);\n\ ZY2:EMA(ZY,17);\n\ ZY3:EMA(ZY,34);' }; return data; } JSIndexScript.prototype.SG_LB = function () { let data = { Name: 'SG-LB', Description: '量比(需下载日线)', IsMainIndex: false, Args: [], Script: //脚本 'ZY2:=VOL/INDEXV*1000;\n\ 量比:ZY2;\n\ MA5:MA(ZY2,5);\n\ MA10:MA(ZY2,10);' }; return data; } JSIndexScript.prototype.SG_PF = function () { let data = { Name: 'SG-PF', Description: '强势股评分(需下载日线)', IsMainIndex: false, Args: [], Script: //脚本 'ZY1:=CLOSE/INDEXC*1000;\n\ A1:=IF(ZY1>HHV(ZY1,3),10,0);\n\ A2:=IF(ZY1>HHV(ZY1,5),15,0);\n\ A3:=IF(ZY1>HHV(ZY1,10),20,0);\n\ A4:=IF(ZY1>HHV(ZY1,2),10,0);\n\ A5:=COUNT(ZY1>REF(ZY1,1) ,9)*5;\n\ 强势股评分:A1+A2+A3+A4+A5;' }; return data; } JSIndexScript.prototype.RAD = function () { let data = { Name: 'RAD', Description: '威力雷达(需下载日线)', IsMainIndex: false, Args: [{ Name: 'D', Value: 3 },{ Name: 'S', Value: 30 },{ Name: 'M', Value: 30 }], Script: //脚本 'SM:=(OPEN+HIGH+CLOSE+LOW)/4;\n\ SMID:=MA(SM,D);\n\ IM:=(INDEXO+INDEXH+INDEXL+INDEXC)/4;\n\ IMID:=MA(IM,D);\n\ SI1:=(SMID-REF(SMID,1))/SMID;\n\ II:=(IMID-REF(IMID,1))/IMID;\n\ RADER1:SUM((SI1-II)*2,S)*1000;\n\ RADERMA:SMA(RADER1,M,1);' }; return data; } JSIndexScript.prototype.SHT = function () { let data = { Name: 'SHT', Description: '龙系短线', IsMainIndex: false, Args: [{ Name: 'N', Value: 5 }], Script: //脚本 'VAR1:=MA((VOL-REF(VOL,1))/REF(VOL,1),5);\n\ VAR2:=(CLOSE-MA(CLOSE,24))/MA(CLOSE,24)*100;\n\ MY: VAR2*(1+VAR1);\n\ SHT: MY, COLORSTICK;\n\ SHTMA: MA(SHT,N);' }; return data; } JSIndexScript.prototype.ZLJC = function () { let data = { Name: 'ZLJC', Description: '主力进出', IsMainIndex: false, Args: [], Script: //脚本 'VAR1:=(CLOSE+LOW+HIGH)/3; \n\ VAR2:=SUM(((VAR1-REF(LOW,1))-(HIGH-VAR1))*VOL/100000/(HIGH-LOW),0); \n\ VAR3:=EMA(VAR2,1); \n\ JCS:VAR3; \n\ JCM:MA(VAR3,12); \n\ JCL:MA(VAR3,26);' }; return data; } JSIndexScript.prototype.ZLMM = function () { let data = { Name: 'ZLMM', Description: '主力买卖', IsMainIndex: false, Args: [], Script: //脚本 'LC :=REF(CLOSE,1);\n\ RSI2:=SMA(MAX(CLOSE-LC,0),12,1)/SMA(ABS(CLOSE-LC),12,1)*100;\n\ RSI3:=SMA(MAX(CLOSE-LC,0),18,1)/SMA(ABS(CLOSE-LC),18,1)*100;\n\ MMS:MA(3*RSI2-2*SMA(MAX(CLOSE-LC,0),16,1)/SMA(ABS(CLOSE-LC),16,1)*100,3);\n\ MMM:EMA(MMS,8);\n\ MML:MA(3*RSI3-2*SMA(MAX(CLOSE-LC,0),12,1)/SMA(ABS(CLOSE-LC),12,1)*100,5);' }; return data; } JSIndexScript.prototype.SLZT = function () { let data = { Name: 'SLZT', Description: '神龙在天', IsMainIndex: false, Args: [], Script: //脚本 '白龙: MA(CLOSE,125);\n\ 黄龙: 白龙+2*STD(CLOSE,170);\n\ 紫龙: 白龙-2*STD(CLOSE,145);\n\ 青龙: SAR(125,1,7), LINESTICK;\n\ VAR2:=HHV(HIGH,70);\n\ VAR3:=HHV(HIGH,20);\n\ 红龙: VAR2*0.83;\n\ 蓝龙: VAR3*0.91;' }; return data; } JSIndexScript.prototype.ADVOL = function () { let data = { Name: 'ADVOL', Description: '龙系离散量', IsMainIndex: false, Args: [], Script: //脚本 'A:=SUM(((CLOSE-LOW)-(HIGH-CLOSE))*VOL/10000/(HIGH-LOW),0);\n\ ADVOL:A;\n\ MA1:MA(A,30);\n\ MA2:MA(MA1,100);' }; return data; } JSIndexScript.prototype.CYC = function () { let data = { Name: 'CYC', Description: '成本均线', IsMainIndex: true, Args: [{ Name: 'P1', Value: 5 },{ Name: 'P2', Value: 13 },{ Name: 'P3', Value: 34 }], Script: //脚本 'JJJ:=IF(DYNAINFO(8)>0.01,0.01*DYNAINFO(10)/DYNAINFO(8),DYNAINFO(3));\n\ DDD:=(DYNAINFO(5)<0.01 || DYNAINFO(6)<0.01);\n\ JJJT:=IF(DDD,1,(JJJ<(DYNAINFO(5)+0.01) && JJJ>(DYNAINFO(6)-0.01)));\n\ CYC1:IF(JJJT,0.01*EMA(AMOUNT,P1)/EMA(VOL,P1),EMA((HIGH+LOW+CLOSE)/3,P1));\n\ CYC2:IF(JJJT,0.01*EMA(AMOUNT,P2)/EMA(VOL,P2),EMA((HIGH+LOW+CLOSE)/3,P2));\n\ CYC3:IF(JJJT,0.01*EMA(AMOUNT,P3)/EMA(VOL,P3),EMA((HIGH+LOW+CLOSE)/3,P3));\n\ CYC4:IF(JJJT,DMA(AMOUNT/(100*VOL),100*VOL/FINANCE(7)),EMA((HIGH+LOW+CLOSE)/3,120));' }; return data; } JSIndexScript.prototype.CYS = function () { let data = { Name: 'CYS', Description: '市场盈亏', IsMainIndex: false, Args: [], Script: //脚本 'CYC13:EMA(AMOUNT,13)/EMA(VOL,13);\n\ CYS:(CLOSE-CYC13)/CYC13*100;' }; return data; } JSIndexScript.prototype.CYQKL = function () { let data = { Name: 'CYQKL', Description: '博弈K线长度', IsMainIndex: false, Args: [], Script: //脚本 'KL:100*(WINNER(CLOSE)-WINNER(OPEN));' }; return data; } JSIndexScript.prototype.SCR = function () { let data = { Name: 'SCR', Description: '筹码集中度', IsMainIndex: false, Args: [{ Name: 'P1', Value: 90 }], Script: //脚本 'A:=P1+(100-P1)/2;\n\ B:=(100-P1)/2;\n\ CC:=COST(A);\n\ DD:=COST(B);\n\ SCR:(CC-DD)/(CC+DD)*100/2;' }; return data; } JSIndexScript.prototype.ASR = function () { let data = { Name: 'ASR', Description: '浮筹比例', IsMainIndex: false, Args: [], Script: //脚本 'ASR:(WINNER(C*1.1)-WINNER(C*0.9))/WINNER(HHV(H,0))*100;' }; return data; } JSIndexScript.prototype.SAR = function () { let data = { Name: 'SAR', Description: '抛物转向', IsMainIndex: true, Args: [{ Name: 'P', Value: 10 },{ Name: 'STEP', Value: 2 },{ Name: 'MAXP', Value: 20 }], Script: //脚本 'S:SAR(P,STEP,MAXP),CIRCLEDOT;' }; return data; } JSIndexScript.prototype.TJCJL = function () { let data = { Name: '太极成交量', Description: '太极成交量', IsMainIndex: true, Args: [], Script: //脚本 '总手:VOL,NODRAW;\n\ ZZ:=IF(REF(C,1)>REF(O,1) AND O>REF(C,1)*1.014 AND CV5*1.2 AND V>V12*1.2 AND ZZ>2 AND C>H*0.975,0,VOL,10,0),COLORRED;\n\ STICKLINE(CROSS(C6,C) AND V>V5*1.2 AND V>V12*1.2,0,VOL,10,0),COLORGREEN;\n\ STICKLINE(VOL>MA(VOL,5)*2 AND V>V34*3 AND CMA(VOL,5)*2 AND V>V34*3 AND CV5*1.2 AND V>V12*1.2 AND ZZ>2 AND C>H*0.975,VOL*0.5,0,10,0),COLORRED;\n\ STICKLINE(VOL>MA(VOL,5)*2 AND V>V34*3 AND CV5*1.2 AND V>V12*1.2,VOL*0.5,0,10,0),COLORRED;' }; return data; } /* 飞龙四式-主图 */ JSIndexScript.prototype.Dragon4_Main = function () { let data = { Name: '飞龙四式', Description: '飞龙四式', IsMainIndex: true, Args: [{ Name: 'N1', Value: 5 }, { Name: 'N2', Value: 10 }, { Name: 'N3', Value: 50 }, { Name: 'N4', Value: 60 }], Script: //脚本 '蜻蜓点水:=EMA(CLOSE,N1),COLORGRAY;\n\ 魔界:=EMA(CLOSE,N2),COLORGREEN;\n\ 水:=EMA(CLOSE,N3),COLORRED;\n\ DRAWKLINE(HIGH,OPEN,LOW,CLOSE);\n\ 生命线:MA(CLOSE,N4),COLORBLUE,LINETHICK2;\n\ DRAWBAND(魔界,\'RGB(186,225,250)\',水,\'RGB(253,194,124)\');\n\ DRAWBAND(蜻蜓点水,\'RGB(128,138,135)\',魔界,\'RGB(0,0,255)\');' }; return data; } JSIndexScript.prototype.Dragon4_Fig=function() { let data = { Name: '飞龙四式', Description: '飞龙四式', IsMainIndex: false, Args: [], Script: //脚本 '倍:VOL>=REF(V,1)*1.90 AND C>REF(C,1),COLORYELLOW;\n\ 低:VOLREF(V,1),3)==3 AND COUNT(C>O,3)==3,COLORBROWN;\n\ 缩量涨:COUNT(C>REF(C,1),2)==2 AND COUNT(V=REF(C,1),V,0,2,0),COLORRED;\n\ STICKLINE(C=2038 AND MONTH>=1,0,1); VAR2:=REF(LOW,1)*VAR1; VAR3:=SMA(ABS(LOW-VAR2),3,1)/SMA(MAX(LOW-VAR2,0),3,1)*100*VAR1; VAR4:=EMA(IF(CLOSE*1.3,VAR3*10,VAR3/10),3)*VAR1; VAR5:=LLV(LOW,30)*VAR1; VAR6:=HHV(VAR4,30)*VAR1; VAR7:=IF(MA(CLOSE,58),1,0)*VAR1; VAR8:=EMA(IF(LOW<=VAR5,(VAR4+VAR6*2)/2,0),3)/618*VAR7*VAR1; 吸筹A:IF(VAR8>100,100,VAR8)*VAR1,COLORRED; 吸筹B:STICKLINE(吸筹A>-150,0,吸筹A,8,0),COLORRED; 散户线: 100*(HHV(HIGH,M)-CLOSE)/(HHV(HIGH,M)-LLV(LOW,M)),COLORFFFF00,LINETHICK2; RSV:=(CLOSE-LLV(LOW,N))/(HHV(HIGH,N)-LLV(LOW,N))*100; K:=SMA(RSV,3,1); D:=SMA(K,3,1); J:=3*K-2*D; 主力线:EMA(J,5),COLORFF00FF,LINETHICK2; DRAWICON(CROSS(主力线,散户线),主力线,1); DRAWICON(CROSS(散户线,主力线),主力线,2); */ JSIndexScript.prototype.FundsAnalysis=function() { let data = { Name: '资金分析', Description: '资金分析', IsMainIndex: false, Args: [{ Name: 'M', Value: 55 }, { Name: 'N', Value: 34 }], Script: //脚本 'LC:=REF(CLOSE,1);\n\ RSI:=((SMA(MAX((CLOSE - LC),0),3,1) / SMA(ABS((CLOSE - LC)),3,1)) * 100);\n\ FF:=EMA(CLOSE,3);\n\ MA15:=EMA(CLOSE,21); DRAWTEXT(CROSS(85,RSI),75,\'▼\'),COLORGREEN;\n\ VAR1:=IF(YEAR>=2038 AND MONTH>=1,0,1);\n\ VAR2:=REF(LOW,1)*VAR1;\n\ VAR3:=SMA(ABS(LOW-VAR2),3,1)/SMA(MAX(LOW-VAR2,0),3,1)*100*VAR1;\n\ VAR4:=EMA(IF(CLOSE*1.3,VAR3*10,VAR3/10),3)*VAR1;\n\ VAR5:=LLV(LOW,30)*VAR1;\n\ VAR6:=HHV(VAR4,30)*VAR1;\n\ VAR7:=IF(MA(CLOSE,58),1,0)*VAR1;\n\ VAR8:=EMA(IF(LOW<=VAR5,(VAR4+VAR6*2)/2,0),3)/618*VAR7*VAR1;\n\ 吸筹A:IF(VAR8>100,100,VAR8)*VAR1,COLORFB2F3B;\n\ {吸筹B}STICKLINE(吸筹A>-150,0,吸筹A,8,0),COLORFB2F3B;\n\ \n\ 散户线: 100*(HHV(HIGH,M)-CLOSE)/(HHV(HIGH,M)-LLV(LOW,M)),COLORAA89BD,LINETHICK2;\n\ RSV:=(CLOSE-LLV(LOW,N))/(HHV(HIGH,N)-LLV(LOW,N))*100;\n\ K:=SMA(RSV,3,1);\n\ D:=SMA(K,3,1);\n\ J:=3*K-2*D;\n\ 主力线:EMA(J,5),COLORF39800,LINETHICK2;\n\ DRAWICON(CROSS(主力线,散户线),主力线,1);\n\ DRAWICON(CROSS(散户线,主力线),主力线,2);' }; return data; } JSIndexScript.prototype.MarginProportion=function() { let data = { Name: '融资占比(%)', Description: '融资占比', IsMainIndex: false, Condition: { Period:[CONDITION_PERIOD.KLINE_DAY_ID] }, Args: [], Script: //脚本 '占比:MARGIN(2);' }; return data; } JSIndexScript.prototype.FXG_BSPoint=function() { let data = { Name: '操盘BS点', Description: '操盘BS点', IsMainIndex: true, Args: [], Script: //脚本 'MA5:MA(CLOSE,5);\n\ MA13:MA(CLOSE,13);\n\ MA21:MA(CLOSE,21);\n\ MA34:MA(CLOSE,34);\n\ {MA55:MA(CLOSE,55),COLOR0000FF;}\n\ {MA120:=MA(CLOSE,120),COLORFFFF00;}\n\ 天使:=EMA(C,2),COLOR000000;\n\ 魔鬼:=EMA(SLOPE(C,21)*20+C,42),COLOR000000;\n\ 买:=CROSS(天使,魔鬼);\n\ 卖:=CROSS(魔鬼,天使);\n\ DRAWICON(买,L*0.97,13);\n\ DRAWICON(卖,H*1.03,14);\n\ DRAWKLINE_IF(天使>=魔鬼,HIGH,CLOSE,LOW,OPEN),COLORRED;\n\ DRAWKLINE_IF(天使<魔鬼,HIGH,CLOSE,LOW,OPEN),COLORBLUE;\n\ DRAWKLINE_IF(CROSS(天使,魔鬼),HIGH,CLOSE,LOW,OPEN),COLORYELLOW;\n\ DRAWKLINE_IF(CROSS(魔鬼,天使),HIGH,CLOSE,LOW,OPEN),COLORBLACK;' }; return data; } JSIndexScript.prototype.FXG_INDEX=function() { let data = { Name: '涨停多空线', Description: '涨停多空线', IsMainIndex: false, Args: [], Script: //脚本 '做多能量线: SMA((CLOSE-LLV(LOW,9))/(HHV(HIGH,9)-LLV(LOW,9))*100,5,1)-8,COLORRED,LINETHICK3;\n\ 做空能量线: SMA((HHV(HIGH,36)-CLOSE)/(HHV(HIGH,36)-LLV(LOW,36))*100,2,1),COLORGREEN,LINETHICK3;\n\ 20,POINTDOT,COLORF00FF0;\n\ 50,POINTDOT,COLORGREEN;\n\ 80,POINTDOT,COLORLIBLUE;' }; return data; } JSIndexScript.prototype.FXG_INDEX2=function() { let data = { Name: '涨停吸筹区', Description: '涨停吸筹区', IsMainIndex: false, Args: [], Script: //脚本 'VAR0:=EMA(HHV(HIGH,500),21); \n\ VAR1:=EMA(HHV(HIGH,250),21);\n\ VAR2:=EMA(HHV(HIGH,90),21); \n\ VAR3:=EMA(LLV(LOW,500),21); \n\ VAR4:=EMA(LLV(LOW,250),21); \n\ VAR5:=EMA(LLV(LOW,90),21);\n\ \n\ VAR6:=EMA((VAR3*0.96+VAR4*0.96+VAR5*0.96+VAR0*0.558+VAR1*0.558+VAR2*0.558)/6,21); \n\ VAR7:=EMA((VAR3*1.25+VAR4*1.23+VAR5*1.2+VAR0*0.55+VAR1*0.55+VAR2*0.65)/6,21); \n\ VAR8:=EMA((VAR3*1.3+VAR4*1.3+VAR5*1.3+VAR0*0.68+VAR1*0.68+VAR2*0.68)/6,21); \n\ VAR9:=EMA((VAR6*3+VAR7*2+VAR8)/6*1.738,21); \n\ VAR10:=REF(LOW,1); \n\ VAR11:=SMA(ABS(LOW-VAR10),3,1)/SMA(MAX(LOW-VAR10,0),3,1)*100; \n\ VAR12:=EMA(IFF(CLOSE*1.35<=VAR9,VAR11*10,VAR11/10),3); \n\ VAR13:=LLV(LOW,30); \n\ VAR14:=HHV(VAR12,30); \n\ VAR15:=IFF(MA(CLOSE,58),1,0); \n\ VAR16:=EMA(IFF(LOW<=VAR13,(VAR12+VAR14*2)/2,0),3)/618*VAR15;\n\ \n\ 资金入场:IFF(VAR16>0,VAR16,0),LINETHICK,LINETHICK2, COLORFF0000; \n\ \n\ A1:IFF(资金入场>0,资金入场*1.2,0),STICK,LINETHICK5, COLORFF0000;\n\ A2:IFF(资金入场>0,资金入场*0.8,0),STICK,LINETHICK5, COLORFF6600;\n\ A3:IFF(资金入场>0,资金入场*0.6,0),STICK,LINETHICK5, COLORFF9900;\n\ A4:IFF(资金入场>0,资金入场*0.4,0) ,STICK,LINETHICK5,COLORFFCC00;\n\ A5:IFF(资金入场>0,资金入场*0.2,0) ,STICK,LINETHICK5,COLORFFFF00;' }; return data; } JSIndexScript.prototype.FXG_INDEX3=function() { let data = { Name: '量能黄金点', Description: '量能黄金点', IsMainIndex: false,FloatPrecision:0, Args: [], Script: //脚本 'A:=IFF((CLOSE>126.32),VOL,VOL); \n\ 主力:=MA(A,4),COLORRED;\n\ 游资:=MA(A,8),COLORYELLOW;\n\ 大户:=MA(A,16),COLORF0F000;\n\ 散户:=MA(A,32),COLOR00FF00;\n\ 主比:=ABS(((主力)/(主力 + 游资 + 大户 + 散户))*(100)),LINESTICK,COLORRED;\n\ 游比:=ABS(((游资)/(主力 + 游资 + 大户 + 散户))*(100)),LINESTICK,COLORYELLOW;\n\ 大比:=ABS(((大户)/(主力 + 游资 + 大户 + 散户))*(100)),LINESTICK,COLORF0F000;\n\ 散比:=ABS(((散户)/(主力 + 游资 + 大户 + 散户))*(100)),LINESTICK,COLOR00FF00;\n\ 警戒线:MA(A,180),COLORFF66FF;\n\ STICKLINE((主力 > 0),0,主力,2.5,0),COLOR1020BB;\n\ STICKLINE((主力 > 0),0,主力,0.7,0),COLORRED;\n\ STICKLINE((游资 > 0),0,游资,2.5,0),COLOR009CFF;\n\ STICKLINE((游资 > 0),0,游资,0.7,0),COLORYELLOW;\n\ STICKLINE((大户 > 0),0,大户,2.5,0),COLORFF8800;\n\ STICKLINE((大户 > 0),0,大户,0.7,0),COLORLIBLUE;\n\ STICKLINE((散户 > 0),0,散户,2.5,0),COLOR00CA00;\n\ STICKLINE((散户 > 0),0,散户,0.7,0),COLORGREEN;' }; return data; } JSIndexScript.prototype.NewsNegative=function() { let data= { Name: '负面新闻', Description: '负面新闻统计', IsMainIndex: false,FloatPrecision:0, Args: [{ Name: 'N', Value: 5 }, { Name: 'N2', Value: 10 }], Script: //脚本 '负面:NEWS(1);\n\ MA1:MA(负面,N);\n\ MA2:MA(负面,N2);' }; return data; } JSIndexScript.prototype.UpDownAnalyze=function() { let data= { Name: '涨跌趋势', Description: '涨跌趋势', IsMainIndex: false,FloatPrecision:0, Condition: { Period:[CONDITION_PERIOD.MINUTE_ID, CONDITION_PERIOD.MULTIDAY_MINUTE_ID, CONDITION_PERIOD.KLINE_DAY_ID] }, Args: [], Script: //脚本 "上涨家数:UPCOUNT('CNA.CI'),COLORRED;\n\ 下跌家数:DOWNCOUNT('CNA.CI'),COLORGREEN;" }; return data; } JSIndexScript.prototype.HK2SHSZ=function() { let data= { Name: '北上资金', Description: '北上资金', IsMainIndex: false,FloatPrecision:0, Condition: { Period:[CONDITION_PERIOD.MINUTE_ID,CONDITION_PERIOD.MULTIDAY_MINUTE_ID,CONDITION_PERIOD.KLINE_DAY_ID] }, Args: [], Script: //脚本 "净流入:HK2SHSZ(1),COLORSTICK;" }; return data; } JSIndexScript.prototype.ShareHolder=function() { let data= { Name: '股东人数', Description: '股东人数', IsMainIndex: false,FloatPrecision:0, Condition: { Period:[ CONDITION_PERIOD.KLINE_DAY_ID, CONDITION_PERIOD.KLINE_MONTH_ID, CONDITION_PERIOD.KLINE_WEEK_ID, CONDITION_PERIOD.KLINE_YEAR_ID] }, Args: [], Script: //脚本 "人数:FINANCE(100);" }; return data; } JSIndexScript.prototype.VOLRate=function() { let data= { Name: '量比', Description: '量比', IsMainIndex: false, Condition: { Period:[CONDITION_PERIOD.MINUTE_ID, CONDITION_PERIOD.MULTIDAY_MINUTE_ID ] }, Args: [], Script: //脚本 "LIANGBI:VOLR;" }; return data; } //////////////////////////////////////////////////////////////////////////////////////////////// //五彩K线 JSIndexScript.prototype.COLOR_KSTAR1=function() { let data= { Name: '十字星', Description: '十字星', IsMainIndex: true, InstructionType:2, Script: //脚本 'KSTAR:CLOSE==OPEN&&HIGH>LOW;' }; return data; } JSIndexScript.prototype.COLOR_KSTAR2=function() { let data= { Name: '早晨之星', Description: '早晨之星', IsMainIndex: true, InstructionType:2, Script: //脚本 'KSTAR:(REF(CLOSE,2)/REF(OPEN,2)<0.95) && (REF(OPEN,1) < REF(CLOSE,2)) && (ABS(REF(OPEN,1)-REF(CLOSE,1))/REF(CLOSE,1)<0.03) && CLOSE/OPEN>1.05 && CLOSE>REF(CLOSE,2);' }; return data; } JSIndexScript.prototype.COLOR_KSTAR3=function() { let data= { Name: '黄昏之星', Description: '黄昏之星', IsMainIndex: true, InstructionType:2, Script: //脚本 'KSTAR:REF(CLOSE,2)/REF(OPEN,2)>1.05 && REF(OPEN,1)>REF(CLOSE,2) && ABS(REF(OPEN,1)-REF(CLOSE,1))/REF(CLOSE,1)<0.03 && CLOSE/OPEN<0.95 && CLOSE1.03;' }; return data; } JSIndexScript.prototype.COLOR_K220=function() { let data= { Name: '身怀六甲', Description: '身怀六甲', IsMainIndex: true, InstructionType:2, Script: //脚本 'KSTAR:ABS(REF(CLOSE,1)-REF(OPEN,1))/REF(CLOSE,1)>0.04&&\n\ ABS(CLOSE-OPEN)/CLOSE<0.005&&\n\ MAX(CLOSE,OPEN)MIN(REF(CLOSE,1),REF(OPEN,1));' }; return data; } JSIndexScript.prototype.COLOR_K300=function() { let data= { Name: '三个白武士', Description: '三个白武士', IsMainIndex: true, InstructionType:2, Script: //脚本 'KSTAR:UPNDAY(CLOSE,3)&&NDAY(CLOSE,OPEN,3);' }; return data; } JSIndexScript.prototype.COLOR_K310=function() { let data= { Name: '三只乌鸦', Description: '三只乌鸦', IsMainIndex: true, InstructionType:2, Script: //脚本 'KSTAR:DOWNNDAY(CLOSE,3)&&NDAY(OPEN,CLOSE,3);' }; return data; } JSIndexScript.prototype.COLOR_K380=function() { let data= { Name: '光头阳线', Description: '光头阳线', IsMainIndex: true, InstructionType:2, Script: //脚本 'KSTAR:HIGH==CLOSE&&HIGH>LOW;' }; return data; } JSIndexScript.prototype.COLOR_K390=function() { let data= { Name: '光脚阴线', Description: '光脚阴线', IsMainIndex: true, InstructionType:2, Script: //脚本 'KSTAR:LOW==CLOSE&&HIGH>LOW;' }; return data; } JSIndexScript.prototype.COLOR_K134=function() { let data= { Name: '垂死十字', Description: '垂死十字', IsMainIndex: true, InstructionType:2, Script: //脚本 'KSTAR:CLOSE==OPEN&&CLOSE==LOW&&CLOSE1.05&&CLOSE>REF(CLOSE,2);' }; return data; } JSIndexScript.prototype.COLOR_K150=function() { let data= { Name: '黄昏十字星', Description: '黄昏十字星', IsMainIndex: true, InstructionType:2, Script: //脚本 'KSTAR:REF(CLOSE,2)/REF(OPEN,2)>1.05&&\n\ REF(OPEN,1)>REF(CLOSE,2)&&\n\ REF(OPEN,1)=REF(CLOSE,1)&&\n\ CLOSE/OPEN<0.95&&CLOSE3*(MAX(OPEN,CLOSE)-LOW)&&\n\ CLOSE>MA(CLOSE,5);' }; return data; } JSIndexScript.prototype.COLOR_K165=function() { let data= { Name: '倒转锤头', Description: '倒转锤头', IsMainIndex: true, InstructionType:2, Script: //脚本 'KSTAR:MIN(OPEN,CLOSE)==LOW&&\n\ HIGH-LOW>3*(MAX(OPEN,CLOSE)-LOW)&&\n\ CLOSE3*(HIGH-MIN(OPEN,CLOSE))&&\n\ CLOSE3*(HIGH-MIN(OPEN,CLOSE))&&\n\ CLOSE>MA(CLOSE,5);' }; return data; } JSIndexScript.prototype.COLOR_K190=function() { let data= { Name: '穿头破脚', Description: '穿头破脚', IsMainIndex: true, InstructionType:2, Script: //脚本 'OUT:(REF(CLOSE,1)/REF(OPEN,1)>1.03&&\n\ CLOSE/OPEN<0.96&&\n\ CLOSEREF(CLOSE,1))||\n\ (REF(CLOSE,1)/REF(OPEN,1)<0.97&&\n\ CLOSE/OPEN>1.04&&\n\ CLOSE>REF(OPEN,1)&&OPENREF(VOL,1)||VOL>(CAPITAL*0.1);\n\ BB:=OPEN>=(REF(HIGH,1))&&REF(HIGH,1)>(REF(HIGH,2)*1.06);\n\ CC:=CLOSE>(REF(CLOSE,1))-(REF(CLOSE,1)*0.01);\n\ DD:=CLOSE<(HIGH*0.965) && HIGH>(OPEN*1.05);\n\ EE:=LOW(REF(CLOSE,1)*1.06);\n\ FF:=(HIGH-(MAX(OPEN,CLOSE)))/2>(MIN(OPEN,CLOSE))-LOW;\n\ GG:=(ABS(OPEN-CLOSE))/2<(MIN(OPEN,CLOSE)-LOW);\n\ SWORDO:AA&&BB&&CC&&DD&&EE&&FF&&GG;' }; return data; } JSIndexScript.prototype.COLOR_CSFR=function() { let data= { Name: '出水芙蓉', Description: '出水芙蓉', IsMainIndex: true, InstructionType:2, Script: //脚本 'A:=CLOSE>OPEN;\n\ B:=A&&CLOSE>MA(CLOSE,S)&&CLOSE>MA(CLOSE,M)&&CLOSE>MA(CLOSE,LL);\n\ CC:=B&&OPEN0.0618*CLOSE;' }; return data; } JSIndexScript.prototype.COLOR_WYGD=function() { let data= { Name: '乌云盖顶', Description: '乌云盖顶', IsMainIndex: true, InstructionType:2, Script: //脚本 'VAR1:BACKSET( \n\ REF(CLOSE,1)/REF(OPEN,1)>1.03 AND \n\ CLOSE/OPEN<0.97 AND \n\ OPEN>REF(CLOSE,1) AND CLOSE1.03 AND \n\ OPENREF(CLOSE,1), 3);' }; return data; } JSIndexScript.prototype.COLOR_SZTAI=function() { let data= { Name: '十字胎', Description: '十字胎', IsMainIndex: true, InstructionType:2, Script: //脚本 'VAR1:BACKSET( ABS(REF(CLOSE,1)-REF(OPEN,1))/REF(CLOSE,1) > 0.04 AND \n\ CLOSE==OPEN AND CLOSE < MAX(REF(CLOSE,1),REF(OPEN,1)) AND \n\ CLOSE > MIN(REF(CLOSE,1),REF(OPEN,1)), 2);' }; return data; } JSIndexScript.prototype.COLOR_PINGDING=function() { let data= { Name: '平顶', Description: '平顶', IsMainIndex: true, InstructionType:2, Script: //脚本 'VAR1:BACKSET(ABS(HIGH-REF(HIGH,1))/HIGH<0.001,2);' }; return data; } JSIndexScript.prototype.COLOR_PINGDI=function() { let data= { Name: '平底', Description: '平底', IsMainIndex: true, InstructionType:2, Script: //脚本 'VAR1:BACKSET((ABS(LOW-REF(LOW,1))/LOW<0.001 AND \n\ ABS(REF(LOW,1)-REF(LOW,2))/REF(LOW,1)<=0.001),2);' }; return data; } JSIndexScript.prototype.COLOR_DAYANZHU=function() { let data= { Name: '大阳烛', Description: '大阳烛', IsMainIndex: true, InstructionType:2, Script: //脚本 'VAR1:CLOSE/OPEN>1.05 AND HIGH/LOW < CLOSE/OPEN+0.018;' }; return data; } JSIndexScript.prototype.COLOR_DAYINGZHU=function() { let data= { Name: '大阴烛', Description: '大阴烛', IsMainIndex: true, InstructionType:2, Script: //脚本 'VAR1:OPEN/CLOSE > 1.05 AND HIGH/LOW < OPEN/CLOSE+0.018;' }; return data; } JSIndexScript.prototype.COLOR_HYFG=function() { let data= { Name: '好友反攻', Description: '好友反攻', IsMainIndex: true, InstructionType:2, Script: //脚本 'VAR1:BACKSET( (REF(CLOSE,1)OPEN AND ABS(CLOSE-REF(CLOSE,1))/CLOSE<0.002),2);' }; return data; } JSIndexScript.prototype.COLOR_TKQK=function() { let data= { Name: '跳空缺口', Description: '跳空缺口', IsMainIndex: true, InstructionType:2, Script: //脚本 'VAR1:BACKSET( HIGHREF(HIGH,1),2);' }; return data; } JSIndexScript.prototype.COLOR_SFWY=function() { let data= { Name: '双飞乌鸦', Description: '双飞乌鸦', IsMainIndex: true, InstructionType:2, Script: //脚本 'VAR1:BACKSET( REF(CLOSE,1)1.03 AND \n\ REF(CLOSE,3)REF(HIGH,3) AND \n\ REF(HIGH,4)>REF(HIGH,2) AND \n\ REF(HIGH,4)>REF(HIGH,1) AND \n\ CLOSE/OPEN>1.03 AND \n\ CLOSE>REF(CLOSE,4), 5);' }; return data; } JSIndexScript.prototype.COLOR_XDSBQ=function() { let data= { Name: '下跌三部曲', Description: '下跌三部曲', IsMainIndex: true, InstructionType:2, Script: //脚本 'VAR1:BACKSET( \n\ REF(CLOSE,4)/REF(OPEN,4)<0.97 AND \n\ REF(CLOSE,3)>REF(OPEN,3) AND \n\ REF(CLOSE,2)>REF(OPEN,2) AND \n\ REF(CLOSE,1)>REF(OPEN,1) AND \n\ REF(LOW,4)REF(HIGH,3) AND \n\ REF(HIGH,4)>REF(HIGH,2) AND \n\ REF(HIGH,4)>REF(HIGH,1) AND \n\ CLOSE/OPEN<0.97 AND \n\ CLOSE0.667;' }; return data; } JSIndexScript.prototype.COLOR_CHSY=function() { let data= { Name: '长上影', Description: '长上影', IsMainIndex: true, InstructionType:2, Script: //脚本 'VAR2:(HIGH-MAX(CLOSE,OPEN))/(HIGH-LOW)>0.667,COLORBLUE;' }; return data; } JSIndexScript.prototype.COLOR_FENLI=function() { let data= { Name: '分离', Description: '分离', IsMainIndex: true, InstructionType:2, Script: //脚本 'VAR1:BACKSET( OPEN==REF(OPEN,1) AND (CLOSE-OPEN)*(REF(CLOSE,1)-REF(OPEN,1))<0,2);' }; return data; } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //交易系统 JSIndexScript.prototype.TRADE_BIAS = function () { let data = { Name: 'BIAS', Description: '乖离率专家系统', IsMainIndex: true, InstructionType:1, Args: [{ Name: 'N', Value: 12 }, { Name: 'LL', Value: 6 },{ Name: 'LH', Value: 6 }], Script: //脚本 'BIAS:=(CLOSE-MA(CLOSE,N))/MA(CLOSE,N)*100;\n\ ENTERLONG:CROSS(-LL,BIAS);\n\ EXITLONG:CROSS(BIAS,LH);' }; return data; } JSIndexScript.prototype.TRADE_CCI = function () { let data = { Name: 'CCI', Description: 'CCI专家系统', IsMainIndex: true, InstructionType:1, Args: [{ Name: 'N', Value: 14 }], Script: //脚本 'TYP:=(HIGH+LOW+CLOSE)/3;\n\ CCI:=(TYP-MA(TYP,N))/(0.015*AVEDEV(TYP,N));\n\ INDEX:=CCI;\n\ ENTERLONG:CROSS(INDEX,-100);\n\ EXITLONG:CROSS(100,INDEX);' }; return data; } JSIndexScript.prototype.TRADE_DMI = function () { let data = { Name: 'DMI', Description: '趋向专家系统', IsMainIndex: true, InstructionType:1, Args: [{ Name: 'N', Value: 14 }], Script: //脚本 'MTR:=SUM(MAX(MAX(HIGH-LOW,ABS(HIGH-REF(CLOSE,1))),ABS(LOW-REF(CLOSE,1))),N);\n\ HD :=HIGH-REF(HIGH,1);\n\ LD :=REF(LOW,1)-LOW;\n\ PDM:=SUM(IF(HD>0&&HD>LD,HD,0),N);\n\ MDM:=SUM(IF(LD>0&&LD>HD,LD,0),N);\n\ PDI:=PDM*100/MTR;\n\ MDI:=MDM*100/MTR;\n\ ENTERLONG:CROSS(PDI,MDI);\n\ EXITLONG:CROSS(MDI,PDI);' }; return data; } JSIndexScript.prototype.TRADE_KD = function () { let data = { Name: 'KD', Description: 'KD指标专家系统', IsMainIndex: true, InstructionType:1, Args: [{ Name: 'N', Value: 9 },{ Name: 'M1', Value: 3 },{ Name: 'M2', Value: 3 }], Script: //脚本 'WRSV:=(CLOSE-LLV(LOW,N))/(HHV(HIGH,N)-LLV(LOW,N))*100;\n\ WK:=SMA(WRSV,M1,1);\n\ D:=SMA(WK,M2,1);\n\ ENTERLONG:CROSS(WK,D)&&WK<20;\n\ EXITLONG:CROSS(D,WK)&&WK>80;' }; return data; } JSIndexScript.prototype.TRADE_BOLL = function () { let data = { Name: 'BOLL', Description: '布林带专家系统', IsMainIndex: true, InstructionType:1, Args: [{ Name: 'N', Value: 20 }], Script: //脚本 'MID :=MA(CLOSE,N);\n\ UPPER:=MID+2*STD(CLOSE,N);\n\ LOWER:=MID-2*STD(CLOSE,N);\n\ ENTERLONG:CROSS(CLOSE,LOWER);\n\ EXITLONG:CROSS(CLOSE,UPPER);' }; return data; } JSIndexScript.prototype.TRADE_KDJ = function () { let data = { Name: 'KDJ', Description: 'KDJ专家系统', IsMainIndex: true, InstructionType:1, Args: [{ Name: 'N', Value: 9 },{ Name: 'M1', Value: 3 }], Script: //脚本 'RSV:=(CLOSE-LLV(LOW,N))/(HHV(HIGH,N)-LLV(LOW,N))*100;\n\ K:=SMA(RSV,M1,1);\n\ D:=SMA(K,M1,1);\n\ J:=3*K-2*D;\n\ ENTERLONG:CROSS(J,0);\n\ EXITLONG:CROSS(100,J);' }; return data; } JSIndexScript.prototype.TRADE_MA = function () { let data = { Name: 'MA', Description: '均线专家系统', IsMainIndex: true, InstructionType:1, Args: [{ Name: 'SHORT', Value: 5 },{ Name: 'LONG', Value: 20 }], Script: //脚本 'ENTERLONG:CROSS(MA(CLOSE,SHORT),MA(CLOSE,LONG));\n\ EXITLONG:CROSS(MA(CLOSE,LONG),MA(CLOSE,SHORT));' }; return data; } JSIndexScript.prototype.TRADE_MACD = function () { let data = { Name: 'MACD', Description: 'MACD专家系统', IsMainIndex: true, InstructionType:1, Args: [{ Name: 'LONG', Value: 26 }, { Name: 'SHORT', Value: 12 }, { Name: 'M', Value: 9 }], Script: //脚本 'DIFF:=EMA(CLOSE,SHORT) - EMA(CLOSE,LONG);\n\ DEA := EMA(DIFF,M);\n\ MACD := 2*(DIFF-DEA);\n\ ENTERLONG:CROSS(MACD,0);\n\ EXITLONG:CROSS(0,MACD);' }; return data; } JSIndexScript.prototype.TRADE_MTM = function () { let data = { Name: 'MTM', Description: '动力指标专家系统', IsMainIndex: true, InstructionType:1, Args: [{ Name: 'N', Value: 6 }], Script: //脚本 'WMTM:=C-REF(C,N);\n\ ENTERLONG:CROSS(WMTM,0);\n\ EXITLONG:CROSS(0,WMTM);' }; return data; } JSIndexScript.prototype.TRADE_PSY = function () { let data = { Name: 'PSY', Description: 'PSY心理线专家系统', IsMainIndex: true, InstructionType:1, Args: [{ Name: 'N', Value: 12 },{ Name: 'LL', Value: 10 },{ Name: 'LH', Value: 85 }], Script: //脚本 'MYPSY:=COUNT(CLOSE>REF(CLOSE,1),N)/N*100;\n\ ENTERLONG:CROSS(LL,MYPSY);\n\ EXITLONG:CROSS(MYPSY,LH);' }; return data; } JSIndexScript.prototype.TRADE_ROC = function () { let data = { Name: 'ROC', Description: '变动速率专家系统', IsMainIndex: true, InstructionType:1, Args: [{ Name: 'N', Value: 12 },{ Name: 'M', Value: 6 }], Script: //脚本 'WROC:=MA(100*(CLOSE-REF(CLOSE,N))/REF(CLOSE,N),M);\n\ ENTERLONG:CROSS(WROC,0);\n\ EXITLONG:CROSS(0,WROC);' }; return data; } JSIndexScript.prototype.TRADE_RSI = function () { let data = { Name: 'RSI', Description: '相对强弱专家系统', IsMainIndex: true, InstructionType:1, Args: [{ Name: 'N', Value: 6 },{ Name: 'LL', Value: 20 },{ Name: 'LH', Value: 80 }], Script: //脚本 'LC:=REF(CLOSE,1);\n\ WRSI:=SMA(MAX(CLOSE-LC,0),N,1)/SMA(ABS(CLOSE-LC),N,1)*100;\n\ ENTERLONG:CROSS(WRSI,LL);\n\ EXITLONG:CROSS(LH,WRSI);' }; return data; } JSIndexScript.prototype.TRADE_VR = function () { let data = { Name: 'VR', Description: 'VR容量比率专家系统', IsMainIndex: true, InstructionType:1, Args: [{ Name: 'N', Value: 26 },{ Name: 'LL', Value: 70 },{ Name: 'LH', Value: 250 }], Script: //脚本 'WVR := SUM((IF(CLOSE>OPEN,VOL,0)+IF(CLOSE=OPEN,VOL/2,0)),N)/SUM((IF(CLOSE REF(VAR5, 1), VAR5,0), COLORRED, NODRAW;\n\ 洗盘: IF(VAR5 < REF(VAR5, 1), VAR5,0), COLORYELLOW, NODRAW;\n\ STICKLINE(VAR5> REF(VAR5, 1),0, VAR5, 20, 0), COLORRED;\n\ STICKLINE(VAR5 < REF(VAR5, 1), 0, VAR5, 20, 0), COLORYELLOW;' }; return data; } JSIndexScript.prototype.Zealink_Index2 = function () { let data = { Name: '牛熊区间', Description: '牛熊区间', IsMainIndex: false,YSpecificMaxMin:{Max:100,Min:1,Count:4},YSplitScale:[1,50,100], Args: [], Script: //脚本 '短高H:=(20*H+19*REF(H,1)+18*REF(H,2)+17*REF(H,3)+16*REF(H,4)+15*REF(H,5)+14*REF(H,6)\n\ + 13 * REF(H, 7) + 12 * REF(H, 8) + 11 * REF(H, 9) + 10 * REF(H, 10) + 9 * REF(H, 11) + 8 * REF(H, 12)\n\ + 7 * REF(H, 13) + 6 * REF(H, 14) + 5 * REF(H, 15) + 4 * REF(H, 16) + 3 * REF(H, 17) + 2 * REF(H, 18) +\n\ REF(H, 20))/ 210, COLORBLUE, LINETHICK1;\n\ 短低L:= (20 * L + 19 * REF(L, 1) + 18 * REF(L, 2) + 17 * REF(L, 3) + 16 * REF(L, 4) + 15 * REF(L, 5) + 14 * REF(L, 6)\n\ + 13 * REF(L, 7) + 12 * REF(L, 8) + 11 * REF(L, 9) + 10 * REF(L, 10) + 9 * REF(L, 11) + 8 * REF(L, 12)\n\ + 7 * REF(L, 13) + 6 * REF(L, 14) + 5 * REF(L, 15) + 4 * REF(L, 16) + 3 * REF(L, 17) + 2 * REF(L, 18) +\n\ REF(L, 20)) / 210, COLORBLUE, LINETHICK1;\n\ D90H:= EMA(短高H, 90), COLORRED, LINETHICK1;\n\ D90L:= EMA(短低L, 90), COLORRED, LINETHICK1;\n\ D90差:= D90H - D90L;\n\ D90顶:= D90H + D90差 * 2, COLORRED, LINETHICK1;\n\ D90底:= D90L - D90差 * 2, COLORRED, LINETHICK1;\n\ 高0:= (EMA(EMA(H, 25), 25) - EMA(EMA(L, 25), 25)) * 1 + EMA(EMA(H, 25), 25), LINETHICK1, COLORWHITE;\n\ 低0:= EMA(EMA(L, 25), 25) - (EMA(EMA(H, 25), 25) - EMA(EMA(L, 25), 25)) * 1, LINETHICK1, COLORWHITE;\n\ 多头定位:= 低0 >= D90底 AND 高0 >= D90顶;\n\ 空头定位:= 高0 <= D90顶 AND 低0 <= D90底;\n\ 震荡定位:= 低0 >= D90底 AND 高0 <= D90顶;\n\ 牛市: IF(多头定位 == 1, 100, 1), COLORRED, NODRAW;\n\ 熊市: IF(空头定位 == 1, 100, 1), COLORGREEN, NODRAW;\n\ 震荡: IF(震荡定位 == 1, 100, 1), COLORGRAY, NODRAW;\n\ STICKLINE(多头定位 == 1, 100, 1, 100, 0), COLORRED;\n\ STICKLINE(空头定位 == 1, 100, 1, 100, 0), COLORGREEN;\n\ STICKLINE(震荡定位 == 1, 100, 1, 100, 0), COLORGRAY;' }; return data; } JSIndexScript.prototype.Zealink_Index3 = function () { let data = { Name: '持仓信号', Description: '持仓信号', IsMainIndex: true, Args: [], Script: //脚本 '买线:=EMA(C,2);\n\ 卖线:=EMA(SLOPE(C,30)*5+C,20); \n\ BU:=CROSS(买线,卖线);\n\ SEL:=CROSS(卖线,买线);\n\ \n\ STICKLINE(买线>=卖线 AND CLOSE>OPEN,LOW,HIGH,0,1),COLORRED;\n\ STICKLINE(买线>=卖线 AND CLOSE=卖线 AND CLOSE>OPEN,CLOSE,OPEN,50,1),COLORRED;\n\ STICKLINE(买线>=卖线 AND CLOSEOPEN,LOW,HIGH,0,1),COLORGREEN;\n\ STICKLINE(买线<卖线 AND CLOSEOPEN,CLOSE,OPEN,50,1),COLORGREEN;\n\ \n\ HHJSJDA:=(3*CLOSE+OPEN+LOW+HIGH)/6;\n\ HHJSJDB:(19*HHJSJDA+19*REF(HHJSJDA,1)+18*REF(HHJSJDA,2)+17*REF(HHJSJDA,3)+16*REF(HHJSJDA,4)+15*REF(HHJSJDA,5)+14*REF(HHJSJDA,6)\n\ +13*REF(HHJSJDA,7)+12*REF(HHJSJDA,8)+11*REF(HHJSJDA,9)+10*REF(HHJSJDA,10)+9*REF(HHJSJDA,11)+8*REF(HHJSJDA,12)+7*REF(HHJSJDA,13)+6*REF(HHJSJDA,14)+5*REF(HHJSJDA,15)+4*REF(HHJSJDA,16)+3*REF(HHJSJDA,17)+2*REF\n\ (HHJSJDA,20)+REF(HHJSJDA,19))/210,COLORYELLOW;\n\ HHJSJDC:MA(HHJSJDB,5),COLORRED;\n\ \n\ SVAR11:=HHV(HIGH,34);\n\ SVAR14:=CLOSE-REF(CLOSE,1);\n\ SVAR15:=MAX(SVAR14,0);\n\ SVAR16:=ABS(SVAR14);\n\ SVAR17:=SMA(SVAR15,7,1)/SMA(SVAR16,7,1)*100;\n\ SVAR18:=SMA(SVAR15,13,1)/SMA(SVAR16,13,1)*100;\n\ SVAR19:=BARSCOUNT(CLOSE);\n\ SVAR20:=SMA(MAX(SVAR14,0),6,1)/SMA(ABS(SVAR14),6,1)*100;\n\ SVAR21:=(-200)*(HHV(HIGH,60)-CLOSE)/(HHV(HIGH,60)-LLV(LOW,60))+100;\n\ SVAR1A:=(CLOSE-LLV(LOW,15))/(HHV(HIGH,15)-LLV(LOW,15))*100;\n\ SVAR1B:=SMA((SMA(SVAR1A,4,1)-50)*2,3,1);\n\ SVAR1C:=(INDEXC-LLV(INDEXL,14))/(HHV(INDEXH,14)-LLV(INDEXL,14))*100;\n\ SVAR1D:=SMA(SVAR1C,4,1);\n\ SVAR1E:=SMA(SVAR1D,3,1);\n\ SVAR1F:=(HHV(HIGH,30)-CLOSE)/CLOSE*100;\n\ SVAR22:=SVAR20<=25 AND SVAR21<-95 AND SVAR1F>20 AND SVAR1B<-30 AND SVAR1E<30 AND SVAR11-CLOSE>=-0.25 AND SVAR17<22 AND SVAR18<28 AND SVAR19>50;\n\ BUY3:=CROSS(SVAR22,0.5) AND COUNT(SVAR22==1,10)==1;\n\ \n\ SVARF:=LOW*0.9;\n\ SVAR10X:=100-3*SMA((OPEN-LLV(LOW,75))/(HHV(HIGH,75)-LLV(LOW,75))*100,20,1)+2*SMA(SMA((OPEN-LLV(LOW,75))/(HHV(HIGH,75)-LLV(LOW,75))*100,20,1),15,1);\n\ SVAR11X:=SVARFREF(VOL,1) AND CLOSE>REF(CLOSE,1);\n\ BUY2:=SVAR11X AND COUNT(SVAR11X,30)==1;\n\ \n\ VAR1:=(CLOSE+HIGH+LOW+OPEN)/4;\n\ VAR2:=SUMBARS(VOL,CAPITAL);\n\ VAR3:=HHV(VAR1,VAR2);\n\ VAR4:=LLV(VAR1,VAR2);\n\ VAR5:=(2*VAR1-VAR4-REF(VAR4,1))/(VAR3-VAR4);\n\ VAR6:=(VAR1-VAR4)/(VAR3-VAR4);\n\ VAR7:=IF(VAR1<=VAR4,VAR5*60,VAR6*60);\n\ VAR8:=600*(EMA(CLOSE,3)-EMA(LOW,30))/EMA(LOW,30);\n\ VAR9:=EMA(VAR8,7);\n\ VARC:=HHV(HIGH,9)-LLV(LOW,9);\n\ VARD:=HHV(HIGH,9)-CLOSE;\n\ VARE:=CLOSE-LLV(LOW,9);\n\ VARF:=VARD/VARC*100-70;\n\ VAR10:=(CLOSE-LLV(LOW,60))/(HHV(HIGH,60)-LLV(LOW,60))*100;\n\ VAR11:=(2*CLOSE+HIGH+LOW)/4;\n\ VAR12:=SMA(VARE/VARC*100,3,1);\n\ VAR13:=LLV(LOW,34);\n\ VAR14:=SMA(VAR12,3,1)-SMA(VARF,9,1);\n\ VAR15:=IF(VAR14>100,VAR14-100,0);\n\ VAR16:=HHV(HIGH,34);\n\ VAR17:=EMA((VAR11-VAR13)/(VAR16-VAR13)*100,8);\n\ VAR18:=EMA(VAR17,5);\n\ BUY:=STICKLINE(VAR17-VAR18>0,VAR17,VAR18,8,1),COLORRED;\n\ SELL:=STICKLINE(VAR17-VAR18<0,VAR17,VAR18,8,1),COLORGREEN;\n\ BUY1:=VAR17>VAR18 AND REF(VAR17,1)REF(VAR18,1);\n\ \n\ 短高H:=(20*H+19*REF(H,1)+18*REF(H,2)+17*REF(H,3)+16*REF(H,4)+15*REF(H,5)+14*REF(H,6)\n\ +13*REF(H,7)+12*REF(H,8)+11*REF(H,9)+10*REF(H,10)+9*REF(H,11)+8*REF(H,12)\n\ +7*REF(H,13)+6*REF(H,14)+5*REF(H,15)+4*REF(H,16)+3*REF(H,17)+2*REF(H,18)+\n\ REF(H,20))/210,COLORBLUE,LINETHICK1;\n\ 短低L:=(20*L+19*REF(L,1)+18*REF(L,2)+17*REF(L,3)+16*REF(L,4)+15*REF(L,5)+14*REF(L,6)\n\ +13*REF(L,7)+12*REF(L,8)+11*REF(L,9)+10*REF(L,10)+9*REF(L,11)+8*REF(L,12)\n\ +7*REF(L,13)+6*REF(L,14)+5*REF(L,15)+4*REF(L,16)+3*REF(L,17)+2*REF(L,18)+\n\ REF(L,20))/210,COLORBLUE,LINETHICK1;\n\ D90H:=EMA(短高H,90),COLORRED,LINETHICK1;\n\ D90L:=EMA(短低L,90),COLORRED,LINETHICK1;\n\ D90差:=D90H-D90L;\n\ D90顶:=D90H+D90差*2,COLORRED,LINETHICK1;\n\ D90底:=D90L-D90差*2,COLORRED,LINETHICK1;\n\ 高0:=(EMA(EMA(H,25),25)-EMA(EMA(L,25),25))*1+EMA(EMA(H,25),25),LINETHICK1,COLORWHITE;\n\ 低0:=EMA(EMA(L,25),25)-(EMA(EMA(H,25),25)-EMA(EMA(L,25),25))*1,LINETHICK1,COLORWHITE;\n\ 多头定位:=低0>=D90底 AND 高0>=D90顶;\n\ 空头定位:=高0<=D90顶 AND 低0<=D90底;\n\ 震荡定位:=低0>=D90底 AND 高0<=D90顶;\n\ \n\ 牛市:=多头定位==1;\n\ 熊市:=空头定位==1;\n\ 震荡:=震荡定位==1;\n\ \n\ 非牛市:=熊市 OR 震荡;\n\ 非熊市:=牛市 OR 震荡;\n\ \n\ BUY11:=BUY1 AND 非熊市;\n\ SELL11:=SELL1 AND 震荡定位==0;\n\ \n\ BUY111:=BUY11 AND COUNT(BUY11,10)<2;\n\ BUY0:=BUY111 AND COUNT(BUY111,21)==1;\n\ SELL111:=SELL11 AND COUNT(SELL11,10)<2;\n\ SELL0:=SELL111 AND COUNT(SELL111,10)==1;\n\ \n\ XK1:=EMA(100*(CLOSE-LLV(LOW,34))/(HHV(HIGH,34)-LLV(LOW,34)),3)/4;\n\ 上穿:=REF(XK1,1)<5 AND XK1>=5;\n\ BUY4:=上穿 AND COUNT(XK1<2,12)<1;\n\ \n\ SELL2:=REF(XK1,1)<=22.5 AND XK1>22.5 AND COUNT(REF(XK1,1)>=22.5 AND XK1<22.5,5)>0;\n\ SELL3:=REF(XK1,1)>=21.5 AND XK1<21.5 AND COUNT(REF(XK1,1)>=22.5 AND XK1<22.5,12)>1;\n\ SELL4:=SELL2 OR SELL3 AND COUNT((SELL2 OR SELL3)==1,5)==1;\n\ \n\ SUPERDRAWTEXT(BUY0,L,"机会",2,10),COLORRED;\n\ SUPERDRAWTEXT(SELL0,H,"风险",1,10),COLORGREEN;\n\ SUPERDRAWTEXT(BUY2,L,"机会",2,10),COLORRED;\n\ SUPERDRAWTEXT(BUY4,L,"机会",2,10),COLORRED;\n\ SUPERDRAWTEXT(SELL4,H,"风险",1,10),COLORGREEN;' }; return data; } JSIndexScript.prototype.Zealink_Index4 = function () { let data = { Name: '股东实际增减持', Description: '股东实际增减持', IsMainIndex: false, FloatPrecision:0, Args: [], Script: //脚本 '增持:NEWS(4),NODRAW,COLORRED;\n\ 减持:NEWS(5),NODRAW,COLORGREEN;\n\ STICKLINE(增持>0,0,增持,1,0),COLORRED;\n\ STICKLINE(减持<0,0,减持,1,0),COLORGREEN;' }; return data; } JSIndexScript.prototype.Zealink_Index5 = function () { let data = { Name: '大宗交易', Description: '大宗交易', IsMainIndex: false, FloatPrecision: 0, Args: [], Script: //脚本 '交易次数:NEWS(7);' }; return data; } JSIndexScript.prototype.Zealink_Index6 = function () { let data = { Name: '信托持股', Description: '信托持股', IsMainIndex: false, FloatPrecision: 0, Args: [], Script: //脚本 '家数:NEWS(6);' }; return data; } JSIndexScript.prototype.Zealink_Index7 = function () { let data = { Name: '官网新闻', Description: '官网新闻', IsMainIndex: false, FloatPrecision: 0, Args: [], Script: //脚本 '个数:NEWS(8);' }; return data; } JSIndexScript.prototype.Zealink_Index8 = function () { let data = { Name: '高管要闻', Description: '高管要闻', IsMainIndex: false, FloatPrecision: 0, Args: [], Script: //脚本 '个数:NEWS(9);' }; return data; } JSIndexScript.prototype.Zealink_Index9 = function () { let data = { Name: '股权质押', Description: '股权质押', IsMainIndex: false, FloatPrecision: 0, Args: [], Script: //脚本 '次数:NEWS(10);' }; return data; } JSIndexScript.prototype.Zealink_Index10 = function () { let data = { Name: '操盘BS点', Description: '操盘BS点', IsMainIndex: true, FloatPrecision: 0, Args: [], Script: //脚本 "JJ:=(CLOSE+HIGH+LOW)/3; \n\ A:=EMA(JJ,10); \n\ B:=REF(A,1);\n\ M1:=EMA(CLOSE,3);\n\ M2:=EMA(CLOSE,8); \n\ M3:=EMA(M2,13); \n\ M4:=EMA(M2,55); \n\ B1:=A>B AND REF(A,1)REF(B,1);\n\ INDEXCLOSE:INDEXC,EXDATA;\n\ INDEXOPEN:INDEXO,EXDATA;\n\ DRAWICON(REF(B1,1),L*0.97,13);\n\ DRAWICON(REF(S1,1),H*1.03,14);" }; return data; } JSIndexScript.prototype.Zealink_Index11 = function () { let data = { Name: '操盘BS点', Description: '操盘BS点', IsMainIndex: true, FloatPrecision: 0, Args: [], Script: //脚本 "JJ:=(CLOSE+HIGH+LOW)/3;\n\ A:=EMA(JJ,10);\n\ B:=REF(A,1);\n\ M1:=EMA(CLOSE,3);\n\ M2:=EMA(CLOSE,8); \n\ M3:=EMA(M2,13);\n\ M4:=EMA(M2,55);\n\ 持股区域:=STICKLINE(A>B,A,B,2,0),COLORYELLOW; \n\ 持币区域:=STICKLINE(A100,VR14-100,0);\n\ VR16:=HHV(H,34);\n\ VR17:=EMA((VR11-VR13)/(VR16-VR13)*100,8);\n\ VR18:=EMA(VR17,5);\n\ \n\ B1:=A>B AND REF(A,1)REF(B,1);\n\ \n\ B9:=BARSLAST(REF(B1,1) AND (REF(VR17>VR18,1) OR MIN(VR17,VR18)>REF(MAX(VR17,VR18),1)));\n\ S9:=BARSLAST(REF(S1,1) AND (REF(VR17VR18,1) OR MIN(VR17,VR18)>REF(MAX(VR17,VR18),1)) AND REF(B9,2)>=S9,L*0.97,13);\n\ DRAWICON(REF(S1,1) AND (REF(VR17=B9,H*1.03,14);\n\ \n\ DRAWKLINE_IF(VR17>VR18,HIGH,CLOSE,LOW,OPEN),COLORRED;\n\ DRAWKLINE_IF(VR17C,H,L, 'RGB(255,94,102)', 2 ,'5,5','RGBA(58,20,62,0.3)' );" }; return data; } /* Copyright (c) 2018 jones http://www.apache.org/licenses/LICENSE-2.0 开源项目 https://github.com/jones2000/HQChart jones_2000@163.com 封装行情类图形控件 (H5版本) */ function JSChart(divElement) { this.DivElement=divElement; this.DivToolElement=null; //工具条 this.JSChartContainer; //画图控件 //h5 canvas this.CanvasElement=document.createElement("canvas"); this.CanvasElement.className='jschart-drawing'; this.CanvasElement.id=Guid(); this.CanvasElement.setAttribute("tabindex",0); if (this.CanvasElement.style) this.CanvasElement.style.outline='none'; if(!divElement.hasChildNodes("canvas")){ divElement.appendChild(this.CanvasElement); } //改参数div this.ModifyIndexDialog=new ModifyIndexDialog(divElement); this.ChangeIndexDialog=new ChangeIndexDialog(divElement); this.MinuteDialog=new MinuteDialog(divElement); this.OnSize=function() { //画布大小通过div获取 var height=parseInt(this.DivElement.style.height.replace("px","")); if (this.ToolElement) { //TODO调整工具条大小 height-=this.ToolElement.style.height.replace("px",""); //减去工具条的高度 } this.CanvasElement.height=height; this.CanvasElement.width=parseInt(this.DivElement.style.width.replace("px","")); this.CanvasElement.style.width=this.CanvasElement.width+'px'; this.CanvasElement.style.height=this.CanvasElement.height+'px'; var pixelTatio = GetDevicePixelRatio(); //获取设备的分辨率 this.CanvasElement.height*=pixelTatio; this.CanvasElement.width*=pixelTatio; console.log(`[JSChart::OnSize] devicePixelRatio=${window.devicePixelRatio}, height=${this.CanvasElement.height}, width=${this.CanvasElement.width}`); if (this.JSChartContainer && this.JSChartContainer.Frame) this.JSChartContainer.Frame.SetSizeChage(true); if (this.JSChartContainer) this.JSChartContainer.Draw(); } //手机屏需要调整 间距 this.AdjustChartBorder=function(chart) { var pixelTatio = GetDevicePixelRatio(); //获取设备的分辨率 chart.Frame.ChartBorder.Left*=pixelTatio; chart.Frame.ChartBorder.Right*=pixelTatio; chart.Frame.ChartBorder.Top*=pixelTatio; chart.Frame.ChartBorder.Bottom*=pixelTatio; } this.AdjustTitleHeight=function(chart) { var pixelTatio = GetDevicePixelRatio(); //获取设备的分辨率 for(let i in chart.Frame.SubFrame) { chart.Frame.SubFrame[i].Frame.ChartBorder.TitleHeight*=pixelTatio; } chart.ChartCorssCursor.TextHeight*=pixelTatio; //十字光标文本信息高度 } //历史K线图 this.CreateKLineChartContainer=function(option) { var chart=null; if (option.Type==="历史K线图横屏") chart=new KLineChartHScreenContainer(this.CanvasElement); else chart=new KLineChartContainer(this.CanvasElement); if (option.NetworkFilter) chart.NetworkFilter=option.NetworkFilter; //创建改参数div chart.ModifyIndexDialog=this.ModifyIndexDialog; chart.ChangeIndexDialog=this.ChangeIndexDialog; chart.MinuteDialog=this.MinuteDialog; //右键菜单 if (option.IsShowRightMenu==true) chart.RightMenu=new KLineRightMenu(this.DivElement); if (option.ScriptError) chart.ScriptErrorCallback=option.ScriptError; chart.SelectRectRightMenu=new KLineSelectRightMenu(this.DivElement); if (option.EnableScrollUpDown==true) chart.EnableScrollUpDown=option.EnableScrollUpDown; if (option.DisableMouse==true) chart.DisableMouse=option.DisableMouse; if (option.KLine) //k线图的属性设置 { if (option.KLine.DragMode>=0) chart.DragMode=option.KLine.DragMode; if (option.KLine.Right>=0) chart.Right=option.KLine.Right; if (option.KLine.Period>=0) chart.Period=option.KLine.Period; if (option.KLine.MaxReqeustDataCount>0) chart.MaxReqeustDataCount=option.KLine.MaxReqeustDataCount; if (option.KLine.Info && option.KLine.Info.length>0) chart.SetKLineInfo(option.KLine.Info,false); if (option.KLine.IndexTreeApiUrl) chart.ChangeIndexDialog.IndexTreeApiUrl=option.KLine.IndexTreeApiUrl; if (option.KLine.KLineDoubleClick==false) chart.MinuteDialog=this.MinuteDialog=null; if (option.KLine.IndexTreeApiUrl!=null) chart.ChangeIndexDialog.IndexTreeApiUrl=option.KLine.IndexTreeApiUrl; if (option.KLine.IsShowTooltip==false) chart.IsShowTooltip=false; if (option.KLine.MaxRequestMinuteDayCount>0) chart.MaxRequestMinuteDayCount=option.KLine.MaxRequestMinuteDayCount; if (option.KLine.DrawType) chart.KLineDrawType=option.KLine.DrawType; if (option.KLine.FirstShowDate>20000101) chart.CustomShow={ Date:option.KLine.FirstShowDate }; } if (option.Page) { if (option.Page.Day && option.Page.Day.Enable==true) chart.Page.Day.Enable=true; if (option.Page.Minute && option.Page.Minute.Enable==true) chart.Page.Minute.Enable=true; } if (option.DragDownload) { if (option.DragDownload.Day && option.DragDownload.Day.Enable==true) chart.DragDownload.Day.Enable=true; if (option.DragDownload.Minute && option.DragDownload.Minute.Enable==true) chart.DragDownload.Minute.Enable=true; } if (option.Language) { if (option.Language==='CN') chart.LanguageID=JSCHART_LANGUAGE_ID.LANGUAGE_CHINESE_ID; else if(option.Language==='EN') chart.LanguageID=JSCHART_LANGUAGE_ID.LANGUAGE_ENGLISH_ID; } if (option.DrawPicture) //画图工具 { if (option.DrawPicture.StorageKey && chart.ChartDrawStorage) chart.ChartDrawStorage.Load(option.DrawPicture.StorageKey); } if (option.StepPixel>0) chart.StepPixel=option.StepPixel; if (option.ZoomStepPixel>0) chart.ZoomStepPixel=option.ZoomStepPixel; if (option.IsApiPeriod==true) chart.IsApiPeriod=option.IsApiPeriod; if (!option.Windows || option.Windows.length<=0) return null; //创建子窗口 chart.Create(option.Windows.length); if (option.Border) { if (!isNaN(option.Border.Left)) chart.Frame.ChartBorder.Left=option.Border.Left; if (!isNaN(option.Border.Right)) chart.Frame.ChartBorder.Right=option.Border.Right; if (!isNaN(option.Border.Top)) chart.Frame.ChartBorder.Top=option.Border.Top; if (!isNaN(option.Border.Bottom)) chart.Frame.ChartBorder.Bottom=option.Border.Bottom; } this.AdjustChartBorder(chart); if (option.KLine) { if (option.KLine.PageSize > 0) //一屏显示的数据个数 { let pageSize = chart.GetMaxMinPageSize(); if (pageSize.Max>10 && pageSize.Max < option.KLine.PageSize) chart.PageSize = pageSize.Max; else if (pageSize.Min>10 && pageSize.Min> option.KLine.PageSize) chart.PageSize=pageSize.Min; else chart.PageSize = option.KLine.PageSize; } } //取消显示十字光标刻度信息 if (option.IsCorssOnlyDrawKLine===true) chart.ChartCorssCursor.IsOnlyDrawKLine=option.IsCorssOnlyDrawKLine; if (option.CorssCursorTouchEnd===true) chart.CorssCursorTouchEnd = option.CorssCursorTouchEnd; if (option.IsClickShowCorssCursor==true) chart.IsClickShowCorssCursor=option.IsClickShowCorssCursor; if (option.CorssCursorInfo) { if (!isNaN(option.CorssCursorInfo.Left)) chart.ChartCorssCursor.ShowTextMode.Left=option.CorssCursorInfo.Left; if (!isNaN(option.CorssCursorInfo.Right)) chart.ChartCorssCursor.ShowTextMode.Right=option.CorssCursorInfo.Right; if (!isNaN(option.CorssCursorInfo.Bottom)) chart.ChartCorssCursor.ShowTextMode.Bottom=option.CorssCursorInfo.Bottom; if (option.CorssCursorInfo.IsShowCorss===false) chart.ChartCorssCursor.IsShowCorss=option.CorssCursorInfo.IsShowCorss; if (option.CorssCursorInfo.IsShowClose == true) chart.ChartCorssCursor.IsShowClose = option.CorssCursorInfo.IsShowClose; //Y轴显示收盘价 if (option.CorssCursorInfo.PressTime) chart.PressTime=option.CorssCursorInfo.PressTime; //长按显示十字光标的时间 } if (option.SplashTitle) chart.ChartSplashPaint.SplashTitle=option.SplashTitle; if (option.Frame) { for(var i in option.Frame) { var item=option.Frame[i]; if (!chart.Frame.SubFrame[i]) continue; if (item.SplitCount) chart.Frame.SubFrame[i].Frame.YSplitOperator.SplitCount=item.SplitCount; if (item.StringFormat) chart.Frame.SubFrame[i].Frame.YSplitOperator.StringFormat=item.StringFormat; if (IFrameSplitOperator.IsNumber(item.FloatPrecision)) chart.Frame.SubFrame[i].Frame.YSplitOperator.FloatPrecision=item.FloatPrecision; if (item.Custom) chart.Frame.SubFrame[i].Frame.YSplitOperator.Custom=item.Custom; if (!isNaN(item.Height)) chart.Frame.SubFrame[i].Height = item.Height; if (item.IsShowLeftText===false || item.IsShowLeftText===true) { chart.Frame.SubFrame[i].Frame.IsShowYText[0]=item.IsShowLeftText; chart.Frame.SubFrame[i].Frame.YSplitOperator.IsShowLeftText=item.IsShowLeftText; //显示左边刻度 } if (item.IsShowRightText===false || item.IsShowRightText===true) { chart.Frame.SubFrame[i].Frame.IsShowYText[1]=item.IsShowRightText; chart.Frame.SubFrame[i].Frame.YSplitOperator.IsShowRightText=item.IsShowRightText; //显示右边刻度 } if (item.TopSpace>=0) chart.Frame.SubFrame[i].Frame.ChartBorder.TopSpace=item.TopSpace; if (item.BottomSpace>=0) chart.Frame.SubFrame[i].Frame.ChartBorder.BottomSpace=item.BottomSpace; } } if (option.KLine) { if (option.KLine.ShowKLine == false) chart.ChartPaint[0].IsShow = false; if (option.KLine.InfoPosition>0) chart.ChartPaint[0].InfoPosition=option.KLine.InfoPosition; } if(option.KLineTitle) { if(option.KLineTitle.IsShowName==false) chart.TitlePaint[0].IsShowName=false; if(option.KLineTitle.IsShowSettingInfo==false) chart.TitlePaint[0].IsShowSettingInfo=false; if(option.KLineTitle.IsShow == false) chart.TitlePaint[0].IsShow = false; } //叠加股票 if (option.Overlay) { for(var i in option.Overlay) { var item=option.Overlay[i]; chart.OverlaySymbol(item.Symbol,item); } } if (option.ExtendChart) { for(var i in option.ExtendChart) { var item=option.ExtendChart[i]; chart.CreateExtendChart(item.Name, item); } } //创建子窗口的指标 let scriptData = new JSIndexScript(); if (option.ColorIndex) //五彩K线 { var item=option.ColorIndex; let indexInfo=scriptData.Get(item.Index); if (indexInfo) { indexInfo.ID=item.Index; chart.ColorIndex=new ScriptIndex(indexInfo.Name, indexInfo.Script, indexInfo.Args,indexInfo); //脚本执行 } } if (option.TradeIndex) //交易指标 { var item=option.TradeIndex; let indexInfo=scriptData.Get(item.Index); if (indexInfo) { indexInfo.ID=item.Index; chart.TradeIndex=new ScriptIndex(indexInfo.Name, indexInfo.Script, indexInfo.Args,indexInfo); //脚本执行 } } for(var i in option.Windows) { var item=option.Windows[i]; if (item.Script) { chart.WindowIndex[i]=new ScriptIndex(item.Name,item.Script,item.Args,item); //脚本执行 } else if (item.JsonData) { chart.WindowIndex[i]=new JsonDataIndex(item.Name,item.Script,item.Args,item); //脚本执行 } else if (item.Local && item.Local.Data) { chart.WindowIndex[i]=new LocalJsonDataIndex(item.Local.Name,item.Local.Args,{JsonData:item.Local.Data}); } else if (item.API) //使用API挂接指标数据 API:{ Name:指标名字, Script:指标脚本可以为空, Args:参数可以为空, Url:指标执行地址 } { var apiItem=item.API; chart.WindowIndex[i]=new APIScriptIndex(apiItem.Name,apiItem.Script,apiItem.Args,item); } else { let indexItem=JSIndexMap.Get(item.Index); if (indexItem) { chart.WindowIndex[i]=indexItem.Create(); chart.CreateWindowIndex(i); } else { let indexInfo = scriptData.Get(item.Index); if (!indexInfo) continue; if (item.Lock) indexInfo.Lock=item.Lock; indexInfo.ID=item.Index; var args=indexInfo.Args; if (item.Args) args=item.Args; chart.WindowIndex[i] = new ScriptIndex(indexInfo.Name, indexInfo.Script, args,indexInfo); //脚本执行 if (item.StringFormat>0) chart.WindowIndex[i].StringFormat=item.StringFormat; if (item.FloatPrecision>=0) chart.WindowIndex[i].FloatPrecision=item.FloatPrecision; } } if (item.Modify!=null) chart.Frame.SubFrame[i].Frame.ModifyIndex=item.Modify; if (item.Change!=null) chart.Frame.SubFrame[i].Frame.ChangeIndex=item.Change; if (item.Close!=null) chart.Frame.SubFrame[i].Frame.CloseIndex=item.Close; if (item.Overlay!=null) chart.Frame.SubFrame[i].Frame.OverlayIndex=item.Overlay; if (!isNaN(item.TitleHeight)) chart.Frame.SubFrame[i].Frame.ChartBorder.TitleHeight=item.TitleHeight; } //叠加指标宽度 if (option.OverlayIndexFrameWidth>40) chart.OverlayIndexFrameWidth=option.OverlayIndexFrameWidth; //叠加指标 for (var i in option.OverlayIndex) { var item=option.OverlayIndex[i]; if (item.Windows>=chart.Frame.SubFrame.length) continue; chart.CreateOverlayWindowsIndex( { WindowIndex:item.Windows,IndexName: item.Index, ShowRightText:item.ShowRightText } ); } this.AdjustTitleHeight(chart); return chart; } //自定义指数历史K线图 this.CreateCustomKLineChartContainer=function(option) { var chart=new CustomKLineChartContainer(this.CanvasElement); //创建改参数div chart.ModifyIndexDialog=this.ModifyIndexDialog; chart.ChangeIndexDialog=this.ChangeIndexDialog; chart.MinuteDialog=this.MinuteDialog; //右键菜单 if (option.IsShowRightMenu==true) chart.RightMenu=new KLineRightMenu(this.DivElement); if (option.KLine) //k线图的属性设置 { if (option.KLine.DragMode>=0) chart.DragMode=option.KLine.DragMode; if (option.KLine.Right>=0) chart.Right=option.KLine.Right; if (option.KLine.Period>=0) chart.Period=option.KLine.Period; if (option.KLine.MaxReqeustDataCount>0) chart.MaxReqeustDataCount=option.KLine.MaxReqeustDataCount; if (option.KLine.Info && option.KLine.Info.length>0) chart.SetKLineInfo(option.KLine.Info,false); if (option.KLine.IndexTreeApiUrl) chart.ChangeIndexDialog.IndexTreeApiUrl=option.KLine.IndexTreeApiUrl; if (option.KLine.KLineDoubleClick==false) chart.MinuteDialog=this.MinuteDialog=null; if (option.KLine.IndexTreeApiUrl!=null) chart.ChangeIndexDialog.IndexTreeApiUrl=option.KLine.IndexTreeApiUrl; if (option.KLine.PageSize>0) chart.PageSize=option.KLine.PageSize; if (option.KLine.IsShowTooltip==false) chart.IsShowTooltip=false; } if (option.CustomStock) chart.CustomStock=option.CustomStock; if (option.QueryDate) chart.QueryDate=option.QueryDate; if (!option.Windows || option.Windows.length<=0) return null; //创建子窗口 chart.Create(option.Windows.length); if (option.Border) { if (!isNaN(option.Border.Left)) chart.Frame.ChartBorder.Left=option.Border.Left; if (!isNaN(option.Border.Right)) chart.Frame.ChartBorder.Right=option.Border.Right; if (!isNaN(option.Border.Top)) chart.Frame.ChartBorder.Top=option.Border.Top; } if (option.IsShowCorssCursorInfo==false) //取消显示十字光标刻度信息 { chart.ChartCorssCursor.IsShowText=option.IsShowCorssCursorInfo; } if (option.Frame) { for(var i in option.Frame) { var item=option.Frame[i]; if (item.SplitCount) chart.Frame.SubFrame[i].Frame.YSplitOperator.SplitCount=item.SplitCount; if (item.StringFormat) chart.Frame.SubFrame[i].Frame.YSplitOperator.StringFormat=item.StringFormat; } } if(option.KLineTitle) { if(option.KLineTitle.IsShowName==false) chart.TitlePaint[0].IsShowName=false; if(option.KLineTitle.IsShowSettingInfo==false) chart.TitlePaint[0].IsShowSettingInfo=false; } //创建子窗口的指标 let scriptData = new JSIndexScript(); for(var i in option.Windows) { var item=option.Windows[i]; if (item.Script) { chart.WindowIndex[i]=new ScriptIndex(item.Name,item.Script,item.Args,item); //脚本执行 } else { let indexItem=JSIndexMap.Get(item.Index); if (indexItem) { chart.WindowIndex[i]=indexItem.Create(); chart.CreateWindowIndex(i); } else { let indexInfo = scriptData.Get(item.Index); if (!indexInfo) continue; if (item.Lock) indexInfo.Lock=item.Lock; chart.WindowIndex[i] = new ScriptIndex(indexInfo.Name, indexInfo.Script, indexInfo.Args,indexInfo); //脚本执行 } } if (item.Modify!=null) chart.Frame.SubFrame[i].Frame.ModifyIndex=item.Modify; if (item.Change!=null) chart.Frame.SubFrame[i].Frame.ChangeIndex=item.Change; if (!isNaN(item.TitleHeight)) chart.Frame.SubFrame[i].Frame.ChartBorder.TitleHeight=item.TitleHeight; } return chart; } //分钟走势图 this.CreateMinuteChartContainer=function(option) { var chart=null; if (option.Type==="分钟走势图横屏") chart=new MinuteChartHScreenContainer(this.CanvasElement); else chart=new MinuteChartContainer(this.CanvasElement); if (option.NetworkFilter) chart.NetworkFilter=option.NetworkFilter; var windowsCount=2; if (option.Windows && option.Windows.length>0) windowsCount+=option.Windows.length; //指标窗口从第3个窗口开始 if (option.EnableScrollUpDown==true) chart.EnableScrollUpDown=option.EnableScrollUpDown; if (option.Language) { if (option.Language==='CN') chart.LanguageID=JSCHART_LANGUAGE_ID.LANGUAGE_CHINESE_ID; else if(option.Language==='EN') chart.LanguageID=JSCHART_LANGUAGE_ID.LANGUAGE_ENGLISH_ID; } if (option.Info && option.Info.length>0) chart.SetMinuteInfo(option.Info,false); chart.Create(windowsCount); //创建子窗口 if (option.CorssCursorInfo) { if (!isNaN(option.CorssCursorInfo.Left)) chart.ChartCorssCursor.ShowTextMode.Left=option.CorssCursorInfo.Left; if (!isNaN(option.CorssCursorInfo.Right)) chart.ChartCorssCursor.ShowTextMode.Right=option.CorssCursorInfo.Right; if (!isNaN(option.CorssCursorInfo.Bottom)) chart.ChartCorssCursor.ShowTextMode.Bottom=option.CorssCursorInfo.Bottom; if (option.CorssCursorInfo.IsShowCorss===false) chart.ChartCorssCursor.IsShowCorss=option.CorssCursorInfo.IsShowCorss; } if (option.MinuteInfo) chart.CreateMinuteInfo(option.MinuteInfo); if (option.IsShowRightMenu==true) chart.RightMenu=new MinuteRightMenu(this.DivElement); if (option.DayCount>1) chart.DayCount=option.DayCount; if (option.Border) { if (!isNaN(option.Border.Left)) chart.Frame.ChartBorder.Left=option.Border.Left; if (!isNaN(option.Border.Right)) chart.Frame.ChartBorder.Right=option.Border.Right; if (!isNaN(option.Border.Top)) chart.Frame.ChartBorder.Top=option.Border.Top; if (!isNaN(option.Border.Bottom)) chart.Frame.ChartBorder.Bottom=option.Border.Bottom; } if (option.SplashTitle) chart.ChartSplashPaint.SplashTitle=option.SplashTitle; this.AdjustChartBorder(chart); if (option.Frame) { for(var i in option.Frame) { var item=option.Frame[i]; if (!chart.Frame.SubFrame[i]) continue; if (item.SplitCount) chart.Frame.SubFrame[i].Frame.YSplitOperator.SplitCount=item.SplitCount; if (item.StringFormat) chart.Frame.SubFrame[i].Frame.YSplitOperator.StringFormat=item.StringFormat; if (item.IsShowLeftText==false) chart.Frame.SubFrame[i].Frame.YSplitOperator.IsShowLeftText=item.IsShowLeftText; //显示左边刻度 if (item.IsShowRightText==false) chart.Frame.SubFrame[i].Frame.YSplitOperator.IsShowRightText=item.IsShowRightText; //显示右边刻度 if (item.Height>0) chart.Frame.SubFrame[i].Height = item.Height; } } if (option.ExtendChart) { for(var i in option.ExtendChart) { var item=option.ExtendChart[i]; chart.CreateExtendChart(item.Name, item); } } //叠加股票 if (option.Overlay) { for(var i in option.Overlay) { var item=option.Overlay[i]; chart.OverlaySymbol(item.Symbol); } } if (option.MinuteLine) { if (option.MinuteLine.IsDrawAreaPrice==false) chart.ChartPaint[0].IsDrawArea=false; if (option.MinuteLine.IsShowLead==false) chart.IsShowLead=false; if (option.MinuteLine.IsShowAveragePrice==false) chart.ChartPaint[1].IsShow=false; if (option.MinuteLine.SplitType===1) chart.Frame.SubFrame[0].Frame.YSplitOperator.SplitType=option.MinuteLine.SplitType; } if(option.MinuteTitle) { if(option.MinuteTitle.IsShowName==false) chart.TitlePaint[0].IsShowName=false; if(option.MinuteTitle.IsShowDate===false || option.MinuteTitle.IsShowDate===true) chart.TitlePaint[0].IsShowDate=option.MinuteTitle.IsShowDate; //if(option.KLineTitle.IsShow == false) chart.TitlePaint[0].IsShow = false; } if (option.CorssCursorTouchEnd===true) chart.CorssCursorTouchEnd = option.CorssCursorTouchEnd; if (option.IsShowBeforeData===true) chart.IsShowBeforeData=option.IsShowBeforeData; //分钟数据指标从第3个指标窗口设置 let scriptData = new JSIndexScript(); for(var i in option.Windows) { var item=option.Windows[i]; if (item.Script) { chart.WindowIndex[2+parseInt(i)]=new ScriptIndex(item.Name,item.Script,item.Args); //脚本执行 } else if (item.API) //使用API挂接指标数据 API:{ Name:指标名字, Script:指标脚本可以为空, Args:参数可以为空, Url:指标执行地址 } { var apiItem=item.API; chart.WindowIndex[2+parseInt(i)]=new APIScriptIndex(apiItem.Name,apiItem.Script,apiItem.Args,item); } else { var indexItem=JSIndexMap.Get(item.Index); if (indexItem) { chart.WindowIndex[2+parseInt(i)]=indexItem.Create(); //创建子窗口的指标 chart.CreateWindowIndex(2+parseInt(i)); } else { let indexInfo = scriptData.Get(item.Index); if (!indexInfo) continue; indexInfo.ID=item.Index; var args=indexInfo.Args; if (item.Args) args=item.Args; chart.WindowIndex[2+parseInt(i)] = new ScriptIndex(indexInfo.Name, indexInfo.Script, args,indexInfo); //脚本执行 if (item.StringFormat>0) chart.WindowIndex[2+parseInt(i)].StringFormat=item.StringFormat; if (item.FloatPrecision>=0) chart.WindowIndex[2+parseInt(i)].FloatPrecision=item.FloatPrecision; } } if (!isNaN(item.TitleHeight)) chart.Frame.SubFrame[2+parseInt(i)].Frame.ChartBorder.TitleHeight=item.TitleHeight; } this.AdjustTitleHeight(chart); if (option.Function) { var func=option.Function; if (func.RequestMinuteData) chart.RequestMinuteData=func.RequestMinuteData; if (func.RecvMinuteData) chart.RecvMinuteData=func.RecvMinuteData; } return chart; } //历史分钟走势图 this.CreateHistoryMinuteChartContainer=function(option) { var chart=new HistoryMinuteChartContainer(this.CanvasElement); var windowsCount=2; if (option.Windows && option.Windows.length>0) windowsCount+=option.Windows.length; //指标窗口从第3个窗口开始 chart.Create(windowsCount); //创建子窗口 if (option.IsShowCorssCursorInfo==false) //取消显示十字光标刻度信息 { chart.ChartCorssCursor.IsShowText=option.IsShowCorssCursorInfo; } if (option.Border) { if (!isNaN(option.Border.Left)) chart.Frame.ChartBorder.Left=option.Border.Left; if (!isNaN(option.Border.Right)) chart.Frame.ChartBorder.Right=option.Border.Right; if (!isNaN(option.Border.Top)) chart.Frame.ChartBorder.Top=option.Border.Top; if (!isNaN(option.Border.Bottom)) chart.Frame.ChartBorder.Bottom=option.Border.Bottom; } let scriptData = new JSIndexScript(); for(var i in option.Windows) { var item=option.Windows[i]; if (item.Script) { chart.WindowIndex[2+parseInt(i)]=new ScriptIndex(item.Name,item.Script,item.Args); //脚本执行 } else { var indexItem=JSIndexMap.Get(item.Index); if (indexItem) { chart.WindowIndex[2+parseInt(i)]=indexItem.Create(); //创建子窗口的指标 chart.CreateWindowIndex(2+parseInt(i)); } else { let indexInfo = scriptData.Get(item.Index); if (!indexInfo) continue; chart.WindowIndex[2+parseInt(i)] = new ScriptIndex(indexInfo.Name, indexInfo.Script, indexInfo.Args); //脚本执行 } } if (!isNaN(item.TitleHeight)) chart.Frame.SubFrame[2+parseInt(i)].Frame.ChartBorder.TitleHeight=item.TitleHeight; } chart.TradeDate=20181009; if (option.HistoryMinute.TradeDate) chart.TradeDate=option.HistoryMinute.TradeDate; if (option.HistoryMinute.IsShowName!=null) chart.TitlePaint[0].IsShowName=option.HistoryMinute.IsShowName; //动态标题是否显示股票名称 if (option.HistoryMinute.IsShowDate!=null) chart.TitlePaint[0].IsShowDate=option.HistoryMinute.IsShowDate; //动态标题是否显示日期 return chart; } this.CreateKLineTrainChartContainer=function(option) { var bHScreen=(option.Type=='K线训练横屏'? true:false); var chart=new KLineTrainChartContainer(this.CanvasElement,bHScreen); if (option.NetworkFilter) chart.NetworkFilter=option.NetworkFilter; //创建改参数div chart.ModifyIndexDialog=this.ModifyIndexDialog; chart.ChangeIndexDialog=this.ChangeIndexDialog; if (option.ScriptError) chart.ScriptErrorCallback=option.ScriptError; if (option.KLine) //k线图的属性设置 { if (option.KLine.Right>=0) chart.Right=option.KLine.Right; if (option.KLine.Period>=0) chart.Period=option.KLine.Period; if (option.KLine.MaxReqeustDataCount>0) chart.MaxReqeustDataCount=option.KLine.MaxReqeustDataCount; if (option.KLine.Info && option.KLine.Info.length>0) chart.SetKLineInfo(option.KLine.Info,false); if (option.KLine.PageSize>0) chart.PageSize=option.KLine.PageSize; if (option.KLine.IsShowTooltip==false) chart.IsShowTooltip=false; if (option.KLine.MaxRequestMinuteDayCount>0) chart.MaxRequestMinuteDayCount=option.KLine.MaxRequestMinuteDayCount; if (option.KLine.DrawType) chart.KLineDrawType=option.KLine.DrawType; } if (option.Train) { if (option.Train.DataCount) chart.TrainDataCount=option.Train.DataCount; if (option.Train.Callback) chart.TrainCallback=option.Train.Callback; } if (!option.Windows || option.Windows.length<=0) return null; //创建子窗口 chart.Create(option.Windows.length); if (option.Border) { if (!isNaN(option.Border.Left)) chart.Frame.ChartBorder.Left=option.Border.Left; if (!isNaN(option.Border.Right)) chart.Frame.ChartBorder.Right=option.Border.Right; if (!isNaN(option.Border.Top)) chart.Frame.ChartBorder.Top=option.Border.Top; if (!isNaN(option.Border.Bottom)) chart.Frame.ChartBorder.Bottom=option.Border.Bottom; } this.AdjustChartBorder(chart); if (option.IsShowCorssCursorInfo==false) chart.ChartCorssCursor.IsShowText=option.IsShowCorssCursorInfo; //取消显示十字光标刻度信息 if (option.IsCorssOnlyDrawKLine===true) chart.ChartCorssCursor.IsOnlyDrawKLine=option.IsCorssOnlyDrawKLine; if (option.CorssCursorTouchEnd===true) chart.CorssCursorTouchEnd = option.CorssCursorTouchEnd; if (option.IsClickShowCorssCursor==true) chart.IsClickShowCorssCursor=option.IsClickShowCorssCursor; if (option.Frame) { for(var i in option.Frame) { var item=option.Frame[i]; if (!chart.Frame.SubFrame[i]) continue; if (item.SplitCount) chart.Frame.SubFrame[i].Frame.YSplitOperator.SplitCount=item.SplitCount; if (item.StringFormat) chart.Frame.SubFrame[i].Frame.YSplitOperator.StringFormat=item.StringFormat; if (item.IsShowLeftText==false) chart.Frame.SubFrame[i].Frame.YSplitOperator.IsShowLeftText=item.IsShowLeftText; //显示左边刻度 if (item.IsShowRightText==false) chart.Frame.SubFrame[i].Frame.YSplitOperator.IsShowRightText=item.IsShowRightText; //显示右边刻度 } } if (option.ExtendChart) { for(var i in option.ExtendChart) { var item=option.ExtendChart[i]; chart.CreateExtendChart(item.Name, item); } } //股票名称 日期 周期都不显示 chart.TitlePaint[0].IsShowName=false; chart.TitlePaint[0].IsShowSettingInfo=false; chart.TitlePaint[0].IsShowDateTime=false; //创建子窗口的指标 let scriptData = new JSIndexScript(); for(var i in option.Windows) { var item=option.Windows[i]; if (item.Script) { chart.WindowIndex[i]=new ScriptIndex(item.Name,item.Script,item.Args,item); //脚本执行 } else { let indexItem=JSIndexMap.Get(item.Index); if (indexItem) { chart.WindowIndex[i]=indexItem.Create(); chart.CreateWindowIndex(i); } else { let indexInfo = scriptData.Get(item.Index); if (!indexInfo) continue; if (item.Lock) indexInfo.Lock=item.Lock; chart.WindowIndex[i] = new ScriptIndex(indexInfo.Name, indexInfo.Script, indexInfo.Args,indexInfo); //脚本执行 } } if (item.Modify!=null) chart.Frame.SubFrame[i].Frame.ModifyIndex=item.Modify; if (item.Change!=null) chart.Frame.SubFrame[i].Frame.ChangeIndex=item.Change; if (item.Close!=null) chart.Frame.SubFrame[i].Frame.CloseIndex=item.Close; if (!isNaN(item.TitleHeight)) chart.Frame.SubFrame[i].Frame.ChartBorder.TitleHeight=item.TitleHeight; } this.AdjustTitleHeight(chart); return chart; } //根据option内容绘制图形 this.SetOption=function(option) { var chart=null; switch(option.Type) { case "历史K线图": case '历史K线图横屏': chart=this.CreateKLineChartContainer(option); break; case "自定义指数历史K线图": chart=this.CreateCustomKLineChartContainer(option); break; case "分钟走势图": case "分钟走势图横屏": chart=this.CreateMinuteChartContainer(option); break; case "历史分钟走势图": chart=this.CreateHistoryMinuteChartContainer(option); break; case 'K线训练': case 'K线训练横屏': chart=this.CreateKLineTrainChartContainer(option); break; case "简单图形": return this.CreateSimpleChart(option); case "饼图": case '雷达图': return this.CreatePieChart(option); case '地图': return this.CreateMapChart(option); default: return false; } if (!chart) return false; //是否自动更新 if (option.IsAutoUpdate!=null) chart.IsAutoUpdate=option.IsAutoUpdate; if (option.AutoUpdateFrequency>0) chart.AutoUpdateFrequency=option.AutoUpdateFrequency; //设置股票代码 if (!option.Symbol) return false; chart.Draw(); chart.ChangeSymbol(option.Symbol); this.JSChartContainer=chart; this.DivElement.JSChart=this; //div中保存一份 this.JSChartContainer.Draw(); } this.CreateSimpleChart=function(option) { var chart=new SimlpleChartContainer(this.CanvasElement); if (option.MainDataControl) chart.MainDataControl=option.MainDataControl; chart.Create(); if (option.Border) //边框设置 { if (!isNaN(option.Border.Left)) chart.Frame.ChartBorder.Left=option.Border.Left; if (!isNaN(option.Border.Right)) chart.Frame.ChartBorder.Right=option.Border.Right; if (!isNaN(option.Border.Top)) chart.Frame.ChartBorder.Top=option.Border.Top; } chart.Draw(); chart.RequestData(); this.JSChartContainer=chart; this.DivElement.JSChart=this; //div中保存一份 this.JSChartContainer.Draw(); } //创建饼图 this.CreatePieChart=function(option) { var chart=new PieChartContainer(this.CanvasElement); if (option.MainDataControl) chart.MainDataControl=option.MainDataControl; if(option.Radius) chart.Radius = option.Radius; chart.Create(); if (option.Border) //边框设置 { if (!isNaN(option.Border.Left)) chart.Frame.ChartBorder.Left=option.Border.Left; if (!isNaN(option.Border.Right)) chart.Frame.ChartBorder.Right=option.Border.Right; if (!isNaN(option.Border.Top)) chart.Frame.ChartBorder.Top=option.Border.Top; } this.AdjustChartBorder(chart); if (option.Frame) { if (option.Frame[0].IsShowBorder == false) chart.Frame.IsShowBorder = option.Frame[0].IsShowBorder; } chart.Draw(); chart.RequestData(); this.JSChartContainer=chart; this.DivElement.JSChart=this; //div中保存一份 this.JSChartContainer.Draw(); } this.CreateMapChart=function(option) { var chart=new MapChartContainer(this.CanvasElement); if (option.MainDataControl) chart.MainDataControl=option.MainDataControl; chart.Create(); if (option.Border) //边框设置 { if (!isNaN(option.Border.Left)) chart.Frame.ChartBorder.Left=option.Border.Left; if (!isNaN(option.Border.Right)) chart.Frame.ChartBorder.Right=option.Border.Right; if (!isNaN(option.Border.Top)) chart.Frame.ChartBorder.Top=option.Border.Top; } chart.Draw(); chart.RequestData(); this.JSChartContainer=chart; this.DivElement.JSChart=this; //div中保存一份 this.JSChartContainer.Draw(); } //创建工具条 this.CreateToolbar=function(option) { } //创建设置div窗口 this.CreateSettingDiv=function(option) { } this.Focus=function() { if (this.CanvasElement) this.CanvasElement.focus(); } //切换股票代码接口 this.ChangeSymbol=function(symbol) { if (this.JSChartContainer) this.JSChartContainer.ChangeSymbol(symbol); } //K线切换指标 this.ChangeIndex=function(windowIndex,indexName,option) { if (this.JSChartContainer && typeof(this.JSChartContainer.ChangeIndex)=='function') this.JSChartContainer.ChangeIndex(windowIndex,indexName,option); } this.ChangeScriptIndex=function(windowIndex,indexData) { if (this.JSChartContainer && typeof(this.JSChartContainer.ChangeScriptIndex)=='function') this.JSChartContainer.ChangeScriptIndex(windowIndex,indexData); } this.ChangePyScriptIndex=function(windowIndex, indexData) //切换py指标 { if (this.JSChartContainer && typeof(this.JSChartContainer.ChangePyScriptIndex)=='function') this.JSChartContainer.ChangePyScriptIndex(windowIndex,indexData); } this.GetIndexInfo=function() { if (this.JSChartContainer && typeof(this.JSChartContainer.GetIndexInfo)=='function') return this.JSChartContainer.GetIndexInfo(); else return []; } this.ChangeInstructionIndex=function(indexName) { if (this.JSChartContainer && typeof(this.JSChartContainer.ChangeInstructionIndex)=='function') this.JSChartContainer.ChangeInstructionIndex(indexName); } this.ChangeInstructionScriptIndex=function(indexData) { if (this.JSChartContainer && typeof(this.JSChartContainer.ChangeInstructionIndex)=='function') this.JSChartContainer.ChangeInstructionScriptIndex(indexData); } this.CancelInstructionIndex=function() { if (this.JSChartContainer && typeof(this.JSChartContainer.CancelInstructionIndex)=='function') this.JSChartContainer.CancelInstructionIndex(); } //K线周期切换 this.ChangePeriod=function(period) { if (this.JSChartContainer && typeof(this.JSChartContainer.ChangePeriod)=='function') this.JSChartContainer.ChangePeriod(period); } //K线复权切换 this.ChangeRight=function(right) { if (this.JSChartContainer && typeof(this.JSChartContainer.ChangeRight)=='function') this.JSChartContainer.ChangeRight(right); } //叠加股票 this.OverlaySymbol=function(symbol,option) { if (this.JSChartContainer && typeof(this.JSChartContainer.OverlaySymbol)=='function') this.JSChartContainer.OverlaySymbol(symbol,option); } //删除一个叠加股票 this.DeleteOverlaySymbol=function(symbol) { if (this.JSChartContainer && typeof(this.JSChartContainer.DeleteOverlaySymbol)=='function') this.JSChartContainer.DeleteOverlaySymbol(symbol); } //设置当前屏的起始日期 { Date:起始日期(必填), PageSize:一屏显示的数据个数(可选)} this.SetFirstShowDate=function(obj) { if (this.JSChartContainer && typeof(this.JSChartContainer.SetFirstShowDate)=='function') this.JSChartContainer.SetFirstShowDate(obj); } //K线切换类型 0=实心K线 1=收盘价线 2=美国线 3=空心K线 this.ChangeKLineDrawType=function(drawType) { if (this.JSChartContainer && typeof(this.JSChartContainer.ChangeKLineDrawType)=='function') this.JSChartContainer.ChangeKLineDrawType(drawType); } //指标窗口个数 this.ChangeIndexWindowCount = function(count){ if(this.JSChartContainer && typeof(this.JSChartContainer.ChangeIndexWindowCount) == 'function'){ this.JSChartContainer.ChangeIndexWindowCount(count); } } //取消叠加 this.ClearOverlaySymbol = function(){ if(this.JSChartContainer && typeof(this.JSChartContainer.ClearOverlaySymbol) == 'function'){ this.JSChartContainer.ClearOverlaySymbol(); } } this.DeleteKLineInfo=function(infoName) { if(this.JSChartContainer && typeof(this.JSChartContainer.DeleteKLineInfo) == 'function') { this.JSChartContainer.DeleteKLineInfo(infoName); } } this.ClearKLineInfo=function() { if(this.JSChartContainer && typeof(this.JSChartContainer.ClearKLineInfo) == 'function') { this.JSChartContainer.ClearKLineInfo(); } } this.AddKLineInfo=function(infoName, bUpdate) { if(this.JSChartContainer && typeof(this.JSChartContainer.AddKLineInfo) == 'function') { this.JSChartContainer.AddKLineInfo(infoName,bUpdate); } } this.ChangMainDataControl=function(dataControl) { if (this.JSChartContainer && typeof(this.JSChartContainer.SetMainDataConotrl)=='function') this.JSChartContainer.SetMainDataConotrl(dataControl); } this.AddOverlayIndex=function(obj) //{WindowIndex:窗口ID, IndexName:指标ID, Identify:叠加指标ID(可选)} { if (this.JSChartContainer && typeof(this.JSChartContainer.AddOverlayIndex)=='function') this.JSChartContainer.AddOverlayIndex(obj); } this.DeleteOverlayWindowsIndex=function(identify) { if (this.JSChartContainer && typeof(this.JSChartContainer.DeleteOverlayWindowsIndex)=='function') this.JSChartContainer.DeleteOverlayWindowsIndex(identify); } this.StopAutoUpdate=function() { if (this.JSChartContainer && typeof(this.JSChartContainer.StopAutoUpdate)=='function') this.JSChartContainer.StopAutoUpdate(); } //设置强制横屏 this.ForceLandscape=function(bForceLandscape) { if (this.JSChartContainer) { console.log("[JSChart::ForceLandscape] bForceLandscape="+bForceLandscape); this.JSChartContainer.IsForceLandscape=bForceLandscape; } } //锁指标 this.LockIndex=function(lockData) { if(this.JSChartContainer && typeof(this.JSChartContainer.LockIndex)=='function') { console.log('[JSChart:LockIndex] lockData', lockData); this.JSChartContainer.LockIndex(lockData); } } //历史分钟数据 更改日期 this.ChangeTradeDate=function(tradeDate) { if(this.JSChartContainer && typeof(this.JSChartContainer.ChangeTradeDate)=='function') { console.log('[JSChart:ChangeTradeDate] date', tradeDate); this.JSChartContainer.ChangeTradeDate(tradeDate); } } //多日走势图 this.ChangeDayCount=function(count) { if(this.JSChartContainer && typeof(this.JSChartContainer.ChangeDayCount)=='function') { console.log('[JSChart:ChangeDayCount] count', count); this.JSChartContainer.ChangeDayCount(count); } } //返回弹幕数据类 this.StartAnimation=function(option) { if(this.JSChartContainer && typeof(this.JSChartContainer.StartAnimation)=='function') { console.log('[JSChart:StartAnimation] start.'); return this.JSChartContainer.StartAnimation(option); } } this.StopAnimation=function() { if(this.JSChartContainer && typeof(this.JSChartContainer.StopAnimation)=='function') { console.log('[JSChart:StopAnimation] start.'); return this.JSChartContainer.StopAnimation(); } } this.SaveToImage = function (format,colorGB) //format=保存的文件格式, colorGB=背景色 { if (this.JSChartContainer && typeof (this.JSChartContainer.SaveToImage) == 'function') return this.JSChartContainer.SaveToImage(format,colorGB); } this.SaveToImageUrl=function(obj, callback) { if (this.JSChartContainer && typeof (this.JSChartContainer.SaveToImageUrl) == 'function') return this.JSChartContainer.SaveToImageUrl(obj, callback); } //事件回调 this.AddEventCallback=function(obj) { if(this.JSChartContainer && typeof(this.JSChartContainer.AddEventCallback)=='function') { console.log('[JSChart:AddEventCallback] ', obj); this.JSChartContainer.AddEventCallback(obj); } } //设置语言 'EN', 'CN' this.SetLanguage=function(language) { if(this.JSChartContainer && typeof(this.JSChartContainer.SetLanguage)=='function') { console.log('[JSChart:SetLanguage] ', language); this.JSChartContainer.SetLanguage(language); } } //切换指标模板 this.ChangeIndexTemplate=function(option) { if(this.JSChartContainer && typeof(this.JSChartContainer.ChangeIndexTemplate)=='function') { console.log('[JSChart:ChangeIndexTemplate] ', option); this.JSChartContainer.ChangeIndexTemplate(option); } } } //初始化 JSChart.Init=function(divElement) { var jsChartControl=new JSChart(divElement); jsChartControl.OnSize(); return jsChartControl; } JSChart.SetDomain=function(domain,cacheDomain) { if (domain) g_JSChartResource.Domain=domain; if (cacheDomain) g_JSChartResource.CacheDomain=cacheDomain; } JSChart.SetPyIndexDomain=function(domain) //设置py指标计算api域名 { if (domain) g_JSChartResource.PyIndexDomain=domain; } //自定义风格 JSChart.SetStyle=function(option) { if (option) g_JSChartResource.SetStyle(option); } //value { EN:'', CH:'' } JSChart.SetTextResource=function(key,value) { g_JSChartLocalization.SetTextResource(key,value); } //获取本地化资源 JSChart.GetLocalization=function() { return g_JSChartLocalization; } //获取设备分辨率比 JSChart.GetDevicePixelRatio=function() { return GetDevicePixelRatio(); } JSChart.CreateGuid=function() { return Guid(); } JSChart.GetResource=function() //获取颜色配置 (设置配必须啊在JSChart.Init()之前) { return g_JSChartResource; } JSChart.GetMinuteTimeStringData=function() { return g_MinuteTimeStringData; } JSChart.GetMinuteCoordinateData=function() { return g_MinuteCoordinateData; } var JSCHART_EVENT_ID= { RECV_KLINE_MATCH:1, //接收到形态匹配 RECV_INDEX_DATA:2, //接收指标数据 RECV_HISTROY_DATA:3,//接收到历史数据 RECV_TRAIN_MOVE_STEP:4, //接收K线训练,移动一次K线 CHART_STATUS:5, //每次Draw() 以后会调用 BARRAGE_PLAY_END:6, //单个弹幕播放完成 RECV_OVERLAY_INDEX_DATA:7,//接收叠加指标数据 DBCLICK_KLINE:8, //双击K线图 RECV_START_AUTOUPDATE:9, //开始自动更新 RECV_STOP_AUTOUPDATE:10, //停止自动更新 ON_CONTEXT_MENU:11, //右键菜单事件 ON_TITLE_DRAW:12, //标题信息绘制事件 } var JSCHART_OPERATOR_ID= { OP_SCROLL_LEFT:1, OP_SCROLL_RIGHT:2, OP_ZOOM_OUT:3, //缩小 OP_ZOOM_IN:4, //放大 OP_GOTO_HOME:5, //第1页数据 } /* 图形控件 */ function JSChartContainer(uielement) { this.ClassName='JSChartContainer'; var _self = this; this.Frame; //框架画法 this.ChartPaint=new Array(); //图形画法 this.ChartPaintEx=[]; //图形扩展画法 this.ChartInfo=new Array(); //K线|走势图上信息地雷 this.ChartInfoPaint; //信息地理 this.ExtendChartPaint=new Array(); //扩展画法 this.TitlePaint=new Array(); //标题画法 this.OverlayChartPaint=new Array(); //叠加信息画法 this.ChartDrawPicture=new Array(); //画图工具 this.ChartDrawStorage; //画图工具保存 this.CurrentChartDrawPicture=null; //当前的画图工具 this.SelectChartDrawPicture=null; //当前选中的画图 this.ChartCorssCursor; //十字光标 this.IsClickShowCorssCursor=false; //手势点击显示十字光标 this.ChartSplashPaint=null; //等待提示 this.Canvas=uielement.getContext("2d"); //画布 this.UIElement=uielement; this.MouseDrag; this.DragMode=1; //拖拽模式 0 禁止拖拽 1 数据拖拽 2 区间选择 this.DragTimer; this.EnableScrollUpDown=false; //是否可以上下滚动图形((手机端才有)) this.CursorIndex=0; //十字光标X轴索引 this.LastPoint=new Point(); //鼠标位置 this.IsForceLandscape=false; //是否强制横屏 this.CorssCursorTouchEnd = false; //手离开屏幕自动隐藏十字光标 this.StepPixel=4; //移动一个数据需要的像素 this.ZoomStepPixel=5; //放大缩小手势需要的最小像素 this.EnableAnimation=false; //是否开启动画 //tooltip提示信息 this.Tooltip=document.createElement("div"); this.Tooltip.className='jschart-tooltip'; this.Tooltip.style.background=g_JSChartResource.TooltipBGColor; this.Tooltip.style.opacity=g_JSChartResource.TooltipAlpha; this.Tooltip.id=Guid(); uielement.parentNode.appendChild(this.Tooltip); this.IsShowTooltip=true; //是否显示K线tooltip //区间选择 this.SelectRect=document.createElement("div"); this.SelectRect.className="jschart-selectrect"; this.SelectRect.style.background=g_JSChartResource.SelectRectBGColor; //this.SelectRect.style.opacity=g_JSChartResource.SelectRectAlpha; this.SelectRect.id=Guid(); uielement.parentNode.appendChild(this.SelectRect); //区间选择右键菜单 this.SelectRectRightMenu; //坐标轴风格方法 double-更加数值型分割 price-更加股票价格分割 this.FrameSplitData=new Map(); this.FrameSplitData.set("double",new SplitData()); this.FrameSplitData.set("price",new PriceSplitData()); //事件回调 this.mapEvent=new Map(); //通知外部调用 key:JSCHART_EVENT_ID value:{Callback:回调,} this.IsOnTouch = false; //是否再操作数据 this.TouchDrawCount = 0; //手势绘制次数 this.DisableMouse=false; //禁止鼠标事件 this.LanguageID=JSCHART_LANGUAGE_ID.LANGUAGE_CHINESE_ID; this.PressTime=500; this.NetworkFilter; //网络请求回调 function(data, callback); //设置事件回调 //{event:事件id, callback:回调函数} this.AddEventCallback=function(object) { if (!object || !object.event || !object.callback) return; var data={Callback:object.callback, Source:object}; this.mapEvent.set(object.event,data); } this.RemoveEventCallback=function(eventid) { if (!this.mapEvent.has(eventid)) return; this.mapEvent.delete(eventid); } this.GetEventCallback=function(id) //获取事件回调 { if (!this.mapEvent.has(id)) return null; var item=this.mapEvent.get(id); return item; } //接收指标数据 this.GetIndexEvent=function() { return this.GetEventCallback(JSCHART_EVENT_ID.RECV_INDEX_DATA); } this.GetOverlayIndexEvent=function() { return this.GetEventCallback(JSCHART_EVENT_ID.RECV_OVERLAY_INDEX_DATA); } uielement.onmousemove=function(e) { //console.log('[uielement.onmousemove] e.clientX, e.clientY, left, top ',e.clientX, e.clientY, this.getBoundingClientRect().left,this.getBoundingClientRect().top); var pixelTatio = GetDevicePixelRatio(); //鼠标移动坐标是原始坐标 需要乘以放大倍速 var x = (e.clientX-this.getBoundingClientRect().left)*pixelTatio; var y = (e.clientY-this.getBoundingClientRect().top)*pixelTatio; //加载数据中,禁用鼠标事件 if (this.JSChartContainer.ChartSplashPaint && this.JSChartContainer.ChartSplashPaint.IsEnableSplash == true) return; if (this.JSChartContainer.DisableMouse==true) return; if(this.JSChartContainer) this.JSChartContainer.OnMouseMove(x,y,e); } uielement.oncontextmenu=function(e) { var x = e.clientX-this.getBoundingClientRect().left; var y = e.clientY-this.getBoundingClientRect().top; if(this.JSChartContainer && typeof(this.JSChartContainer.OnRightMenu)=='function') this.JSChartContainer.OnRightMenu(x,y,e); //右键菜单事件 return false; } uielement.onmousedown=function(e) { if(!this.JSChartContainer) return; if(this.JSChartContainer.DragMode==0) return; var pixelTatio = GetDevicePixelRatio(); this.JSChartContainer.IsOnTouch=true; if (this.JSChartContainer.TryClickLock) { //console.log('[uielement.onmousedown] left, top ',e.clientX, e.clientY, this.getBoundingClientRect().left,this.getBoundingClientRect().top); var x = (e.clientX-this.getBoundingClientRect().left)*pixelTatio; var y = (e.clientY-this.getBoundingClientRect().top)*pixelTatio; if (this.JSChartContainer.TryClickLock(x,y)) return; } this.JSChartContainer.HideSelectRect(); if (this.JSChartContainer.SelectRectRightMenu) this.JSChartContainer.SelectRectRightMenu.Hide(); if (this.JSChartContainer.ChartPictureMenu) this.JSChartContainer.ChartPictureMenu.Hide(); var drag= { "Click":{}, "LastMove":{} //最后移动的位置 }; drag.Click.X=e.clientX; drag.Click.Y=e.clientY; drag.LastMove.X=e.clientX; drag.LastMove.Y=e.clientY; this.JSChartContainer.MouseDrag=drag; document.JSChartContainer=this.JSChartContainer; this.JSChartContainer.SelectChartDrawPicture=null; if (this.JSChartContainer.CurrentChartDrawPicture) //画图工具模式 { var drawPicture=this.JSChartContainer.CurrentChartDrawPicture; if (drawPicture.Status==2) this.JSChartContainer.SetChartDrawPictureThirdPoint(drag.Click.X,drag.Click.Y); else { this.JSChartContainer.SetChartDrawPictureFirstPoint(drag.Click.X,drag.Click.Y); //只有1个点 直接完成 if (this.JSChartContainer.FinishChartDrawPicturePoint()) this.JSChartContainer.DrawDynamicInfo(); } } else //是否在画图工具上 { var drawPictrueData={}; var pixelTatio = GetDevicePixelRatio(); //鼠标移动坐标是原始坐标 需要乘以放大倍速 drawPictrueData.X=(e.clientX-this.getBoundingClientRect().left)*pixelTatio; drawPictrueData.Y=(e.clientY-this.getBoundingClientRect().top)*pixelTatio; if (this.JSChartContainer.GetChartDrawPictureByPoint(drawPictrueData)) { drawPictrueData.ChartDrawPicture.Status=20; drawPictrueData.ChartDrawPicture.ValueToPoint(); drawPictrueData.ChartDrawPicture.MovePointIndex=drawPictrueData.PointIndex; this.JSChartContainer.CurrentChartDrawPicture=drawPictrueData.ChartDrawPicture; this.JSChartContainer.SelectChartDrawPicture=drawPictrueData.ChartDrawPicture; this.JSChartContainer.OnSelectChartPicture(drawPictrueData.ChartDrawPicture); //选中画图工具事件 } } uielement.ondblclick=function(e) { var x = e.clientX-this.getBoundingClientRect().left; var y = e.clientY-this.getBoundingClientRect().top; if(this.JSChartContainer) this.JSChartContainer.OnDoubleClick(x,y,e); } document.onmousemove=function(e) { if(!this.JSChartContainer) return; //加载数据中,禁用鼠标事件 if (this.JSChartContainer.ChartSplashPaint && this.JSChartContainer.ChartSplashPaint.IsEnableSplash == true) return; var drag=this.JSChartContainer.MouseDrag; if (!drag) return; var moveSetp=Math.abs(drag.LastMove.X-e.clientX); if (this.JSChartContainer.CurrentChartDrawPicture) { var drawPicture=this.JSChartContainer.CurrentChartDrawPicture; if (drawPicture.Status==1 || drawPicture.Status==2) { if(Math.abs(drag.LastMove.X-e.clientX)<5 && Math.abs(drag.LastMove.Y-e.clientY)<5) return; if(this.JSChartContainer.SetChartDrawPictureSecondPoint(e.clientX,e.clientY)) { this.JSChartContainer.DrawDynamicInfo(); } } else if (drawPicture.Status==3) { if(this.JSChartContainer.SetChartDrawPictureThirdPoint(e.clientX,e.clientY)) { this.JSChartContainer.DrawDynamicInfo(); } } else if (drawPicture.Status==20) //画图工具移动 { if(Math.abs(drag.LastMove.X-e.clientX)<5 && Math.abs(drag.LastMove.Y-e.clientY)<5) return; if(this.JSChartContainer.MoveChartDrawPicture(e.clientX-drag.LastMove.X,e.clientY-drag.LastMove.Y)) { this.JSChartContainer.DrawDynamicInfo(); } } drag.LastMove.X=e.clientX; drag.LastMove.Y=e.clientY; } else if (this.JSChartContainer.DragMode==1) //数据左右拖拽 { if (moveSetp<5) return; var isLeft=true; if (drag.LastMove.X0 && moveSetp<=3 && this.JSChartContainer.EnableScrollUpDown==true) { clearTimeout(this.DragTimer); this.DragTimer=null; return; } if (moveSetp<5) { jsChart.PreventTouchEvent(e); return; } var isLeft=true; if (drag.LastMove.X0) //放大 { var cursorIndex={}; cursorIndex.Index=parseInt(Math.abs(this.JSChartContainer.CursorIndex-0.5).toFixed(0)); if (!this.JSChartContainer.Frame.ZoomUp(cursorIndex)) return; this.JSChartContainer.CursorIndex=cursorIndex.Index; this.JSChartContainer.UpdatePointByCursorIndex(); this.JSChartContainer.UpdataDataoffset(); this.JSChartContainer.UpdateFrameMaxMin(); this.JSChartContainer.Draw(); this.JSChartContainer.ShowTooltipByKeyDown(); } else //缩小 { var cursorIndex={}; cursorIndex.Index=parseInt(Math.abs(this.JSChartContainer.CursorIndex-0.5).toFixed(0)); if (!this.JSChartContainer.Frame.ZoomDown(cursorIndex)) return; this.JSChartContainer.CursorIndex=cursorIndex.Index; this.JSChartContainer.UpdataDataoffset(); this.JSChartContainer.UpdatePointByCursorIndex(); this.JSChartContainer.UpdateFrameMaxMin(); this.JSChartContainer.Draw(); this.JSChartContainer.ShowTooltipByKeyDown(); } phonePinch.Last={"X":touches[0].pageX,"Y":touches[0].pageY,"X2":touches[1].pageX,"Y2":touches[1].pageY}; } jsChart.PreventTouchEvent(e); }; uielement.ontouchend=function(e) { console.log('[KLineChartContainer::uielement.ontouchend]',e); this.JSChartContainer.IsOnTouch = false; this.JSChartContainer.OnTouchFinished(); this.JSChartContainer.TouchDrawCount=0; clearTimeout(this.DragTimer); } } this.Draw=function() { if (this.UIElement.width<=0 || this.UIElement.height<=0) return; this.Canvas.clearRect(0,0,this.UIElement.width,this.UIElement.height); var pixelTatio = GetDevicePixelRatio(); //获取设备的分辨率 this.Canvas.lineWidth=pixelTatio; //手机端需要根据分辨率比调整线段宽度 if (this.ChartSplashPaint && this.ChartSplashPaint.IsEnableSplash) { this.Frame.Draw(); this.ChartSplashPaint.Draw(); return; } //框架 this.Frame.Draw(); this.Frame.CalculateLock(); //框架内图形 for (var i in this.ChartPaint) { var item=this.ChartPaint[i]; if (item.IsDrawFirst) item.Draw(); } for(var i in this.ChartPaint) { var item=this.ChartPaint[i]; if (!item.IsDrawFirst) item.Draw(); } for(var i in this.ChartPaintEx) { var item=this.ChartPaintEx[i]; item.Draw(); } //叠加股票 for(var i in this.OverlayChartPaint) { var item=this.OverlayChartPaint[i]; item.Draw(); } if (this.Frame.DrawOveraly) this.Frame.DrawOveraly(); //画叠加指标 //固定扩展图形 for(var i in this.ExtendChartPaint) { var item=this.ExtendChartPaint[i]; if (!item.IsDynamic && item.IsAnimation==false) item.Draw(); } if (this.Frame.DrawInsideHorizontal) this.Frame.DrawInsideHorizontal(); if (this.Frame.DrawCustomHorizontal) this.Frame.DrawCustomHorizontal(); if (this.ChartInfoPaint) this.ChartInfoPaint.Draw(); this.Frame.DrawLock(); this.Frame.Snapshot(); for(var i in this.ExtendChartPaint) //动态扩展图形 { var item=this.ExtendChartPaint[i]; if (item.IsDynamic && item.DrawAfterTitle===false) item.Draw(); } if (this.LastPoint.X!=null || this.LastPoint.Y!=null) { if (this.ChartCorssCursor) { this.ChartCorssCursor.LastPoint=this.LastPoint; this.ChartCorssCursor.CursorIndex=this.CursorIndex; //移动端 拖拽数据的时候 不显示十字光标, 没有按屏的时候也不显示十字光标 if (!(this.CorssCursorTouchEnd===true && this.MouseDrag) && !(this.CorssCursorTouchEnd==true && this.IsOnTouch==false) ) this.ChartCorssCursor.Draw(); } } var eventTitleDraw=this.GetEventCallback(JSCHART_EVENT_ID.ON_TITLE_DRAW); for(var i in this.TitlePaint) { var item=this.TitlePaint[i]; if (!item.IsDynamic) continue; item.CursorIndex=this.CursorIndex; item.OnDrawEvent=eventTitleDraw; item.Draw(); } for(var i in this.ExtendChartPaint) //动态扩展图形 { var item=this.ExtendChartPaint[i]; if (item.IsDynamic && item.DrawAfterTitle===true && item.IsAnimation==false) item.Draw(); } if (this.EnableAnimation) { for(var i in this.ExtendChartPaint) //动画 { var item=this.ExtendChartPaint[i]; if (item.IsAnimation===true) item.Draw(); } } for(var i in this.ChartDrawPicture) { var item=this.ChartDrawPicture[i]; item.Draw(); } if (this.CurrentChartDrawPicture && this.CurrentChartDrawPicture.Status!=10) { this.CurrentChartDrawPicture.Draw(); } //发送图形状态给外部 if (this.mapEvent.has(JSCHART_EVENT_ID.CHART_STATUS)) { var event=this.mapEvent.get(JSCHART_EVENT_ID.CHART_STATUS); var data={ }; if (typeof(this.GetChartStatus)=='function') data=this.GetChartStatus(); event.Callback(event,data,this); } ++this.TouchDrawCount; } //画动态信息 this.DrawDynamicInfo=function() { if (this.Frame.ScreenImageData==null) return; var isErase=false; if (this.ChartCorssCursor) { if (this.ChartCorssCursor.PointX!=null || this.ChartCorssCursor.PointY!=null) isErase=true; } isErase=true; //每次都擦除背景 if (isErase==false) { for(var i in this.ExtendChartPaint) { var item=this.ExtendChartPaint[i]; if (item.IsDynamic && item.IsEraseBG) { isErase=true; break; } } } if (isErase) this.Canvas.putImageData(this.Frame.ScreenImageData,0,0); for(var i in this.ExtendChartPaint) //动态扩展图形 { var item=this.ExtendChartPaint[i]; if (item.IsDynamic && item.DrawAfterTitle===false && item.IsAnimation==false) item.Draw(); } if (this.ChartCorssCursor) { this.ChartCorssCursor.LastPoint=this.LastPoint; this.ChartCorssCursor.CursorIndex=this.CursorIndex; if ( !(this.IsOnTouch===false && this.CorssCursorTouchEnd===true)) this.ChartCorssCursor.Draw(); } for(var i in this.TitlePaint) { var item=this.TitlePaint[i]; if (!item.IsDynamic) continue; item.CursorIndex=this.CursorIndex; item.Draw(); } for(var i in this.ExtendChartPaint) //动态扩展图形 在动态标题以后画 { var item=this.ExtendChartPaint[i]; if (item.IsDynamic && item.DrawAfterTitle===true) item.Draw(); } if (this.EnableAnimation) { for(var i in this.ExtendChartPaint) //动画 { var item=this.ExtendChartPaint[i]; if (item.IsAnimation===true) item.Draw(); } } for(var i in this.ChartDrawPicture) { var item=this.ChartDrawPicture[i]; item.Draw(); } if (this.CurrentChartDrawPicture && this.CurrentChartDrawPicture.Status!=10) { this.CurrentChartDrawPicture.Draw(); } ++this.TouchDrawCount; } this.DrawAnimation=function() //绘制动画 如弹幕 { if (!this.EnableAnimation) return; if (this.Frame.ScreenImageData && !this.IsOnTouch) { for(var i in this.ExtendChartPaint) { var item=this.ExtendChartPaint[i]; if (item.IsAnimation===true) item.IsMoveStep=true; //移动弹幕 } this.DrawDynamicInfo(); } var self=this; window.requestAnimationFrame(function() { self.DrawAnimation(); }); } this.StartAnimation=function(option) { var bCreated=false; //是否已经创建了弹幕画法 var barrageData=null; for(var i in this.ExtendChartPaint) { var item=this.ExtendChartPaint[i]; if (item.ClassName==='BarragePaint') { bCreated=true; barrageData=item.BarrageList; break; } } if (!bCreated) { var chart=new BarragePaint(); chart.Canvas=this.Canvas; chart.ChartBorder=this.Frame.ChartBorder; chart.ChartFrame=this.Frame; chart.HQChart=this; chart.SetOption(option); this.ExtendChartPaint.push(chart); barrageData=chart.BarrageList; } this.EnableAnimation=true; var self=this; window.requestAnimationFrame(function() { self.DrawAnimation(); }); return barrageData; } this.StopAnimation=function() { this.EnableAnimation=false; this.DrawDynamicInfo(); } this.OnMouseMove=function(x,y,e) { this.LastPoint.X=x; this.LastPoint.Y=y; this.CursorIndex=this.Frame.GetXData(x); var bDrawPicture=false; //是否正在画图 if (this.CurrentChartDrawPicture) { if (this.CurrentChartDrawPicture.SetLastPoint) this.CurrentChartDrawPicture.SetLastPoint({X:x,Y:y}); bDrawPicture=true; } else { var drawPictrueData={}; drawPictrueData.X=x; drawPictrueData.Y=y; if (this.GetChartDrawPictureByPoint(drawPictrueData)) { if (drawPictrueData.PointIndex===100) this.UIElement.style.cursor="move"; else this.UIElement.style.cursor="pointer"; bDrawPicture=true; } else { if (!this.MouseDrag) this.UIElement.style.cursor="default"; } } this.DrawDynamicInfo(); if (this.IsShowTooltip && bDrawPicture==false) { var toolTip=new TooltipData(); for(var i in this.ChartPaint) { var item=this.ChartPaint[i]; if (item.GetTooltipData(x,y,toolTip)) { break; } } if (!toolTip.Data) { for(var i in this.OverlayChartPaint) { var item=this.OverlayChartPaint[i]; if (item.GetTooltipData(x,y,toolTip)) { break; } } } if (toolTip.Data) { var xTooltip = e.clientX-this.UIElement.getBoundingClientRect().left; var yTooltip = e.clientY-this.UIElement.getBoundingClientRect().top; this.ShowTooltip(xTooltip,yTooltip,toolTip); } else { this.HideTooltip(); } } } this.OnKeyDown=function(e) { var keyID = e.keyCode ? e.keyCode :e.which; switch(keyID) { case 37: //left if (this.CursorIndex<=0.99999) { if (!this.DataMoveLeft()) break; this.UpdataDataoffset(); this.UpdatePointByCursorIndex(); this.UpdateFrameMaxMin(); this.Draw(); this.ShowTooltipByKeyDown(); } else { --this.CursorIndex; this.UpdatePointByCursorIndex(); this.DrawDynamicInfo(); this.ShowTooltipByKeyDown(); } break; case 39: //right var xPointcount=0; if (this.Frame.XPointCount) xPointcount=this.Frame.XPointCount; else xPointcount=this.Frame.SubFrame[0].Frame.XPointCount; if (this.CursorIndex+1>=xPointcount) { if (!this.DataMoveRight()) break; this.UpdataDataoffset(); this.UpdatePointByCursorIndex(); this.UpdateFrameMaxMin(); this.Draw(); this.ShowTooltipByKeyDown(); } else { //判断是否在最后一个数据上 var data=null; if (this.Frame.Data) data=this.Frame.Data; else data=this.Frame.SubFrame[0].Frame.Data; if (!data) break; if (this.CursorIndex+data.DataOffset+1>=data.Data.length) break; ++this.CursorIndex; this.UpdatePointByCursorIndex(); this.DrawDynamicInfo(); this.ShowTooltipByKeyDown(); } break; case 38: //up var cursorIndex={}; cursorIndex.Index=parseInt(Math.abs(this.CursorIndex-0.5).toFixed(0)); if (!this.Frame.ZoomUp(cursorIndex)) break; this.CursorIndex=cursorIndex.Index; this.UpdatePointByCursorIndex(); this.UpdataDataoffset(); this.UpdateFrameMaxMin(); this.Draw(); this.ShowTooltipByKeyDown(); break; case 40: //down var cursorIndex={}; cursorIndex.Index=parseInt(Math.abs(this.CursorIndex-0.5).toFixed(0)); if (!this.Frame.ZoomDown(cursorIndex)) break; this.CursorIndex=cursorIndex.Index; this.UpdataDataoffset(); this.UpdatePointByCursorIndex(); this.UpdateFrameMaxMin(); this.Draw(); this.ShowTooltipByKeyDown(); break; case 46: //del if (!this.SelectChartDrawPicture) break; var drawPicture=this.SelectChartDrawPicture; console.log(drawPicture,"drawPicturedrawPicturedrawPicture") this.SelectChartDrawPicture=null; this.ClearChartDrawPicture(drawPicture); //删除选中的画图工具 break; default: return; } //不让滚动条滚动 if(e.preventDefault) e.preventDefault(); else e.returnValue = false; } this.OnDoubleClick=function(x,y,e) { //console.log(e); } this.UpdatePointByCursorIndex=function() { this.LastPoint.X=this.Frame.GetXFromIndex(this.CursorIndex); var index=Math.abs(this.CursorIndex-0.5); index=parseInt(index.toFixed(0)); if (this.ClassName=='KLineChartContainer') index=this.CursorIndex; var data=this.Frame.Data; if (data.DataOffset+index>=data.Data.length) { return; } var close=data.Data[data.DataOffset+index].Close; this.LastPoint.Y=this.Frame.GetYFromData(close); } this.ShowTooltipByKeyDown=function() { var index=Math.abs(this.CursorIndex-0.5); index=parseInt(index.toFixed(0)); if (this.ClassName=='KLineChartContainer') index=this.CursorIndex; var data=this.Frame.Data; var toolTip=new TooltipData(); toolTip.Data=data.Data[data.DataOffset+index]; toolTip.ChartPaint=this.ChartPaint[0]; var pixelTatio = GetDevicePixelRatio(); if (pixelTatio===0) pixelTatio=1; //div 缩放还是使用原始坐标 this.ShowTooltip(this.LastPoint.X/pixelTatio,this.LastPoint.Y/pixelTatio,toolTip); } this.ShowTooltip=function(x,y,toolTip) { if (!this.IsShowTooltip) return; var pixelTatio = GetDevicePixelRatio(); //获取设备的分辨率 var xMove=15/pixelTatio; //顶部坐标偏移位置 if (toolTip.Type===0) //K线信息 { var format=new HistoryDataStringFormat(); format.Value=toolTip; format.Symbol=this.Symbol; format.LanguageID=this.LanguageID; if (!format.Operator()) return; var textHeight=format.LineCount*25; //每行的行高25 var scrollPos=GetScrollPosition(); var left = x; var top = y; var width=157; if (this.LanguageID==JSCHART_LANGUAGE_ID.LANGUAGE_ENGLISH_ID) width=180; this.Tooltip.style.width = width+"px"; this.Tooltip.style.height =textHeight+"px"; //console.log(`[JSChartContainer::ShowTooltip] left=${left} top=${top} xMove=${xMove}` ); //if (toolTip.ChartPaint.Name=="Overlay-KLine") this.Tooltip.style.height =220+"px"; this.Tooltip.style.position = "absolute"; //console.log('[JSChartContainer::ShowTooltip] getBoundingClientRect() ',this.UIElement.getBoundingClientRect()) if (left+width>this.UIElement.getBoundingClientRect().width) this.Tooltip.style.left = (left-width) + "px"; else this.Tooltip.style.left = left + "px"; this.Tooltip.style.top = (top + xMove)+ "px"; this.Tooltip.className='jschart-tooltip'; this.Tooltip.innerHTML=format.Text; this.Tooltip.style.display = "block"; } else if (toolTip.Type===1) //信息地雷提示信息 { var scrollPos=GetScrollPosition(); var left = x; var top = y; var width=500; var format=new KLineInfoDataStringFormat(); format.Value=toolTip; format.Symbol=this.Symbol; if (!format.Operator()) return; this.Tooltip.className='jchart-klineinfo-tooltip'; this.Tooltip.style.position = "absolute"; if(left+width>this.UIElement.getBoundingClientRect().width){ this.Tooltip.style.left = (left-width) + "px"; }else{ this.Tooltip.style.left = left + "px"; } this.Tooltip.style.top = (top +xMove)+ "px"; this.Tooltip.style.width = width+"px"; this.Tooltip.style.height =null; this.Tooltip.innerHTML=format.Text; this.Tooltip.style.display = "block"; } } this.HideTooltip=function() { this.Tooltip.style.display = "none"; } this.ShowSelectRect=function(x,y,x2,y2) { var left = x; var top = y; var borderRight=this.Frame.ChartBorder.GetRight(); var borderLeft=this.Frame.ChartBorder.GetLeft(); if (x>borderRight) x=borderRight; if (x2>borderRight) x2=borderRight; if (xx2) left=x2; if (y>y2) top=y2; var width=Math.abs(x-x2); var height=Math.abs(y-y2); this.SelectRect.style.width = width+"px"; this.SelectRect.style.height =height+"px"; this.SelectRect.style.position = "absolute"; this.SelectRect.style.left = left +"px"; this.SelectRect.style.top = top +"px"; this.SelectRect.style.display = "block"; } this.UpdateSelectRect=function(start,end) { if (!this.ChartPaint[0].Data) return; var data=this.ChartPaint[0].Data; var offset=data.DataOffset; var fixedStart=start-offset; var fixedEnd=end-offset; var x=this.Frame.GetXFromIndex(fixedStart); var x2=this.Frame.GetXFromIndex(fixedEnd); console.log('[JSChartContainer::UpdateSelectRect]',start,end,x,x2); var scrollPos=GetScrollPosition(); this.SelectRect.style.left = x + scrollPos.Left+"px"; this.SelectRect.style.width = (x2-x)+"px"; } this.HideSelectRect=function() { this.SelectRect.style.display = "none"; } this.ResetFrameXYSplit=function() { if (typeof(this.Frame.ResetXYSplit)=='function') this.Frame.ResetXYSplit(); } this.UpdateFrameMaxMin=function() { var frameMaxMinData=new Array(); var chartPaint=new Array(); for(var i in this.ChartPaint) { var item=this.ChartPaint[i]; if (item.IsShow==false) continue; //隐藏的图形不计算 chartPaint.push(this.ChartPaint[i]); } for(var i in this.OverlayChartPaint) { chartPaint.push(this.OverlayChartPaint[i]); } for(var i in chartPaint) { var paint=chartPaint[i]; var range=paint.GetMaxMin(); if (range==null || range.Max==null || range.Min==null) continue; var frameItem=null; for(var j in frameMaxMinData) { if (frameMaxMinData[j].Frame==paint.ChartFrame) { frameItem=frameMaxMinData[j]; break; } } if (frameItem) { if (frameItem.Range.Maxrange.Min) frameItem.Range.Min=range.Min; } else { frameItem={}; frameItem.Frame=paint.ChartFrame; frameItem.Range=range; frameMaxMinData.push(frameItem); } } for(var i in frameMaxMinData) { var item=frameMaxMinData[i]; if (!item.Frame || !item.Range) continue; if (item.Range.Max==null || item.Range.Min==null) continue; if (item.Frame.YSpecificMaxMin) { item.Frame.HorizontalMax=item.Frame.YSpecificMaxMin.Max; item.Frame.HorizontalMin=item.Frame.YSpecificMaxMin.Min; } else { item.Frame.HorizontalMax=item.Range.Max; item.Frame.HorizontalMin=item.Range.Min; } item.Frame.XYSplit=true; } //更新子坐标 for(var i in this.Frame.SubFrame) { var subFrame=this.Frame.SubFrame[i]; for(var j in subFrame.OverlayIndex) { var overlayItem=subFrame.OverlayIndex[j]; overlayItem.UpdateFrameMaxMin(); } } } this.DataMoveLeft=function() { var data=null; if (!this.Frame.Data) data=this.Frame.Data; else data=this.Frame.SubFrame[0].Frame.Data; if (!data) return false; if (data.DataOffset<=0) return false; --data.DataOffset; return true; } this.DataMoveRight=function() { var data=null; if (!this.Frame.Data) data=this.Frame.Data; else data=this.Frame.SubFrame[0].Frame.Data; if (!data) return false; var xPointcount=0; if (this.Frame.XPointCount) xPointcount=this.Frame.XPointCount; else xPointcount=this.Frame.SubFrame[0].Frame.XPointCount; if (!xPointcount) return false; if (xPointcount+data.DataOffset>=data.Data.length) return false; ++data.DataOffset; return true; } this.UpdataDataoffset=function() { var data=null; if (this.Frame.Data) data=this.Frame.Data; else data=this.Frame.SubFrame[0].Frame.Data; if (!data) return; for(var i in this.ChartPaint) { var item =this.ChartPaint[i]; if (!item.Data) continue; item.Data.DataOffset=data.DataOffset; } for(var i in this.OverlayChartPaint) { var item =this.OverlayChartPaint[i]; if (!item.Data) continue; item.Data.DataOffset=data.DataOffset; } //叠加指标当前显示的数据偏移 for (var i in this.Frame.SubFrame) { var subFrame=this.Frame.SubFrame[i]; for(var j in subFrame.OverlayIndex) { var overlayItem=subFrame.OverlayIndex[j]; for(var k in overlayItem.ChartPaint) { var item=overlayItem.ChartPaint[k]; if (!item.Data) continue; item.Data.DataOffset=data.DataOffset; } } } } this.DataMove=function(step,isLeft) { step=parseInt(step/this.StepPixel); //除以4个像素 if (step<=0) return false; var data=null; if (!this.Frame.Data) data=this.Frame.Data; else data=this.Frame.SubFrame[0].Frame.Data; if (!data) return false; var xPointcount=0; if (this.Frame.XPointCount) xPointcount=this.Frame.XPointCount; else xPointcount=this.Frame.SubFrame[0].Frame.XPointCount; if (!xPointcount) return false; if (isLeft) //--> { if (xPointcount+data.DataOffset>=data.Data.length) return false; data.DataOffset+=step; if (data.DataOffset+xPointcount>=data.Data.length) data.DataOffset=data.Data.length-xPointcount; return true; } else //<-- { if (data.DataOffset<=0) return false; data.DataOffset-=step; if (data.DataOffset<0) data.DataOffset=0; return true; } } //获取鼠标在当前子窗口id this.GetSubFrameIndex=function(x,y) { if (!this.Frame.SubFrame || this.Frame.SubFrame.length<=0) return -1; for(var i in this.Frame.SubFrame) { var frame=this.Frame.SubFrame[i].Frame; var left=frame.ChartBorder.GetLeft(); var top=frame.ChartBorder.GetTop(); var height=frame.ChartBorder.GetHeight(); var width=frame.ChartBorder.GetWidth(); this.Canvas.beginPath(); this.Canvas.rect(left,top,width,height); if (this.Canvas.isPointInPath(x,y)) return parseInt(i); } return 0; } //根据X坐标获取数据索引 this.GetDataIndexByPoint=function(x) { var frame=this.Frame; if (this.Frame.SubFrame && this.Frame.SubFrame.length>0) frame=this.Frame.SubFrame[0].Frame; var data=null; if (this.Frame.Data) data=this.Frame.Data; else data=this.Frame.SubFrame[0].Frame.Data; if (!data || !frame) return; var index=parseInt(frame.GetXData(x)); //console.log('x='+ x +' date='+data.Data[data.DataOffset+index].Date); return data.DataOffset+index; } //获取主数据 this.GetSelectRectData=function(selectData) { if (Math.abs(selectData.XStart-selectData.XEnd)<5) return false; var data=null; if (this.Frame.Data) data=this.Frame.Data; else data=this.Frame.SubFrame[0].Frame.Data; if (!data) return false; var start=this.GetDataIndexByPoint(selectData.XStart); var end=this.GetDataIndexByPoint(selectData.XEnd); if (Math.abs(start-end)<2) return false; selectData.Data=data; if (start>end) { selectData.Start=end; selectData.End=start; } else { selectData.Start=start; selectData.End=end; } return true; } //获取当前的点对应的 画图工具的图形 //data.X data.Y 鼠标位置 返回 data.ChartDrawPicture 数据在画图工具 data.PointIndex 在画图工具对应点索引 this.GetChartDrawPictureByPoint=function(data) { for(var i in this.ChartDrawPicture) { var item =this.ChartDrawPicture[i]; var pointIndex=item.IsPointIn(data.X,data.Y); if (pointIndex===false) continue; if (pointIndex>=0) { data.ChartDrawPicture=item; data.PointIndex=pointIndex; return true; } } return false; } // 保存图片 this.SaveToImage = function (format,colorGB) { if (this.UIElement.width<=0 || this.UIElement.height<=0) return null; if (this.ChartSplashPaint && this.ChartSplashPaint.IsEnableSplash) return null; // 数据加载中不能保存 console.log('[JSChartContainer::SaveToImage]', this.UIElement); var clrBG='rgb(255,255,255)'; if (colorGB) clrBG=colorGB; this.Canvas.clearRect(0,0,this.UIElement.width,this.UIElement.height); this.Canvas.fillStyle=clrBG; this.Canvas.fillRect(0,0,this.UIElement.width,this.UIElement.height); //画一个背景色, 不然是一个黑的背景 var pixelTatio = GetDevicePixelRatio(); //获取设备的分辨率 this.Canvas.lineWidth=pixelTatio; //手机端需要根据分辨率比调整线段宽度 this.Frame.Draw(); //框架 for (var i in this.ChartPaint) //框架内图形 { var item=this.ChartPaint[i]; if (item.IsDrawFirst) item.Draw(); } for(var i in this.ChartPaint) { var item=this.ChartPaint[i]; if (!item.IsDrawFirst) item.Draw(); } for(var i in this.ChartPaintEx) { var item=this.ChartPaintEx[i]; item.Draw(); } for(var i in this.OverlayChartPaint) //叠加股票 { var item=this.OverlayChartPaint[i]; item.Draw(); } for(var i in this.ExtendChartPaint) //固定扩展图形 { var item=this.ExtendChartPaint[i]; if (!item.IsDynamic && item.IsAnimation==false) item.Draw(); } if (this.Frame.DrawInsideHorizontal) this.Frame.DrawInsideHorizontal(); this.Frame.DrawLock(); for(var i in this.ExtendChartPaint) //动态扩展图形 { var item=this.ExtendChartPaint[i]; if (item.IsDynamic && item.DrawAfterTitle===false) item.Draw(); } if (this.LastPoint.X!=null || this.LastPoint.Y!=null) { if (this.ChartCorssCursor) //十字光标不画 { this.ChartCorssCursor.LastPoint=this.LastPoint; this.ChartCorssCursor.CursorIndex=this.CursorIndex; } } for(var i in this.TitlePaint) { var item=this.TitlePaint[i]; if (!item.IsDynamic) continue; item.CursorIndex=this.CursorIndex; item.Draw(); } for(var i in this.ExtendChartPaint) //动态扩展图形 { var item=this.ExtendChartPaint[i]; if (item.IsDynamic && item.DrawAfterTitle===true && item.IsAnimation==false) item.Draw(); } if (this.EnableAnimation) { for(var i in this.ExtendChartPaint) //动画 { var item=this.ExtendChartPaint[i]; if (item.IsAnimation===true) item.Draw(); } } for(var i in this.ChartDrawPicture) { var item=this.ChartDrawPicture[i]; item.Draw(); } if (this.CurrentChartDrawPicture && this.CurrentChartDrawPicture.Status!=10) { this.CurrentChartDrawPicture.Draw(); } var dataURL=this.UIElement.toDataURL(format ? format:'image/png', 1.0); console.log('[JSChartContainer::SaveToImage] data= ', dataURL); return dataURL; } this.SaveToImageUrl=function(obj,callback) //obj:{Format: 图片格式, ColorGB: 背景色}, callback:function(bSuccess,obj) { if (!obj) obj={Format:'image/png', ColorGB:'rgb(255,255,255)'}; var imageData=this.SaveToImage(obj.Format, obj.ColorGB); var postData={"Base64":imageData, "BucketName":"downloadcache", "Path":"hqchart/hq_snapshot"}; var url=g_JSChartResource.Domain+'/API/FileUploadForBase64'; JSNetwork.HttpRequest({ url: url, method: "POST", dataType: "json", data: postData, success: function (data) { console.log('[JSChartContainer::SaveToImageUrl] recv data', data); var result={Path:data.relativeurl, Domain:'https://opensourcedownload.zealink.com'}; result.Url=`${result.Domain}/${result.Path}`; if (callback) callback(true,result,''); }, error: function (request) { console.log('[JSChartContainer::SaveToImageUrl] error ', request); if (callback) callback(false,null,'upload failed'); } }); } this.SetLanguage=function(language) { var languageID=null; switch(language) { case 'EN': languageID=JSCHART_LANGUAGE_ID.LANGUAGE_ENGLISH_ID; break; case 'CN': languageID=JSCHART_LANGUAGE_ID.LANGUAGE_CHINESE_ID; break; default: console.warn(`[JSChartContainer::SetLanguage] language=${language} error`); return; } if (this.LanguageID==languageID) return; this.LanguageID=languageID; if (this.ChartCorssCursor && this.ChartCorssCursor.StringFormatY) this.ChartCorssCursor.StringFormatY.LanguageID=this.LanguageID; for(var i in this.TitlePaint) { var item=this.TitlePaint[i]; if (item) item.LanguageID=this.LanguageID; } if (this.Frame && this.Frame.SetLanguage) this.Frame.SetLanguage(this.LanguageID); this.Frame.SetSizeChage(true); this.Draw(); } } function GetDevicePixelRatio() { if (typeof(window) =='undefined') return 1; return window.devicePixelRatio || 1; } function IsPhoneWeb() { var userAgentInfo=navigator.userAgent; const Agents =new Array("Android","iPhone","SymbianOS","Windows Phone","iPad","iPod"); for(var v=0;v0) return true; } return false; } function OnKeyDown(e) //键盘事件 { if(this.JSChartContainer && this.JSChartContainer.OnKeyDown) this.JSChartContainer.OnKeyDown(e); } function OnWheel(e) //上下滚动事件 { if(this.JSChartContainer && this.JSChartContainer.OnWheel) this.JSChartContainer.OnWheel(e); } function ToFixed(number, precision) { var b = 1; if (isNaN(number)) return number; if (number < 0) b = -1; var multiplier = Math.pow(10, precision); var value=Math.round(Math.abs(number) * multiplier) / multiplier * b; if (/^(\d+(?:\.\d+)?)(e)([\-]?\d+)$/.test(value)) var s=value.toFixed2(precision); else var s = value.toString(); var rs = s.indexOf('.'); if (rs < 0 && precision>0) { rs = s.length; s += '.'; } while (s.length <= rs + precision) { s += '0'; } return s; } Number.prototype.toFixed2=Number.prototype.toFixed; //备份下老的 Number.prototype.toFixed = function( precision ) { return ToFixed(this,precision); } function Guid() { function S4() { return (((1+Math.random())*0x10000)|0).toString(16).substring(1); } return (S4()+S4()+"-"+S4()+"-"+S4()+"-"+S4()+"-"+S4()+S4()+S4()); } function GetScrollPosition() { var scrollPos={}; var scrollTop=0; var scrollLeft=0; if(document.documentElement && document.documentElement.scrollTop) { scrollTop=document.documentElement.scrollTop; scrollLeft=document.documentElement.scrollLeft; }else if(document.body) { scrollTop=document.body.scrollTop; scrollLeft=document.body.scrollLeft; } scrollPos.Top=scrollTop; scrollPos.Left=scrollLeft; return scrollPos; } //修正线段有毛刺 function ToFixedPoint(value) { return parseInt(value)+0.5; } function ToFixedRect(value) { // With a bitwise or. //rounded = (0.5 + somenum) | 0; // A double bitwise not. //rounded = ~~ (0.5 + somenum); // Finally, a left bitwise shift. var rounded; return rounded = (0.5 + value) << 0; } function Point() { this.X; this.Y; } function SelectRectData() { this.Data; //主数据 this.JSChartContainer; //行情控件 this.Start; //数据起始位子 this.End; //数据结束位置 this.XStart;//X坐标起始位置 this.XEnd; //X位置结束为止 } //坐标信息 function CoordinateInfo() { this.Value; //坐标数据 this.Message=new Array(); //坐标输出文字信息 this.TextColor=g_JSChartResource.FrameSplitTextColor //文字颜色 this.Font=g_JSChartResource.FrameSplitTextFont; //字体 this.LineColor=g_JSChartResource.FrameSplitPen; //线段颜色 this.LineType=1; //线段类型 -1 不画线段 2 虚线 } //边框信息 function ChartBorder() { this.UIElement; //四周间距 this.Left=50; this.Right=80; this.Top=50; this.Bottom=50; this.TitleHeight=24; //标题高度 this.TopSpace=0; this.BottomSpace=0; this.GetChartWidth=function() { return this.UIElement.width; } this.GetChartHeight=function() { return this.UIElement.height; } this.GetLeft=function() { return this.Left; } this.GetRight=function() { return this.UIElement.width-this.Right; } this.GetTop=function() { return this.Top; } this.GetTopEx=function() //去掉标题,上面间距 { return this.Top+this.TitleHeight+this.TopSpace; } this.GetTopTitle=function() //去掉标题 { return this.Top+this.TitleHeight; } this.GetBottom=function() { return this.UIElement.height-this.Bottom; } this.GetBottomEx=function() { return this.UIElement.height-this.Bottom-this.BottomSpace; } this.GetWidth=function() { return this.UIElement.width-this.Left-this.Right; } this.GetHeight=function() { return this.UIElement.height-this.Top-this.Bottom; } this.GetHeightEx=function() //去掉标题的高度, 上下间距 { return this.UIElement.height-this.Top-this.Bottom-this.TitleHeight-this.TopSpace-this.BottomSpace; } this.GetRightEx=function() //横屏去掉标题高度的 上面间距 { return this.UIElement.width-this.Right-this.TitleHeight- this.TopSpace; } this.GetWidthEx=function() //横屏去掉标题宽度 上下间距 { return this.UIElement.width-this.Left-this.Right-this.TitleHeight- this.TopSpace - this.BottomSpace; } this.GetLeftEx = function () //横屏 { return this.Left+this.BottomSpace; } this.GetRightTitle = function ()//横屏 { return this.UIElement.width - this.Right - this.TitleHeight; } this.GetTitleHeight=function() { return this.TitleHeight; } } function IChartFramePainting() { this.HorizontalInfo=new Array(); //Y轴 this.VerticalInfo=new Array(); //X轴 this.Canvas; //画布 this.Identify; //窗口标识 this.ChartBorder; this.PenBorder=g_JSChartResource.FrameBorderPen; //边框颜色 this.TitleBGColor=g_JSChartResource.FrameTitleBGColor; //标题背景色 this.IsShow=true; //是否显示 this.SizeChange=true; //大小是否改变 this.XYSplit=true; //XY轴坐标信息改变 this.HorizontalMax; //Y轴最大值 this.HorizontalMin; //Y轴最小值 this.XPointCount=10; //X轴数据个数 this.YSplitOperator; //Y轴分割 this.XSplitOperator; //X轴分割 this.Data; //主数据 this.IsLocked=false; //是否上锁 this.LockPaint = null; this.YSpecificMaxMin=null; //指定Y轴最大最小值 this.IsShowBorder = true; //是否显示边框 this.Draw=function() { this.DrawFrame(); this.DrawBorder(); this.SizeChange=false; this.XYSplit=false; } this.DrawFrame=function() { } //画边框 this.DrawBorder=function() { if (!this.IsShowBorder) return; var left=ToFixedPoint(this.ChartBorder.GetLeft()); var top=ToFixedPoint(this.ChartBorder.GetTop()); var right=ToFixedPoint(this.ChartBorder.GetRight()); var bottom=ToFixedPoint(this.ChartBorder.GetBottom()); var width=right-left; var height=bottom-top; //console.log('[IChartFramePainting.DrawBorder] bottom',bottom); this.Canvas.strokeStyle=this.PenBorder; this.Canvas.strokeRect(left,top,width,height); } //画标题背景色 this.DrawTitleBG=function() { if (this.ChartBorder.TitleHeight<=0) return; var left=ToFixedPoint(this.ChartBorder.GetLeft()); var top=ToFixedPoint(this.ChartBorder.GetTop()); var right=ToFixedPoint(this.ChartBorder.GetRight()); var bottom=ToFixedPoint(this.ChartBorder.GetTopTitle()); var width=right-left; var height=bottom-top; this.Canvas.fillStyle=this.TitleBGColor; this.Canvas.fillRect(left,top,width,height); } this.DrawLock=function() { if (this.IsLocked) { if (this.LockPaint == null) this.LockPaint = new ChartLock(); this.LockPaint.Canvas=this.Canvas; this.LockPaint.ChartBorder=this.ChartBorder; this.LockPaint.ChartFrame=this; this.LockPaint.Draw(true); } } this.CalculateLock=function() { if (this.IsLocked) { if (this.LockPaint == null) this.LockPaint = new ChartLock(); this.LockPaint.Canvas=this.Canvas; this.LockPaint.ChartBorder=this.ChartBorder; this.LockPaint.ChartFrame=this; this.LockPaint.Draw(false); } } //设施上锁 this.SetLock=function(lockData) { if (!lockData) //空数据不上锁 { this.IsLocked=false; return; } this.IsLocked=true; if (!this.LockPaint) this.LockPaint=new ChartLock(); //创建锁 if (lockData.Callback) this.LockPaint.Callback=lockData.Callback; //回调 if (lockData.IndexName) this.LockPaint.IndexName=lockData.IndexName; //指标名字 if (lockData.ID) this.LockPaint.LockID=lockData.ID; //锁ID if (lockData.BG) this.LockPaint.BGColor=lockData.BG; //背景色 if (lockData.Text) this.LockPaint.Title= lockData.Text; if (lockData.TextColor) this.LockPaint.TextColor=lockData.TextColor; if (lockData.Font) this.LockPaint.Font=lockData.Font; if (lockData.Count) this.LockPaint.LockCount=lockData.Count; if (lockData.MinWidth>0) this.LockPaint.MinWidth=lockData.MinWidth; } this.GetLockRect=function() { if (!this.IsLocked) return null; if (!this.LockPaint) return null; return this.LockPaint.LockRect; } } //空框架只画边框 function NoneFrame() { this.newMethod=IChartFramePainting; //派生 this.newMethod(); delete this.newMethod; this.Snapshot=function() { } this.SetSizeChage=function(sizeChange) { this.SizeChange=sizeChange; //画布的位置 this.Position={ X:this.ChartBorder.UIElement.offsetLeft, Y:this.ChartBorder.UIElement.offsetTop, W:this.ChartBorder.UIElement.clientWidth, H:this.ChartBorder.UIElement.clientHeight }; } } function AverageWidthFrame() { this.newMethod=IChartFramePainting; //派生 this.newMethod(); delete this.newMethod; this.DataWidth=50*GetDevicePixelRatio(); this.DistanceWidth=10*GetDevicePixelRatio(); this.MinXDistance = 30*GetDevicePixelRatio(); //X轴刻度最小间距 this.MinYDistance=10*GetDevicePixelRatio(); //Y轴刻度最小间距 this.CoordinateType=0; //坐标类型 0=普通坐标 1=反转坐标 this.IsShowYText=[true,true]; //是否显示Y轴坐标坐标 [0=左侧] [1=右侧] this.DrawFrame=function() { if (this.XPointCount>0) { let dInterval=this.ChartBorder.GetWidth()/(6*this.XPointCount); //分6份, 数据4 间距2 this.DistanceWidth=2*dInterval; this.DataWidth=4*dInterval; } this.DrawHorizontal(); this.DrawVertical(); } //isLimit 是否限制在当前坐标下 this.GetYFromData=function(value, isLimit) { if (isLimit===false) { if (this.CoordinateType==1) { var height=this.ChartBorder.GetHeightEx()*(value-this.HorizontalMin)/(this.HorizontalMax-this.HorizontalMin); return this.ChartBorder.GetTopEx()+height; } else { var height=this.ChartBorder.GetHeightEx()*(value-this.HorizontalMin)/(this.HorizontalMax-this.HorizontalMin); return this.ChartBorder.GetBottomEx()-height; } } else { if (this.CoordinateType==1) { if(value<=this.HorizontalMin) return this.ChartBorder.GetTopEx(); if(value>=this.HorizontalMax) return this.ChartBorder.GetBottomEx(); var height=this.ChartBorder.GetHeightEx()*(value-this.HorizontalMin)/(this.HorizontalMax-this.HorizontalMin); return this.ChartBorder.GetTopEx()+height; } else { if(value<=this.HorizontalMin) return this.ChartBorder.GetBottomEx(); if(value>=this.HorizontalMax) return this.ChartBorder.GetTopEx(); var height=this.ChartBorder.GetHeightEx()*(value-this.HorizontalMin)/(this.HorizontalMax-this.HorizontalMin); return this.ChartBorder.GetBottomEx()-height; } } } //画Y轴 this.DrawHorizontal=function() { var left=this.ChartBorder.GetLeft(); var right=this.ChartBorder.GetRight(); var bottom = this.ChartBorder.GetBottom(); var top = this.ChartBorder.GetTopTitle(); var borderRight=this.ChartBorder.Right; var borderLeft=this.ChartBorder.Left; var yPrev=null; //上一个坐标y的值 for(var i=this.HorizontalInfo.length-1; i>=0; --i) //从上往下画分割线 { var item=this.HorizontalInfo[i]; var y=this.GetYFromData(item.Value); if (y!=null && Math.abs(y-yPrev)= bottom - 2) this.Canvas.textBaseline = 'bottom'; else if (y <= top + 2) this.Canvas.textBaseline = 'top'; else this.Canvas.textBaseline = "middle"; //坐标信息 左边 间距小于10 不画坐标 if (item.Message[0]!=null && borderLeft>10 && this.IsShowYText[0]===true) { if (item.Font!=null) this.Canvas.font=item.Font; this.Canvas.fillStyle=item.TextColor; this.Canvas.textAlign="right"; this.Canvas.fillText(item.Message[0],left-2,y); } //坐标信息 右边 间距小于10 不画坐标 if (item.Message[1]!=null && borderRight>10 && this.IsShowYText[1]===true) { if (item.Font!=null) this.Canvas.font=item.Font; this.Canvas.fillStyle=item.TextColor; this.Canvas.textAlign="left"; this.Canvas.fillText(item.Message[1],right+2,y); } yPrev=y; } } //Y刻度画在左边内部 this.DrawInsideHorizontal = function () { if (this.IsHScreen===true) return; //横屏不画 if (this.IsShowYText[0]===false && this.IsShowYText[1]===false) return; var left = this.ChartBorder.GetLeft(); var right = this.ChartBorder.GetRight(); var bottom = this.ChartBorder.GetBottom(); var top = this.ChartBorder.GetTopTitle(); var borderRight = this.ChartBorder.Right; var borderLeft = this.ChartBorder.Left; var titleHeight = this.ChartBorder.TitleHeight; if ( (borderLeft<10 && this.IsShowYText[0]===true) || (borderRight<10 && this.IsShowYText[1]===true) ) { var pixelTatio = GetDevicePixelRatio(); var yPrev = null; //上一个坐标y的值 for (var i = this.HorizontalInfo.length - 1; i >= 0; --i) //从上往下画分割线 { var item = this.HorizontalInfo[i]; var y = this.GetYFromData(item.Value); if (y != null && yPrev!=null && Math.abs(y - yPrev) < this.MinYDistance) continue; //两个坐标在近了 就不画了 //坐标信息 左边 间距小于10 画在内部 if (item.Message[0] != null && borderLeft < 10 && this.IsShowYText[0]===true) { if (item.Font != null) this.Canvas.font = item.Font; this.Canvas.fillStyle = item.TextColor; this.Canvas.textAlign = "left"; if (y >= bottom - 2) this.Canvas.textBaseline = 'bottom'; else if (y <= top + 2) this.Canvas.textBaseline = 'top'; else this.Canvas.textBaseline = "middle"; var textObj={ X:left, Y:y, Text:{ BaseLine:this.Canvas.textBaseline, TextAlign: this.Canvas.textAlign, Font:this.Canvas.font, Value:item.Message[0]}} ; if (!this.IsOverlayMaxMin || !this.IsOverlayMaxMin(textObj)) this.Canvas.fillText(item.Message[0], left + 1*pixelTatio, y); } if (item.Message[1] != null && borderRight < 10 && this.IsShowYText[1]===true) { if (item.Font != null) this.Canvas.font = item.Font; this.Canvas.fillStyle = item.TextColor; this.Canvas.textAlign = "right"; if (y >= bottom - 2) this.Canvas.textBaseline = 'bottom'; else if (y <= top + 2) this.Canvas.textBaseline = 'top'; else this.Canvas.textBaseline = "middle"; var textWidth = this.Canvas.measureText(item.Message[1]).width; var textObj={ X:right-textWidth, Y:y, Text:{ BaseLine:this.Canvas.textBaseline, TextAlign: this.Canvas.textAlign, Font:this.Canvas.font, Value:item.Message[1]}} ; if (!this.IsOverlayMaxMin || !this.IsOverlayMaxMin(textObj)) this.Canvas.fillText(item.Message[1], right - 1*pixelTatio, y); } yPrev = y; } } } this.GetXFromIndex=function(index) { var count=this.XPointCount; if (count==1) { if (index==0) return this.ChartBorder.GetLeft(); else return this.ChartBorder.GetRight(); } else if (count<=0) { return this.ChartBorder.GetLeft(); } else if (index>=count) { return this.ChartBorder.GetRight(); } else { var offset=this.ChartBorder.GetLeft()+this.ChartBorder.GetWidth()*index/count; return offset; } } //画X轴 this.DrawVertical=function() { var top=this.ChartBorder.GetTopTitle(); var bottom=this.ChartBorder.GetBottom(); var right=this.ChartBorder.GetRight(); var pixelTatio = GetDevicePixelRatio(); //获取设备的分辨率 //console.log('[AverageWidthFrame.DrawVertical] bottom',bottom); var xPrev=null; //上一个坐标x的值 var textRightPrev=null; //上一次刻度输出右边x坐标 for(var i in this.VerticalInfo) { var x=this.GetXFromIndex(this.VerticalInfo[i].Value); if (x>right) break; if (xPrev!=null && Math.abs(x-xPrev)0) { this.Canvas.strokeStyle=this.VerticalInfo[i].LineColor; this.Canvas.beginPath(); this.Canvas.moveTo(ToFixedPoint(x),top); this.Canvas.lineTo(ToFixedPoint(x),bottom); this.Canvas.stroke(); } if (this.VerticalInfo[i].Message[0]!=null) { if (this.VerticalInfo[i].Font!=null) this.Canvas.font=this.VerticalInfo[i].Font; var textLeft=0; this.Canvas.fillStyle=this.VerticalInfo[i].TextColor; var testWidth=this.Canvas.measureText(this.VerticalInfo[i].Message[0]).width; if (x= this.ChartBorder.GetChartWidth()) { this.Canvas.textAlign = "right"; this.Canvas.textBaseline="top"; textLeft=x-testWidth; } else { this.Canvas.textAlign="center"; this.Canvas.textBaseline="top"; textLeft=x-(testWidth/2); } if (textRightPrev==null || textLeft>textRightPrev) { this.Canvas.fillText(this.VerticalInfo[i].Message[0],x,bottom+1*pixelTatio); textRightPrev=textLeft+testWidth; } } xPrev=x; } } //Y坐标转y轴数值 this.GetYData=function(y) { if (this.CoordinateType==1) //反转坐标 { if (ythis.ChartBorder.GetBottomEx()) return this.HorizontalMax; return (y-this.ChartBorder.GetTopEx())/this.ChartBorder.GetHeightEx()*(this.HorizontalMax-this.HorizontalMin)+this.HorizontalMin; } else { if (ythis.ChartBorder.GetBottomEx()) return this.HorizontalMin; return (this.ChartBorder.GetBottomEx()-y)/this.ChartBorder.GetHeightEx()*(this.HorizontalMax-this.HorizontalMin)+this.HorizontalMin; } } //X坐标转x轴数值 this.GetXData=function(x) { if (x<=this.ChartBorder.GetLeft()) return 0; if (x>=this.ChartBorder.GetRight()) return this.XPointCount; return (x-this.ChartBorder.GetLeft())*(this.XPointCount*1.0/this.ChartBorder.GetWidth()); } } function MinuteFrame() { this.newMethod=AverageWidthFrame; //派生 this.newMethod(); delete this.newMethod; this.MinuteCount=243; //每天的分钟个数 this.IsBeforeData=false; //是否显示集合竞价 this.BeforeBGColor=g_JSChartResource.Minute.BeforeBGColor; //集合竞价背景 this.DrawFrame=function() { this.SplitXYCoordinate(); if (this.IsBeforeData) this.DrawBeforeDataBG(); this.DrawTitleBG(); this.DrawHorizontal(); this.DrawVertical(); } //画集合竞价背景 this.DrawBeforeDataBG=function() { var left=ToFixedPoint(this.ChartBorder.GetLeft()); var top=ToFixedPoint(this.ChartBorder.GetTopEx()); var right=this.GetXFromIndex(14); var bottom=ToFixedPoint(this.ChartBorder.GetBottom()); var width=right-left; var height=bottom-top; this.Canvas.fillStyle=this.BeforeBGColor; this.Canvas.fillRect(left,top,width,height); } //分割x,y轴坐标信息 this.SplitXYCoordinate=function() { if (this.XYSplit==false) return; if (this.YSplitOperator!=null) this.YSplitOperator.Operator(); if (this.XSplitOperator!=null) this.XSplitOperator.Operator(); } this.GetXFromIndex=function(index) { var count=this.XPointCount-1; if (count==1) { if (index==0) return this.ChartBorder.GetLeft(); else return this.ChartBorder.GetRight(); } else if (count<=0) { return this.ChartBorder.GetLeft(); } else if (index>=count) { return this.ChartBorder.GetRight(); } else { var offset=this.ChartBorder.GetLeft()+this.ChartBorder.GetWidth()*index/count; return offset; } } //X坐标转x轴数值 this.GetXData=function(x) { var count=this.XPointCount-1; if (count<0) count=0; if (x<=this.ChartBorder.GetLeft()) return 0; if (x>=this.ChartBorder.GetRight()) return count; return (x-this.ChartBorder.GetLeft())*(count*1.0/this.ChartBorder.GetWidth()); } } //走势图 横屏框架 function MinuteHScreenFrame() { this.newMethod=MinuteFrame; //派生 this.newMethod(); delete this.newMethod; this.IsHScreen=true; //是否是横屏 //画标题背景色 this.DrawTitleBG=function() { if (this.ChartBorder.TitleHeight<=0) return; var left=ToFixedPoint(this.ChartBorder.GetRightEx()); var top=ToFixedPoint(this.ChartBorder.GetTop()); var bottom=ToFixedPoint(this.ChartBorder.GetBottom()); var width=this.ChartBorder.TitleHeight; var height=bottom-top; this.Canvas.fillStyle=this.TitleBGColor; this.Canvas.fillRect(left,top,width,height); } //画集合竞价背景 this.DrawBeforeDataBG=function() { var left=ToFixedPoint(this.ChartBorder.GetLeft()); var right=ToFixedPoint(this.ChartBorder.GetRightEx()); var top=ToFixedPoint(this.ChartBorder.GetTop()); var bottom=this.GetXFromIndex(14); var width=right-left; var height=bottom-top; this.Canvas.fillStyle=this.BeforeBGColor; this.Canvas.fillRect(left,top,width,height); } //Y坐标转y轴数值 this.GetYData=function(x) { if (xthis.ChartBorder.GetRightEx()) return this.HorizontalMax; return (x-this.ChartBorder.GetLeft())/this.ChartBorder.GetWidthEx()*(this.HorizontalMax-this.HorizontalMin)+this.HorizontalMin; } //X坐标转x轴数值 this.GetXData=function(y) { if (y<=this.ChartBorder.GetTop()) return 0; if (y>=this.ChartBorder.GetBottom()) return this.XPointCount; return (y-this.ChartBorder.GetTop())*(this.XPointCount*1.0/this.ChartBorder.GetHeight()); } this.GetXFromIndex=function(index) { var count=this.XPointCount-1; if (count==1) { if (index==0) return this.ChartBorder.GetTop(); else return this.ChartBorder.GetBottom(); } else if (count<=0) { return this.ChartBorder.GetTop(); } else if (index>=count) { return this.ChartBorder.GetBottom(); } else { var offset=this.ChartBorder.GetTop()+this.ChartBorder.GetHeight()*index/count; return offset; } } this.GetYFromData=function(value) { if(value<=this.HorizontalMin) return this.ChartBorder.GetLeft(); if(value>=this.HorizontalMax) return this.ChartBorder.GetRightEx(); var width=this.ChartBorder.GetWidthEx()*(value-this.HorizontalMin)/(this.HorizontalMax-this.HorizontalMin); return this.ChartBorder.GetLeft()+width; } //画Y轴 this.DrawHorizontal=function() { var top=this.ChartBorder.GetTop(); var bottom=this.ChartBorder.GetBottom(); var left=this.ChartBorder.GetLeft(); var right=this.ChartBorder.GetRight(); var borderTop=this.ChartBorder.Top; var borderBottom=this.ChartBorder.Bottom; var yPrev=null; //上一个坐标y的值 for(var i=this.HorizontalInfo.length-1; i>=0; --i) //从左往右画分割线 { var item=this.HorizontalInfo[i]; var y=this.GetYFromData(item.Value); if (y!=null && Math.abs(y-yPrev)= right - 2) { this.Canvas.textBaseline = 'top'; y = right; } else if (y <= left + 2) { this.Canvas.textBaseline = 'bottom'; y=left; if (y != null && Math.abs(y - yPrev) < 2*this.MinYDistance) continue; //两个坐标在近了 就不画了 } else { this.Canvas.textBaseline = "middle"; } //坐标信息 左边 间距小于10 不画坐标 if (item.Message[0]!=null && borderTop>10) { if (item.Font!=null) this.Canvas.font=item.Font; this.Canvas.fillStyle=item.TextColor; this.Canvas.textAlign="right"; var xText=y,yText=top; this.Canvas.save(); this.Canvas.translate(xText, yText); this.Canvas.rotate(90 * Math.PI / 180); this.Canvas.fillText(item.Message[0], -2, 0); this.Canvas.restore(); } //坐标信息 右边 间距小于10 不画坐标 if (item.Message[1]!=null && borderBottom>10) { if (item.Font!=null) this.Canvas.font=item.Font; this.Canvas.fillStyle=item.TextColor; this.Canvas.textAlign="left"; var xText=y,yText=bottom; this.Canvas.save(); this.Canvas.translate(xText, yText); this.Canvas.rotate(90 * Math.PI / 180); this.Canvas.fillText(item.Message[1], 2, 0); this.Canvas.restore(); } yPrev=y; } } //画X轴 this.DrawVertical=function() { var left=this.ChartBorder.GetLeft(); var right=this.ChartBorder.GetRightEx(); var bottom=this.ChartBorder.GetBottom(); var xPrev=null; //上一个坐标x的值 for(var i in this.VerticalInfo) { var x=this.GetXFromIndex(this.VerticalInfo[i].Value); if (x>bottom) break; if (xPrev!=null && Math.abs(x-xPrev)= this.ChartBorder.GetChartHeight()) { this.Canvas.textAlign = "right"; this.Canvas.textBaseline = "top"; } else { this.Canvas.textAlign="center"; this.Canvas.textBaseline="top"; } var xText=left,yText=x; this.Canvas.save(); this.Canvas.translate(xText, yText); this.Canvas.rotate(90 * Math.PI / 180); this.Canvas.fillText(this.VerticalInfo[i].Message[0], 0, 0); this.Canvas.restore(); } xPrev=x; } } } //K线框架 function KLineFrame() { this.newMethod=AverageWidthFrame; //派生 this.newMethod(); delete this.newMethod; this.ToolbarID=Guid(); //工具条Div id this.ModifyIndex=true; //是否显示'改参数'菜单 this.ChangeIndex=true; //是否显示'换指标'菜单 this.CloseIndex=true; //是否显示'关闭指标窗口'菜单 this.OverlayIndex=false; //是否显示叠加指标 this.ModifyIndexEvent; //改参数 点击事件 this.ChangeIndexEvent; //换指标 点击事件 this.LastCalculateStatus={ Width:0, XPointCount:0 }; //最后一次计算宽度的状态 this.CustomHorizontalInfo=[]; this.DrawToolbar=function() { if (!this.ChartBorder.UIElement) return; var divToolbar=document.getElementById(this.ToolbarID); if (!divToolbar) { divToolbar=document.createElement("div"); divToolbar.className='klineframe-toolbar'; divToolbar.id=this.ToolbarID; //为divToolbar添加属性identify divToolbar.setAttribute("identify",this.Identify.toString()); this.ChartBorder.UIElement.parentNode.appendChild(divToolbar); } if (!this.ModifyIndex && !this.ChangeIndex && !this.OverlayIndex) { divToolbar.style.display='none'; return; } //使用外城div尺寸 画图尺寸是被放大的 var pixelTatio = GetDevicePixelRatio(); var chartWidth=parseInt(this.ChartBorder.UIElement.parentElement.style.width.replace("px","")); var chartHeight=parseInt(this.ChartBorder.UIElement.parentElement.style.height.replace("px","")); //console.log('[KLineFrame::DrawToolbar] ',chartWidth,chartHeight,pixelTatio); var toolbarWidth=100; var toolbarHeight=this.ChartBorder.GetTitleHeight(); var left=chartWidth-(this.ChartBorder.Right/pixelTatio)-toolbarWidth; var top=this.ChartBorder.GetTop()/pixelTatio; var spanIcon = "" + "" + ""; if (this.Identify!==0 && this.CloseIndex) //第1个窗口不能关闭 { const spanCloseIcon=""; spanIcon+=spanCloseIcon; } //var scrollPos=GetScrollPosition(); //left = left+scrollPos.Left; //top = top+scrollPos.Top; divToolbar.style.left = left + "px"; divToolbar.style.top = top + "px"; divToolbar.style.width=toolbarWidth+"px"; //宽度先不调整吧 divToolbar.style.height=(toolbarHeight/pixelTatio)+'px'; //只调整高度 divToolbar.innerHTML=spanIcon; var chart=this.ChartBorder.UIElement.JSChartContainer; var identify=this.Identify; if (!this.ModifyIndex) //隐藏'改参数' $("#"+divToolbar.id+" .index_param").hide(); else if (typeof(this.ModifyIndexEvent)=='function') //绑定点击事件 $("#"+divToolbar.id+" .index_param").click( { Chart:this.ChartBorder.UIElement.JSChartContainer, Identify:this.Identify },this.ModifyIndexEvent); if (!this.ChangeIndex) //隐藏'换指标' { $("#"+divToolbar.id+" .index_change").hide(); } else if (typeof(this.ChangeIndexEvent)=='function') { $("#"+divToolbar.id+" .index_change").click( { Chart:this.ChartBorder.UIElement.JSChartContainer, Identify:this.Identify, IsOverlay:false },this.ChangeIndexEvent); } if (!this.OverlayIndex) { $("#"+divToolbar.id+" .index_overlay").hide(); } else { $("#"+divToolbar.id+" .index_overlay").click( { Chart:this.ChartBorder.UIElement.JSChartContainer, Identify:this.Identify, IsOverlay:true },this.ChangeIndexEvent); } $("#"+divToolbar.id+" .index_close").click( { Chart:this.ChartBorder.UIElement.JSChartContainer, Identify:this.Identify }, function(event) { var hqChart=event.data.Chart; var id=event.data.Identify; hqChart.RemoveIndexWindow(id); }); divToolbar.style.display = "block"; } this.ClearToolbar=function() { var divToolbar=document.getElementById(this.ToolbarID); if (!divToolbar) return; this.ChartBorder.UIElement.parentNode.removeChild(divToolbar); } this.DrawFrame=function() { this.SplitXYCoordinate(); if (this.SizeChange==true) this.CalculateDataWidth(); this.DrawTitleBG(); this.DrawHorizontal(); this.DrawVertical(); if (this.SizeChange==true) this.DrawToolbar(); //大小变动才画工具条 } //isLimit 是否限制在当前屏坐标下 this.GetXFromIndex=function(index,isLimit) { if (isLimit===false) { if (index>=0) { var offset=this.ChartBorder.GetLeft()+2+this.DistanceWidth/2+this.DataWidth/2; for(var i=1;i<=index;++i) { offset+=this.DistanceWidth+this.DataWidth; } } else { var offset=this.ChartBorder.GetLeft()+2+this.DistanceWidth/2+this.DataWidth/2; var absIndex=Math.abs(index); for(var i=0;i this.xPointCount - 1) index = this.xPointCount - 1; var offset=this.ChartBorder.GetLeft()+2+this.DistanceWidth/2+this.DataWidth/2; for(var i=1;i<=index;++i) { offset+=this.DistanceWidth+this.DataWidth; } } return offset; } //X坐标转x轴数值 this.GetXData=function(x) { if (x<=this.ChartBorder.GetLeft()) return 0; if (x>=this.ChartBorder.GetRight()) return this.XPointCount; var left=this.ChartBorder.GetLeft(); var right=this.ChartBorder.GetRight(); var distanceWidth=this.DistanceWidth; var dataWidth=this.DataWidth; var index=0; var xPoint=left+dataWidth+distanceWidth; while(xPointx) break; xPoint+=(dataWidth+distanceWidth); ++index; } //var test=(x-this.ChartBorder.GetLeft())*(this.XPointCount*1.0/this.ChartBorder.GetWidth()); return index; } //计算数据宽度 this.CalculateDataWidth=function() { if (this.XPointCount<2) return; //console.log(`[KLineFrame::CalculateDataWidth] ZoomIndex=${this.ZoomIndex}, XPointCount=${this.XPointCount}, DataWidth=${this.DataWidth}, DistanceWidth=${this.DistanceWidth}`); var width=this.ChartBorder.GetWidth()-4; if (this.ZoomIndex>0 && this.LastCalculateStatus.Width==width && this.LastCalculateStatus.XPointCount==this.XPointCount) //宽度没变 尝试使用原来的柱子宽度 { if ((this.DataWidth + this.DistanceWidth) * this.XPointCount <= width) //当前的柱子宽度够用 就不调整了 return; } this.LastCalculateStatus.Width=width; this.LastCalculateStatus.XPointCount=this.XPointCount; for(var i=0;i width) { this.DistanceWidth -= 0.01; break; } this.DistanceWidth += 0.01; } } //当前坐标信息 是否覆盖最大 最小值输出 this.IsOverlayMaxMin=function(obj) { if (!this.ChartKLine) return false; if (!this.ChartKLine.Max || !this.ChartKLine.Min) return false; var textWidth=this.Canvas.measureText(obj.Text.Value).width+4; //刻度文字宽度 if (obj.Text.TextAlign==='right') obj.X-=textWidth; var max=this.ChartKLine.Max, min=this.ChartKLine.Min; var isOverlayMax=false, isOverlayMin=false; const textHeight=20; //字体高度 if (max.X>=obj.X && max.X<=obj.X+textWidth) //最大值X 坐标不在 刻度文字范围内 { var y1=max.Y+textHeight, y2=max.Y-textHeight; if ( (y1>=obj.Y-textHeight && y1<=obj.Y+textHeight) || (y2>=obj.Y-textHeight && y2<=obj.Y+textHeight)) isOverlayMax=true; } if (isOverlayMax==true) return true; if (min.X>=obj.X && min.X<=obj.X+textWidth) { var y1=min.Y+textHeight, y2=min.Y-textHeight; if ( (y1>=obj.Y-textHeight && y1<=obj.Y+textHeight) || (y2>=obj.Y-textHeight && y2<=obj.Y+textHeight)) isOverlayMin=true; } return isOverlayMax || isOverlayMin; } //分割x,y轴坐标信息 this.SplitXYCoordinate=function() { if (this.XYSplit==false) return; if (this.YSplitOperator!=null) this.YSplitOperator.Operator(); if (this.XSplitOperator!=null) this.XSplitOperator.Operator(); } this.CalculateCount=function(zoomIndex) { var width=this.ChartBorder.GetWidth()-4; return parseInt(width/(ZOOM_SEED[zoomIndex][0] + ZOOM_SEED[zoomIndex][1])); } this.ZoomUp=function(cursorIndex) { if (this.ZoomIndex<=0) return false; if (this.Data.DataOffset<0) return false; var lastDataIndex = this.Data.DataOffset + this.XPointCount - 1; //最右边的数据索引 var lastCursorIndex=this.Data.DataOffset + cursorIndex.Index; if (lastDataIndex>this.Data.Data.length) lastDataIndex=this.Data.Data.length-1; //console.log(`[KLineFrame::ZoomUp] old status. XPointCount=${this.XPointCount} ZoomIndex=${this.ZoomIndex}`); --this.ZoomIndex; var xPointCount=this.CalculateCount(this.ZoomIndex); this.XPointCount=xPointCount; this.DataWidth = ZOOM_SEED[this.ZoomIndex][0]; this.DistanceWidth = ZOOM_SEED[this.ZoomIndex][1]; this.TrimKLineDataWidth(this.ChartBorder.GetWidth()); this.LastCalculateStatus.XPointCount=this.XPointCount; //console.log(`[KLineFrame::ZoomUp] new status. XPointCount=${this.XPointCount} ZoomIndex=${this.ZoomIndex}`); if (lastDataIndex>=this.Data.Data.length) { this.Data.DataOffset=this.Data.Data.length-this.XPointCount-2; cursorIndex.Index=this.Data.Data.length-this.Data.DataOffset-1; } else { if (lastDataIndex=ZOOM_SEED.length) return false; if (this.Data.DataOffset<0) return false; var lastDataIndex = this.Data.DataOffset + this.XPointCount - 1; //最右边的数据索引 if (lastDataIndex>=this.Data.Data.length) lastDataIndex=this.Data.Data.length-1; //console.log(`[KLineFrame::ZoomDown] old status. XPointCount=${this.XPointCount} ZoomIndex=${this.ZoomIndex}`); var xPointCount=this.CalculateCount(this.ZoomIndex+1); var lastCursorIndex=this.Data.DataOffset + cursorIndex.Index; ++this.ZoomIndex; this.XPointCount=xPointCount; this.DataWidth = ZOOM_SEED[this.ZoomIndex][0]; this.DistanceWidth = ZOOM_SEED[this.ZoomIndex][1]; this.TrimKLineDataWidth(this.ChartBorder.GetWidth()); this.LastCalculateStatus.XPointCount=this.XPointCount; //console.log(`[KLineFrame::ZoomDown] new status. XPointCount=${this.XPointCount} ZoomIndex=${this.ZoomIndex}`); if (lastDataIndex-xPointCount+1<0) this.Data.DataOffset=0; else this.Data.DataOffset = lastDataIndex - this.XPointCount+1; cursorIndex.Index=lastCursorIndex-this.Data.DataOffset; return true; } this.DrawCustomHorizontal=function() //Y轴刻度定制显示 { for(var i in this.CustomHorizontalInfo) { var item=this.CustomHorizontalInfo[i]; switch(item.Type) { case 0: this.DrawLatestPrice(item); break; } } } this.DrawLatestPrice=function(item) //显示最新价格 { if (this.IsHScreen===true) return; //横屏不画 if (!item.Message[1] && !item.Message[0]) return; if (item.Value>this.HorizontalMax || item.Value=0; --i) //从上往下画分割线 { var item=this.HorizontalInfo[i]; var y=this.GetYFromData(item.Value); if (y!=null && Math.abs(y-yPrev)= bottom - 2) this.Canvas.textBaseline = 'bottom'; else if (y <= top + 2) this.Canvas.textBaseline = 'top'; else this.Canvas.textBaseline = "middle"; this.Canvas.strokeStyle=this.PenBorder; this.Canvas.beginPath(); this.Canvas.moveTo(right-2,ToFixedPoint(y)); this.Canvas.lineTo(right,ToFixedPoint(y)); this.Canvas.stroke(); //坐标信息 右边 间距小于10 不画坐标 if (item.Message[1]!=null && borderRight>10) { if (item.Font!=null) this.Canvas.font=item.Font; this.Canvas.fillStyle=item.TextColor; this.Canvas.textAlign="left"; this.Canvas.fillText(item.Message[1],right+2,y); } yPrev=y; } } //画X轴 this.DrawVertical=function() { var top=this.ChartBorder.GetTopEx(); //var left=this.ChartBorder.GetLeft(); var right=this.ChartBorder.GetRight(); var bottom=this.ChartBorder.GetBottomEx(); right+=this.RightOffset; this.Canvas.strokeStyle=this.PenBorder; this.Canvas.beginPath(); this.Canvas.moveTo(ToFixedPoint(right),ToFixedPoint(top)); this.Canvas.lineTo(ToFixedPoint(right),ToFixedPoint(bottom)); this.Canvas.stroke(); } } //K线横屏框架 function KLineHScreenFrame() { this.newMethod=KLineFrame; //派生 this.newMethod(); delete this.newMethod; this.IsHScreen=true; //是否是横屏 //画标题背景色 this.DrawTitleBG=function() { if (this.ChartBorder.TitleHeight<=0) return; var left=ToFixedPoint(this.ChartBorder.GetRightTitle()); var top=ToFixedPoint(this.ChartBorder.GetTop()); var bottom=ToFixedPoint(this.ChartBorder.GetBottom()); var width=this.ChartBorder.TitleHeight; var height=bottom-top; this.Canvas.fillStyle=this.TitleBGColor; this.Canvas.fillRect(left,top,width,height); } this.DrawToolbar=function() { return; } this.GetYFromData=function(value) { if(value<=this.HorizontalMin) return this.ChartBorder.GetLeftEx(); if(value>=this.HorizontalMax) return this.ChartBorder.GetRightEx(); var width=this.ChartBorder.GetWidthEx()*(value-this.HorizontalMin)/(this.HorizontalMax-this.HorizontalMin); return this.ChartBorder.GetLeftEx()+width; } //画Y轴 this.DrawHorizontal=function() { var top=this.ChartBorder.GetTop(); var bottom=this.ChartBorder.GetBottom(); var borderTop=this.ChartBorder.Top; var borderBottom=this.ChartBorder.Bottom; var yPrev=null; //上一个坐标y的值 var pixelTatio = GetDevicePixelRatio(); //获取设备的分辨率 for(var i=this.HorizontalInfo.length-1; i>=0; --i) //从左往右画分割线 { var item=this.HorizontalInfo[i]; var y=this.GetYFromData(item.Value); if (y!=null && Math.abs(y-yPrev)<15) continue; //两个坐标在近了 就不画了 this.Canvas.strokeStyle=item.LineColor; this.Canvas.beginPath(); this.Canvas.moveTo(ToFixedPoint(y),top); this.Canvas.lineTo(ToFixedPoint(y),bottom); this.Canvas.stroke(); //坐标信息 左边 间距小于10 不画坐标 if (item.Message[0]!=null && borderTop>10*pixelTatio) { if (item.Font!=null) this.Canvas.font=item.Font; this.Canvas.fillStyle=item.TextColor; this.Canvas.textAlign="right"; this.Canvas.textBaseline="middle"; var xText=y,yText=top; this.Canvas.save(); this.Canvas.translate(xText, yText); this.Canvas.rotate(90 * Math.PI / 180); this.Canvas.fillText(item.Message[0], -2, 0); this.Canvas.restore(); } //坐标信息 右边 间距小于10 不画坐标 if (item.Message[1]!=null && borderBottom>10*pixelTatio) { if (item.Font!=null) this.Canvas.font=item.Font; this.Canvas.fillStyle=item.TextColor; this.Canvas.textAlign="left"; this.Canvas.textBaseline="middle"; var xText=y,yText=bottom; this.Canvas.save(); this.Canvas.translate(xText, yText); this.Canvas.rotate(90 * Math.PI / 180); this.Canvas.fillText(item.Message[1], 2, 0); this.Canvas.restore(); } yPrev=y; } } this.GetXFromIndex=function(index) { if (index < 0) index = 0; if (index > this.xPointCount - 1) index = this.xPointCount - 1; var offset=this.ChartBorder.GetTop()+2+this.DistanceWidth/2+this.DataWidth/2; for(var i=1;i<=index;++i) { offset+=this.DistanceWidth+this.DataWidth; } return offset; } //画X轴 this.DrawVertical=function() { var left=this.ChartBorder.GetLeft(); var right=this.ChartBorder.GetRightTitle(); var bottom=this.ChartBorder.GetBottom(); var xPrev=null; //上一个坐标x的值 for(var i in this.VerticalInfo) { var x=this.GetXFromIndex(this.VerticalInfo[i].Value); if (x>=bottom) break; if (xPrev!=null && Math.abs(x-xPrev)<80) continue; this.Canvas.strokeStyle=this.VerticalInfo[i].LineColor; this.Canvas.beginPath(); this.Canvas.moveTo(left,ToFixedPoint(x)); this.Canvas.lineTo(right,ToFixedPoint(x)); this.Canvas.stroke(); if (this.VerticalInfo[i].Message[0]!=null) { if (this.VerticalInfo[i].Font!=null) this.Canvas.font=this.VerticalInfo[i].Font; this.Canvas.fillStyle=this.VerticalInfo[i].TextColor; var testWidth=this.Canvas.measureText(this.VerticalInfo[i].Message[0]).width; if (xthis.ChartBorder.GetRightEx()) return this.HorizontalMax; return (x-this.ChartBorder.GetLeftEx())/this.ChartBorder.GetWidthEx()*(this.HorizontalMax-this.HorizontalMin)+this.HorizontalMin; } //X坐标转x轴数值 this.GetXData=function(y) { if (y<=this.ChartBorder.GetTop()) return 0; if (y>=this.ChartBorder.GetBottom()) return this.XPointCount; return (y-this.ChartBorder.GetTop())*(this.XPointCount*1.0/this.ChartBorder.GetHeight()); } //计算数据宽度 this.CalculateDataWidth=function() { if (this.XPointCount<2) return; var width=this.ChartBorder.GetHeight()-4; for(var i=0;ithis.Data.Data.length) lastDataIndex=this.Data.Data.length-1; --this.ZoomIndex; var xPointCount=this.CalculateCount(this.ZoomIndex); this.XPointCount=xPointCount; this.DataWidth = ZOOM_SEED[this.ZoomIndex][0]; this.DistanceWidth = ZOOM_SEED[this.ZoomIndex][1]; this.TrimKLineDataWidth(this.ChartBorder.GetHeight()); if (lastDataIndex>=this.Data.Data.length) { this.Data.DataOffset=this.Data.Data.length-this.XPointCount-2; cursorIndex.Index=this.Data.Data.length-this.Data.DataOffset-1; } else { if (lastDataIndex=ZOOM_SEED.length) return false; if (this.Data.DataOffset<0) return false; var lastDataIndex = this.Data.DataOffset + this.XPointCount - 1; //最右边的数据索引 if (lastDataIndex>=this.Data.Data.length) lastDataIndex=this.Data.Data.length-1; var xPointCount=this.CalculateCount(this.ZoomIndex+1); var lastCursorIndex=this.Data.DataOffset + cursorIndex.Index; ++this.ZoomIndex; this.XPointCount=xPointCount; this.DataWidth = ZOOM_SEED[this.ZoomIndex][0]; this.DistanceWidth = ZOOM_SEED[this.ZoomIndex][1]; this.TrimKLineDataWidth(this.ChartBorder.GetHeight()); if (lastDataIndex-xPointCount+1<0) this.Data.DataOffset=0; else this.Data.DataOffset = lastDataIndex - this.XPointCount+1; cursorIndex.Index=lastCursorIndex-this.Data.DataOffset; return true; } } function OverlayKLineHScreenFrame() { this.newMethod=KLineHScreenFrame; //派生 this.newMethod(); delete this.newMethod; this.MainFrame=null; //主框架 this.RightOffset=50; this.PenBorder=g_JSChartResource.OverlayFrame.BolderPen; //'rgb(0,0,0)' this.IsShow=true; //坐标是否显示 this.Title=null; this.TitleColor=g_JSChartResource.OverlayFrame.TitleColor; this.TitleFont=g_JSChartResource.OverlayFrame.TitleFont; this.Draw=function() { this.SplitXYCoordinate(); if (this.IsShow) { this.DrawVertical(); this.DrawHorizontal(); this.DrawTitle(); } this.SizeChange=false; this.XYSplit=false; } this.DrawTitle=function() //画标题 { /* if (!this.Title) return; var top = this.ChartBorder.GetTopTitle(); var bottom = this.ChartBorder.GetBottom(); var right=this.ChartBorder.GetRight(); right+=this.RightOffset; this.Canvas.fillStyle=this.TitleColor; this.Canvas.font=this.TitleFont; this.Canvas.textAlign="center"; this.Canvas.textBaseline="top"; var xText=right-2,yText=top+(bottom-top)/2; this.Canvas.save(); this.Canvas.translate(xText, yText); this.Canvas.rotate(90 * Math.PI / 180); this.Canvas.fillText(this.Title, 0, 0); this.Canvas.restore(); */ } //分割x,y轴坐标信息 this.SplitXYCoordinate=function() { if (this.XYSplit==false) return; if (this.YSplitOperator!=null) this.YSplitOperator.Operator(); // if (this.XSplitOperator!=null) this.XSplitOperator.Operator(); 子坐标和主坐标X轴一致 所以不用计算 } //画Y轴 this.DrawHorizontal=function() { /* var left=this.ChartBorder.GetLeft(); var right=this.ChartBorder.GetRight(); var bottom = this.ChartBorder.GetBottom(); var top = this.ChartBorder.GetTopTitle(); var borderRight=this.ChartBorder.Right; right+=this.RightOffset; var yPrev=null; //上一个坐标y的值 for(var i=this.HorizontalInfo.length-1; i>=0; --i) //从上往下画分割线 { var item=this.HorizontalInfo[i]; var y=this.GetYFromData(item.Value); if (y!=null && Math.abs(y-yPrev)= bottom - 2) this.Canvas.textBaseline = 'bottom'; else if (y <= top + 2) this.Canvas.textBaseline = 'top'; else this.Canvas.textBaseline = "middle"; this.Canvas.strokeStyle=this.PenBorder; this.Canvas.beginPath(); this.Canvas.moveTo(right-2,ToFixedPoint(y)); this.Canvas.lineTo(right,ToFixedPoint(y)); this.Canvas.stroke(); //坐标信息 右边 间距小于10 不画坐标 if (item.Message[1]!=null && borderRight>10) { if (item.Font!=null) this.Canvas.font=item.Font; this.Canvas.fillStyle=item.TextColor; this.Canvas.textAlign="left"; this.Canvas.fillText(item.Message[1],right+2,y); } yPrev=y; } */ } //画X轴 this.DrawVertical=function() { /* var top=this.ChartBorder.GetTopEx(); //var left=this.ChartBorder.GetLeft(); var right=this.ChartBorder.GetRight(); var bottom=this.ChartBorder.GetBottomEx(); right+=this.RightOffset; this.Canvas.strokeStyle=this.PenBorder; this.Canvas.beginPath(); this.Canvas.moveTo(ToFixedPoint(right),ToFixedPoint(top)); this.Canvas.lineTo(ToFixedPoint(right),ToFixedPoint(bottom)); this.Canvas.stroke(); */ } } function SubFrameItem() { this.Frame; this.Height; this.OverlayIndex=[]; //叠加指标 this.Interval=60; //子坐标间间距 } function OverlayIndexItem() { this.Frame; this.ChartPaint=[]; this.Identify=Guid(); this.Scprit; //脚本 this.UpdateFrameMaxMin=function() //调整坐标最大 最小值 { var value={Max:null, Min:null} if (this.Frame.YSpecificMaxMin) //固定坐标 { value.Max=this.Frame.YSpecificMaxMin.Max; value.Min=this.Frame.YSpecificMaxMin.Min; } else { for(var i in this.ChartPaint) { var paint=this.ChartPaint[i]; var range=paint.GetMaxMin(); if (value.Max==null || value.Maxrange.Min) value.Min=range.Min } } if (value.Max!=null && value.Min!=null) { this.Frame.HorizontalMax=value.Max; this.Frame.HorizontalMin=value.Min; this.Frame.XYSplit=true; } } } //行情框架 function HQTradeFrame() { this.SubFrame=new Array(); //SubFrameItem 数组 this.SizeChange=true; //大小是否改变 this.ChartBorder; this.Canvas; //画布 this.ScreenImageData; //截图 this.Data; //主数据 this.Position; //画布的位置 this.SizeChange=true; this.CalculateChartBorder=function() //计算每个子框架的边框信息 { if (this.SubFrame.length<=0) return; var top=this.ChartBorder.GetTop(); var height=this.ChartBorder.GetHeight(); var totalHeight=0; for(var i in this.SubFrame) { var item=this.SubFrame[i]; totalHeight+=item.Height; } for(var i in this.SubFrame) { var item=this.SubFrame[i]; item.Frame.ChartBorder.Top=top; item.Frame.ChartBorder.Left=this.ChartBorder.Left; item.Frame.ChartBorder.Right=this.ChartBorder.Right; var frameHeight=height*(item.Height/totalHeight)+top; item.Frame.ChartBorder.Bottom=this.ChartBorder.GetChartHeight()-frameHeight; top=frameHeight; } } this.CalculateChartBorder2=function() //计算每个子框架的边框信息(思维导图用) { if (this.SubFrame.length<=0) return; var top=this.ChartBorder.Top; var bottom=this.ChartBorder.Bottom; var height=this.ChartBorder.GetHeight(); var totalHeight=0; for(var i in this.SubFrame) { var item=this.SubFrame[i]; totalHeight+=item.Height; } var tempHeight=0; for(var i in this.SubFrame) { var item=this.SubFrame[i]; item.Frame.ChartBorder.Top=top; item.Frame.ChartBorder.Left=this.ChartBorder.Left; item.Frame.ChartBorder.Right=this.ChartBorder.Right; item.Frame.ChartBorder.X=this.ChartBorder.X; item.Frame.ChartBorder.Y=this.ChartBorder.Y; item.Frame.ChartBorder.Width=this.ChartBorder.Width; item.Frame.ChartBorder.Height=this.ChartBorder.Height; var frameHeight=height*(item.Height/totalHeight); tempHeight+=frameHeight; bottom=this.ChartBorder.Bottom+(height-tempHeight); item.Frame.ChartBorder.Bottom=bottom; top+=frameHeight; } } this.Draw=function() { if (this.SizeChange===true) this.CalculateChartBorder(); for(var i in this.SubFrame) { var item=this.SubFrame[i]; item.Frame.Draw(); var rightOffset=item.Interval; for(var j in item.OverlayIndex) { var overlayItem=item.OverlayIndex[j]; //把主坐标部分设置给子坐标下来 overlayItem.Frame.DataWidth=item.Frame.DataWidth; overlayItem.Frame.DistanceWidth=item.Frame.DistanceWidth; overlayItem.Frame.XPointCount=item.Frame.XPointCount; if (overlayItem.ChartPaint.length>0 && overlayItem.Frame.IsShow) { overlayItem.Frame.RightOffset=rightOffset; overlayItem.Frame.Draw(); rightOffset+=item.Interval; } } } this.SizeChange=false; } this.DrawOveraly=function() { for(var i in this.SubFrame) { var item=this.SubFrame[i]; for(var j in item.OverlayIndex) { var overlayItem=item.OverlayIndex[j]; for(var k in overlayItem.ChartPaint) { if (overlayItem.ChartPaint[k].IsShow) overlayItem.ChartPaint[k].Draw(); } } } } this.DrawLock=function() { for (var i in this.SubFrame) { var item = this.SubFrame[i]; item.Frame.DrawLock(); } } this.CalculateLock=function() { for (var i in this.SubFrame) { var item = this.SubFrame[i]; item.Frame.CalculateLock(); } } this.DrawInsideHorizontal = function () { for (var i in this.SubFrame) { var item = this.SubFrame[i]; if (item.Frame.DrawInsideHorizontal) item.Frame.DrawInsideHorizontal(); } } this.DrawCustomHorizontal=function() //定制坐标 { for (var i in this.SubFrame) { var item = this.SubFrame[i]; if (item.Frame.DrawCustomHorizontal) item.Frame.DrawCustomHorizontal(); } } this.SetSizeChage=function(sizeChange) { this.SizeChange=sizeChange; for(var i in this.SubFrame) { var item=this.SubFrame[i]; item.Frame.SizeChange=sizeChange; for(var j in item.OverlayIndex) { var overlayItem=item.OverlayIndex[j]; if (overlayItem.Frame) overlayItem.Frame.SizeChange=sizeChange; } } //画布的位置 if (this.ChartBorder.UIElement) { this.Position={ X:this.ChartBorder.UIElement.offsetLeft, Y:this.ChartBorder.UIElement.offsetTop, W:this.ChartBorder.UIElement.clientWidth, H:this.ChartBorder.UIElement.clientHeight }; } } //图形快照 this.Snapshot=function() { this.ScreenImageData=this.Canvas.getImageData(0,0,this.ChartBorder.GetChartWidth(),this.ChartBorder.GetChartHeight()); } this.GetXData=function(x) { return this.SubFrame[0].Frame.GetXData(x); } this.GetYData=function(y,outObject) //outObject 可以保存返回的额外数据 { var frame; for(var i in this.SubFrame) { var item=this.SubFrame[i]; var left=item.Frame.ChartBorder.GetLeft(); var top=item.Frame.ChartBorder.GetTopEx(); var width=item.Frame.ChartBorder.GetWidth(); var height=item.Frame.ChartBorder.GetHeightEx(); item.Frame.Canvas.beginPath(); item.Frame.Canvas.rect(left,top,width,height); if (item.Frame.Canvas.isPointInPath(left,y)) { frame=item.Frame; if (outObject) outObject.FrameID=parseInt(i); //转成整形 break; } } if (frame!=null) return frame.GetYData(y); } this.PtInFrame=function(x,y) //鼠标哪个指标窗口 { for(var i in this.SubFrame) { var item=this.SubFrame[i]; var left=item.Frame.ChartBorder.GetLeft(); var top=item.Frame.ChartBorder.GetTop(); var width=item.Frame.ChartBorder.GetWidth(); var height=item.Frame.ChartBorder.GetHeight(); item.Frame.Canvas.beginPath(); item.Frame.Canvas.rect(left,top,width,height); if (item.Frame.Canvas.isPointInPath(x,y)) { return parseInt(i); //转成整形 } } return -1; } this.GetXFromIndex=function(index) { return this.SubFrame[0].Frame.GetXFromIndex(index); } this.GetYFromData=function(value) { return this.SubFrame[0].Frame.GetYFromData(value); } this.ZoomUp=function(cursorIndex) { var result=this.SubFrame[0].Frame.ZoomUp(cursorIndex); var mainFrame=this.SubFrame[0].Frame; for(var i=0;i0) //第1个窗口主坐标已经算好了 { item.Frame.XPointCount= mainFrame.XPointCount; item.Frame.ZoomIndex= mainFrame.ZoomIndex; item.Frame.DataWidth= mainFrame.DataWidth; item.Frame.DistanceWidth= mainFrame.DistanceWidth; item.Frame.LastCalculateStatus.Width=mainFrame.LastCalculateStatus.Width; item.Frame.LastCalculateStatus.XPointCount=mainFrame.LastCalculateStatus.XPointCount; } for(var j in item.OverlayIndex) { var overlayItem=this.SubFrame[i].OverlayIndex[j]; overlayItem.Frame.XPointCount= mainFrame.XPointCount; overlayItem.Frame.ZoomIndex= mainFrame.ZoomIndex; overlayItem.Frame.DataWidth= mainFrame.DataWidth; overlayItem.Frame.DistanceWidth= mainFrame.DistanceWidth; overlayItem.Frame.LastCalculateStatus.Width=mainFrame.LastCalculateStatus.Width; overlayItem.Frame.LastCalculateStatus.XPointCount=mainFrame.LastCalculateStatus.XPointCount; } } return result; } this.ZoomDown=function(cursorIndex) { var result=this.SubFrame[0].Frame.ZoomDown(cursorIndex); var mainFrame=this.SubFrame[0].Frame; for(var i=0;i0) //第1个窗口主坐标已经算好了 { item.Frame.XPointCount= mainFrame.XPointCount; item.Frame.ZoomIndex= mainFrame.ZoomIndex; item.Frame.DataWidth= mainFrame.DataWidth; item.Frame.DistanceWidth= mainFrame.DistanceWidth; item.Frame.LastCalculateStatus.Width=mainFrame.LastCalculateStatus.Width; item.Frame.LastCalculateStatus.XPointCount=mainFrame.LastCalculateStatus.XPointCount; } for(var j in item.OverlayIndex) { var overlayItem=this.SubFrame[i].OverlayIndex[j]; overlayItem.Frame.XPointCount= mainFrame.XPointCount; overlayItem.Frame.ZoomIndex= mainFrame.ZoomIndex; overlayItem.Frame.DataWidth= mainFrame.DataWidth; overlayItem.Frame.DistanceWidth= mainFrame.DistanceWidth; overlayItem.Frame.LastCalculateStatus.Width=mainFrame.LastCalculateStatus.Width; overlayItem.Frame.LastCalculateStatus.XPointCount=mainFrame.LastCalculateStatus.XPointCount; } } return result; } //设置重新计算刻度坐标 this.ResetXYSplit=function() { for(let i in this.SubFrame) { this.SubFrame[i].Frame.XYSplit=true; } } this.SetLanguage=function(languageID) { for(let i in this.SubFrame) { var item=this.SubFrame[i]; if (item && item.Frame ) { if (item.Frame.YSplitOperator) item.Frame.YSplitOperator.LanguageID=languageID; if (item.Frame.XSplitOperator) item.Frame.XSplitOperator.LanguageID=languageID; } } } } //行情框架横屏 function HQTradeHScreenFrame() { this.newMethod=HQTradeFrame; //派生 this.newMethod(); delete this.newMethod; this.IsHScreen=true; //是否是横屏 this.CalculateChartBorder=function() //计算每个子框架的边框信息 { if (this.SubFrame.length<=0) return; var right=this.ChartBorder.Right; var left=this.ChartBorder.GetRight(); var width=this.ChartBorder.GetWidth(); var totalHeight=0; for(var i in this.SubFrame) { var item=this.SubFrame[i]; totalHeight+=item.Height; } for(var i in this.SubFrame) { var item=this.SubFrame[i]; item.Frame.ChartBorder.Top=this.ChartBorder.Top; item.Frame.ChartBorder.Bottom=this.ChartBorder.Bottom; var frameWidth=width*(item.Height/totalHeight); item.Frame.ChartBorder.Right=right; item.Frame.ChartBorder.Left=left-frameWidth; right+=frameWidth; left-=frameWidth; } } this.GetYData=function(x,outObject) { var frame; for(var i in this.SubFrame) { var item=this.SubFrame[i]; var left=item.Frame.ChartBorder.GetLeftEx(); var top=item.Frame.ChartBorder.GetTop(); var width=item.Frame.ChartBorder.GetWidthEx(); var height=item.Frame.ChartBorder.GetHeight(); item.Frame.Canvas.beginPath(); item.Frame.Canvas.rect(left,top,width,height); if (item.Frame.Canvas.isPointInPath(x,top)) { frame=item.Frame; if (outObject) outObject.FrameID=i; break; } } if (frame!=null) return frame.GetYData(x); } } function SimpleChartFrame() { this.newMethod=AverageWidthFrame; //派生 this.newMethod(); delete this.newMethod; this.ScreenImageData; //截图 this.Position; //画布的位置 this.DrawFrame=function() { if (this.XPointCount>0) { let dInterval=this.ChartBorder.GetWidth()/(6*this.XPointCount); //分6份, 数据4 间距2 this.DistanceWidth=2*dInterval; this.DataWidth=4*dInterval; } this.SplitXYCoordinate(); this.DrawHorizontal(); this.DrawVertical(); } this.GetXFromIndex=function(index) { if (index < 0) index = 0; if (index > this.xPointCount - 1) index = this.xPointCount - 1; var offset=this.ChartBorder.GetLeft()+2+this.DistanceWidth/2+this.DataWidth/2; for(var i=1;i<=index;++i) { offset+=this.DistanceWidth+this.DataWidth; } return offset; } //分割x,y轴坐标信息 this.SplitXYCoordinate=function() { if (this.XYSplit==false) return; if (this.YSplitOperator!=null) this.YSplitOperator.Operator(); if (this.XSplitOperator!=null) this.XSplitOperator.Operator(); } //图形快照 this.Snapshot=function() { this.ScreenImageData=this.Canvas.getImageData(0,0,this.ChartBorder.GetChartWidth(),this.ChartBorder.GetChartHeight()); } this.SetSizeChage=function(sizeChange) { this.SizeChange=sizeChange; //画布的位置 this.Position={ X:this.ChartBorder.UIElement.offsetLeft, Y:this.ChartBorder.UIElement.offsetTop, W:this.ChartBorder.UIElement.clientWidth, H:this.ChartBorder.UIElement.clientHeight }; } } //历史K线数据 function HistoryData() { this.Date; this.YClose; this.Open; this.Close; this.High; this.Low; this.Vol; this.Amount; this.Time; this.FlowCapital=0; //流通股本 //指数才有的数据 this.Stop; //停牌家数 this.Up; //上涨 this.Down; //下跌 this.Unchanged; //平盘 } //数据复制 HistoryData.Copy=function(data) { var newData=new HistoryData(); newData.Date=data.Date; newData.YClose=data.YClose; newData.Open=data.Open; newData.Close=data.Close; newData.High=data.High; newData.Low=data.Low; newData.Vol=data.Vol; newData.Amount=data.Amount; newData.Time=data.Time; newData.FlowCapital=data.FlowCapital; newData.Stop=data.Stop; newData.Up=data.Up; newData.Down=data.Down; newData.Unchanged=data.Unchanged; return newData; } //把数据 src 复制到 dest中 HistoryData.CopyTo=function(dest,src) { dest.Date=src.Date; dest.YClose=src.YClose; dest.Open=src.Open; dest.Close=src.Close; dest.High=src.High; dest.Low=src.Low; dest.Vol=src.Vol; dest.Amount=src.Amount; dest.Time=src.Time; dest.FlowCapital=src.FlowCapital; dest.Stop=src.Stop; dest.Up=src.Up; dest.Down=src.Down; dest.Unchanged=src.Unchanged; } //数据复权拷贝 HistoryData.CopyRight=function(data,seed) { var newData=new HistoryData(); newData.Date=data.Date; newData.YClose=data.YClose*seed; newData.Open=data.Open*seed; newData.Close=data.Close*seed; newData.High=data.High*seed; newData.Low=data.Low*seed; newData.Vol=data.Vol; newData.Amount=data.Amount; newData.FlowCapital=data.FlowCapital; return newData; } function MinuteData() { this.Close; this.Open; this.High; this.Low; this.Vol; this.Amount; this.DateTime; this.Increase; this.Risefall; this.AvPrice; this.Lead=null; this.Time; this.Date; } //单指标数据 function SingleData() { this.Date; //日期 this.Time; //时间 this.Value; //数据 (可以是一个数组) } var KLINE_INFO_TYPE= { INVESTOR:1, //互动易 ANNOUNCEMENT:2, //公告 PFORECAST:3, //业绩预告 ANNOUNCEMENT_QUARTER_1:4, //一季度报 ANNOUNCEMENT_QUARTER_2:5, //半年报 ANNOUNCEMENT_QUARTER_3:6, //2季度报 ANNOUNCEMENT_QUARTER_4:7, //年报 RESEARCH:8, //调研 BLOCKTRADING:9, //大宗交易 TRADEDETAIL:10 //龙虎榜 } function KLineInfoData() { this.ID; this.Date; this.Title; this.InfoType; this.ExtendData; //扩展数据 } function DataPlus () { }; //外部数据计算方法接口 DataPlus.GetMinutePeriodData=null; /* DataPlus.GetMinutePeriodData=function(period,data,self) { } */ function ChartData() { this.Data=new Array(); this.DataOffset=0; //数据偏移 this.Period=0; //周期 0 日线 1 周线 2 月线 3年线 this.Right=0; //复权 0 不复权 1 前复权 2 后复权 this.Symbol; //股票代码 this.Data2=new Array(); //第1组数据 走势图:历史分钟数据 this.GetCloseMA=function(dayCount) { var result=new Array(); for (var i = 0, len = this.Data.length; i < len; i++) { if (i < dayCount) { result[i]=null; continue; } var sum = 0; for (var j = 0; j < dayCount; j++) { sum += this.Data[i - j].Close; } result[i]=sum / dayCount; } return result; } this.GetVolMA=function(dayCount) { var result=new Array(); for (var i = 0, len = this.Data.length; i < len; i++) { if (i < dayCount) { result[i]=null; continue; } var sum = 0; for (var j = 0; j < dayCount; j++) { sum += this.Data[i - j].Vol; } result[i]=sum / dayCount; } return result; } this.GetAmountMA=function(dayCount) { var result=new Array(); for (var i = 0, len = this.Data.length; i < len; i++) { if (i < dayCount) { result[i]=null; continue; } var sum = 0; for (var j = 0; j < dayCount; j++) { sum += this.Data[i - j].Amount; } result[i]=sum / dayCount; } return result; } //获取收盘价 this.GetClose=function() { var result=new Array(); for(var i in this.Data) { result[i]=this.Data[i].Close; } return result; } this.GetYClose=function() { var result=new Array(); for(var i in this.Data) { result[i]=this.Data[i].YClose; } return result; } this.GetHigh=function() { var result=new Array(); for(var i in this.Data) { result[i]=this.Data[i].High; } return result; } this.GetLow=function() { var result=new Array(); for(var i in this.Data) { result[i]=this.Data[i].Low; } return result; } this.GetOpen=function() { var result=new Array(); for(var i in this.Data) { result[i]=this.Data[i].Open; } return result; } this.GetVol=function() { var result=new Array(); for(var i in this.Data) { result[i]=this.Data[i].Vol; } return result; } this.GetAmount=function() { var result=new Array(); for(var i in this.Data) { result[i]=this.Data[i].Amount; } return result; } this.GetLead=function() { var result=new Array(); for(var i in this.Data) { result[i]=this.Data[i].Lead; } return result; } this.GetDate=function() { var result=new Array(); for(var i in this.Data) { result[i]=this.Data[i].Date; } return result; } this.GetTime=function() { var result=new Array(); for(var i in this.Data) { result[i]=this.Data[i].Time; } return result; } this.GetUp=function() //上涨家数 { var result=[]; for(var i in this.Data) { result[i]=this.Data[i].Up; } return result; } this.GetDown=function() //下跌家数 { var result=[]; for(var i in this.Data) { result[i]=this.Data[i].Down; } return result; } this.GetYear=function() { var result=new Array(); for(var i in this.Data) { result[i]=parseInt(this.Data[i].Date/10000); } return result; } this.GetMonth=function() { var result=new Array(); for(var i in this.Data) { result[i]=parseInt(this.Data[i].Date%10000/100); } return result; } //计算分钟 this.GetMinutePeriodData=function(period) { if (DataPlus.GetMinutePeriodData) return DataPlus.GetMinutePeriodData(period,this.Data,this); var result = new Array(); var periodDataCount = 5; if (period == 5) periodDataCount = 5; else if (period == 6) periodDataCount = 15; else if (period == 7) periodDataCount = 30; else if (period == 8) periodDataCount = 60; else if (period==11) periodDataCount=120; else if (period==12) periodDataCount=240; else if (period>CUSTOM_MINUTE_PERIOD_START && period<=CUSTOM_MINUTE_PERIOD_END) { periodDataCount=period-CUSTOM_MINUTE_PERIOD_START; return this.GetMinuteCustomPeriodData(periodDataCount); } else return this.Data; var bFirstPeriodData = false; var newData = null; var preTime=null; //上一次的计算时间 for (var i = 0; i < this.Data.length; ) { bFirstPeriodData = true; for (var j = 0; j < periodDataCount && i < this.Data.length; ++i) { if (bFirstPeriodData) { newData = new HistoryData(); result.push(newData); bFirstPeriodData = false; } var minData = this.Data[i]; if (minData == null) { ++j; continue; } if (minData.Time==925 && (preTime==null || preTime!=924)) //9:25, 9:30 不连续就不算个数 { } else if (minData.Time == 930 && (preTime==null || preTime!=929) ) { } else if (minData.Time == 1300 && (preTime==null || preTime!=1259) ) //1点的数据 如果不是连续的 就不算个数 { } else ++j; newData.Date = minData.Date; newData.Time = minData.Time; preTime=newData.Time; if (minData.Open==null || minData.Close==null) continue; if (newData.Open==null || newData.Close==null) { newData.Open=minData.Open; newData.High=minData.High; newData.Low=minData.Low; newData.YClose=minData.YClose; newData.Close=minData.Close; newData.Vol=minData.Vol; newData.Amount=minData.Amount; newData.FlowCapital=minData.FlowCapital; } else { if (newData.HighminData.Low) newData.Low=minData.Low; newData.Close=minData.Close; newData.Vol+=minData.Vol; if (minData.Amount!=null) newData.Amount+=minData.Amount; newData.FlowCapital=minData.FlowCapital; } if (i+1 < this.Data.length) //判断下一个数据是否是不同日期的 { var nextItem=this.Data[i+1]; if (nextItem && nextItem.Date!=minData.Date) //不同日期的, 周期结束 { ++i; break; } } } } return result; } //自定义分钟 this.GetMinuteCustomPeriodData=function(count) { var result = new Array(); var periodDataCount = count; var bFirstPeriodData = false; var newData = null; for (var i = 0; i < this.Data.length; ) { bFirstPeriodData = true; for (var j = 0; j < periodDataCount && i < this.Data.length; ++i, ++j) { if (bFirstPeriodData) { newData = new HistoryData(); result.push(newData); bFirstPeriodData = false; } var minData = this.Data[i]; if (minData == null) continue; newData.Date = minData.Date; newData.Time = minData.Time; if (minData.Open==null || minData.Close==null) continue; if (newData.Open==null || newData.Close==null) { newData.Open=minData.Open; newData.High=minData.High; newData.Low=minData.Low; newData.YClose=minData.YClose; newData.Close=minData.Close; newData.Vol=minData.Vol; newData.Amount=minData.Amount; newData.FlowCapital=minData.FlowCapital; } else { if (newData.HighminData.Low) newData.Low=minData.Low; newData.Close=minData.Close; newData.Vol+=minData.Vol; if (minData.Amount!=null) newData.Amount+=minData.Amount; //null数据不相加 newData.FlowCapital=minData.FlowCapital; } } } return result; } //计算周,月,年 this.GetDayPeriodData=function(period) { if (period>CUSTOM_DAY_PERIOD_START && period<=CUSTOM_DAY_PERIOD_END) return this.GetDayCustomPeriodData(period-CUSTOM_DAY_PERIOD_START); var isBit=MARKET_SUFFIX_NAME.IsBIT(this.Symbol); var result=new Array(); var index=0; var startDate=0; var newData=null; for(var i in this.Data) { var isNewData=false; var dayData=this.Data[i]; switch(period) { case 1: //周线 if (isBit) //数字货币全年的 { var sundayDate=ChartData.GetSunday(dayData.Date); if (sundayDate!=startDate) { isNewData=true; startDate=sundayDate; } } else { var fridayDate=ChartData.GetFirday(dayData.Date); if (fridayDate!=startDate) { isNewData=true; startDate=fridayDate; } } break; case 2: //月线 if (parseInt(dayData.Date/100)!=parseInt(startDate/100)) { isNewData=true; startDate=dayData.Date; } break; case 3: //年线 if (parseInt(dayData.Date/10000)!=parseInt(startDate/10000)) { isNewData=true; startDate=dayData.Date; } break; case 9: //季线 var now=ChartData.GetQuarter(dayData.Date); now=parseInt(dayData.Date/10000)*10+now; var last=ChartData.GetQuarter(startDate); last=parseInt(startDate/10000)*10+last; if (now!=last) { isNewData=true; startDate=dayData.Date; } break; } if (isNewData) { newData=new HistoryData(); newData.Date=dayData.Date; result.push(newData); if (dayData.Open==null || dayData.Close==null) continue; newData.Open=dayData.Open; newData.High=dayData.High; newData.Low=dayData.Low; newData.YClose=dayData.YClose; newData.Close=dayData.Close; newData.Vol=dayData.Vol; newData.Amount=dayData.Amount; newData.FlowCapital=dayData.FlowCapital; } else { if (newData==null) continue; if (dayData.Open==null || dayData.Close==null) continue; if (newData.Open==null || newData.Close==null) { newData.Open=dayData.Open; newData.High=dayData.High; newData.Low=dayData.Low; newData.YClose=dayData.YClose; newData.Close=dayData.Close; newData.Vol=dayData.Vol; newData.Amount=dayData.Amount; newData.FlowCapital=dayData.FlowCapital; } else { if (newData.HighdayData.Low) newData.Low=dayData.Low; newData.Close=dayData.Close; newData.Vol+=dayData.Vol; if (dayData.Amount!=null) newData.Amount+=dayData.Amount; newData.FlowCapital=dayData.FlowCapital; newData.Date=dayData.Date; } } } return result; } this.GetDayCustomPeriodData=function(count) { var result = []; var periodDataCount = count; var bFirstPeriodData = false; var newData = null; for (var i = 0; i < this.Data.length; ) { bFirstPeriodData = true; for (var j = 0; j < periodDataCount && i < this.Data.length; ++i, ++j) { if (bFirstPeriodData) { newData = new HistoryData(); result.push(newData); bFirstPeriodData = false; } var dayData = this.Data[i]; if (dayData == null) continue; newData.Date = dayData.Date; if (dayData.Open==null || dayData.Close==null) continue; if (newData.Open==null || newData.Close==null) { newData.Open=dayData.Open; newData.High=dayData.High; newData.Low=dayData.Low; newData.YClose=dayData.YClose; newData.Close=dayData.Close; newData.Vol=dayData.Vol; newData.Amount=dayData.Amount; newData.FlowCapital=dayData.FlowCapital; } else { if (newData.HighdayData.Low) newData.Low=dayData.Low; newData.Close=dayData.Close; newData.Vol+=dayData.Vol; if (dayData.Amount!=null) newData.Amount+=dayData.Amount; newData.FlowCapital=dayData.FlowCapital; } } } return result; } //周期数据 1=周 2=月 3=年 this.GetPeriodData=function(period) { if (MARKET_SUFFIX_NAME.IsBIT(this.Symbol)) { if (period==5 || period==6 || period==7 || period==8 || (period>CUSTOM_MINUTE_PERIOD_START && period<=CUSTOM_MINUTE_PERIOD_END)) //分钟K线 { var periodDataCount = 5; if (period == 5) periodDataCount = 5; else if (period == 6) periodDataCount = 15; else if (period == 7) periodDataCount = 30; else if (period == 8) periodDataCount = 60; else if (period==11) periodDataCount = 120; else if (period==12) periodDataCount = 240; else if (period>CUSTOM_MINUTE_PERIOD_START && period<=CUSTOM_MINUTE_PERIOD_END) periodDataCount=period-CUSTOM_MINUTE_PERIOD_START; return this.GetMinuteCustomPeriodData(periodDataCount); } } if (period==1 || period==2 || period==3 || period==9 || (period>CUSTOM_DAY_PERIOD_START && period<=CUSTOM_DAY_PERIOD_END)) return this.GetDayPeriodData(period); if (period==5 || period==6 || period==7 || period==8 || period==11 || period==12 || (period>CUSTOM_MINUTE_PERIOD_START && period<=CUSTOM_MINUTE_PERIOD_END)) return this.GetMinutePeriodData(period); } //复权 0 不复权 1 前复权 2 后复权 this.GetRightDate=function(right) { var result=[]; if (this.Data.length<=0) return result; if (right==1) { var index=this.Data.length-1; var seed=1; //复权系数 var yClose=this.Data[index].YClose; result[index]=HistoryData.Copy(this.Data[index]); for(--index; index>=0; --index) { if (yClose!=this.Data[index].Close) break; result[index]=HistoryData.Copy(this.Data[index]); yClose=this.Data[index].YClose; } for(; index>=0; --index) { if(yClose!=this.Data[index].Close) seed *= yClose/this.Data[index].Close; result[index]=HistoryData.CopyRight(this.Data[index],seed); yClose=this.Data[index].YClose; } } else if (right==2) { var index=0; var seed=1; var close=this.Data[index].Close; result[index]=HistoryData.Copy(this.Data[index]); for(++index;index=overlayData.length) { result[i]=new HistoryData(); result[i].Date=date; ++i; continue;; } var overlayDate=overlayData[j].Date; if (overlayDate==date) { result[i]=new HistoryData(); result[i].Date=overlayData[j].Date; result[i].YClose=overlayData[j].YClose; result[i].Open=overlayData[j].Open; result[i].High=overlayData[j].High; result[i].Low=overlayData[j].Low; result[i].Close=overlayData[j].Close; result[i].Vol=overlayData[j].Vol; result[i].Amount=overlayData[j].Amount; //涨跌家数数据 result[i].Stop=overlayData[j].Stop; result[i].Up=overlayData[j].Up; result[i].Down=overlayData[j].Down; result[i].Unchanged=overlayData[j].Unchanged; ++j; ++i; } else if (overlayDate=overlayData.length) { result[i]=new HistoryData(); result[i].Date=date; result[i].Time=time; ++i; continue;; } var overlayDate=overlayData[j].Date; var overlayTime=overlayData[j].Time; if (overlayDate==date && overlayTime==time) { result[i]=new HistoryData(); result[i].Date=overlayData[j].Date; result[i].Time=overlayData[j].Time; result[i].YClose=overlayData[j].YClose; result[i].Open=overlayData[j].Open; result[i].High=overlayData[j].High; result[i].Low=overlayData[j].Low; result[i].Close=overlayData[j].Close; result[i].Vol=overlayData[j].Vol; result[i].Amount=overlayData[j].Amount; //涨跌家数数据 result[i].Stop=overlayData[j].Stop; result[i].Up=overlayData[j].Up; result[i].Down=overlayData[j].Down; result[i].Unchanged=overlayData[j].Unchanged; ++j; ++i; } else if (overlayDate=overlayData.length) { result[i]=null; ++i; continue;; } var overlayDate=overlayData[j].Date; if (overlayDate==date) { var item=new SingleData(); item.Date=overlayData[j].Date; item.Value=overlayData[j].Value; result[i]=item; ++j; ++i; } else if (overlayDate=overlayData.length) { result[i]=new SingleData(); result[i].Date=date; result[i].Value=emptyValue; ++i; continue;; } var overlayDate=overlayData[j].Date; if (overlayDate==date) { var item=new SingleData(); item.Date=overlayData[j].Date; item.Value=overlayData[j].Value; result[i]=item; ++j; ++i; } else if (overlayDate=data.length) break; var dateItem=data[j]; if (dateItem.Date==date) { dateItem.Index=i; ++j; } else if (dateItem.Date=data.length) break; var dateTimeItem=data[j]; if (dateTimeItem.Date==date && dateTimeItem.Time==time) { dateTimeItem.Index=i; ++j; } else if (dateTimeItem.Date=overlayData.length) { result[i]=null; ++i; continue;; } var overlayDate=overlayData[j].Date; var overlayTime=overlayData[j].Time; const overlayItem=overlayData[j]; if (overlayDate==date && overlayTime==time) { var item=new SingleData(); item.Date=overlayItem.Date; item.Time=overlayItem.Time; item.Value=overlayItem.Value; result[i]=item; ++j; ++i; } else if (overlayDate=overlayData.length) { result[i]=null; ++i; continue;; } var overlayDate=overlayData[j].Date; if (overlayDate==date) { var item=new SingleData(); item.Date=overlayData[j].Date; item.Value=overlayData[j].Value; item.Text=overlayData[j].Text; result[i]=item; ++j; ++i; } else if (preDate!=null && preDateoverlayDate) { var item=new SingleData(); item.Date=date; item.OverlayDate=overlayData[j].Date; item.Value=overlayData[j].Value; item.Text=overlayData[j].Text; result[i]=item; ++j; ++i; } else if (overlayDate=0;--i) { var date=this.Data[i].Date; var time=this.Data[i].Time; if (firstItem.Date>=date && firstItem.Time>=time) { index=i; break; } } if (index==null) return false; for(var j=index,i=0;i=this.Data.length-1) { if (j-1>0 && !item.YClose) item.YClose=this.Data[j-1].YClose; //前收盘如果没有就是上一记录的收盘 var newItem=HistoryData.Copy(item); this.Data[j]=newItem; ++j; ++i; } else { var oldItem=this.Data[j]; if (oldItem.Date==item.Date && oldItem.Time==item.Time) //更新数据 { HistoryData.CopyTo(oldItem,item); ++j; ++i; } else { ++j; } } } //console.log('[ChartData::MergeMinuteData] ', this.Data, data); return true; } } ChartData.GetFirday=function(value) { var date=new Date(parseInt(value/10000),(value/100%100-1),value%100); var day=date.getDay(); if (day==5) return value; var timestamp=date.getTime(); if (day<5) { var prevTimestamp=(24*60*60*1000)*(5-day); timestamp+=prevTimestamp; } else { var prevTimestamp=(24*60*60*1000)*(day-5); timestamp-=prevTimestamp; } date.setTime(timestamp); var fridayDate= date.getFullYear()*10000+(date.getMonth()+1)*100+date.getDate(); var week=date.getDay(); return fridayDate; } ChartData.GetSunday=function(value) { var date=new Date(parseInt(value/10000),(value/100%100-1),value%100); var day=date.getDay(); if (day==0) return value; var timestamp=date.getTime(); if (day>0) { var prevTimestamp=(24*60*60*1000)*(7-day); timestamp+=prevTimestamp; } date.setTime(timestamp); var sundayDate= date.getFullYear()*10000+(date.getMonth()+1)*100+date.getDate(); var week=date.getDay(); return sundayDate; } ChartData.GetQuarter=function(value) { var month=parseInt(value%10000/100); if (month==1 || month==2 || month==3) return 1; else if (month==4 || month==5 || month==6) return 2; else if (month==7 || month==8 || month==9) return 3; else if (month==10 || month==11 || month==12) return 4; else return 0; } //是否是日线周期 0=日线 1=周线 2=月线 3=年线 9=季线 [40001-50000] 自定义日线 (isIncludeBase 是否包含基础日线周期) var CUSTOM_DAY_PERIOD_START=40000, CUSTOM_DAY_PERIOD_END=50000; ChartData.IsDayPeriod=function(period, isIncludeBase) { if (period==1 || period==2 || period==3 || period==9) return true; if (period>CUSTOM_DAY_PERIOD_START && period<=CUSTOM_DAY_PERIOD_END) return true; if (period==0 && isIncludeBase==true) return true; return false; } //是否是分钟周期 4=1分钟 5=5分钟 6=15分钟 7=30分钟 8=60分钟 11=120分钟 12=240分钟 [20001-30000] 自定义分钟 (isIncludeBase 是否包含基础1分钟周期) var CUSTOM_MINUTE_PERIOD_START=20000, CUSTOM_MINUTE_PERIOD_END=30000; ChartData.IsMinutePeriod=function(period,isIncludeBase) { if (period==5 || period==6 || period==7 || period==8 ||period==11 || period==12) return true; if (period>CUSTOM_MINUTE_PERIOD_START && period<=CUSTOM_MINUTE_PERIOD_END) return true; if (period==4 && isIncludeBase==true) return true; return false; } //是否是分笔图 10=分笔 ChartData.IsTickPeriod=function(period) { return period==10; } function TooltipData() //提示信息 { this.ChartPaint; this.Data; this.Type=0; } function Rect(x,y,width,height) { this.X=x, this.Y=y; this.Width=width; this.Height=height; } //图新画法接口类 function IChartPainting() { this.Canvas; //画布 this.ChartBorder; //边框信息 this.ChartFrame; //框架画法 this.Name; //名称 this.ClassName='IChartPainting'; //类名 this.Data=new ChartData(); //数据区 this.NotSupportMessage=null; this.MessageFont=g_JSChartResource.Index.NotSupport.Font; this.MessageColor=g_JSChartResource.Index.NotSupport.TextColor; this.IsDrawFirst=false; this.IsShow=true; this.Draw=function() { } this.DrawNotSupportmessage=function() { this.Canvas.font=this.MessageFont; this.Canvas.fillStyle=this.MessageColor; var left=this.ChartBorder.GetLeft(); var width=this.ChartBorder.GetWidth(); var top=this.ChartBorder.GetTopEx(); var height=this.ChartBorder.GetHeightEx(); var x=left+width/2; var y=top+height/2; this.Canvas.textAlign="center"; this.Canvas.textBaseline="middle"; this.Canvas.fillText(this.NotSupportMessage,x,y); } this.GetTooltipData=function(x,y,tooltip) { return false; } this.GetMaxMin=function() { var xPointCount=this.ChartFrame.XPointCount; var range={}; range.Min=null; range.Max=null; if(!this.Data || !this.Data.Data) return range; for(var i=this.Data.DataOffset,j=0;ivalue) range.Min=value; } return range; } this.GetDynamicFont=function(dataWidth) //根据宽度自动获取对应字体 { var pixelTatio = GetDevicePixelRatio(); var font; if (dataWidth < 5) font =4*pixelTatio + 'px Arial'; //字体根据数据宽度动态调整 else if (dataWidth < 7) font = 6*pixelTatio +'px Arial'; else if (dataWidth < 9) font = 8*pixelTatio +'px Arial'; else if (dataWidth < 11) font =10*pixelTatio +'px Arial'; else if (dataWidth < 13) font =12*pixelTatio +'px Arial'; else if (dataWidth < 15) font =14*pixelTatio + 'px Arial'; else font =16*pixelTatio + 'px Arial'; return font; } this.GetLockRect=function() { return this.ChartFrame.GetLockRect(); } } //缩放因子 /* var ZOOM_SEED= [ [49,10], [46,9], [43,8], [41,7.5], [39,7], [37,6], [31,5.5], [27,5], [23,4.5], [21,4], [18,3.5], [16,3], [13,2.5], [11,2], [8,1.5], [6,1], [3,0.6], [2.2,0.5], //太多了卡, //[1.1,0.3], //[0.9,0.2], [0.7,0.15], //[0.6,0.12], [0.5,0.1], [0.4,0.08], //[0.3,0.06], [0.2,0.04], [0.1,0.02] ]; */ var ZOOM_SEED= //0=柱子宽度 1=间距 [ [48,10], [44,10], [40,9], [36,9], [32,8], [28,8], [24,7], [20,7], [18,6], [16,6], [14,5], [12,5], [8,4], [6,4], [4,4], [3,3], [3,1], [2,1], [1,1], [1,0], ]; //K线画法 支持横屏 function ChartKLine() { this.newMethod=IChartPainting; //派生 this.newMethod(); delete this.newMethod; this.ClassName='ChartKLine'; //类名 this.Symbol; //股票代码 this.DrawType=0; // 0=实心K线柱子 1=收盘价线 2=美国线 3=空心K线柱子 4=收盘价面积图 this.CloseLineColor=g_JSChartResource.CloseLineColor; this.CloseLineAreaColor=g_JSChartResource.CloseLineAreaColor; this.UpColor=g_JSChartResource.UpBarColor; this.DownColor=g_JSChartResource.DownBarColor; this.UnchagneColor=g_JSChartResource.UnchagneBarColor; //平盘 this.ColorData; //五彩K线颜色 >0:g_JSChartResource.UpBarColor 其他:g_JSChartResource.DownBarColor this.TradeData; //交易系统 包含买卖数据{Buy:, Sell:} this.TradeIcon=g_JSChartResource.KLine.TradeIcon; this.TooltipRect=new Array(); //2位数组 0 数据序号 1 区域 this.InfoTooltipRect=[]; //2维数组 0 数据, 1 区域 this.IsShowMaxMinPrice=true; //是否显示最大最小值 this.IsShowKTooltip=true; //是否显示K线tooltip this.TextFont=g_JSChartResource.KLine.MaxMin.Font; this.TextColor=g_JSChartResource.KLine.MaxMin.Color; this.InfoData; //信息地雷 key=日期 value=信息数据 this.InfoPosition=0; // 0=K线上 1 底部 this.PtMax; //最大值的位置 this.PtMin; //最小值的位置 this.TickSymbol='╳'; //分笔显示的图标 this.TickFontName='arial'; this.Period; //周期 this.DrawAKLine=function() //美国线 { var isHScreen=(this.ChartFrame.IsHScreen===true); var dataWidth=this.ChartFrame.DataWidth; var distanceWidth=this.ChartFrame.DistanceWidth; var xOffset=this.ChartBorder.GetLeft()+distanceWidth/2.0+2.0; if (isHScreen) xOffset=this.ChartBorder.GetTop()+distanceWidth/2.0+2.0; var chartright=this.ChartBorder.GetRight(); if (isHScreen) chartright=this.ChartBorder.GetBottom(); var xPointCount=this.ChartFrame.XPointCount; var upColor=this.UpColor; var downColor=this.DownColor; var unchagneColor=this.UnchagneColor; var ptMax={X:null,Y:null,Value:null,Align:'left'}; var ptMin={X:null,Y:null,Value:null,Align:'left'}; for(var i=this.Data.DataOffset,j=0;ichartright) break; var x=left+(right-left)/2; var yLow=this.ChartFrame.GetYFromData(data.Low); var yHigh=this.ChartFrame.GetYFromData(data.High); var yOpen=this.ChartFrame.GetYFromData(data.Open); var yClose=this.ChartFrame.GetYFromData(data.Close); if (ptMax.Value==null || ptMax.Valuedata.Low) //求最小值 { ptMin.X=x; ptMin.Y=yLow; ptMin.Value=data.Low; ptMin.Align=jdata.Close) this.Canvas.strokeStyle=this.DownColor; //阳线 else this.Canvas.strokeStyle=this.UnchagneColor; //平线 if (this.ColorData) ///五彩K线颜色设置 { if (i0?this.UpColor:this.DownColor); else upColor=downColor=unchagneColor=this.DownColor; } this.Canvas.beginPath(); //最高-最低 if (isHScreen) { this.Canvas.moveTo(yHigh,ToFixedPoint(x)); this.Canvas.lineTo(yLow,ToFixedPoint(x)); } else { this.Canvas.moveTo(ToFixedPoint(x),yHigh); this.Canvas.lineTo(ToFixedPoint(x),yLow); } this.Canvas.stroke(); if (dataWidth>=4) { this.Canvas.beginPath(); //开盘 if (isHScreen) { this.Canvas.moveTo(ToFixedPoint(yOpen),left); this.Canvas.lineTo(ToFixedPoint(yOpen),x); } else { this.Canvas.moveTo(left,ToFixedPoint(yOpen)); this.Canvas.lineTo(x,ToFixedPoint(yOpen)); } this.Canvas.stroke(); this.Canvas.beginPath(); //收盘 if (isHScreen) { this.Canvas.moveTo(ToFixedPoint(yClose),right); this.Canvas.lineTo(ToFixedPoint(yClose),x); } else { this.Canvas.moveTo(right,ToFixedPoint(yClose)); this.Canvas.lineTo(x,ToFixedPoint(yClose)); } this.Canvas.stroke(); } if(this.Data.DataType==0) { var infoItem={Xleft:left,XRight:right, YMax:yHigh, XCenter:x, YMin:yLow, DayData:data, Index:j}; this.DrawInfo(infoItem); } } this.PtMax=ptMax; this.PtMin=ptMin; } this.DrawCloseArea=function() //收盘价面积图 { var isHScreen=(this.ChartFrame.IsHScreen===true); var dataWidth=this.ChartFrame.DataWidth; var distanceWidth=this.ChartFrame.DistanceWidth; var xOffset=this.ChartBorder.GetLeft()+distanceWidth/2.0+2.0; if (isHScreen) xOffset=this.ChartBorder.GetTop()+distanceWidth/2.0+2.0; var chartright=this.ChartBorder.GetRight(); if (isHScreen) chartright=this.ChartBorder.GetBottom(); var xPointCount=this.ChartFrame.XPointCount; var bFirstPoint=true; var firstPoint=null; this.Canvas.beginPath(); this.Canvas.strokeStyle=this.CloseLineColor; for(var i=this.Data.DataOffset,j=0;ichartright) break; var x=left+(right-left)/2; var yClose=this.ChartFrame.GetYFromData(data.Close); if (bFirstPoint) { if (isHScreen) { this.Canvas.moveTo(yClose,x); firstPoint={ X:yClose, Y:x }; } else { this.Canvas.moveTo(x,yClose); firstPoint={ X:x, Y:yClose }; } bFirstPoint=false; } else { if (isHScreen) this.Canvas.lineTo(yClose,x); else this.Canvas.lineTo(x,yClose); } } if (bFirstPoint) return; this.Canvas.stroke(); if (isHScreen) { this.Canvas.lineTo(this.ChartBorder.GetLeft(),x); this.Canvas.lineTo(this.ChartBorder.GetLeft(),firstPoint.Y); } else { this.Canvas.lineTo(x,this.ChartBorder.GetBottom()); this.Canvas.lineTo(firstPoint.X,this.ChartBorder.GetBottom()); } this.Canvas.closePath(); if (Array.isArray(this.CloseLineAreaColor)) { if (isHScreen) { let gradient = this.Canvas.createLinearGradient(this.ChartBorder.GetRightEx(),this.ChartBorder.GetTop(), this.ChartBorder.GetLeft(),this.ChartBorder.GetTop()); gradient.addColorStop(0, this.CloseLineAreaColor[0]); gradient.addColorStop(1, this.CloseLineAreaColor[1]); this.Canvas.fillStyle=gradient; } else { let gradient = this.Canvas.createLinearGradient(firstPoint.X,this.ChartBorder.GetTopEx(), firstPoint.X,this.ChartBorder.GetBottom()); gradient.addColorStop(0, this.CloseLineAreaColor[0]); gradient.addColorStop(1, this.CloseLineAreaColor[1]); this.Canvas.fillStyle=gradient; } } else { this.Canvas.fillStyle=this.CloseLineAreaColor; } this.Canvas.fill(); } this.DrawCloseLine=function() //收盘价线 { var isHScreen=(this.ChartFrame.IsHScreen===true); var dataWidth=this.ChartFrame.DataWidth; var distanceWidth=this.ChartFrame.DistanceWidth; var xOffset=this.ChartBorder.GetLeft()+distanceWidth/2.0+2.0; if (isHScreen) xOffset=this.ChartBorder.GetTop()+distanceWidth/2.0+2.0; var chartright=this.ChartBorder.GetRight(); if (isHScreen) chartright=this.ChartBorder.GetBottom(); var xPointCount=this.ChartFrame.XPointCount; var bFirstPoint=true; this.Canvas.beginPath(); this.Canvas.strokeStyle=this.CloseLineColor; for(var i=this.Data.DataOffset,j=0;ichartright) break; var x=left+(right-left)/2; var yClose=this.ChartFrame.GetYFromData(data.Close); if (bFirstPoint) { if (isHScreen) this.Canvas.moveTo(yClose,x); else this.Canvas.moveTo(x,yClose); bFirstPoint=false; } else { if (isHScreen) this.Canvas.lineTo(yClose,x); else this.Canvas.lineTo(x,yClose); } } if (bFirstPoint==false) this.Canvas.stroke(); } this.DrawKBar=function() //蜡烛头 { var isHScreen=(this.ChartFrame.IsHScreen===true); var dataWidth=this.ChartFrame.DataWidth; var distanceWidth=this.ChartFrame.DistanceWidth; var xOffset=this.ChartBorder.GetLeft()+distanceWidth/2.0+2.0; var chartright=this.ChartBorder.GetRight(); var xPointCount=this.ChartFrame.XPointCount; if (isHScreen) { xOffset=this.ChartBorder.GetTop()+distanceWidth/2.0+2.0; chartright=this.ChartBorder.GetBottom(); } var ptMax={X:null,Y:null,Value:null,Align:'left'}; var ptMin={X:null,Y:null,Value:null,Align:'left'}; var upColor=this.UpColor; var downColor=this.DownColor; var unchagneColor=this.UnchagneColor; for(var i=this.Data.DataOffset,j=0;ichartright) break; var x=left+(right-left)/2; var yLow=this.ChartFrame.GetYFromData(data.Low); var yHigh=this.ChartFrame.GetYFromData(data.High); var yOpen=this.ChartFrame.GetYFromData(data.Open); var yClose=this.ChartFrame.GetYFromData(data.Close); var y=yHigh; if (ptMax.Value==null || ptMax.Valuedata.Low) //求最小值 { ptMin.X=x; ptMin.Y=yLow; ptMin.Value=data.Low; ptMin.Align=j0?this.UpColor:this.DownColor); else upColor=downColor=unchagneColor=this.DownColor; } if (data.Open=4) { this.Canvas.strokeStyle=upColor; if (data.High>data.Close) //上影线 { this.Canvas.beginPath(); if (isHScreen) { this.Canvas.moveTo(ToFixedPoint(y),ToFixedPoint(x)); this.Canvas.lineTo(ToFixedPoint(this.DrawType==3?Math.max(yClose,yOpen):yClose),ToFixedPoint(x)); } else { this.Canvas.moveTo(ToFixedPoint(x),ToFixedPoint(y)); this.Canvas.lineTo(ToFixedPoint(x),ToFixedPoint(this.DrawType==3?Math.min(yClose,yOpen):yClose)); } this.Canvas.stroke(); y=yClose; } else { y=yClose; } this.Canvas.fillStyle=upColor; if (isHScreen) { if (Math.abs(yOpen-y)<1) { this.Canvas.fillRect(ToFixedRect(y),ToFixedRect(left),1,ToFixedRect(dataWidth)); //高度小于1,统一使用高度1 } else { if (this.DrawType==3) //空心柱 { this.Canvas.beginPath(); this.Canvas.rect(ToFixedPoint(y),ToFixedPoint(left),ToFixedRect(yOpen-y),ToFixedRect(dataWidth)); this.Canvas.stroke(); } else { this.Canvas.fillRect(ToFixedRect(y),ToFixedRect(left),ToFixedRect(yOpen-y),ToFixedRect(dataWidth)); } } } else { if (Math.abs(yOpen-y)<1) { this.Canvas.fillRect(ToFixedRect(left),ToFixedRect(y),ToFixedRect(dataWidth),1); //高度小于1,统一使用高度1 } else { if (this.DrawType==3) //空心柱 { this.Canvas.beginPath(); this.Canvas.rect(ToFixedPoint(left),ToFixedPoint(y),ToFixedRect(dataWidth),ToFixedRect(yOpen-y)); this.Canvas.stroke(); } else { this.Canvas.fillRect(ToFixedRect(left),ToFixedRect(Math.min(y,yOpen)),ToFixedRect(dataWidth),ToFixedRect(Math.abs(yOpen-y))); } } } if (data.Open>data.Low) //下影线 { this.Canvas.beginPath(); if (isHScreen) { this.Canvas.moveTo(ToFixedPoint(this.DrawType==3?Math.min(yClose,yOpen):y),ToFixedPoint(x)); this.Canvas.lineTo(ToFixedPoint(yLow),ToFixedPoint(x)); } else { this.Canvas.moveTo(ToFixedPoint(x),ToFixedPoint(this.DrawType==3?Math.max(yClose,yOpen):y)); this.Canvas.lineTo(ToFixedPoint(x),ToFixedPoint(yLow)); } this.Canvas.stroke(); } } else { this.Canvas.beginPath(); if (isHScreen) { this.Canvas.moveTo(yHigh,ToFixedPoint(x)); this.Canvas.lineTo(yLow,ToFixedPoint(x)); } else { this.Canvas.moveTo(ToFixedPoint(x),yHigh); this.Canvas.lineTo(ToFixedPoint(x),yLow); } this.Canvas.strokeStyle=upColor; this.Canvas.stroke(); } } else if (data.Open>data.Close) //阴线 { if (dataWidth>=4) { this.Canvas.strokeStyle=downColor; if (data.High>data.Close) //上影线 { this.Canvas.beginPath(); if (isHScreen) { this.Canvas.moveTo(ToFixedPoint(y),ToFixedPoint(x)); this.Canvas.lineTo(ToFixedPoint(yOpen),ToFixedPoint(x)); } else { this.Canvas.moveTo(ToFixedPoint(x),ToFixedPoint(y)); this.Canvas.lineTo(ToFixedPoint(x),ToFixedPoint(yOpen)); } this.Canvas.stroke(); y=yOpen; } else { y=yOpen } this.Canvas.fillStyle=downColor; if (isHScreen) { if (Math.abs(yClose-y)<1) this.Canvas.fillRect(ToFixedRect(y),ToFixedRect(left),1,ToFixedRect(dataWidth)); //高度小于1,统一使用高度1 else this.Canvas.fillRect(ToFixedRect(y),ToFixedRect(left),ToFixedRect(yClose-y),ToFixedRect(dataWidth)); } else { if (Math.abs(yClose-y)<1) this.Canvas.fillRect(ToFixedRect(left),ToFixedRect(y),ToFixedRect(dataWidth),1); //高度小于1,统一使用高度1 else this.Canvas.fillRect(ToFixedRect(left),ToFixedRect(Math.min(y,yClose)),ToFixedRect(dataWidth),ToFixedRect(Math.abs(yClose-y))); } if (data.Open>data.Low) //下影线 { this.Canvas.beginPath(); if (isHScreen) { this.Canvas.moveTo(ToFixedPoint(y),ToFixedPoint(x)); this.Canvas.lineTo(ToFixedPoint(yLow),ToFixedPoint(x)); } else { this.Canvas.moveTo(ToFixedPoint(x),ToFixedPoint(y)); this.Canvas.lineTo(ToFixedPoint(x),ToFixedPoint(yLow)); } this.Canvas.stroke(); } } else { this.Canvas.beginPath(); if (isHScreen) { this.Canvas.moveTo(yHigh,ToFixedPoint(x)); this.Canvas.lineTo(yLow,ToFixedPoint(x)); } else { this.Canvas.moveTo(ToFixedPoint(x),yHigh); this.Canvas.lineTo(ToFixedPoint(x),yLow); } this.Canvas.strokeStyle=downColor; this.Canvas.stroke(); } } else // 平线 { if (dataWidth>=4) { this.Canvas.strokeStyle=unchagneColor; this.Canvas.beginPath(); if (data.High>data.Close) //上影线 { if (isHScreen) { this.Canvas.moveTo(y,ToFixedPoint(x)); this.Canvas.lineTo(yOpen,ToFixedPoint(x)); } else { this.Canvas.moveTo(ToFixedPoint(x),y); this.Canvas.lineTo(ToFixedPoint(x),yOpen); } y=yOpen; } else { y=yOpen; } if (isHScreen) { this.Canvas.moveTo(ToFixedPoint(y),ToFixedPoint(left)); this.Canvas.lineTo(ToFixedPoint(y),ToFixedPoint(right)); } else { this.Canvas.moveTo(ToFixedPoint(left),ToFixedPoint(y)); this.Canvas.lineTo(ToFixedPoint(right),ToFixedPoint(y)); } if (data.Open>data.Low) //下影线 { if (isHScreen) { this.Canvas.moveTo(ToFixedPoint(y),ToFixedPoint(x)); this.Canvas.lineTo(ToFixedPoint(yLow),ToFixedPoint(x)); } else { this.Canvas.moveTo(ToFixedPoint(x),ToFixedPoint(y)); this.Canvas.lineTo(ToFixedPoint(x),ToFixedPoint(yLow)); } } this.Canvas.stroke(); } else { this.Canvas.beginPath(); if (isHScreen) { this.Canvas.moveTo(yHigh,ToFixedPoint(x)); this.Canvas.lineTo(yLow,ToFixedPoint(x)); } else { this.Canvas.moveTo(ToFixedPoint(x),yHigh); this.Canvas.lineTo(ToFixedPoint(x),yLow); } this.Canvas.strokeStyle=unchagneColor; this.Canvas.stroke(); } } if (this.IsShowKTooltip && !isHScreen) //添加tooltip区域 { var yTop=Math.min(yOpen,yClose); var yBottom=Math.max(yOpen,yClose); if (Math.abs(yOpen-yClose)<5) //高度太小了, 上下各+5px { yTop=Math.min(yHigh,yTop-5); yBottom=Math.max(yLow,yBottom+5); } var rect=new Rect(left,yTop,dataWidth,yBottom-yTop); //this.Canvas.fillStyle="rgb(0,0,100)"; //this.Canvas.fillRect(rect.X,rect.Y,rect.Width,rect.Height); this.TooltipRect.push([i,rect]); //[0]数据索引 [1]数据区域 } if(this.Data.DataType==0) { var infoItem={Xleft:left,XRight:right, XCenter:x, YMax:yHigh, YMin:yLow, DayData:data, Index:j}; this.DrawInfo(infoItem); } } this.PtMax=ptMax; this.PtMin=ptMin; } this.DrawTrade=function() //交易系统 { if (!this.TradeData) return; var isHScreen=(this.ChartFrame.IsHScreen===true); var dataWidth=this.ChartFrame.DataWidth; var distanceWidth=this.ChartFrame.DistanceWidth; var xOffset=this.ChartBorder.GetLeft()+distanceWidth/2.0+2.0; var chartright=this.ChartBorder.GetRight(); var xPointCount=this.ChartFrame.XPointCount; if (isHScreen) { xOffset=this.ChartBorder.GetTop()+distanceWidth/2.0+2.0; chartright=this.ChartBorder.GetBottom(); } var sellData=this.TradeData.Sell; var buyData=this.TradeData.Buy; var arrowWidth=dataWidth; if (arrowWidth>10) arrowWidth=10; for(var i=this.Data.DataOffset,j=0;i0; if (buyData && i0; if (!sell && !buy) continue; var left=xOffset; var right=xOffset+dataWidth; if (right>chartright) break; var x=left+(right-left)/2; var yLow=this.ChartFrame.GetYFromData(data.Low); var yHigh=this.ChartFrame.GetYFromData(data.High); var yOpen=this.ChartFrame.GetYFromData(data.Open); var yClose=this.ChartFrame.GetYFromData(data.Close); var y=yHigh; if (buy) { this.Canvas.fillStyle=this.UpColor; this.Canvas.strokeStyle=this.UnchagneColor; this.Canvas.beginPath(); if (isHScreen) { this.Canvas.moveTo(yLow-1,x); this.Canvas.lineTo(yLow-arrowWidth-1,x-arrowWidth/2); this.Canvas.lineTo(yLow-arrowWidth-1,x+arrowWidth/2); } else { this.Canvas.moveTo(x,yLow+1); this.Canvas.lineTo(x-arrowWidth/2,yLow+arrowWidth+1); this.Canvas.lineTo(x+arrowWidth/2,yLow+arrowWidth+1); } this.Canvas.closePath(); this.Canvas.fill(); this.Canvas.stroke(); } if (sell) { this.Canvas.fillStyle=this.DownColor; this.Canvas.strokeStyle=this.UnchagneColor; this.Canvas.beginPath(); if (isHScreen) { this.Canvas.moveTo(yHigh+1,x); this.Canvas.lineTo(yHigh+arrowWidth+1,x-arrowWidth/2); this.Canvas.lineTo(yHigh+arrowWidth+1,x+arrowWidth/2); } else { this.Canvas.moveTo(x,yHigh-1); this.Canvas.lineTo(x-arrowWidth/2,yHigh-arrowWidth-1); this.Canvas.lineTo(x+arrowWidth/2,yHigh-arrowWidth-1); } this.Canvas.closePath(); this.Canvas.fill(); this.Canvas.stroke(); } } } this.DrawTick=function() //分笔图 { var isHScreen=(this.ChartFrame.IsHScreen===true); var dataWidth=this.ChartFrame.DataWidth; var distanceWidth=this.ChartFrame.DistanceWidth; var xOffset=this.ChartBorder.GetLeft()+distanceWidth/2.0+2.0; if (isHScreen) xOffset=this.ChartBorder.GetTop()+distanceWidth/2.0+2.0; var chartright=this.ChartBorder.GetRight(); if (isHScreen) chartright=this.ChartBorder.GetBottom(); var xPointCount=this.ChartFrame.XPointCount; var fontSize=parseInt(dataWidth); if (fontSize<=1) fontSize=2; else if (fontSize>=18) fontSize=18; var bFirstPoint=true; this.Canvas.beginPath(); this.Canvas.font=fontSize*GetDevicePixelRatio()+'px '+this.TickFontName; for(var i=this.Data.DataOffset,j=0;ichartright) break; var x=left+(right-left)/2; var yClose=this.ChartFrame.GetYFromData(data.Close); if (data.Flag===0) this.Canvas.fillStyle=this.UpColor; else if (data.Flag==1) this.Canvas.fillStyle=this.DownColor; else this.Canvas.fillStyle=this.UnchagneColor; this.Canvas.textAlign='center' this.Canvas.textBaseline='middle'; if (isHScreen) this.Canvas.fillText(this.TickSymbol,yClose,x); else this.Canvas.fillText(this.TickSymbol,x,yClose); } } this.Draw=function() { this.TooltipRect=[]; this.InfoTooltipRect=[]; this.PtMax={X:null,Y:null,Value:null,Align:'left'}; //清空最大 this.PtMin={X:null,Y:null,Value:null,Align:'left'}; //清空最小 this.ChartFrame.ChartKLine={Max:null, Min:null }; //保存K线上 显示最大最小值坐标 if (!this.IsShow) return; if (ChartData.IsTickPeriod(this.Period)) //分笔图 { this.DrawTick(); return; } if (this.DrawType==1) { this.DrawCloseLine(); return; } else if (this.DrawType==2) { this.DrawAKLine(); } else if (this.DrawType==4) { this.DrawCloseArea(); } else { this.DrawKBar(); } if (this.TradeIcon) this.DrawTradeIcon() else this.DrawTrade(); if (this.IsShowMaxMinPrice) //标注最大值最小值 { if (this.ChartFrame.IsHScreen===true) this.HScreenDrawMaxMinPrice(this.PtMax,this.PtMin); else this.DrawMaxMinPrice(this.PtMax,this.PtMin); } } this.DrawMaxMinPrice=function(ptMax,ptMin) { if (ptMax.X==null || ptMax.Y==null || ptMax.Value==null) return; if (ptMin.X==null || ptMin.Y==null || ptMin.Value==null) return; var defaultfloatPrecision=GetfloatPrecision(this.Symbol); this.Canvas.font=this.TextFont; this.Canvas.fillStyle=this.TextColor; var ptTop=ptMax; if (ptMax.Y>ptMin.Y) ptTop=ptMin; this.Canvas.textAlign=ptTop.Align; this.Canvas.textBaseline='bottom'; var left=ptTop.Align=='left'?ptTop.X:ptTop.X; var text=ptTop.Value.toFixed(defaultfloatPrecision); if (ptTop.Align=='left') text='←'+text; else text=text+'→'; this.Canvas.fillText(text,left,ptTop.Y); this.ChartFrame.ChartKLine.Max={X:left, Y:ptTop.Y, Text: { BaseLine:'bottom'}}; var ptBottom=ptMin; if (ptMin.Y=2 && numText && bShowNum) //太小了 就不显示了 { var iconID=value.Data.length; if (iconID>=numText.length) iconID=0; this.Canvas.fillStyle=g_JSChartResource.KLine.NumIcon.Color; var text=numText[iconID]; this.Canvas.fillText(text,value.TextRect.X,value.TextRect.Y,iconSize); } if (!isHScreen) this.InfoTooltipRect.push(value); //横屏没有tooltip } } //画交易图标 this.DrawTradeIcon=function() { if (!this.TradeData) return; var isHScreen=(this.ChartFrame.IsHScreen===true); var dataWidth=this.ChartFrame.DataWidth; var distanceWidth=this.ChartFrame.DistanceWidth; var xOffset=this.ChartBorder.GetLeft()+distanceWidth/2.0+2.0; var chartright=this.ChartBorder.GetRight(); var xPointCount=this.ChartFrame.XPointCount; if (isHScreen) { xOffset=this.ChartBorder.GetTop()+distanceWidth/2.0+2.0; chartright=this.ChartBorder.GetBottom(); } var sellData=this.TradeData.Sell; var buyData=this.TradeData.Buy; var iconSize=dataWidth+distanceWidth; var pixelTatio = GetDevicePixelRatio(); //获取设备的分辨率 var iconSizeMax=24*pixelTatio,iconSizeMin=12*pixelTatio; if (iconSizeiconSizeMax) iconSize=iconSizeMax; this.Canvas.font=iconSize+'px '+this.TradeIcon.Family; for(var i=this.Data.DataOffset,j=0;i0; if (buyData && i0; if (!sell && !buy) continue; var left=xOffset; var right=xOffset+dataWidth; if (right>chartright) break; var x=left+(right-left)/2; var yLow=this.ChartFrame.GetYFromData(data.Low); var yHigh=this.ChartFrame.GetYFromData(data.High); var yOpen=this.ChartFrame.GetYFromData(data.Open); var yClose=this.ChartFrame.GetYFromData(data.Close); var y=yHigh; if (buy) { this.Canvas.fillStyle=this.TradeIcon.Buy.Color; if (isHScreen) { this.Canvas.textAlign='right'; this.Canvas.textBaseline='middle'; this.Canvas.fillText(this.TradeIcon.Buy.HScreenText,yLow,x); } else { this.Canvas.textAlign='center'; this.Canvas.textBaseline='top'; this.Canvas.fillText(this.TradeIcon.Buy.Text,x,yLow); } } if (sell) { this.Canvas.fillStyle=this.TradeIcon.Sell.Color; if (isHScreen) { this.Canvas.textAlign='left'; this.Canvas.textBaseline='middle'; this.Canvas.fillText(this.TradeIcon.Sell.HScreenText,yHigh,x); } else { this.Canvas.textAlign='center'; this.Canvas.textBaseline='bottom'; this.Canvas.fillText(this.TradeIcon.Sell.Text,x,yHigh); } } } } this.GetTooltipData=function(x,y,tooltip) { for(var i in this.InfoTooltipRect) { var item=this.InfoTooltipRect[i]; if (!item.Rect) continue; var rect=item.Rect; this.Canvas.beginPath(); this.Canvas.rect(rect.X,rect.Y,rect.Width,rect.Height); if (this.Canvas.isPointInPath(x,y)) { //console.log('[ChartKLine::GetTooltipData]', item); tooltip.Data=item; tooltip.ChartPaint=this; tooltip.Type=1; //信息地雷 return true; } } for(var i in this.TooltipRect) { var rect=this.TooltipRect[i][1]; this.Canvas.beginPath(); this.Canvas.rect(rect.X,rect.Y,rect.Width,rect.Height); if (this.Canvas.isPointInPath(x,y)) { var index=this.TooltipRect[i][0]; tooltip.Data=this.Data.Data[index]; tooltip.ChartPaint=this; tooltip.Type=0; //K线信息 return true; } } return false; } //计算当天显示数据的最大最小值 this.GetMaxMin=function() { var xPointCount=this.ChartFrame.XPointCount; var range={}; range.Max=null; range.Min=null; for(var i=this.Data.DataOffset,j=0;idata.Low) range.Min=data.Low; } return range; } //获取所有的价格 this.GetAllPrice=function() { var xPointCount=this.ChartFrame.XPointCount; var setPrice=new Set(); for(var i=this.Data.DataOffset,j=0;ichartright) break; var x=left+(right-left)/2; var yLow=this.ChartFrame.GetYFromData(data.Low/firstOverlayOpen*firstOpen); var yHigh=this.ChartFrame.GetYFromData(data.High/firstOverlayOpen*firstOpen); var yOpen=this.ChartFrame.GetYFromData(data.Open/firstOverlayOpen*firstOpen); var yClose=this.ChartFrame.GetYFromData(data.Close/firstOverlayOpen*firstOpen); var y=yHigh; if (data.Open=4) { if (data.High>data.Close) //上影线 { if (isHScreen) { this.Canvas.moveTo(ToFixedPoint(y),ToFixedPoint(x)); this.Canvas.lineTo(ToFixedPoint(this.DrawType==3?Math.max(yClose,yOpen):yClose),ToFixedPoint(x)); } else { this.Canvas.moveTo(ToFixedPoint(x),ToFixedPoint(y)); this.Canvas.lineTo(ToFixedPoint(x),ToFixedPoint(this.DrawType==3?Math.min(yClose,yOpen):yClose)); } y=yClose; } else { y=yClose; } if (isHScreen) { if (Math.abs(yOpen-y)<1) { this.Canvas.fillRect(ToFixedRect(y),ToFixedRect(left),1,ToFixedRect(dataWidth)); //高度小于1,统一使用高度1 } else { if (drawType==3) this.Canvas.rect(ToFixedPoint(y),ToFixedPoint(left),ToFixedRect(yOpen-y),ToFixedRect(dataWidth)); //空心柱 else this.Canvas.fillRect(ToFixedRect(y),ToFixedRect(left),ToFixedRect(yOpen-y),ToFixedRect(dataWidth)); } } else { if (Math.abs(yOpen-y)<1) { this.Canvas.fillRect(ToFixedRect(left),ToFixedRect(y),ToFixedRect(dataWidth),1); //高度小于1,统一使用高度1 } else { if (drawType==3) this.Canvas.rect(ToFixedPoint(left),ToFixedPoint(y),ToFixedRect(dataWidth),ToFixedRect(yOpen-y)); //空心柱 else this.Canvas.fillRect(ToFixedRect(left),ToFixedRect(y),ToFixedRect(dataWidth),ToFixedRect(yOpen-y)); } } if (data.Open>data.Low) { if (isHScreen) { this.Canvas.moveTo(ToFixedPoint(this.DrawType==3?Math.min(yClose,yOpen):y),ToFixedPoint(x)); this.Canvas.lineTo(ToFixedPoint(yLow),ToFixedPoint(x)); } else { this.Canvas.moveTo(ToFixedPoint(x),ToFixedPoint(this.DrawType==3?Math.max(yClose,yOpen):y)); this.Canvas.lineTo(ToFixedPoint(x),ToFixedPoint(yLow)); } } } else { if (isHScreen) { this.Canvas.moveTo(yHigh,ToFixedPoint(x)); this.Canvas.lineTo(yLow,ToFixedPoint(x)); } else { this.Canvas.moveTo(ToFixedPoint(x),yHigh); this.Canvas.lineTo(ToFixedPoint(x),yLow); } } } else if (data.Open>data.Close) //阴线 { if (dataWidth>=4) { if (data.High>data.Close) //上影线 { if (isHScreen) { this.Canvas.moveTo(ToFixedPoint(y),ToFixedPoint(x)); this.Canvas.lineTo(ToFixedPoint(yOpen),ToFixedPoint(x)); } else { this.Canvas.moveTo(ToFixedPoint(x),ToFixedPoint(y)); this.Canvas.lineTo(ToFixedPoint(x),ToFixedPoint(yOpen)); } y=yOpen; } else { y=yOpen } if (isHScreen) { if (Math.abs(yClose-y)<1) this.Canvas.fillRect(ToFixedRect(y),ToFixedRect(left),1,ToFixedRect(dataWidth)); //高度小于1,统一使用高度1 else this.Canvas.fillRect(ToFixedRect(y),ToFixedRect(left),ToFixedRect(yClose-y),ToFixedRect(dataWidth)); } else { if (Math.abs(yClose-y)<1) this.Canvas.fillRect(ToFixedRect(left),ToFixedRect(y),ToFixedRect(dataWidth),1); //高度小于1,统一使用高度1 else this.Canvas.fillRect(ToFixedRect(left),ToFixedRect(y),ToFixedRect(dataWidth),ToFixedRect(yClose-y)); } if (data.Open>data.Low) //下影线 { if (isHScreen) { this.Canvas.moveTo(ToFixedPoint(y),ToFixedPoint(x)); this.Canvas.lineTo(ToFixedPoint(yLow),ToFixedPoint(x)); } else { this.Canvas.moveTo(ToFixedPoint(x),ToFixedPoint(y)); this.Canvas.lineTo(ToFixedPoint(x),ToFixedPoint(yLow)); } } } else { if (isHScreen) { this.Canvas.moveTo(yHigh,ToFixedPoint(x)); this.Canvas.lineTo(yLow,ToFixedPoint(x)); } else { this.Canvas.moveTo(ToFixedPoint(x),yHigh); this.Canvas.lineTo(ToFixedPoint(x),yLow); } } } else // 平线 { if (dataWidth>=4) { if (data.High>data.Close) //上影线 { if (isHScreen) { this.Canvas.moveTo(y,ToFixedPoint(x)); this.Canvas.lineTo(yOpen,ToFixedPoint(x)); } else { this.Canvas.moveTo(ToFixedPoint(x),y); this.Canvas.lineTo(ToFixedPoint(x),yOpen); } y=yOpen; } else { y=yOpen; } if (isHScreen) { this.Canvas.moveTo(ToFixedPoint(y),ToFixedPoint(left)); this.Canvas.lineTo(ToFixedPoint(y),ToFixedPoint(right)); } else { this.Canvas.moveTo(ToFixedPoint(left),ToFixedPoint(y)); this.Canvas.lineTo(ToFixedPoint(right),ToFixedPoint(y)); } if (data.Open>data.Low) //下影线 { if (isHScreen) { this.Canvas.moveTo(ToFixedPoint(y),ToFixedPoint(x)); this.Canvas.lineTo(ToFixedPoint(yLow),ToFixedPoint(x)); } else { this.Canvas.moveTo(ToFixedPoint(x),ToFixedPoint(y)); this.Canvas.lineTo(ToFixedPoint(x),ToFixedPoint(yLow)); } } } else { if (isHScreen) { this.Canvas.moveTo(yHigh,ToFixedPoint(x)); this.Canvas.lineTo(yLow,ToFixedPoint(x)); } else { this.Canvas.moveTo(ToFixedPoint(x),yHigh); this.Canvas.lineTo(ToFixedPoint(x),yLow); } } } //添加tooltip区域 { var yTop=Math.min(yLow,yHigh,yOpen,yClose); var yBottom=Math.max(yLow,yHigh,yOpen,yClose); var rect=new Rect(left,yTop,dataWidth,yBottom-yTop); //this.Canvas.fillStyle="rgb(0,0,100)"; //this.Canvas.fillRect(rect.X,rect.Y,rect.Width,rect.Height); this.TooltipRect.push([i,rect]); //[0]数据索引 [1]数据区域 } } if (isFristDraw==false) this.Canvas.stroke(); } this.DrawAKLine=function(firstOpen) //美国线 { var isHScreen=(this.ChartFrame.IsHScreen===true); var dataWidth=this.ChartFrame.DataWidth; var distanceWidth=this.ChartFrame.DistanceWidth; var xOffset=this.ChartBorder.GetLeft()+distanceWidth/2.0+2.0; if (isHScreen) xOffset=this.ChartBorder.GetTop()+distanceWidth/2.0+2.0; var chartright=this.ChartBorder.GetRight(); if (isHScreen) chartright=this.ChartBorder.GetBottom(); var xPointCount=this.ChartFrame.XPointCount; var firstOverlayOpen=null; this.Canvas.strokeStyle=this.Color; for(var i=this.Data.DataOffset,j=0;ichartright) break; var x=left+(right-left)/2; var yLow=this.ChartFrame.GetYFromData(data.Low/firstOverlayOpen*firstOpen); var yHigh=this.ChartFrame.GetYFromData(data.High/firstOverlayOpen*firstOpen); var yOpen=this.ChartFrame.GetYFromData(data.Open/firstOverlayOpen*firstOpen); var yClose=this.ChartFrame.GetYFromData(data.Close/firstOverlayOpen*firstOpen); this.Canvas.beginPath(); //最高-最低 if (isHScreen) { this.Canvas.moveTo(yHigh,ToFixedPoint(x)); this.Canvas.lineTo(yLow,ToFixedPoint(x)); } else { this.Canvas.moveTo(ToFixedPoint(x),yHigh); this.Canvas.lineTo(ToFixedPoint(x),yLow); } this.Canvas.stroke(); if (dataWidth>=4) { this.Canvas.beginPath(); //开盘 if (isHScreen) { this.Canvas.moveTo(ToFixedPoint(yOpen),left); this.Canvas.lineTo(ToFixedPoint(yOpen),x); } else { this.Canvas.moveTo(left,ToFixedPoint(yOpen)); this.Canvas.lineTo(x,ToFixedPoint(yOpen)); } this.Canvas.stroke(); this.Canvas.beginPath(); //收盘 if (isHScreen) { this.Canvas.moveTo(ToFixedPoint(yClose),right); this.Canvas.lineTo(ToFixedPoint(yClose),x); } else { this.Canvas.moveTo(right,ToFixedPoint(yClose)); this.Canvas.lineTo(x,ToFixedPoint(yClose)); } this.Canvas.stroke(); } } } this.DrawCloseLine=function(firstOpen) //收盘价线 { var isHScreen=(this.ChartFrame.IsHScreen===true); var dataWidth=this.ChartFrame.DataWidth; var distanceWidth=this.ChartFrame.DistanceWidth; var xOffset=this.ChartBorder.GetLeft()+distanceWidth/2.0+2.0; if (isHScreen) xOffset=this.ChartBorder.GetTop()+distanceWidth/2.0+2.0; var chartright=this.ChartBorder.GetRight(); if (isHScreen) chartright=this.ChartBorder.GetBottom(); var xPointCount=this.ChartFrame.XPointCount; var firstOverlayOpen=null; var bFirstPoint=true; this.Canvas.strokeStyle=this.Color; this.Canvas.beginPath(); for(var i=this.Data.DataOffset,j=0;ichartright) break; var x=left+(right-left)/2; var yClose=this.ChartFrame.GetYFromData(data.Close/firstOverlayOpen*firstOpen); if (bFirstPoint) { if (isHScreen) this.Canvas.moveTo(yClose,x); else this.Canvas.moveTo(x,yClose); bFirstPoint=false; } else { if (isHScreen) this.Canvas.lineTo(yClose,x); else this.Canvas.lineTo(x,yClose); } } if (bFirstPoint==false) this.Canvas.stroke(); } this.Draw=function() { this.TooltipRect=[]; this.InfoTooltipRect=[]; if (!this.MainData || !this.Data) return; var xPointCount=this.ChartFrame.XPointCount; var firstOpen=null; //主线数据第1个开盘价 for(var i=this.Data.DataOffset,j=0;ilow) range.Min=low; } return range; } this.GetTooltipData=function(x,y,tooltip) { for(var i in this.TooltipRect) { var rect=this.TooltipRect[i][1]; this.Canvas.beginPath(); this.Canvas.rect(rect.X,rect.Y,rect.Width,rect.Height); if (this.Canvas.isPointInPath(x,y)) { var index=this.TooltipRect[i][0]; tooltip.Data=this.Data.Data[index]; tooltip.ChartPaint=this; return true; } } return false; } } //分钟成交量 支持横屏 function ChartMinuteVolumBar() { this.newMethod=IChartPainting; //派生 this.newMethod(); delete this.newMethod; this.ClassName='ChartMinuteVolumBar'; //类名 this.UpColor = g_JSChartResource.UpBarColor; this.DownColor = g_JSChartResource.DownBarColor; this.YClose; //前收盘 this.Draw=function() { var isHScreen = (this.ChartFrame.IsHScreen === true); var chartright=this.ChartBorder.GetRight(); if (isHScreen) chartright = this.ChartBorder.GetBottom(); var xPointCount=this.ChartFrame.XPointCount; var yBottom=this.ChartFrame.GetYFromData(0); var yPrice=this.YClose; //上一分钟的价格 var data=this.Data; for(var i=data.DataOffset,j=0;ichartright) break; //价格>=上一分钟价格 红色 否则绿色 this.Canvas.strokeStyle = price >= yPrice ? this.UpColor:this.DownColor; this.Canvas.beginPath(); if (isHScreen) { this.Canvas.moveTo(y,ToFixedPoint(x)); this.Canvas.lineTo(yBottom,ToFixedPoint(x)); } else { this.Canvas.moveTo(ToFixedPoint(x),y); this.Canvas.lineTo(ToFixedPoint(x),yBottom); } this.Canvas.stroke(); if (price) yPrice=price; } } this.GetMaxMin=function() { var xPointCount=this.ChartFrame.XPointCount; var range={}; range.Min=0; range.Max=null; for(var i=this.Data.DataOffset,j=0;i0) this.Canvas.lineWidth=this.LineWidth * GetDevicePixelRatio(); var bFirstPoint=true; var drawCount=0; for(var i=this.Data.DataOffset,j=0;ichartright) break; if (bFirstPoint) { this.Canvas.strokeStyle=this.Color; this.Canvas.beginPath(); if (bHScreen) this.Canvas.moveTo(y,x); //横屏坐标轴对调 else this.Canvas.moveTo(x,y); bFirstPoint=false; } else { if (bHScreen) this.Canvas.lineTo(y,x); else this.Canvas.lineTo(x,y); } ++drawCount; } if (drawCount>0) this.Canvas.stroke(); this.Canvas.restore(); } //无效数不画 this.DrawStraightLine=function() { var bHScreen=(this.ChartFrame.IsHScreen===true); var dataWidth=this.ChartFrame.DataWidth; var distanceWidth=this.ChartFrame.DistanceWidth; var chartright=this.ChartBorder.GetRight(); if (bHScreen) chartright=this.ChartBorder.GetBottom(); var xPointCount=this.ChartFrame.XPointCount; var lockRect=this.GetLockRect(); if (lockRect) { if (bHScreen) chartright=lockRect.Top; else chartright=lockRect.Left; } this.Canvas.save(); if (this.LineWidth>0) this.Canvas.lineWidth=this.LineWidth * GetDevicePixelRatio(); this.Canvas.strokeStyle=this.Color; if (this.IsDotLine) this.Canvas.setLineDash([3,5]); //画虚线 var bFirstPoint=true; var drawCount=0; for(var i=this.Data.DataOffset,j=0;i0) this.Canvas.stroke(); bFirstPoint=true; drawCount=0; continue; } var x=this.ChartFrame.GetXFromIndex(j); var y=this.ChartFrame.GetYFromData(value); if (x>chartright) break; if (bFirstPoint) { this.Canvas.beginPath(); if (bHScreen) this.Canvas.moveTo(y,x); //横屏坐标轴对调 else this.Canvas.moveTo(x,y); bFirstPoint=false; } else { if (bHScreen) this.Canvas.lineTo(y,x); else this.Canvas.lineTo(x,y); } ++drawCount; } if (drawCount>0) this.Canvas.stroke(); this.Canvas.restore(); } } //彩色线段 function ChartPartLine() { this.newMethod=IChartPainting; //派生 this.newMethod(); delete this.newMethod; this.ClassName='ChartPartLine'; //类名 this.LineWidth; //线段宽度 this.Draw=function() { if (!this.IsShow) return; if (this.NotSupportMessage) { this.DrawNotSupportmessage(); return; } if (!this.Data || !this.Data.Data) return; this.DrawLine(); } this.DrawLine=function() { var bHScreen=(this.ChartFrame.IsHScreen===true); var dataWidth=this.ChartFrame.DataWidth; var distanceWidth=this.ChartFrame.DistanceWidth; var chartright=this.ChartBorder.GetRight(); if (bHScreen) chartright=this.ChartBorder.GetBottom(); var xPointCount=this.ChartFrame.XPointCount; this.Canvas.save(); if (this.LineWidth>0) this.Canvas.lineWidth=this.LineWidth * GetDevicePixelRatio(); var bFirstPoint=true; var drawCount=0; var lastColor; var lastPoint={X:null,Y:null}; for(var i=this.Data.DataOffset,j=0;ichartright) break; if (color!=lastColor) { if (lastColor && drawCount>0) this.Canvas.stroke(); drawCount=0; lastColor=color; this.Canvas.strokeStyle=color; this.Canvas.beginPath(); if (lastPoint.X!=null && lastPoint.Y!=null) //接着上一个点连线 { if (bHScreen) this.Canvas.moveTo(lastPoint.Y,lastPoint.X); //横屏坐标轴对调 else this.Canvas.moveTo(lastPoint.X,lastPoint.Y); if (bHScreen) this.Canvas.lineTo(y,x); else this.Canvas.lineTo(x,y); ++drawCount; } else { if (bHScreen) this.Canvas.moveTo(y,x); //横屏坐标轴对调 else this.Canvas.moveTo(x,y); } } else { if (bHScreen) this.Canvas.lineTo(y,x); else this.Canvas.lineTo(x,y); ++drawCount; } lastPoint.X=x; lastPoint.Y=y; } if (drawCount>0) this.Canvas.stroke(); this.Canvas.restore(); } this.GetMaxMin=function() { var xPointCount=this.ChartFrame.XPointCount; var range={}; range.Min=null; range.Max=null; for(var i=this.Data.DataOffset,j=0;iitem.Value) range.Min = item.Value; } return range; } } //POINTDOT 圆点 支持横屏 function ChartPointDot() { this.newMethod=IChartPainting; //派生 this.newMethod(); delete this.newMethod; this.ClassName='ChartPointDot'; //类名 this.Color="rgb(255,193,37)"; //线段颜色 this.Radius=1; //点半径 this.Draw=function() { if (!this.IsShow) return; if (this.NotSupportMessage) { this.DrawNotSupportmessage(); return; } if (!this.Data || !this.Data.Data) return; var bHScreen=(this.ChartFrame.IsHScreen===true); var dataWidth=this.ChartFrame.DataWidth; var distanceWidth=this.ChartFrame.DistanceWidth; var chartright=this.ChartBorder.GetRight(); if (bHScreen===true) chartright=this.ChartBorder.GetBottom(); var xPointCount=this.ChartFrame.XPointCount; this.Canvas.save(); this.Canvas.fillStyle=this.Color; for(var i=this.Data.DataOffset,j=0;ichartright) break; this.Canvas.beginPath(); if (bHScreen) this.Canvas.arc(y, x, this.Radius, 0, Math.PI*2, true); else this.Canvas.arc(x, y, this.Radius, 0, Math.PI*2, true); this.Canvas.closePath(); this.Canvas.fill(); } this.Canvas.restore(); } } //通达信语法 STICK 支持横屏 function ChartStick() { this.newMethod=IChartPainting; //派生 this.newMethod(); delete this.newMethod; this.Color="rgb(255,193,37)"; //线段颜色 this.LineWidth; //线段宽度 this.ClassName='ChartStick'; this.DrawLine=function() { if (!this.Data || !this.Data.Data) return; var isHScreen=(this.ChartFrame.IsHScreen===true); var dataWidth=this.ChartFrame.DataWidth; var distanceWidth=this.ChartFrame.DistanceWidth; var chartright=this.ChartBorder.GetRight(); if (isHScreen===true) chartright=this.ChartBorder.GetBottom(); var xPointCount=this.ChartFrame.XPointCount; this.Canvas.save(); if (this.LineWidth>0) this.Canvas.lineWidth=this.LineWidth * GetDevicePixelRatio(); var bFirstPoint=true; var drawCount=0; for(var i=this.Data.DataOffset,j=0;ichartright) break; if (bFirstPoint) { this.Canvas.strokeStyle=this.Color; this.Canvas.beginPath(); if (isHScreen) this.Canvas.moveTo(y,x); else this.Canvas.moveTo(x,y); bFirstPoint=false; } else { if (isHScreen) this.Canvas.lineTo(y,x); else this.Canvas.lineTo(x,y); } ++drawCount; } if (drawCount>0) this.Canvas.stroke(); this.Canvas.restore(); } this.DrawStick=function() { if (!this.Data || !this.Data.Data) return; var bHScreen=(this.ChartFrame.IsHScreen===true); var chartright=this.ChartBorder.GetRight(); if (bHScreen) chartright=this.ChartBorder.GetBottom(); var xPointCount=this.ChartFrame.XPointCount; var yBottom=this.ChartBorder.GetBottom(); var xLeft=this.ChartBorder.GetLeft(); this.Canvas.save(); this.Canvas.strokeStyle=this.Color; if (this.LineWidth) this.Canvas.lineWidth=this.LineWidth * GetDevicePixelRatio(); for(var i=this.Data.DataOffset,j=0;ichartright) break; this.Canvas.beginPath(); if (bHScreen) { this.Canvas.moveTo(xLeft,x); this.Canvas.lineTo(y,x); this.Canvas.stroke(); } else { var xFix=parseInt(x.toString())+0.5; this.Canvas.moveTo(xFix,y); this.Canvas.lineTo(xFix,yBottom); } this.Canvas.stroke(); } this.Canvas.restore(); } this.Draw=function() { if (!this.IsShow) return; if (this.NotSupportMessage) { this.DrawNotSupportmessage(); return; } if (!this.Data || !this.Data.Data) return; this.DrawStick(); } } //通达信语法 LINESTICK 支持横屏 function ChartLineStick() { this.newMethod=ChartStick; //派生 this.newMethod(); delete this.newMethod; this.ClassName='ChartLineStick'; this.Draw=function() { if (!this.IsShow) return; if (this.NotSupportMessage) { this.DrawNotSupportmessage(); return; } this.DrawStick(); this.DrawLine(); } } //通达信语法 VOLSTICK 支持横屏 function ChartVolStick() { this.newMethod=IChartPainting; //派生 this.newMethod(); delete this.newMethod; this.UpColor=g_JSChartResource.UpBarColor; this.DownColor=g_JSChartResource.DownBarColor; this.HistoryData; //历史数据 this.KLineDrawType=0; this.ClassName='ChartVolStick'; this.Draw=function() { if (this.ChartFrame.IsHScreen===true) { this.HScreenDraw(); return; } var dataWidth=this.ChartFrame.DataWidth; var distanceWidth=this.ChartFrame.DistanceWidth; var xOffset=this.ChartBorder.GetLeft()+distanceWidth/2.0+2.0; var chartright=this.ChartBorder.GetRight(); var xPointCount=this.ChartFrame.XPointCount; var lockRect=this.GetLockRect(); if (lockRect) chartright=lockRect.Left; var yBottom=this.ChartFrame.GetYFromData(0); if (dataWidth>=4) { yBottom=ToFixedRect(yBottom); for(var i=this.Data.DataOffset,j=0;ichartright) break; var y=this.ChartFrame.GetYFromData(value); var bUp=false; if (kItem.Close>=kItem.Open) { this.Canvas.fillStyle=this.UpColor; bUp=true; } else { this.Canvas.fillStyle=this.DownColor; } var height=ToFixedRect(yBottom-y);//高度调整为整数 y=yBottom-height; if (bUp && (this.KLineDrawType==1 || this.KLineDrawType==2 || this.KLineDrawType==3)) //空心柱子 { this.Canvas.strokeStyle=this.UpColor; this.Canvas.beginPath(); this.Canvas.rect(ToFixedPoint(left),ToFixedPoint(y),ToFixedRect(dataWidth),height); this.Canvas.stroke(); } else { this.Canvas.fillRect(ToFixedRect(left),y,ToFixedRect(dataWidth),height); } } } else //太细了直接话线 { for(var i=this.Data.DataOffset,j=0;ichartright) break; if (kItem.Close>=kItem.Open) this.Canvas.strokeStyle=this.UpColor; else this.Canvas.strokeStyle=this.DownColor; var x=this.ChartFrame.GetXFromIndex(j); this.Canvas.beginPath(); this.Canvas.moveTo(ToFixedPoint(x),y); this.Canvas.lineTo(ToFixedPoint(x),yBottom); this.Canvas.stroke(); } } } this.HScreenDraw=function() //横屏画法 { var dataWidth=this.ChartFrame.DataWidth; var distanceWidth=this.ChartFrame.DistanceWidth; var xOffset=this.ChartBorder.GetTop()+distanceWidth/2.0+2.0; var chartBottom=this.ChartBorder.GetBottom(); var xPointCount=this.ChartFrame.XPointCount; var lockRect=this.GetLockRect(); if (lockRect) chartBottom=lockRect.Top; var yBottom=this.ChartFrame.GetYFromData(0); if (dataWidth>=4) { yBottom=ToFixedRect(yBottom); for(var i=this.Data.DataOffset,j=0;ichartBottom) break; var y=this.ChartFrame.GetYFromData(value); var bUp=false; if (kItem.Close>=kItem.Open) { bUp=true; this.Canvas.fillStyle=this.UpColor; } else { this.Canvas.fillStyle=this.DownColor; } var height=ToFixedRect(y-yBottom); //高度调整为整数 if (bUp && (this.KLineDrawType==1 || this.KLineDrawType==2 || this.KLineDrawType==3)) //空心柱子 { this.Canvas.strokeStyle=this.UpColor; this.Canvas.beginPath(); this.Canvas.rect(ToFixedPoint(yBottom),ToFixedPoint(left),height,ToFixedRect(dataWidth)); this.Canvas.stroke(); } else { this.Canvas.fillRect(yBottom,ToFixedRect(left),height,ToFixedRect(dataWidth)); } } } else //太细了直接话线 { for(var i=this.Data.DataOffset,j=0;ichartBottom) break; if (kItem.Close>kItem.Open) this.Canvas.strokeStyle=this.UpColor; else this.Canvas.strokeStyle=this.DownColor; var x=this.ChartFrame.GetXFromIndex(j); this.Canvas.beginPath(); this.Canvas.moveTo(y,ToFixedPoint(x)); this.Canvas.lineTo(yBottom,ToFixedPoint(x)); this.Canvas.stroke(); } } } this.GetMaxMin=function() { var xPointCount=this.ChartFrame.XPointCount; var range={}; range.Min=0; range.Max=null; for(var i=this.Data.DataOffset,j=0;ichartright) break; for(var index in aryValue) { var value =aryValue[index].Value; var y=this.ChartFrame.GetYFromData(value); if (bFirstPoint) { this.Canvas.strokeStyle=this.Color; this.Canvas.beginPath(); if (isHScreen) this.Canvas.moveTo(y,x); else this.Canvas.moveTo(x,y); bFirstPoint=false; } else { if (isHScreen) this.Canvas.lineTo(y,x); else this.Canvas.lineTo(x,y); } ++drawCount; } } if (drawCount>0) this.Canvas.stroke(); } this.GetMaxMin=function() { var xPointCount=this.ChartFrame.XPointCount; var range={}; range.Min=null; range.Max=null; if(!this.Data || !this.Data.Data) return range; for(var i=this.Data.DataOffset,j=0;ivalue) range.Min=value; } } return range; } } //柱子 支持横屏 function ChartStickLine() { this.newMethod=IChartPainting; //派生 this.newMethod(); delete this.newMethod; this.ClassName='ChartStickLine'; //类名 this.Color="rgb(255,193,37)"; //线段颜色 this.LineWidth=2*GetDevicePixelRatio(); //线段宽度 this.BarType=0; //柱子类型 0=实心 1=空心 this.Draw=function() { if (this.NotSupportMessage) { this.DrawNotSupportmessage(); return; } if (!this.Data || !this.Data.Data) return; var isHScreen=(this.ChartFrame.IsHScreen===true); var dataWidth=this.ChartFrame.DataWidth; var distanceWidth=this.ChartFrame.DistanceWidth; var chartright=this.ChartBorder.GetRight(); if (isHScreen) chartright=this.ChartBorder.GetBottom(); var xPointCount=this.ChartFrame.XPointCount; var xOffset=this.ChartBorder.GetLeft()+distanceWidth/2.0+2.0; if (isHScreen) xOffset=this.ChartBorder.GetTop()+distanceWidth/2.0+2.0; this.Canvas.save(); var bFillBar=false; var bFillKLine=false; if (this.LineWidth==50) //宽度==50 跟K线宽度保持一致 { if (dataWidth>=4) { bFillKLine=true; this.Canvas.fillStyle=this.Color; this.Canvas.strokeStyle=this.Color; } else //太细了 画竖线 { this.Canvas.lineWidth=GetDevicePixelRatio(); this.Canvas.strokeStyle=this.Color; } } else if (this.LineWidth<100) { var LineWidth=this.LineWidth; if (dataWidth<=4) LineWidth=GetDevicePixelRatio(); else if (dataWidthchartright) break; if (bFillBar) { if (isHScreen) { var left=xOffset-fixedWidth; this.Canvas.fillRect(Math.min(y,y2),left,Math.abs(y-y2),dataWidth+distanceWidth+fixedWidth*2); } else { var left=xOffset-fixedWidth; var barWidth=dataWidth+distanceWidth+fixedWidth*2; if (left+barWidth>chartright) barWidth=chartright-left; //不要超过右边框子 this.Canvas.fillRect(ToFixedRect(left),ToFixedRect(Math.min(y,y2)),ToFixedRect(barWidth),ToFixedRect(Math.abs(y-y2))); } } else if (bFillKLine) { if (this.BarType==1) //实心 { if (isHScreen) { this.Canvas.beginPath(); this.Canvas.fillRect(ToFixedRect(Math.min(y,y2)),ToFixedRect(xOffset),ToFixedRect(Math.abs(y-y2)),ToFixedRect(dataWidth)); this.Canvas.stroke(); } else { this.Canvas.beginPath(); this.Canvas.rect(ToFixedRect(xOffset),ToFixedRect(Math.min(y,y2)),ToFixedRect(dataWidth),ToFixedRect(Math.abs(y-y2))); this.Canvas.stroke(); } } else { if (isHScreen) this.Canvas.fillRect(ToFixedRect(Math.min(y,y2)),ToFixedRect(xOffset),ToFixedRect(Math.abs(y-y2)),ToFixedRect(dataWidth)); else this.Canvas.fillRect(ToFixedRect(xOffset),ToFixedRect(Math.min(y,y2)),ToFixedRect(dataWidth),ToFixedRect(Math.abs(y-y2))); } } else { if (isHScreen) { this.Canvas.beginPath(); this.Canvas.moveTo(y,ToFixedPoint(x)); this.Canvas.lineTo(y2,ToFixedPoint(x)); this.Canvas.stroke(); } else { var xFix=parseInt(x.toString())+0.5; this.Canvas.beginPath(); this.Canvas.moveTo(xFix,y); this.Canvas.lineTo(xFix,y2); this.Canvas.stroke(); } } } this.Canvas.restore(); } this.GetMaxMin=function() { var xPointCount=this.ChartFrame.XPointCount; var range={}; range.Min=null; range.Max=null; if(!this.Data || !this.Data.Data) return range; for(var i=this.Data.DataOffset,j=0;ivalueMin) range.Min=valueMin; } return range; } } function ChartText() { this.newMethod=IChartPainting; //派生 this.newMethod(); delete this.newMethod; this.ClassName='ChartText'; //类名 this.TextFont="14px 微软雅黑"; this.Draw=function() { if (this.NotSupportMessage) { this.DrawNotSupportmessage(); return; } if (!this.Data || !this.Data.Data) return; var dataWidth=this.ChartFrame.DataWidth; var distanceWidth=this.ChartFrame.DistanceWidth; var chartright=this.ChartBorder.GetRight(); var xPointCount=this.ChartFrame.XPointCount; for(var i in this.Data.Data) { var value=this.Data.Data[i]; if (value==null) continue; var price=value.Value; var position=value.Position; if (position=='Left') { var x=this.ChartFrame.GetXFromIndex(0); var y=this.ChartFrame.GetYFromData(price); if (x>chartright) continue; this.Canvas.textAlign='left'; this.Canvas.textBaseline='middle'; this.Canvas.fillStyle=value.Color; this.Canvas.font=this.TextFont; this.Canvas.fillText(value.Message,x,y); } } } this.GetMaxMin=function() { var xPointCount=this.ChartFrame.XPointCount; var range={}; range.Min=null; range.Max=null; if(!this.Data || !this.Data.Data) return range; for(var i in this.Data.Data) { var data=this.Data.Data[i]; if (data==null || isNaN(data.Value)) continue; var value=data.Value; if (range.Max==null) range.Max=value; if (range.Min==null) range.Min=value; if (range.Maxvalue) range.Min=value; } return range; } } /* 文字输出 支持横屏 数组不为null的数据中输出 this.Text文本 */ function ChartSingleText() { this.newMethod=IChartPainting; //派生 this.newMethod(); delete this.newMethod; this.ClassName='ChartSingleText'; //类名 this.Color="rgb(255,193,37)"; //线段颜色 this.TextFont="14px 微软雅黑"; //线段宽度 this.Text; this.TextAlign='left'; this.Direction=0; //0=middle 1=bottom 2=top this.YOffset=0; this.Position; //指定输出位置 this.IconFont; //Iconfont this.Draw=function() { if (!this.IsShow) return; if (this.NotSupportMessage) { this.DrawNotSupportmessage(); return; } if (this.Position) { this.DrawPosition(); return; } if (!this.Data || !this.Data.Data) return; var isHScreen=(this.ChartFrame.IsHScreen===true) var dataWidth=this.ChartFrame.DataWidth; var distanceWidth=this.ChartFrame.DistanceWidth; var chartright=this.ChartBorder.GetRight(); var top=this.ChartBorder.GetTopEx(); var bottom=this.ChartBorder.GetBottomEx(); if (isHScreen) { chartright=this.ChartBorder.GetBottom(); top=this.ChartBorder.GetRightEx(); bottom=this.ChartBorder.GetLeftEx(); } var xPointCount=this.ChartFrame.XPointCount; var isArrayText=Array.isArray(this.Text); var pixelTatio = GetDevicePixelRatio(); if (this.Direction==1) this.Canvas.textBaseline='bottom'; else if (this.Direction==2) this.Canvas.textBaseline='top'; else this.Canvas.textBaseline='middle'; if (this.IconFont) { this.Color=this.IconFont.Color; this.Text=this.IconFont.Text; var iconSize=dataWidth; var minIconSize=12*pixelTatio; var maxIconSize=24*pixelTatio; if (iconSizemaxIconSize) iconSize=maxIconSize; this.Canvas.font=iconSize+'px '+this.IconFont.Family; } else { this.TextFont=this.GetDynamicFont(dataWidth*2*pixelTatio); this.Canvas.font=this.TextFont; } for(var i=this.Data.DataOffset,j=0;ichartright) break; this.Canvas.textAlign=this.TextAlign; this.Canvas.fillStyle=this.Color; if (this.YOffset>0 && this.Direction>0) { var yPrice=y; this.Canvas.save(); this.Canvas.setLineDash([5,10]); this.Canvas.strokeStyle=this.Color; this.Canvas.beginPath(); if (isHScreen) { if (this.Direction==1) { y=top-this.YOffset*pixelTatio; yPrice+=5*pixelTatio; } else { y=bottom+this.YOffset*pixelTatio; yPrice-=5*pixelTatio; } this.Canvas.moveTo(ToFixedPoint(yPrice),ToFixedPoint(x)); this.Canvas.lineTo(ToFixedPoint(y),ToFixedPoint(x)); } else { if (this.Direction==1) { y=top+this.YOffset*pixelTatio; yPrice+=5*pixelTatio; } else { y=bottom-this.YOffset*pixelTatio; yPrice-=5*pixelTatio; } this.Canvas.moveTo(ToFixedPoint(x),ToFixedPoint(yPrice)); this.Canvas.lineTo(ToFixedPoint(x),ToFixedPoint(y)); } this.Canvas.stroke(); this.Canvas.restore(); } if (isArrayText) { var text=this.Text[i]; if (!text) continue; this.DrawText(text,x,y,isHScreen); } else { //console.log('[ChartSingleText::Draw] ',this.Direction,this.Text) this.DrawText(this.Text,x,y,isHScreen); } } } this.DrawPosition=function() //绘制在指定位置上 { if (!this.Text) return; var isHScreen=(this.ChartFrame.IsHScreen===true) if (isHScreen) { var x=this.ChartBorder.GetLeft()+this.ChartBorder.GetWidthEx()*this.Position.Y; var y=this.ChartBorder.GetTop()+this.ChartBorder.GetHeight()*this.Position.X; } else { var x=this.ChartBorder.GetLeft()+this.ChartBorder.GetWidth()*this.Position.X; var y=this.ChartBorder.GetTopEx()+this.ChartBorder.GetHeight()*this.Position.Y; } if (isHScreen) { chartright=this.ChartBorder.GetBottom(); top=this.ChartBorder.GetRightEx(); bottom=this.ChartBorder.GetLeftEx(); } this.Canvas.fillStyle=this.Color; if (this.Position.Type==0) this.Canvas.textAlign='left'; else if (this.Position.Type==2) this.Canvas.textAlign='center'; else this.Canvas.textAlign='right'; this.DrawText(this.Text,x,y,isHScreen); } this.DrawText=function(text,x,y,isHScreen) { if (isHScreen) { this.Canvas.save(); this.Canvas.translate(y, x); this.Canvas.rotate(90 * Math.PI / 180); this.Canvas.fillText(text,0,0); this.Canvas.restore(); } else { this.Canvas.fillText(text,x,y); /* var textWidth=this.Canvas.measureText(text).width; var rectSize=textWidth*2; var xRect,yRect; if (this.Direction==1) yRect=y-rectSize; //底部 else if (this.Direction==2) yRect=y; //顶部 else yRect=y-rectSize/2; //居中 if (this.TextAlign=='left') xRect=x; else if (this.TextAlign=='right') xRect=x-rectSize; else xRect=x-rectSize/2; this.Canvas.fillStyle=this.Color; this.Canvas.fillRect(xRect,yRect,rectSize,rectSize); this.Canvas.fillStyle='rgb(255,255,255)'; this.Canvas.fillText(text,x,y); */ } } } //直线 水平直线 只有1个数据 function ChartStraightLine() { this.newMethod=IChartPainting; //派生 this.newMethod(); delete this.newMethod; this.ClassName='ChartStraightLine'; //类名 this.Color="rgb(255,193,37)"; //线段颜色 this.Draw=function() { if (!this.Data || !this.Data.Data) return; if (this.Data.Data.length!=1) return; var dataWidth=this.ChartFrame.DataWidth; var distanceWidth=this.ChartFrame.DistanceWidth; var chartright=this.ChartBorder.GetRight(); var xPointCount=this.ChartFrame.XPointCount; var yValue=this.Data.Data[0]; var y=this.ChartFrame.GetYFromData(yValue); var xLeft=this.ChartFrame.GetXFromIndex(0); var xRight=this.ChartFrame.GetXFromIndex(xPointCount-1); var yFix=parseInt(y.toString())+0.5; this.Canvas.beginPath(); this.Canvas.moveTo(xLeft,yFix); this.Canvas.lineTo(xRight,yFix); this.Canvas.strokeStyle=this.Color; this.Canvas.stroke(); } this.GetMaxMin=function() { var xPointCount=this.ChartFrame.XPointCount; var range={}; range.Min=null; range.Max=null; if (!this.Data || !this.Data.Data) return range; if (this.Data.Data.length!=1) return range; range.Min=this.Data.Data[0]; range.Max=this.Data.Data[0]; return range; } } /* 水平面积 只有1个数据 Data 数据结构 Value, Value2 区间最大最小值 Color=面积的颜色 Title=标题 TitleColor=标题颜色 支持横屏 */ function ChartStraightArea() { this.newMethod = IChartPainting; //派生 this.newMethod(); delete this.newMethod; this.ClassName='ChartStraightArea'; //类名 this.Color = "rgb(255,193,37)"; //线段颜色 this.Font ='11px 微软雅黑'; this.Draw = function () { if (this.NotSupportMessage) { this.DrawNotSupportmessage(); return; } if (!this.Data || !this.Data.Data) return; if (this.ChartFrame.IsHScreen===true) { this.HScreenDraw(); return; } var dataWidth = this.ChartFrame.DataWidth; var distanceWidth = this.ChartFrame.DistanceWidth; var chartright = this.ChartBorder.GetRight(); var bottom = this.ChartBorder.GetBottom(); var left = this.ChartBorder.GetLeft(); var xPointCount = this.ChartFrame.XPointCount; var xRight = this.ChartFrame.GetXFromIndex(xPointCount - 1); for(let i in this.Data.Data) { let item=this.Data.Data[i]; if (item==null || isNaN(item.Value) || isNaN(item.Value2)) continue; if (item.Color==null) continue; let valueMax=Math.max(item.Value,item.Value2); let valueMin=Math.min(item.Value,item.Value2); var yTop=this.ChartFrame.GetYFromData(valueMax); var yBottom=this.ChartFrame.GetYFromData(valueMin); this.Canvas.fillStyle = item.Color; this.Canvas.fillRect(ToFixedRect(left), ToFixedRect(yTop), ToFixedRect(xRight - left), ToFixedRect(yBottom - yTop)); if(item.Title && item.TitleColor) { this.Canvas.textAlign = 'right'; this.Canvas.textBaseline = 'middle'; this.Canvas.fillStyle = item.TitleColor; this.Canvas.font = this.Font; let y = yTop + (yBottom - yTop)/2; this.Canvas.fillText(item.Title, xRight, y); } } } this.HScreenDraw=function() { var bottom = this.ChartBorder.GetBottom(); var top=this.ChartBorder.GetTop(); var height=this.ChartBorder.GetHeight(); for(let i in this.Data.Data) { let item=this.Data.Data[i]; if (item==null || isNaN(item.Value) || isNaN(item.Value2)) continue; if (item.Color==null) continue; let valueMax=Math.max(item.Value,item.Value2); let valueMin=Math.min(item.Value,item.Value2); var yTop=this.ChartFrame.GetYFromData(valueMax); var yBottom=this.ChartFrame.GetYFromData(valueMin); this.Canvas.fillStyle = item.Color; this.Canvas.fillRect(ToFixedRect(yBottom), ToFixedRect(top), ToFixedRect(yTop-yBottom),ToFixedRect(height)); if(item.Title && item.TitleColor) { var xText=yTop + (yBottom - yTop)/2; var yText=bottom; this.Canvas.save(); this.Canvas.translate(xText, yText); this.Canvas.rotate(90 * Math.PI / 180); this.Canvas.textAlign = 'right'; this.Canvas.textBaseline = 'middle'; this.Canvas.fillStyle = item.TitleColor; this.Canvas.font = this.Font; this.Canvas.fillText(item.Title, 0, -2); this.Canvas.restore(); } } } this.GetMaxMin=function() { var xPointCount=this.ChartFrame.XPointCount; var range={}; range.Min=null; range.Max=null; if (!this.Data || !this.Data.Data) return range; for (let i in this.Data.Data) { let item = this.Data.Data[i]; if (item==null || isNaN(item.Value) || isNaN(item.Value2)) continue; let valueMax=Math.max(item.Value,item.Value2); let valueMin=Math.min(item.Value,item.Value2); if (range.Max==null) range.Max=valueMax; if (range.Min==null) range.Min=valueMin; if (range.MaxvalueMin) range.Min=valueMin; } return range; } } //分钟线 支持横屏 function ChartMinutePriceLine() { this.newMethod=ChartLine; //派生 this.newMethod(); delete this.newMethod; this.ClassName='ChartMinutePriceLine'; //类名 this.YClose; this.IsDrawArea=true; //是否画价格面积图 this.AreaColor='rgba(0,191,255,0.1)'; this.SourceData; this.IsShowLead=false; this.LeadData; this.UpColor=g_JSChartResource.UpBarColor; this.DownColor=g_JSChartResource.DownBarColor; this.Draw=function() { if (this.NotSupportMessage) { this.DrawNotSupportmessage(); return; } if (!this.IsShow) return; var isHScreen=(this.ChartFrame.IsHScreen===true); var dataWidth=this.ChartFrame.DataWidth; var distanceWidth=this.ChartFrame.DistanceWidth; var chartright=this.ChartBorder.GetRight(); if (isHScreen===true) chartright=this.ChartBorder.GetBottom(); var xPointCount=this.ChartFrame.XPointCount; var minuteCount=this.ChartFrame.MinuteCount; var bottom=this.ChartBorder.GetBottomEx(); var left=this.ChartBorder.GetLeftEx(); var data=this.Data; var isBeforeData=false; if (this.SourceData) { data=this.SourceData; isBeforeData=true; } if (this.IsShowLead) this.DrawLead(); var bFirstPoint=true; var ptFirst={}; //第1个点 var drawCount=0; for(var i=data.DataOffset,j=0;i=minuteCount) //上一天的数据和这天地数据线段要断开 { bFirstPoint=true; this.Canvas.stroke(); if (this.IsDrawArea) //画面积 { if (isHScreen) { this.Canvas.lineTo(left,x); this.Canvas.lineTo(left,ptFirst.X); } else { this.Canvas.lineTo(x,bottom); this.Canvas.lineTo(ptFirst.X,bottom); } this.Canvas.fillStyle=this.AreaColor; this.Canvas.fill(); } drawCount=0; } } if (drawCount>0) { this.Canvas.stroke(); if (this.IsDrawArea) //画面积 { if (isHScreen) { this.Canvas.lineTo(left,x); this.Canvas.lineTo(left,ptFirst.X); } else { this.Canvas.lineTo(x,bottom); this.Canvas.lineTo(ptFirst.X,bottom); } this.Canvas.fillStyle=this.AreaColor; this.Canvas.fill(); } } } //画领先指标 this.DrawLead=function() { if (!this.LeadData) return; var isHScreen=(this.ChartFrame.IsHScreen===true); //if (isHScreen) return; //var dataWidth=this.ChartFrame.DataWidth; //var distanceWidth=this.ChartFrame.DistanceWidth; //var chartright=this.ChartBorder.GetRight(); var xPointCount=this.ChartFrame.XPointCount; var minuteCount=this.ChartFrame.MinuteCount; var bottom=this.ChartBorder.GetBottomEx(); var top=this.ChartBorder.GetTopEx(); if (isHScreen===true) top=this.ChartBorder.GetRightEx(); if (xPointCount>minuteCount) return; var aryLead=[]; //{X: Value:} var max=null, min=null; var yCenter=this.ChartFrame.GetYFromData(this.YClose); var leadHeight=(yCenter-top)/3; var data=this.LeadData; for(var i=data.DataOffset,j=0;ivalue) min=value; aryLead.push({X:x, Value:value}) } if (aryLead.length<=0) return; var maxValue=Math.max(Math.abs(max),Math.abs(min)); for(var i in aryLead) { var item=aryLead[i]; if (item.Value>0) this.Canvas.strokeStyle=this.UpColor; else this.Canvas.strokeStyle=this.DownColor; var y=yCenter-(item.Value*leadHeight/maxValue); var x=ToFixedPoint(item.X); this.Canvas.beginPath(); if (isHScreen===true) { this.Canvas.moveTo(yCenter,x); this.Canvas.lineTo(y,x); } else { this.Canvas.moveTo(x,yCenter); this.Canvas.lineTo(x,y); } this.Canvas.stroke(); } } this.GetMaxMin=function() { var xPointCount=this.ChartFrame.XPointCount; var range={}; if (this.YClose==null) return range; if (!this.IsShow) return range; range.Min=this.YClose; range.Max=this.YClose; var data=this.Data; var isBeforeData=false; if (this.SourceData) { data=this.SourceData; isBeforeData=true; } for(var i=data.DataOffset,j=0;ivalue) range.Min=value; } if (range.Max==this.YClose && range.Min==this.YClose) { range.Max=this.YClose+this.YClose*0.1; range.Min=this.YClose-this.YClose*0.1; return range; } var distance=Math.max(Math.abs(this.YClose-range.Max),Math.abs(this.YClose-range.Min)); range.Max=this.YClose+distance; range.Min=this.YClose-distance; return range; } } //分钟线叠加 支持横屏 function ChartOverlayMinutePriceLine() { this.newMethod=IChartPainting; //派生 this.newMethod(); delete this.newMethod; this.Color="rgb(65,105,225)"; this.MainData; //主图数据 this.MainYClose; //主图股票的前收盘价 this.SourceData; //原始数据 this.BeforeDataCount=0; this.IsBeforeData=false; this.ClassName="ChartOverlayMinutePriceLine"; this.Title; this.Symbol; //叠加的股票代码 this.YClose; //叠加的股票前收盘 this.Status=OVERLAY_STATUS_ID.STATUS_NONE_ID; this.Draw=function() { if (!this.Data) return; if (this.NotSupportMessage) { this.DrawNotSupportmessage(); return; } var isHScreen=(this.ChartFrame.IsHScreen===true); var dataWidth=this.ChartFrame.DataWidth; var distanceWidth=this.ChartFrame.DistanceWidth; var chartright=this.ChartBorder.GetRight(); if (isHScreen===true) chartright=this.ChartBorder.GetBottom(); var xPointCount=this.ChartFrame.XPointCount; var minuteCount=this.ChartFrame.MinuteCount; var bFirstPoint=true; var drawCount=0; var xOffset=0; if (this.IsBeforeData) xOffset=1; //集合竞价模式从第2个数据开始 第1个数据是9:25数据 for(var i=this.Data.DataOffset+xOffset,j=0;i=minuteCount) //上一天的数据和这天地数据线段要断开 { bFirstPoint=true; this.Canvas.stroke(); drawCount=0; } } if (drawCount>0) this.Canvas.stroke(); } this.GetMaxMin=function() { var xPointCount=this.ChartFrame.XPointCount; var range={}; if (this.YClose==null) return range; range.Min=this.MainYClose; range.Max=this.MainYClose; for(var i=this.Data.DataOffset,j=0;ivalue) range.Min=value; } if (range.Max==this.MainYClose && range.Min==this.MainYClose) { range.Max=this.MainYClose+this.MainYClose*0.1; range.Min=this.MainYClose-this.MainYClose*0.1; return range; } var distance=Math.max(Math.abs(this.MainYClose-range.Max),Math.abs(this.MainYClose-range.Min)); range.Max=this.MainYClose+distance; range.Min=this.MainYClose-distance; //console.log(`[ChartOverlayMinutePriceLine::GetMaxMin] max=${range.Max} min=${range.Min}`); return range; } } //分钟信息地雷 支持横屏 function ChartMinuteInfo() { this.newMethod=IChartPainting; //派生 this.newMethod(); delete this.newMethod; this.ClassName="ChartMinuteInfo"; this.Data=new Map() //Map key=date-time, value=[{Date, Time, Title, Type, ID:}] this.SourceData; this.ChartMinutePrice; this.YClose; this.HQChartBorder; this.TextColor=g_JSChartResource.MinuteInfo.TextColor; this.Font=g_JSChartResource.MinuteInfo.Font; this.PointColor=g_JSChartResource.MinuteInfo.PointColor; this.LineColor=g_JSChartResource.MinuteInfo.LineColor; this.TextBGColor=g_JSChartResource.MinuteInfo.TextBGColor; this.PixelTatio = GetDevicePixelRatio(); //获取设备的分辨率 this.TextHeight=20; this.TextRectCache=[]; this.InfoDrawCache=[]; this.FrameBottom; this.FrameTop; this.FrameLeft; this.FrameRight; this.YOffset=5; this.IsHScreen=false; this.IsDrawFull=false; //是否全屏画 this.SetOption=function(option) { if (option.TextColor) this.TextColor=option.TextColor; if (option.TextBGColor) this.TextBGColor=option.TextBGColor; if (option.Font) this.Font=option.Font; if (option.PointColor) this.PointColor=option.PointColor; if (option.LineColor) this.LineColor=option.LineColor; if (option.TextHeight>0) this.TextHeight=option.TextHeight; if (option.IsDrawFull==true) this.IsDrawFull=true; } this.Draw=function() { if (!this.ChartMinutePrice) return; if (!this.Data || this.Data.size<=0) return; this.TextRectCache=[]; this.InfoDrawCache=[]; this.PixelTatio=GetDevicePixelRatio(); this.YOffset=5*this.PixelTatio; this.IsHScreen=(this.ChartFrame.IsHScreen===true); var xPointCount=this.ChartFrame.XPointCount; var minuteCount=this.ChartFrame.MinuteCount; this.FrameBottom=this.ChartBorder.GetBottom(); if (this.IsDrawFull && this.HQChartBorder) this.FrameBottom=this.HQChartBorder.GetBottom(); this.FrameTop=this.ChartBorder.GetTop(); this.FrameLeft=this.ChartBorder.GetLeft(); this.FrameRight=this.ChartBorder.GetRight(); if (this.IsHScreen) { this.FrameRight=this.ChartBorder.GetBottom(); this.FrameLeft=this.ChartBorder.GetTop(); this.FrameBottom=this.ChartBorder.GetLeft(); this.FrameTop=this.ChartBorder.GetRight(); } this.YClose=this.ChartMinutePrice.YClose; var data=this.ChartMinutePrice.Data; var isBeforeData=false; if (this.ChartMinutePrice.SourceData) { data=this.ChartMinutePrice.SourceData; isBeforeData=true; } for(var i=data.DataOffset,j=0;ithis.YClose) xData.X=xData.X.reverse(); var rtBorder={X:null, Y:y, Width:textWidth,Height:textHeight}; if (!isDrawLeft) rtBorder.Y-=rtBorder.Height; this.FixHScreenTextRect(rtBorder,xData); var InfoDrawItem={ Border:rtBorder, Start:{X:x,Y:y}, IsLeft:isDrawLeft, Title:showItem.Title }; this.InfoDrawCache.push(InfoDrawItem); this.TextRectCache.push(rtBorder); } this.DrawInfoLines=function(item) { var rtBorder=item.Border; var isDrawLeft=item.IsLeft; this.Canvas.strokeStyle=this.LineColor; this.Canvas.beginPath(); this.Canvas.moveTo(ToFixedPoint(item.Start.X),item.Start.Y); if (isDrawLeft) { this.Canvas.lineTo(ToFixedPoint(item.Start.X),rtBorder.Y); } else { if (this.IsHScreen) this.Canvas.lineTo(rtBorder.X,rtBorder.Y+rtBorder.Height); else this.Canvas.lineTo(ToFixedPoint(item.Start.X),rtBorder.Y); } this.Canvas.stroke(); this.Canvas.fillStyle = this.PointColor; this.Canvas.beginPath(); this.Canvas.arc(item.Start.X,item.Start.Y, 5, 0, 2 * Math.PI); this.Canvas.closePath(); this.Canvas.fill(); } this.DrawInfoText=function(item) { var rtBorder=item.Border; var x=rtBorder.X, y=rtBorder.Y; this.Canvas.fillStyle=this.TextBGColor; this.Canvas.fillRect(x, y, rtBorder.Width,rtBorder.Height); this.Canvas.strokeStyle=this.LineColor; this.Canvas.beginPath(); this.Canvas.rect(x,y,rtBorder.Width,rtBorder.Height); this.Canvas.stroke(); if (this.IsHScreen) { this.Canvas.save(); this.Canvas.translate(rtBorder.X,rtBorder.Y); this.Canvas.rotate(90 * Math.PI / 180); x=0;y=0; } this.Canvas.textAlign = 'left' this.Canvas.textBaseline = 'middle'; this.Canvas.fillStyle = this.TextColor; this.Canvas.font = this.Font; if (this.IsHScreen) this.Canvas.fillText(item.Title, x+2*this.PixelTatio, y-rtBorder.Width/2); else this.Canvas.fillText(item.Title, x+2*this.PixelTatio, y+rtBorder.Height/2); if (this.IsHScreen) this.Canvas.restore(); } this.FixTextRect=function(rect,yData) { for(var k in yData.Y) { var yItem=yData.Y[k]; rect.Y=yItem.Value; var y; for(var j=0;j<10;++j) { var isOverlap=false; for(var i in this.TextRectCache) { var item=this.TextRectCache[i]; if (this.IsOverlap(item, rect)) { isOverlap=true; break; } } if (isOverlap==false) return; y=rect.Y; y+=yItem.Offset; if (y+rect.Height>this.FrameBottom || ythis.FrameTop) break; rect.X=x; } } } this.IsOverlap=function(rc1, rc2) { if (rc1.X + rc1.Width > rc2.X &&rc2.X + rc2.Width > rc1.X &&rc1.Y + rc1.Height > rc2.Y &&rc2.Y + rc2.Height > rc1.Y) return true; else return false; } this.GetMaxMin=function() { var range={Min:null, Max:null}; return range; } } //MACD森林线 支持横屏 function ChartMACD() { this.newMethod=IChartPainting; //派生 this.newMethod(); delete this.newMethod; this.ClassName="ChartMACD"; this.UpColor=g_JSChartResource.UpBarColor; this.DownColor=g_JSChartResource.DownBarColor; this.Draw=function() { if (this.NotSupportMessage) { this.DrawNotSupportmessage(); return; } if (this.ChartFrame.IsHScreen===true) { this.HScreenDraw(); return; } var dataWidth=this.ChartFrame.DataWidth; var distanceWidth=this.ChartFrame.DistanceWidth; var chartright=this.ChartBorder.GetRight(); var xPointCount=this.ChartFrame.XPointCount; var lockRect=this.GetLockRect(); if (lockRect) chartright=lockRect.Left; var bFirstPoint=true; var drawCount=0; var yBottom=this.ChartFrame.GetYFromData(0); for(var i=this.Data.DataOffset,j=0;ichartright) break; var xFix=parseInt(x.toString())+0.5; //毛边修正 this.Canvas.beginPath(); this.Canvas.moveTo(xFix,yBottom); this.Canvas.lineTo(xFix,y); if (value>=0) this.Canvas.strokeStyle=this.UpColor; else this.Canvas.strokeStyle=this.DownColor; this.Canvas.stroke(); this.Canvas.closePath(); } } this.HScreenDraw=function() { var chartright=this.ChartBorder.GetBottom(); var xPointCount=this.ChartFrame.XPointCount; var lockRect=this.GetLockRect(); if (lockRect) chartright=lockRect.Top; var yBottom=this.ChartFrame.GetYFromData(0); for(var i=this.Data.DataOffset,j=0;ichartright) break; this.Canvas.beginPath(); this.Canvas.moveTo(yBottom,ToFixedPoint(x)); this.Canvas.lineTo(y,ToFixedPoint(x)); if (value>=0) this.Canvas.strokeStyle=this.UpColor; else this.Canvas.strokeStyle=this.DownColor; this.Canvas.stroke(); this.Canvas.closePath(); } } } //柱子 function ChartBar() { this.newMethod=IChartPainting; //派生 this.newMethod(); delete this.newMethod; this.ClassName="ChartBar"; this.UpBarColor=g_JSChartResource.UpBarColor; this.DownBarColor=g_JSChartResource.DownBarColor; this.Draw=function() { if (this.NotSupportMessage) { this.DrawNotSupportmessage(); return; } var dataWidth=this.ChartFrame.DataWidth; var distanceWidth=this.ChartFrame.DistanceWidth; var chartright=this.ChartBorder.GetRight(); var xPointCount=this.ChartFrame.XPointCount; var xOffset=this.ChartBorder.GetLeft()+distanceWidth/2.0+2.0; var bFirstPoint=true; var drawCount=0; var yBottom=this.ChartFrame.GetYFromData(0); if (dataWidth>=4) { yBottom=ToFixedRect(yBottom); //调整为整数 for(var i=this.Data.DataOffset,j=0;ichartright) break; var x=this.ChartFrame.GetXFromIndex(j); var y=this.ChartFrame.GetYFromData(value); if (value>0) this.Canvas.fillStyle=this.UpBarColor; else this.Canvas.fillStyle=this.DownBarColor; //高度调整为整数 var height=ToFixedRect(Math.abs(yBottom-y)); if(yBottom-y>0) y=yBottom-height; else y=yBottom+height; this.Canvas.fillRect(ToFixedRect(left),y,ToFixedRect(dataWidth),height); } } else //太细了 直接画柱子 { for(var i=this.Data.DataOffset,j=0;ichartright) break; var x=this.ChartFrame.GetXFromIndex(j); var y=this.ChartFrame.GetYFromData(value); if (value>0) this.Canvas.strokeStyle=this.UpBarColor; else this.Canvas.strokeStyle=this.DownBarColor; this.Canvas.beginPath(); this.Canvas.moveTo(ToFixedPoint(x),y); this.Canvas.lineTo(ToFixedPoint(x),yBottom); this.Canvas.stroke(); } } } this.GetMaxMin=function() { var xPointCount=this.ChartFrame.XPointCount; var range={}; range.Min=0; range.Max=null; for(var i=this.Data.DataOffset,j=0;i 1) { this.Canvas.save(); this.Canvas.beginPath(); for (var i = 0; i < firstlinePoints.length; ++i) { if (i == 0) this.Canvas.moveTo(firstlinePoints[i].x, firstlinePoints[i].y); else this.Canvas.lineTo(firstlinePoints[i].x, firstlinePoints[i].y); } for (var j = secondlinePoints.length-1; j >= 0; --j) { this.Canvas.lineTo(secondlinePoints[j].x, secondlinePoints[j].y); } this.Canvas.closePath(); this.Canvas.clip(); this.Canvas.beginPath(); this.Canvas.moveTo(firstlinePoints[0].x, this.ChartBorder.GetBottom()); for (var i = 0; i < firstlinePoints.length; ++i) { this.Canvas.lineTo(firstlinePoints[i].x, firstlinePoints[i].y); } this.Canvas.lineTo(firstlinePoints[firstlinePoints.length-1].x, this.ChartBorder.GetBottom()); this.Canvas.closePath(); this.Canvas.fillStyle = this.FirstColor; this.Canvas.fill(); this.Canvas.beginPath(); this.Canvas.moveTo(secondlinePoints[0].x, this.ChartBorder.GetBottom()); for (var i = 0; i < secondlinePoints.length; ++i) { this.Canvas.lineTo(secondlinePoints[i].x, secondlinePoints[i].y); } this.Canvas.lineTo(secondlinePoints[secondlinePoints.length-1].x, this.ChartBorder.GetBottom()); this.Canvas.closePath(); this.Canvas.fillStyle = this.SecondColor; this.Canvas.fill(); this.Canvas.restore(); } } this.GetMaxMin=function() { var xPointCount=this.ChartFrame.XPointCount; var range={}; range.Min=null; range.Max=null; for(var i=this.Data.DataOffset,j=0;ivalue.Value2?value.Value:value.Value2; var minData = value.Value minData) range.Min = minData; } return range; } } // 通道面积图 支持横屏 function ChartChannel() { this.newMethod=IChartPainting; //派生 this.newMethod(); delete this.newMethod; this.IsDrawFirst = true; this.ClassName="ChartChannel"; this.IsHScreen=false; //是否是横屏 this.PointCount=0; this.DataWidth=0; this.DistanceWidth=0; this.ChartRight=0; //可以绘制的最右边 this.LineColor='RGB(255,0,0)'; this.LineDotted=[3,3]; this.AreaColor='RGB(255,222,173)'; this.LineWidth=1; this.CalculateData=function() //把数据通过nul值分割开, 并计算坐标 { var data=[]; var lineData=[]; for(var i=this.Data.DataOffset,j=0;i0) { data.push(lineData); lineData=[]; //创建新的一组数据 } continue; } var x=this.ChartFrame.GetXFromIndex(j); if (x>this.ChartRight) break; var y=this.ChartFrame.GetYFromData(item.Value); var y2=this.ChartFrame.GetYFromData(item.Value2); lineData.push({X:x, Y:y,Y2:y2}); } if (lineData.length>0) data.push(lineData); return data; } this.DrawArea=function(lineData) { if (lineData.length<=0) return; this.Canvas.beginPath(); var drawCount=0; var firstItem=lineData[0]; if (this.IsHScreen) this.Canvas.moveTo(firstItem.Y,firstItem.X); else this.Canvas.moveTo(firstItem.X,firstItem.Y); for(var i=1;i=0;--i) { var item=lineData[i]; if (this.IsHScreen) this.Canvas.lineTo(item.Y2,item.X); else this.Canvas.lineTo(item.X,item.Y2); ++drawCount; } this.Canvas.closePath(); this.Canvas.fillStyle = this.AreaColor; this.Canvas.fill(); } this.DrawLine=function(lineData) { this.Canvas.strokeStyle=this.LineColor; for(var k=0;k<2;++k) { var bFirstPoint=true; var drawCount=0; for(var i=0;i0) this.Canvas.stroke(); } } this.Draw=function() { if (this.NotSupportMessage) { this.DrawNotSupportmessage(); return; } this.IsHScreen=(this.ChartFrame.IsHScreen===true); this.PointCount=this.ChartFrame.XPointCount; this.DataWidth=this.ChartFrame.DataWidth; this.DistanceWidth=this.ChartFrame.DistanceWidth; if (this.IsHScreen) this.ChartRight=this.ChartBorder.GetBottom(); else this.ChartRight=this.ChartBorder.GetRight(); var drawData=this.CalculateData(); if (!drawData || drawData.length<=0) return; this.Canvas.save(); this.Canvas.lineWidth=this.LineWidth*GetDevicePixelRatio(); this.Canvas.setLineDash(this.LineDotted); //虚线 for(var i=0;ivalue.Value2?value.Value:value.Value2; var minData = value.Value minData) range.Min = minData; } return range; } } //填充背景 TODO:横屏 function ChartBackground() { this.newMethod=IChartPainting; //派生 this.newMethod(); delete this.newMethod; this.Color=null; this.ColorAngle=0; //0 竖向 1 横向 this.Draw=function() { if (!this.IsShow) return; if (!this.Color) return; if (this.Color.length<=0) return; if (this.Color.length==2) { if (this.ColorAngle==0) { var ptStart={ X:this.ChartBorder.GetLeft(), Y:this.ChartBorder.GetTopEx() }; var ptEnd={ X:this.ChartBorder.GetLeft(), Y:this.ChartBorder.GetBottomEx() }; } else { var ptStart={ X:this.ChartBorder.GetLeft(), Y:this.ChartBorder.GetTopEx() }; var ptEnd={ X:this.ChartBorder.GetRight(), Y:this.ChartBorder.GetTopEx() }; } let gradient = this.Canvas.createLinearGradient(ptStart.X,ptStart.Y, ptEnd.X,ptEnd.Y); gradient.addColorStop(0, this.Color[0]); gradient.addColorStop(1, this.Color[1]); this.Canvas.fillStyle=gradient; } else if (this.Color.length==1) { this.Canvas.fillStyle=this.Color[0]; } else { return; } var left=this.ChartBorder.GetLeft(); var top=this.ChartBorder.GetTopEx(); var width=this.ChartBorder.GetWidth(); var height=this.ChartBorder.GetHeightEx(); this.Canvas.fillRect(left, top,width, height); } } //画矩形 function ChartRectangle() { this.newMethod=IChartPainting; //派生 this.newMethod(); delete this.newMethod; this.Color=[]; this.Rect; this.BorderColor=g_JSChartResource.FrameBorderPen; this.Draw=function() { if (!this.IsShow) return; if (!this.Color || !this.Rect) return; if (this.Color.length<=0) return; this.Canvas.strokeStyle=this.BorderColor; var bFill=false; if (this.Color.length==2) { /* TODO 渐变下次做吧 if (this.ColorAngle==0) { var ptStart={ X:this.ChartBorder.GetLeft(), Y:this.ChartBorder.GetTopEx() }; var ptEnd={ X:this.ChartBorder.GetLeft(), Y:this.ChartBorder.GetBottomEx() }; } else { var ptStart={ X:this.ChartBorder.GetLeft(), Y:this.ChartBorder.GetTopEx() }; var ptEnd={ X:this.ChartBorder.GetRight(), Y:this.ChartBorder.GetTopEx() }; } let gradient = this.Canvas.createLinearGradient(ptStart.X,ptStart.Y, ptEnd.X,ptEnd.Y); gradient.addColorStop(0, this.Color[0]); gradient.addColorStop(1, this.Color[1]); this.Canvas.fillStyle=gradient; */ this.Canvas.fillStyle=this.Color[0]; bFill=true; } else if (this.Color.length==1) { if (this.Color[0]) { this.Canvas.fillStyle=this.Color[0]; bFill=true; } } else { return; } var chartWidth=this.ChartBorder.GetWidth(); var chartHeight=this.ChartBorder.GetHeightEx(); var left=this.Rect.Left/1000*chartWidth; var top=this.Rect.Top/1000*chartHeight; var right=this.Rect.Right/1000*chartWidth; var bottom=this.Rect.Bottom/1000*chartHeight; left=this.ChartBorder.GetLeft()+left top=this.ChartBorder.GetTopEx()+top; right=this.ChartBorder.GetLeft()+right; bottom=this.ChartBorder.GetTopEx()+bottom; var width=Math.abs(left-right); var height=Math.abs(top-bottom); if (bFill) this.Canvas.fillRect(left, top,width, height); this.Canvas.rect(ToFixedPoint(left), ToFixedPoint(top),ToFixedRect(width), ToFixedRect(height)); this.Canvas.stroke(); } } // 文字+线段输出 function ChartTextLine() { this.newMethod=IChartPainting; //派生 this.newMethod(); delete this.newMethod; this.Text; //Text=内容 Color this.Line; //Type=线段类型 0=不画 1=直线 2=虚线, Color this.Price; this.Draw=function() { if (!this.IsShow) return; if (!this.Text || !this.Line || !IFrameSplitOperator.IsNumber(this.Price)) return; this.IsHScreen=(this.ChartFrame.IsHScreen===true); var left=this.ChartBorder.GetLeft(); var right=this.ChartBorder.GetRight(); var bottom=this.ChartBorder.GetBottomEx(); var top=this.ChartBorder.GetTopEx(); var y=this.ChartFrame.GetYFromData(this.Price); var textWidth=0; if (this.Text.Title) { var x=left+2*GetDevicePixelRatio(); var yText=y; this.Canvas.textAlign = 'left'; this.Canvas.textBaseline = 'middle'; var offsetY=8*GetDevicePixelRatio(); if (y-offsetYbottom) { this.Canvas.textBaseline='bottom'; yText=bottom; } this.Canvas.fillStyle = this.Text.Color; this.Canvas.font = this.Text.Font; this.Canvas.fillText(this.Text.Title, x, yText); textWidth=this.Canvas.measureText(this.Text.Title).width+4*GetDevicePixelRatio(); } if (this.Line.Type>0) { if (this.Line.Type==2) //虚线 { this.Canvas.save(); this.Canvas.setLineDash([3,5]); //虚线 } var x=left+textWidth; this.Canvas.strokeStyle=this.Line.Color; this.Canvas.beginPath(); this.Canvas.moveTo(x,ToFixedPoint(y)); this.Canvas.lineTo(right,ToFixedPoint(y)); this.Canvas.stroke(); if (this.Line.Type==2) { this.Canvas.restore(); } } } this.GetMaxMin=function() { var range={Min:null, Max:null}; if (IFrameSplitOperator.IsNumber(this.Price)) { range.Min=this.Price; range.Max=this.Price; } return range; } } // 线段集合 支持横屏 function ChartMultiLine() { this.newMethod=IChartPainting; //派生 this.newMethod(); delete this.newMethod; this.Lines=[]; // [ {Point:[ {Index, Value }, ], Color: }, ] this.IsHScreen=false; this.Draw=function() { if (!this.IsShow) return; if (!this.Data || this.Data.length<=0) return; this.IsHScreen=(this.ChartFrame.IsHScreen===true); var xPointCount=this.ChartFrame.XPointCount; var offset=this.Data.DataOffset; var drawLines=[]; for(var i in this.Lines) { var line=this.Lines[i]; var drawPoints={ Point:[], Color:line.Color }; for(var j in line.Point) { var point=line.Point[j]; if (!IFrameSplitOperator.IsNumber(point.Index)) continue; var index=point.Index-offset; if (index>=0 && index=2) drawLines.push(drawPoints) } for(var i in drawLines) { var item=drawLines[i]; this.DrawLine(item); } } this.DrawLine=function(line) { this.Canvas.strokeStyle=line.Color; for(var i in line.Point) { var item=line.Point[i]; if (i==0) { this.Canvas.beginPath(); if (this.IsHScreen) this.Canvas.moveTo(item.Y,item.X); else this.Canvas.moveTo(item.X,item.Y); } else { if (this.IsHScreen) this.Canvas.lineTo(item.Y,item.X); else this.Canvas.lineTo(item.X,item.Y); } } this.Canvas.stroke(); } this.GetMaxMin=function() { var range={ Min:null, Max:null }; var xPointCount=this.ChartFrame.XPointCount; var start=this.Data.DataOffset; var end=start+xPointCount; for(var i in this.Lines) { var line=this.Lines[i]; for(var j in line.Point) { var point=line.Point[j]; if (point.Index>=start && point.Indexpoint.Value) range.Min=point.Value; } } } return range; } } // 多文本集合 function ChartMultiText() { this.newMethod=IChartPainting; //派生 this.newMethod(); delete this.newMethod; this.Texts=[]; //[ {Index:, Value:, Text:, Color:, Font: , Baseline:} ] this.Font=g_JSChartResource.DefaultTextFont; this.Color=g_JSChartResource.DefaultTextColor; this.Draw=function() { if (!this.IsShow) return; if (!this.Data || this.Data.length<=0) return; if (!this.Texts) return; var xPointCount=this.ChartFrame.XPointCount; var offset=this.Data.DataOffset; var left=this.ChartBorder.GetLeft(); var right=this.ChartBorder.GetRight(); for(var i in this.Texts) { var item=this.Texts[i]; if (!item.Text) continue; if (!IFrameSplitOperator.IsNumber(item.Index)) continue; var index=item.Index-offset; if (index>=0 && index=right) { this.Canvas.textAlign='right'; x=right; } else if (x-textWidth/2=start && item.Indexitem.Value) range.Min=item.Value; } } return range; } } // 图标集合 支持横屏 function ChartMultiSVGIcon() { this.newMethod=IChartPainting; //派生 this.newMethod(); delete this.newMethod; this.Icon; //[ {Index:, Value:, Symbol:, Color:, Baseline:} ] this.Family; this.Color=g_JSChartResource.DefaultTextColor; this.IsHScreen=false; this.Draw=function() { if (!this.IsShow) return; if (!this.Data || this.Data.length<=0) return; if (!this.Family || !this.Icon) return; this.IsHScreen=(this.ChartFrame.IsHScreen===true); var xPointCount=this.ChartFrame.XPointCount; var offset=this.Data.DataOffset; var left=this.ChartBorder.GetLeft(); var right=this.ChartBorder.GetRight(); this.DataWidth=this.ChartFrame.DataWidth; this.DistanceWidth=this.ChartFrame.DistanceWidth; if (this.IsHScreen) { left=this.ChartBorder.GetTop(); right=this.ChartBorder.GetBottom(); } var fontSize=(this.DataWidth+this.DistanceWidth)-2; if (fontSize<8) fontSize=8; this.Canvas.font=fontSize+'px '+this.Family; for(var i in this.Icon) { var item=this.Icon[i]; if (!IFrameSplitOperator.IsNumber(item.Index)) continue; var index=item.Index-offset; if (index>=0 && index=right) { this.Canvas.textAlign='right'; x+=this.DataWidth/2; } else if (x-textWidth/2=start && item.Indexitem.Value) range.Min=item.Value; } } return range; } } //锁 支持横屏 function ChartLock() { this.newMethod=IChartPainting; //派生 this.newMethod(); delete this.newMethod; this.ClassName="ChartLock"; this.WidthDiv = 0.2; // 框子宽度占比 this.LockCount = 20; // 锁最新的几个数据 this.BGColor = g_JSChartResource.LockBGColor; this.TextColor = g_JSChartResource.LockTextColor; this.Font = g_JSChartResource.DefaultTextFont; this.Title = '🔒开通权限'; this.LockRect=null; //上锁区域 this.LockID; //锁ID this.Callback; //回调 this.IndexName; //指标名字 this.MinWidth=null; //最小宽度 this.Draw=function(isDraw) { this.LockRect=null; if (this.NotSupportMessage) { this.DrawNotSupportmessage(); return; } if (this.ChartFrame.IsHScreen===true) { this.HScreenDraw(isDraw); return; } var xOffset = this.ChartBorder.GetRight(); var lOffsetWidth = 0; if (this.ChartFrame.Data != null) { var dataWidth=this.ChartFrame.DataWidth; var distanceWidth=this.ChartFrame.DistanceWidth; xOffset=this.ChartBorder.GetLeft()+distanceWidth/2.0+2.0; var chartright=this.ChartBorder.GetRight(); var xPointCount=this.ChartFrame.XPointCount; for(var i=this.ChartFrame.Data.DataOffset,j=0;ichartright) break; } lOffsetWidth = (dataWidth + distanceWidth) * this.LockCount; } if (lOffsetWidth == 0) { lOffsetWidth = (xOffset - this.ChartBorder.GetLeft()) * this.WidthDiv; } var lLeft = xOffset - lOffsetWidth; if (lLeft < this.ChartBorder.GetLeft()) lLeft = this.ChartBorder.GetLeft(); var lHeight = this.ChartBorder.GetBottom() - this.ChartBorder.GetTop(); var lWidth = this.ChartBorder.GetRight() - lLeft; if (this.MinWidth>10 && lWidthchartright) break; } lOffsetWidth = (dataWidth + distanceWidth) * this.LockCount; } if (lOffsetWidth == 0) { lOffsetWidth = (xOffset - this.ChartBorder.GetTop()) * this.WidthDiv; } var lLeft = xOffset - lOffsetWidth; if (lLeft < this.ChartBorder.GetTop()) lLeft = this.ChartBorder.GetTop(); var lHeight = this.ChartBorder.GetRight()-this.ChartBorder.GetLeft(); var lWidth = this.ChartBorder.GetBottom() - lLeft; this.Canvas.fillStyle = this.BGColor; this.Canvas.fillRect(this.ChartBorder.GetLeft(), lLeft,lHeight,lWidth); var xCenter = this.ChartBorder.GetLeft() + lHeight / 2; var yCenter = lLeft + lWidth / 2; this.Canvas.save(); this.Canvas.translate(xCenter, yCenter); this.Canvas.rotate(90 * Math.PI / 180); this.Canvas.textAlign = 'center'; this.Canvas.textBaseline = 'middle'; this.Canvas.fillStyle = this.TextColor; this.Canvas.font = this.Font; this.Canvas.fillText(this.Title, 0, 0); this.Canvas.restore(); this.LockRect={Left:this.ChartBorder.GetLeft(),Top:lLeft,Width:lHeight,Heigh:lWidth}; //保存上锁区域 } //x,y是否在上锁区域 this.GetTooltipData=function(x,y,tooltip) { if (this.LockRect==null) return false; this.Canvas.beginPath(); this.Canvas.rect(this.LockRect.Left,this.LockRect.Top,this.LockRect.Width,this.LockRect.Heigh); if (this.Canvas.isPointInPath(x,y)) { tooltip.Data={ ID:this.LockID, Callback:this.Callback, IndexName:this.IndexName }; tooltip.ChartPaint=this; return true; } return false; } } //买卖盘 function ChartBuySell() { this.newMethod=ChartSingleText; //派生 this.newMethod(); delete this.newMethod; this.ClassName="ChartBuySell"; this.TextFont=g_JSChartResource.KLineTrain.Font; //"bold 14px arial"; //买卖信息字体 this.LastDataIcon=g_JSChartResource.KLineTrain.LastDataIcon; //{Color:'rgb(0,0,205)',Text:'↓'}; this.BuyIcon=g_JSChartResource.KLineTrain.BuyIcon; //{Color:'rgb(0,0,205)',Text:'B'}; this.SellIcon=g_JSChartResource.KLineTrain.SellIcon; //{Color:'rgb(0,0,205)',Text:'S'}; this.BuySellData=new Map(); //{Date:日期, Op:买/卖 0=buy 1=sell} this.LastData={}; //当前屏最后一个数据 this.IconFont=g_JSChartResource.KLineTrain.IconFont; this.Draw=function() { if (!this.Data || !this.Data.Data) return; var isHScreen=(this.ChartFrame.IsHScreen===true); var dataWidth=this.ChartFrame.DataWidth; var distanceWidth=this.ChartFrame.DistanceWidth; var chartright=this.ChartBorder.GetRight(); if (isHScreen===true) chartright=this.ChartBorder.GetBottom(); var xPointCount=this.ChartFrame.XPointCount; if (this.IconFont) { var pixelTatio = GetDevicePixelRatio(); //获取设备的分辨率 var iconSize=dataWidth+distanceWidth; var minIconSize=18*pixelTatio; if (iconSizechartright) break; this.LastData={ID:j,Data:value}; if (!this.BuySellData.has(value.Date)) continue; var bsItem=this.BuySellData.get(value.Date); var x=this.ChartFrame.GetXFromIndex(j); var yHigh=this.ChartFrame.GetYFromData(value.High); var yLow=this.ChartFrame.GetYFromData(value.Low); if (bsItem.Op==0) //买 标识在最低价上 { this.Canvas.textAlign='center'; this.Canvas.textBaseline='top'; if (this.IconFont) { this.Canvas.fillStyle=this.IconFont.Buy.Color this.DrawText(this.IconFont.Buy.Text,x,yLow,isHScreen); } else { this.Canvas.fillStyle=this.BuyIcon.Color; this.DrawText(this.BuyIcon.Text,x,yLow,isHScreen); } } else //卖 标识在最高价上 { this.Canvas.textAlign='center'; this.Canvas.textBaseline='bottom'; if (this.IconFont) { this.Canvas.fillStyle=this.IconFont.Sell.Color this.DrawText(this.IconFont.Sell.Text,x,yHigh,isHScreen); } else { this.Canvas.fillStyle=this.SellIcon.Color; this.DrawText(this.SellIcon.Text,x,yHigh,isHScreen); } } } //最后一个位置 var x=this.ChartFrame.GetXFromIndex(this.LastData.ID); var yHigh=this.ChartFrame.GetYFromData(this.LastData.Data.High); this.Canvas.textAlign='center'; this.Canvas.textBaseline='bottom'; if (this.IconFont) { this.Canvas.fillStyle=this.IconFont.Last.Color this.DrawText(this.IconFont.Last.Text,x,yHigh,isHScreen); } else { this.Canvas.fillStyle=this.LastDataIcon.Color; this.Canvas.font=this.TextFont; this.DrawText(this.LastDataIcon.Text,x,yHigh,isHScreen); } } } /* 饼图 */ function ChartPie() { this.newMethod=IChartPainting; //派生 this.newMethod(); delete this.newMethod; this.Radius = 100; //半径默认值 this.Distance = 30; //指示线超出圆饼的距离 this.txtLine = 20; // 文本下划线 this.paddingX = 20 / 3;// 设置文本的移动 // return; this.Draw=function() { if (!this.Data || !this.Data.Data || !(this.Data.Data.length>0)) return this.DrawEmptyData(); let left=this.ChartBorder.GetLeft(); let right=this.ChartBorder.GetRight(); let top=this.ChartBorder.GetTop(); let bottom=this.ChartBorder.GetBottom(); let width=this.ChartBorder.GetWidth(); let height=this.ChartBorder.GetHeight(); if(isNaN(this.Radius)){ let str = this.Radius.replace("%",""); str = str/100; if(width >= height){ this.Radius = str*height; } if(width < height) this.Radius = str*width; } this.Canvas.save(); this.Canvas.translate(width/2,height/2); let totalValue=0; //求和 for(let i in this.Data.Data) { totalValue += this.Data.Data[i].Value; } let start = 0; let end = 0; //画饼图 for(let i in this.Data.Data) { let item =this.Data.Data[i]; let rate=(item.Value/totalValue).toFixed(2); //占比 //console.log('[ChartPie::Draw]', i, rate, item); // 绘制扇形 this.Canvas.beginPath(); this.Canvas.moveTo(0,0); end += rate*2*Math.PI;//终止角度 this.Canvas.strokeStyle = "white"; this.Canvas.fillStyle = item.Color; this.Canvas.arc(0,0,this.Radius,start,end); this.Canvas.fill(); this.Canvas.closePath(); this.Canvas.stroke(); // 绘制直线 this.Canvas.beginPath(); this.Canvas.strokeStyle = item.Color; this.Canvas.moveTo(0,0); let x = (this.Radius + this.Distance)*Math.cos(end- (end-start)/2); let y = (this.Radius + this.Distance)*Math.sin(end - (end-start)/2); this.Canvas.lineTo(x,y); // console.log(x,y,"xy") // 绘制横线 let txtLine = this.txtLine; let paddingX = this.paddingX; this.Canvas.textAlign = 'left'; if( end - (end-start)/2 < 1.5*Math.PI && end - (end-start)/2 > 0.5*Math.PI ){ txtLine = - this.txtLine; paddingX = - this.paddingX; this.Canvas.textAlign = 'right'; } this.Canvas.lineTo( x + txtLine, y ); this.Canvas.stroke(); // 写文字 if(item.Text){ this.Canvas.fillText( item.Text, x + txtLine + paddingX, y ); }else{ let text = `${item.Name}:${item.Value}`; this.Canvas.fillText( text, x + txtLine + paddingX, y ); } start += rate*2*Math.PI;//起始角度 } this.Canvas.restore(); } //空数据 this.DrawEmptyData=function() { console.log('[ChartPie::DrawEmptyData]') } } /* 雷达图 */ function ChartRadar() { this.newMethod=IChartPainting; //派生 this.newMethod(); delete this.newMethod; this.BorderPoint=[]; //边框点 this.DataPoint=[]; //数据点 this.CenterPoint={}; this.StartAngle=0; this.Color='rgb(198,198,198)'; this.AreaColor='rgba(242,154,118,0.4)'; //面积图颜色 this.AreaLineColor='rgb(242,154,118)'; this.TitleFont=24*GetDevicePixelRatio()+'px 微软雅黑'; this.TitleColor='rgb(102,102,102)'; this.BGColor = ['rgb(255,255,255)', 'rgb(224,224,224)']//背景色 this.DrawBorder=function() //画边框 { if (this.BorderPoint.length<=0) return; this.Canvas.font=this.TitleFont; this.Canvas.strokeStyle = this.Color; const aryBorder=[1,0.8,0.6,0.4,0.2]; for (let j in aryBorder) { var rate = aryBorder[j]; var isFirstDraw=true; for(let i in this.BorderPoint) { var item=this.BorderPoint[i]; item.X = this.CenterPoint.X + item.Radius * Math.cos(item.Angle * Math.PI / 180) * rate; item.Y = this.CenterPoint.Y + item.Radius * Math.sin(item.Angle * Math.PI / 180) * rate; if (isFirstDraw) { this.Canvas.beginPath(); this.Canvas.moveTo(item.X,item.Y); isFirstDraw=false; } else { this.Canvas.lineTo(item.X,item.Y); } } this.Canvas.closePath(); this.Canvas.stroke(); this.Canvas.fillStyle = this.BGColor[j%2==0?0:1]; this.Canvas.fill(); } this.Canvas.beginPath(); for(let i in this.BorderPoint) { var item=this.BorderPoint[i]; item.X = this.CenterPoint.X + item.Radius * Math.cos(item.Angle * Math.PI / 180); item.Y = this.CenterPoint.Y + item.Radius * Math.sin(item.Angle * Math.PI / 180); this.Canvas.moveTo(this.CenterPoint.X,this.CenterPoint.Y); this.Canvas.lineTo(item.X,item.Y); this.DrawText(item); } this.Canvas.stroke(); } this.DrawArea=function() { if (!this.DataPoint || this.DataPoint.length<=0) return; this.Canvas.fillStyle = this.AreaColor; this.Canvas.strokeStyle = this.AreaLineColor; this.Canvas.beginPath(); var isFirstDraw=true; for(let i in this.DataPoint) { var item=this.DataPoint[i]; if (isFirstDraw) { this.Canvas.beginPath(); this.Canvas.moveTo(item.X,item.Y); isFirstDraw=false; } else { this.Canvas.lineTo(item.X,item.Y); } } this.Canvas.closePath(); this.Canvas.fill(); this.Canvas.stroke(); } this.DrawText=function(item) { if (!item.Text) return; //console.log(item.Text, item.Angle); this.Canvas.fillStyle = this.TitleColor; var xText = item.X, yText = item.Y; //显示每个角度的位置 if (item.Angle > 0 && item.Angle < 45) { this.Canvas.textAlign = 'left'; this.Canvas.textBaseline = 'middle'; xText += 2; } else if (item.Angle >= 0 && item.Angle < 90) { this.Canvas.textAlign = 'left'; this.Canvas.textBaseline = 'top'; xText += 2; } else if (item.Angle >= 90 && item.Angle < 135) { this.Canvas.textAlign = 'right'; this.Canvas.textBaseline = 'top'; xText -= 2; } else if (item.Angle >= 135 && item.Angle < 180) { this.Canvas.textAlign = 'right'; this.Canvas.textBaseline = 'top'; xText -= 2; } else if (item.Angle >= 180 && item.Angle < 225) { this.Canvas.textAlign = 'right'; this.Canvas.textBaseline = 'middle'; xText -= 2; } else if (item.Angle >= 225 && item.Angle <= 270) { this.Canvas.textAlign = 'center'; this.Canvas.textBaseline = 'bottom'; } else if (item.Angle > 270 && item.Angle < 315) { this.Canvas.textAlign = 'left'; this.Canvas.textBaseline = 'bottom'; xText += 2; } else { this.Canvas.textAlign = 'left'; this.Canvas.textBaseline = 'middle'; xText += 2; } this.Canvas.fillText(item.Text, xText, yText); } this.Draw=function() { this.BorderPoint=[]; this.DataPoint=[]; this.CenterPoint={}; if (!this.Data || !this.Data.Data || !(this.Data.Data.length>0)) this.CalculatePoints(null); else this.CalculatePoints(this.Data.Data); this.DrawBorder(); this.DrawArea(); } this.CalculatePoints=function(data) { let left=this.ChartBorder.GetLeft(); let right=this.ChartBorder.GetRight(); let top=this.ChartBorder.GetTop(); let bottom=this.ChartBorder.GetBottom(); let width=this.ChartBorder.GetWidth(); let height=this.ChartBorder.GetHeight(); let ptCenter={X:left+width/2, Y:top+height/2}; //中心点 let radius=Math.min(width/2,height/2)-2 //半径 let count=Math.max(5,data?data.length:0); let averageAngle=360/count; for(let i=0;i=1) value=1; var dataRadius=radius*value; ptData.X=ptCenter.X+dataRadius*Math.cos(angle*Math.PI/180); ptData.Y=ptCenter.Y+dataRadius*Math.sin(angle*Math.PI/180); } this.DataPoint.push(ptData); } this.BorderPoint.push(ptBorder); } this.CenterPoint=ptCenter; } //空数据 this.DrawEmptyData=function() { console.log('[ChartPie::DrawEmptyData]') } } /* 中国地图 */ function ChartChinaMap() { this.newMethod=IChartPainting; //派生 this.newMethod(); delete this.newMethod; this.ImageData=null; this.Left; this.Top; this.Width; this.Height; this.ImageWidth; this.ImageHeight; this.DefaultColor=[217,222,239]; this.Color= [ {Name:'海南', Color:'rgb(217,222,223)'}, {Name:'内蒙古', Color:'rgb(217,222,225)'}, {Name:'新疆', Color:'rgb(217,222,226)'}, {Name:'青海', Color:'rgb(217,222,227)'}, {Name:'西藏', Color:'rgb(217,222,228)'}, {Name:'云南', Color:'rgb(217,222,229)'}, {Name:'黑龙江', Color:'rgb(217,222,230)'}, {Name:'吉林', Color:'rgb(217,222,231)'}, {Name:'辽宁', Color:'rgb(217,222,232)'}, {Name:'河北', Color:'rgb(217,222,233)'}, {Name:'山东', Color:'rgb(217,222,234)'}, {Name:'江苏', Color:'rgb(217,222,235)'}, {Name:'浙江', Color:'rgb(217,222,236)'}, {Name:'福建', Color:'rgb(217,222,237)'}, {Name:'广东', Color:'rgb(217,222,238)'}, {Name:'广西', Color:'rgb(217,222,239)'}, {Name:'贵州', Color:'rgb(217,222,240)'}, {Name:'湖南', Color:'rgb(217,222,241)'}, {Name:'江西', Color:'rgb(217,222,242)'}, {Name:'安徽', Color:'rgb(217,222,243)'}, {Name:'湖北', Color:'rgb(217,222,244)'}, {Name:'重庆', Color:'rgb(217,222,245)'}, {Name:'四川', Color:'rgb(217,222,246)'}, {Name:'甘肃', Color:'rgb(217,222,247)'}, {Name:'陕西', Color:'rgb(217,222,248)'}, {Name:'山西', Color:'rgb(217,222,249)'}, {Name:'河南', Color:'rgb(217,222,250)'} ]; this.Draw=function() { let left=this.ChartBorder.GetLeft()+1; let right=this.ChartBorder.GetRight()-1; let top=this.ChartBorder.GetTop()+1; let bottom=this.ChartBorder.GetBottom()-1; let width=this.ChartBorder.GetWidth()-2; let height=this.ChartBorder.GetHeight()-2; let imageWidth=CHINA_MAP_IMAGE.width; let imageHeight=CHINA_MAP_IMAGE.height; let drawImageWidth=imageWidth; let drawImageHeight=imageHeight; if (height0) { for(let i in this.Data) { let item=this.Data[i]; nameMap.set(item.Name,item.Color) } } console.log(this.Data); for(let i in this.Color) { let item=this.Color[i]; if (nameMap.has(item.Name)) { colorMap.set(item.Color,nameMap.get(item.Name)); } else { defaultColorSet.add(item.Color); } } var color; for (let i=0;i0) lineCount=9; //分钟K线多一列时间 if (MARKET_SUFFIX_NAME.IsSHSZStockA(this.HQChart.Symbol) && klineData.FlowCapital>0) ++lineCount; } //this.TitleColor=this.KLineTitlePaint.UnchagneColor; this.IsHScreen=this.ChartFrame.IsHScreen===true; this.Canvas.font=this.Font[0]; this.Width=this.Canvas.measureText(' 擎: 9999.99亿 ').width; this.Height=this.LineHeight*lineCount+2*GetDevicePixelRatio()*2; this.DrawBG(); this.DrawTooltipData(klineData); this.DrawBorder(); } this.DrawTooltipData=function(item) { //console.log('[KLineTooltipPaint::DrawKLineData] ', item); var defaultfloatPrecision=GetfloatPrecision(this.HQChart.Symbol);//价格小数位数 var left=this.GetLeft()+2*GetDevicePixelRatio(); var top=this.GetTop()+3*GetDevicePixelRatio(); if (this.IsHScreen) { this.Canvas.save(); var x=this.GetLeft()+this.Height, y=this.GetTop(); this.Canvas.translate(x, y); this.Canvas.rotate(90 * Math.PI / 180); //x, y 作为原点 left=2*GetDevicePixelRatio(); top=3*GetDevicePixelRatio(); } this.Canvas.textBaseline="top"; this.Canvas.textAlign="left"; this.Canvas.font=this.Font[0]; var labelWidth=this.Canvas.measureText('擎: ').width; var text=IFrameSplitOperator.FormatDateString(item.Date); this.Canvas.fillStyle=this.TitleColor; this.Canvas.fillText(text, left,top); if(item.Time!=null && !isNaN(item.Time) && item.Time>0) { top+=this.LineHeight; text=IFrameSplitOperator.FormatTimeString(item.Time); this.Canvas.fillText(text, left,top); } top+=this.LineHeight; this.Canvas.fillStyle=this.TitleColor; text=g_JSChartLocalization.GetText('Tooltip-Open',this.LanguageID); this.Canvas.fillText(text, left,top); var color=this.KLineTitlePaint.GetColor(item.Open,item.YClose); text=item.Open.toFixed(defaultfloatPrecision); this.Canvas.fillStyle=color; this.Canvas.fillText(text,left+labelWidth,top); top+=this.LineHeight; this.Canvas.fillStyle=this.TitleColor; text=g_JSChartLocalization.GetText('Tooltip-High',this.LanguageID); this.Canvas.fillText(text, left,top); var color=this.KLineTitlePaint.GetColor(item.High,item.YClose); var text=item.High.toFixed(defaultfloatPrecision); this.Canvas.fillStyle=color; this.Canvas.fillText(text,left+labelWidth,top); top+=this.LineHeight; this.Canvas.fillStyle=this.TitleColor; text=g_JSChartLocalization.GetText('Tooltip-Low',this.LanguageID); this.Canvas.fillText(text, left,top); var color=this.KLineTitlePaint.GetColor(item.Low,item.YClose); var text=item.Low.toFixed(defaultfloatPrecision); this.Canvas.fillStyle=color; this.Canvas.fillText(text,left+labelWidth,top); top+=this.LineHeight; this.Canvas.fillStyle=this.TitleColor; text=g_JSChartLocalization.GetText('Tooltip-Close',this.LanguageID); this.Canvas.fillText(text, left,top); var color=this.KLineTitlePaint.GetColor(item.Close,item.YClose); var text=item.Close.toFixed(defaultfloatPrecision); this.Canvas.fillStyle=color; this.Canvas.fillText(text,left+labelWidth,top); top+=this.LineHeight; this.Canvas.fillStyle=this.TitleColor; text=g_JSChartLocalization.GetText('Tooltip-Increase',this.LanguageID); this.Canvas.fillText(text, left,top); if (item.YClose>0) { var value=(item.Close-item.YClose)/item.YClose*100; var color = this.KLineTitlePaint.GetColor(value, 0); var text = value.toFixed(2)+'%'; } else { var text='--.--'; var color=this.KLineTitlePaint.GetColor(0, 0); } this.Canvas.fillStyle=color; this.Canvas.fillText(text,left+labelWidth,top); this.Canvas.fillStyle=this.TitleColor; top+=this.LineHeight; text=g_JSChartLocalization.GetText('Tooltip-Vol',this.LanguageID); this.Canvas.fillText(text, left,top); var text=IFrameSplitOperator.FromatIntegerString(item.Vol,2,this.LanguageID); this.Canvas.fillText(text,left+labelWidth,top); if (IFrameSplitOperator.IsNumber(item.Amount)) { top+=this.LineHeight; text=g_JSChartLocalization.GetText('Tooltip-Amount',this.LanguageID); this.Canvas.fillText(text, left,top); var text=IFrameSplitOperator.FormatValueString(item.Amount,2,this.LanguageID); this.Canvas.fillText(text,left+labelWidth,top); } //换手率 if (MARKET_SUFFIX_NAME.IsSHSZStockA(this.HQChart.Symbol) && item.FlowCapital>0) { top+=this.LineHeight; text=g_JSChartLocalization.GetText('Tooltip-Exchange',this.LanguageID); this.Canvas.fillText(text, left,top); var value=item.Vol/item.FlowCapital*100; var text=value.toFixed(2)+'%'; this.Canvas.fillText(text,left+labelWidth,top); } if (this.IsHScreen) this.Canvas.restore(); } this.DrawBorder=function() { var isHScreen=(this.ChartFrame.IsHScreen===true); var left=this.GetLeft(); var top=this.GetTop(); this.Canvas.strokeStyle=this.BorderColor; if (isHScreen) this.Canvas.strokeRect(ToFixedPoint(left),ToFixedPoint(top),this.Height,this.Width); else this.Canvas.strokeRect(ToFixedPoint(left),ToFixedPoint(top),this.Width,this.Height); } this.DrawBG=function() { var isHScreen=(this.ChartFrame.IsHScreen===true); var left=this.GetLeft(); var top=this.GetTop(); this.Canvas.fillStyle=this.BGColor; if (isHScreen) this.Canvas.fillRect(left,top,this.Height,this.Width); else this.Canvas.fillRect(left,top,this.Width,this.Height); } //设置参数接口 this.SetOption=function(option) { if (option.LineHeight>0) this.LineHeight=option.LineHeight*GetDevicePixelRatio(); if (option.BGColor) this.BGColor=option.BGColor; if (option.LanguageID>0) this.LanguageID=option.LanguageID; } } function MinuteTooltipPaint() { this.newMethod=KLineTooltipPaint; //派生 this.newMethod(); delete this.newMethod; this.ClassName='MinuteTooltipPaint'; this.Left=1*GetDevicePixelRatio(); this.Top=1*GetDevicePixelRatio(); this.YClose; this.GetTop=function() { if (this.IsHScreen) return this.ChartBorder.GetTop(); return this.ChartBorder.GetTop()+this.Top; } this.DrawTooltipData=function(item) { //console.log('[KLineTooltipPaint::DrawKLineData] ', item); var defaultfloatPrecision=GetfloatPrecision(this.HQChart.Symbol);//价格小数位数 var left=this.GetLeft()+2*GetDevicePixelRatio(); var top=this.GetTop()+3*GetDevicePixelRatio(); this.YClose=this.KLineTitlePaint.YClose; if (this.IsHScreen) { this.Canvas.save(); var x=this.GetLeft()+this.Height, y=this.GetTop(); this.Canvas.translate(x, y); this.Canvas.rotate(90 * Math.PI / 180); //x, y 作为原点 left=2*GetDevicePixelRatio(); top=3*GetDevicePixelRatio(); } this.Canvas.textBaseline="top"; this.Canvas.textAlign="left"; this.Canvas.font=this.Font[0]; var labelWidth=this.Canvas.measureText('擎: ').width; var aryDateTime=item.DateTime.split(' '); if (aryDateTime && aryDateTime.length==2) { var text=IFrameSplitOperator.FormatDateString(aryDateTime[0]); this.Canvas.fillStyle=this.TitleColor; this.Canvas.fillText(text, left,top); top+=this.LineHeight; text=IFrameSplitOperator.FormatTimeString(aryDateTime[1]); this.Canvas.fillText(text, left,top); } var close=item.Close; var increase=item.Increase; var vol=item.Vol; var amount=item.Amount; if (item.Before) //读取盘前数据 { close=item.Before.Close; increase=item.Before.Increase; vol=item.Before.Vol; amount=item.Before.Amount; } //最新价格 top+=this.LineHeight; this.Canvas.fillStyle=this.TitleColor; text=g_JSChartLocalization.GetText('Tooltip-Price',this.LanguageID); this.Canvas.fillText(text, left,top); var color=this.KLineTitlePaint.GetColor(close,this.YClose); var text=close.toFixed(defaultfloatPrecision); this.Canvas.fillStyle=color; this.Canvas.fillText(text,left+labelWidth,top); //均价 if (!item.Before) //集合竞价没有均价 { top+=this.LineHeight; this.Canvas.fillStyle=this.TitleColor; text=g_JSChartLocalization.GetText('Tooltip-AvPrice',this.LanguageID); this.Canvas.fillText(text, left,top); var color=this.KLineTitlePaint.GetColor(item.AvPrice,this.YClose); var text=item.AvPrice.toFixed(defaultfloatPrecision); this.Canvas.fillStyle=color; this.Canvas.fillText(text,left+labelWidth,top); } //涨幅 top+=this.LineHeight; this.Canvas.fillStyle=this.TitleColor; text=g_JSChartLocalization.GetText('Tooltip-Increase',this.LanguageID); this.Canvas.fillText(text, left,top); var value=(close-this.YClose)/this.YClose*100; var color = this.KLineTitlePaint.GetColor(value, 0); var text = value.toFixed(2)+'%'; this.Canvas.fillStyle=color; this.Canvas.fillText(text,left+labelWidth,top); //成交量 this.Canvas.fillStyle=this.TitleColor; top+=this.LineHeight; text=g_JSChartLocalization.GetText('Tooltip-Vol',this.LanguageID); this.Canvas.fillText(text, left,top); var text=IFrameSplitOperator.FromatIntegerString(vol,2,this.LanguageID); this.Canvas.fillText(text,left+labelWidth,top); //成交金额 if (IFrameSplitOperator.IsNumber(amount)) { top+=this.LineHeight; text=g_JSChartLocalization.GetText('Tooltip-Amount',this.LanguageID); this.Canvas.fillText(text, left,top); var text=IFrameSplitOperator.FormatValueString(amount,2,this.LanguageID); this.Canvas.fillText(text,left+labelWidth,top); } if (this.IsHScreen) this.Canvas.restore(); } } //股票信息 function StockInfoExtendChartPaint() { this.newMethod=IExtendChartPainting; //派生 this.newMethod(); delete this.newMethod; this.Left=80; this.Right=1; this.Top=1; this.Bottom=1; this.BorderColor=g_JSChartResource.FrameBorderPen; this.Symbol; this.Name; this.TitleFont=["14px 微软雅黑"]; this.Draw=function() { var left=this.ChartBorder.GetRight()+this.Left; var right=this.ChartBorder.GetChartWidth()-this.Right; var y=this.Top+18; var middle=left+(right-left)/2; if (this.Symbol && this.Name) { this.Canvas.font=this.TitleFont[0]; this.Canvas.textAlign="right"; this.Canvas.textBaseline="bottom"; this.Canvas.fillText(this.Symbol,middle-2,y); this.Canvas.textAlign="left"; this.Canvas.fillText(this.Name,middle+2,y); } ; this.Canvas.strokeStyle=this.BorderColor; this.Canvas.moveTo(left,y); this.Canvas.lineTo(right,y); this.Canvas.stroke(); y+=30; this.DrawBorder(); } this.DrawBorder=function() { var left=this.ChartBorder.GetRight()+this.Left; var right=this.ChartBorder.GetChartWidth()-this.Right; var top=this.Top; var bottom=this.ChartBorder.GetChartHeight()-this.Bottom; this.Canvas.strokeStyle=this.BorderColor; this.Canvas.strokeRect(left,top,(right-left),(bottom-top)); } } //筹码分布 function StockChip() { this.newMethod=IExtendChartPainting; //派生 this.newMethod(); delete this.newMethod; this.Name='筹码分布'; this.ClassName='StockChip'; this.HQChart; this.PenBorder=g_JSChartResource.FrameBorderPen; //边框 this.ColorProfit='rgb(255,0,0)'; //盈利的线段 this.ColorNoProfit='rgb(90,141,248)'; //非盈利 this.ColorAveragePrice='rgb(0,139,0)'; //平均价线 this.ColorBG='rgb(190,190,190)'; //筹码背景线段颜色 this.PixelRatio=GetDevicePixelRatio(); this.ShowType=0; //0=所有筹码 1=周期前 2=周期内 this.IsDynamic=true; this.ClientRect={}; this.Font=g_JSChartResource.TitleFont; this.InfoColor='rgb(0,0,0)'; this.DayInfoColor='rgb(255,255,255)'; this.LineHeight=16; this.Left=50*this.PixelRatio; //左边间距 this.IsShowX=false; //是否显示X刻度 成交量 this.ShowXCount=3; this.Width=150*this.PixelRatio; //筹码图宽度 this.ButtonID=Guid(); //工具条Div id this.DAY_COLOR= [ ['rgb(255,0,0)','rgb(255,128,128)','rgb(255,0,128)','rgb(255,100,0)','rgb(192,128,0)','rgb(255,192,0)'], ['rgb(120,80,225)','rgb(160,160,225)','rgb(80,80,255)','rgb(120,120,255)','rgb(32,64,192)','rgb(0,64,128)'], ]; this.SetOption=function(option) { if (!option) return; if (option.ShowType>0) this.ShowType=option.ShowType; if (option.IsShowX) this.IsShowX=option.IsShowX; if (option.ShowXCount>0) this.ShowXCount=option.ShowXCount; if (option.Width>100) this.Width=option.Width*GetDevicePixelRatio(); } this.Draw=function() { this.PixelRatio=GetDevicePixelRatio(); var left=ToFixedPoint(this.ChartBorder.GetRight()+this.Left); var top=ToFixedPoint(this.ChartBorder.GetTop()); var right=ToFixedPoint(left+this.Width-1*this.PixelRatio); var bottom=ToFixedPoint(this.ChartBorder.GetBottom()); var width=right-left; var height=bottom-top; this.ClientRect={Left:left,Top:top,Width:width,Height:height}; if (this.CalculateChip()) { this.DrawFrame(); this.DrawAllChip(); if (this.ShowType==1|| this.ShowType==2) this.DrawDayChip(); this.CalculateCast(); //计算成本 this.DrawChipInfo(); } else { console.log('[StockChip::Draw] no data'); } this.DrawBorder(); if (this.SizeChange==true) this.DrawButton(); this.SizeChange=false; } this.DrawChipInfo=function() { var bottom=this.ClientRect.Top+this.ClientRect.Height-1; var left=this.ClientRect.Left+2; var right=this.ClientRect.Left+this.ClientRect.Width; this.Canvas.font=this.Font; this.Canvas.fillStyle=this.InfoColor; this.Canvas.textBaseline='bottom'; this.Canvas.textAlign='left'; var lineHeight=this.LineHeight*GetDevicePixelRatio(); var text='70%成本价'+ this.Data.Cast[1].MinPrice.toFixed(2)+'-'+this.Data.Cast[1].MaxPrice.toFixed(2)+'集中'+this.Data.Cast[1].Rate.toFixed(2)+'%'; this.Canvas.fillText(text,left,bottom); bottom-=lineHeight; text='90%成本价'+ this.Data.Cast[0].MinPrice.toFixed(2)+'-'+this.Data.Cast[0].MaxPrice.toFixed(2)+'集中'+this.Data.Cast[0].Rate.toFixed(2)+'%';; this.Canvas.fillText(text,left,bottom); bottom-=lineHeight; text='平均成本:'+this.Data.ChipInfo.AveragePrice.toFixed(2)+'元'; this.Canvas.fillText(text,left,bottom); bottom-=lineHeight; text=+this.Data.YPrice.toFixed(2)+'处获利盘:'+this.Data.ChipInfo.YProfitRate.toFixed(2)+'%'; this.Canvas.fillText(text,left,bottom); bottom-=lineHeight; text='获利比例:'; this.Canvas.fillText(text,left,bottom); var textWidth=this.Canvas.measureText(text).width+2; var barLeft=left+textWidth; var barWidth=(right-5-barLeft); this.Canvas.strokeStyle=this.ColorNoProfit; this.Canvas.strokeRect(barLeft,bottom-lineHeight,barWidth,lineHeight); this.Canvas.strokeStyle=this.ColorProfit; this.Canvas.strokeRect(barLeft,bottom-lineHeight,barWidth*(this.Data.ChipInfo.ProfitRate/100),lineHeight); text=this.Data.ChipInfo.ProfitRate.toFixed(2)+'%'; this.Canvas.textAlign='center'; this.Canvas.fillText(text,barLeft+barWidth/2,bottom); bottom-=lineHeight; this.Canvas.textAlign='left'; text='成本分布,日期:'+IFrameSplitOperator.FormatDateString(this.Data.SelectData.Date); if (this.Data.SelectData.Time) text+=' '+IFrameSplitOperator.FormatTimeString(this.Data.SelectData.Time); this.Canvas.fillText(text,left,bottom); bottom-=lineHeight; if (this.ShowType!=1 && this.ShowType!=2) return; var right=this.ClientRect.Left+this.ClientRect.Width-1; this.Canvas.textAlign='right'; var textWidth=50; this.Data.DayChip.sort(function(a,b){return b.Day-a.Day;}) for(var i in this.Data.DayChip) { var item=this.Data.DayChip[i]; var rate=0; if (this.Data.ChipInfo && this.Data.ChipInfo.Vol>0) rate=item.Vol/this.Data.ChipInfo.Vol*100; text=item.Day+'周期'+(this.ShowType==1?'前':'内')+'成本'+rate.toFixed(2)+'%'; if (i==0) textWidth=this.Canvas.measureText(text).width+8; this.Canvas.fillStyle=item.Color; this.Canvas.fillRect(right-textWidth,bottom-lineHeight,textWidth,lineHeight); this.Canvas.fillStyle=this.DayInfoColor; this.Canvas.fillText(text,right,bottom); bottom-=lineHeight; } } this.DrawDayChip=function() { var KLineFrame=this.HQChart.Frame.SubFrame[0].Frame; for(var i in this.Data.DayChip) { var aryPoint=[]; var chipData=this.Data.DayChip[i].Chip; if (!chipData) continue; var totalVol=0; for(var j=0;j0) spanHtml+='  '; spanHtml+=spanItem; } divButton.style.right = Math.floor((chartRight-right+2)/pixelTatio) + "px"; divButton.style.top = top + "px"; //divButton.style.width=toolbarWidth+"px"; divButton.style.height=toolbarHeight+'px'; divButton.innerHTML=spanHtml; var self = this; for(var i in ICON_LIST) { var item=ICON_LIST[i]; $("#"+this.ButtonID+" ."+item.ID).click( { IconID:item.ID, ShowType:i }, function (event) { var id=event.data.IconID; var showType=event.data.ShowType; self.ShowType=showType; if (self.HQChart) self.HQChart.Draw(); for(var i in ICON_LIST) { var item=ICON_LIST[i]; var style=$("#"+self.ButtonID+" ."+item.ID)[0].style; style['color']=item.Color[i==showType?1:0]; } } ) } } this.DrawAllChip=function() { var KLineFrame=this.HQChart.Frame.SubFrame[0].Frame; var selectPrice=this.Data.SelectData.Close; var aryProfitPoint=[]; var aryNoProfitPoint=[]; var totalVol=0,totalAmount=0,totalProfitVol=0, totalYProfitVol=0; //总的成交量, 总的成交金额, 总的盈利的成交量 var yPrice=this.Data.YPrice; var maxPrice=KLineFrame.HorizontalMax; var minPrice=KLineFrame.HorizontalMin; var MaxVol=1; for(var i=0;i=minPrice) { if (MaxVolmaxPrice || price0?totalProfitVol/totalVol*100:0, YProfitRate:totalVol>0?totalYProfitVol/totalVol*100:0 }; if (this.ShowType==0) { this.DrawLines(aryProfitPoint,this.ColorProfit); this.DrawLines(aryNoProfitPoint,this.ColorNoProfit); var averagePrice=this.Data.ChipInfo.AveragePrice; if (averagePrice>0 && averagePrice<=maxPrice && averagePrice>=minPrice) { averagePrice=averagePrice.toFixed(2); this.DrawAveragePriceLine(aryProfitPoint,aryNoProfitPoint,KLineFrame.GetYFromData(averagePrice),this.ColorAveragePrice); } } else //在火焰山模式下, 筹码用一个颜色 { this.DrawLines(aryProfitPoint,this.ColorBG); this.DrawLines(aryNoProfitPoint,this.ColorBG); } } this.CalculateCast=function() //计算 90% 70%的成本价 { if (!this.Data.ChipInfo || !this.Data.ChipInfo.Vol) return; var aryCast= [ {Start:0.05,End:0.95, MaxPrice:0, MinPrice:0, Rate:0}, {Start:0.15,End:0.85, MaxPrice:0, MinPrice:0, Rate:0} ]; var averagePrice=this.Data.ChipInfo.AveragePrice; var totalProfitVol=this.Data.ChipInfo.ProfitVol; var tempVol=0; for(var i=0, castCount=0;iitemCast.Start) { itemCast.MinPrice=price; ++castCount; } if (itemCast.MaxPrice<=0 && rate>itemCast.End) { itemCast.MaxPrice=price; ++castCount; } } } for(var i in aryCast) { var item=aryCast[i]; var addPrice=item.MaxPrice+item.MinPrice; if (addPrice) item.Rate=Math.abs(item.MaxPrice-item.MinPrice)/addPrice*100; } this.Data.Cast=aryCast; } this.DrawArea=function(aryPoint,color) { if (aryPoint.length<=0) return; this.Canvas.fillStyle=color; this.Canvas.beginPath(); this.Canvas.moveTo(this.ClientRect.Left,aryPoint[0].Y); for(var i in aryPoint) { var item=aryPoint[i]; this.Canvas.lineTo(item.X,item.Y); } this.Canvas.lineTo(this.ClientRect.Left,aryPoint[aryPoint.length-1].Y); this.Canvas.fill(); } this.DrawLines=function(aryPoint,color) { if (aryPoint.length<=0) return; this.Canvas.strokeStyle=color; this.Canvas.beginPath(); for(var i in aryPoint) { var item=aryPoint[i]; this.Canvas.moveTo(this.ClientRect.Left,item.Y); this.Canvas.lineTo(item.X,item.Y); } this.Canvas.stroke(); } this.DrawAveragePriceLine=function(aryProfitPoint,aryNoProfitPoint,y,color) { for(var i in aryProfitPoint) { var item=aryProfitPoint[i]; if (item.Y==y) { this.Canvas.strokeStyle=color; this.Canvas.beginPath(); this.Canvas.moveTo(this.ClientRect.Left,item.Y); this.Canvas.lineTo(item.X,item.Y); this.Canvas.stroke(); return; } } for(var i in aryNoProfitPoint) { var item=aryNoProfitPoint[i]; if (item.Y==y) { this.Canvas.strokeStyle=color; this.Canvas.beginPath(); this.Canvas.moveTo(this.ClientRect.Left,item.Y); this.Canvas.lineTo(item.X,item.Y); this.Canvas.stroke(); return; } } } this.DrawBorder=function() { this.Canvas.strokeStyle=this.PenBorder; this.Canvas.strokeRect(this.ClientRect.Left,this.ClientRect.Top,this.ClientRect.Width,this.ClientRect.Height); } this.CalculateChip=function() //计算筹码 { if (!this.HQChart) return false; if (!this.HQChart.FlowCapitalReady) return false; var symbol=this.HQChart.Symbol; if (!symbol) return false; if (MARKET_SUFFIX_NAME.IsSHSZIndex(symbol)) return false; //指数暂时不支持移动筹码 var bindData=this.HQChart.ChartPaint[0].Data; //if (bindData.Period>=4) return false; //分钟K线不支持, 没时间做,以后再做吧 var count=bindData.DataOffset+parseInt(this.HQChart.CursorIndex); if (count>=bindData.Data.length) count=bindData.Data.length-1; var selData=bindData.Data[count]; var yPrice=selData.Close; var mouseY=this.HQChart.LastPoint.Y; if (mouseY) yPrice=this.HQChart.Frame.SubFrame[0].Frame.GetYData(mouseY); //console.log("[StockChip::CalculateChip]",count,this.HQChart.CursorIndex,selData); const rate=1; var aryVol=[]; var seed=1,vol,maxPrice,minPrice; for(let i=count;i>=0;--i) { var item=bindData.Data[i]; var changeRate=1; //换手率 if (item.FlowCapital>0) changeRate=item.Vol/item.FlowCapital; if (i==count) vol=item.Vol*changeRate; else vol=item.Vol*seed; var dataItem={Vol:vol,High:item.High,Low:item.Low}; aryVol.push(dataItem); seed*=(1-changeRate*rate); if (!maxPrice || maxPriceitem.Low) minPrice=item.Low; } //console.log("[StockChip::CalculateChip]",maxPrice,minPrice); if (!maxPrice || !minPrice) return true; maxPrice=parseInt(maxPrice*100); minPrice=parseInt(minPrice*100); var dataCount=maxPrice-minPrice; var aryChip=new Array() for(let i=0;i<=dataCount;++i) { aryChip.push(0); } var maxVol=1; var dayChip=[]; if (this.ShowType==2) { var dayChip= [ {Day:100, Color:this.DAY_COLOR[1][5]}, {Day:60, Color:this.DAY_COLOR[1][4]}, {Day:30, Color:this.DAY_COLOR[1][3]}, {Day:20, Color:this.DAY_COLOR[1][2]}, {Day:10, Color:this.DAY_COLOR[1][1]}, {Day:5, Color:this.DAY_COLOR[1][0]} ]; for(let i in aryVol) { var item=aryVol[i]; var high=parseInt(item.High*100); var low=parseInt(item.Low*100); var averageVol=item.Vol; if (high-low>0) averageVol=item.Vol/(high-low); if (averageVol<=0.000000001) continue; for(var k=0;k=0;--i) { var item=aryVol[i]; var high=parseInt(item.High*100); var low=parseInt(item.Low*100); var averageVol=item.Vol; if (high-low>0) averageVol=item.Vol/(high-low); if (averageVol<=0.000000001) continue; for(var k=0;k0) averageVol=item.Vol/(high-low); if (averageVol<=0.000000001) continue; for(var j=low;j<=high && j<=maxPrice;++j) { var index=j-minPrice; aryChip[index]+=averageVol; if (maxVol10) this.Width=option.Width*pixelRatio; } this.Clear=function() { if (this.ToolsDiv) this.ChartBorder.UIElement.parentNode.removeChild(this.ToolsDiv); } this.Draw = function () { if (this.SizeChange == false) return; //工具列表 const TOOL_LIST = [ [ { HTML: { Title: '线段', IClass: 'iconfont icon-draw_line', ID: 'icon-segment' }, Name: '线段' }, { HTML: { Title: '射线', IClass: 'iconfont icon-draw_rays', ID: 'icon-beam' }, Name: '射线' }, { HTML: { Title: '趋势线', IClass: 'iconfont icon-draw_trendline', ID: 'icon-trendline' }, Name: '趋势线' }, { HTML: { Title: '水平线', IClass: 'iconfont icon-draw_hline', ID: 'icon-hline' }, Name: '水平线' }, { HTML: { Title: '平行线', IClass: 'iconfont icon-draw_parallel_lines', ID: 'icon-parallellines' }, Name: '平行线' }, { HTML: { Title: '平行通道', IClass: 'iconfont icon-draw_parallelchannel', ID: 'icon-parallelchannel' }, Name: '平行通道' }, { HTML: { Title: '价格通道线', IClass: 'iconfont icon-draw_pricechannel', ID: 'icon-pricechannel' }, Name: '价格通道线' }, { HTML: { Title: 'M头W底', IClass: 'iconfont icon-draw_wavemw', ID: 'icon-wavemw' }, Name: 'M头W底' }, ], [ { HTML: { Title: '圆弧', IClass: 'iconfont icon-draw_arc', ID: 'icon-arc' }, Name: '圆弧线' }, { HTML: { Title: '矩形', IClass: 'iconfont icon-rectangle', ID: 'icon-rect' }, Name: '矩形' }, { HTML: { Title: '平行四边形', IClass: 'iconfont icon-draw_quadrangle', ID: 'icon-quad' }, Name: '平行四边形' }, { HTML: { Title: '三角形', IClass: 'iconfont icon-draw_triangle', ID: 'icon-triangle' }, Name: '三角形' }, { HTML: { Title: '圆', IClass: 'iconfont icon-draw_circle', ID: 'icon-circle' }, Name: '圆' }, { HTML: { Title: '对称角度', IClass: 'iconfont icon-draw_symangle', ID: 'icon-symangle' }, Name: '对称角度' }, ], [ { HTML: { Title: '文本', IClass: 'iconfont icon-draw_text', ID: 'icon-text' }, Name: '文本' }, { HTML: { Title: '向上箭头', IClass: 'iconfont icon-arrow_up', ID: 'icon-arrowup' }, Name: 'icon-arrow_up' }, { HTML: { Title: '向下箭头', IClass: 'iconfont icon-arrow_down', ID: 'icon-arrowdown' }, Name: 'icon-arrow_down' }, { HTML: { Title: '向左箭头', IClass: 'iconfont icon-arrow_left', ID: 'icon-arrowleft' }, Name: 'icon-arrow_left' }, { HTML: { Title: '向右箭头', IClass: 'iconfont icon-arrow_right', ID: 'icon-arrowright' }, Name: 'icon-arrow_right' }, ], [ { HTML: { Title: '江恩角度线', IClass: 'iconfont icon-draw_gannfan', ID: 'icon-gannfan' }, Name: '江恩角度线' }, { HTML: { Title: '斐波那契周期线', IClass: 'iconfont icon-draw_fibonacci', ID: 'icon-fibonacci' }, Name: '斐波那契周期线' }, { HTML: { Title: '阻速线', IClass: 'iconfont icon-draw_resline', ID: 'icon-resline' }, Name: '阻速线' }, { HTML: { Title: '黄金分割', IClass: 'iconfont icon-draw_goldensection', ID: 'icon-goldensection' }, Name: '黄金分割' }, { HTML: { Title: '百分比线', IClass: 'iconfont icon-draw_percentage', ID: 'icon-percentage' }, Name: '百分比线' }, { HTML: { Title: '波段线', IClass: 'iconfont icon-draw_waveband', ID: 'icon-waveband' }, Name: '波段线' }, ], [{ HTML: { Title: '全部删除', IClass: 'iconfont icon-recycle_bin', ID: 'icon-delete' }, Name: '全部删除' }] ]; var hqChart = this.HQChart; if (!this.ToolsDiv) { var div = document.createElement("div"); div.className = 'drawtools'; div.id = this.ID; var spanList = ""; //一层菜单 var menuTwoList = ""; //二层菜单 var menuOne = new Array(); TOOL_LIST.forEach(function(item,index){ menuOne.push(item[0]); }); for (var i = 0; i < TOOL_LIST.length; i++) { var itemOut = menuOne[i]; var itemIn = TOOL_LIST[i]; var menuTwoStr = ""; var contentArrow = ""; for (var j = 0; j < itemIn.length; j++) { var currentItem = itemIn[j]; var menuTwoName = currentItem.Name; if(menuTwoName.indexOf('up') > -1){ menuTwoName = "向上箭头"; }else if(menuTwoName.indexOf('down') > -1){ menuTwoName = "向下箭头"; }else if(menuTwoName.indexOf('left') > -1){ menuTwoName = "向左箭头"; }else if(menuTwoName.indexOf('right') > -1){ menuTwoName = "向右箭头"; } menuTwoStr += ''; } if (i !== TOOL_LIST.length - 1) { //不是“全部删除”项 menuTwoList = ''; contentArrow = ''; } else { menuTwoList = ""; contentArrow = ""; } var spanNode = '
' + menuTwoList + contentArrow +'
'; spanList += spanNode; } this.ChartBorder.UIElement.parentNode.appendChild(div); div.innerHTML = spanList; this.ToolsDiv = div; for (var i in TOOL_LIST) { var item = TOOL_LIST[i][0]; $('#' + this.ID + " .first-" + item.HTML.ID).hover(function(){ //箭头的旋转过渡 $(".drawtools").find(".contentArrow").hide(); $(this).find(".contentArrow").removeClass("trans").show(); }); $('#' + this.ID + " .first-" + item.HTML.ID+" .contentArrow").click(function(event){ //点击三角展示二级菜单 event.stopPropagation(); $(".drawtools").find(".menuTwo").hide(); $(this).siblings('.menuTwo').show(); }); $('#' + this.ID + " .first-" + item.HTML.ID+" .trans").click(function(){ //点击三角隐藏二级菜单 event.stopPropagation(); $(this).siblings('.menuTwo').hide(); }); if (item.Name == '全部删除') { $('#' + this.ID + " .first-icon-delete").click(function () { $(".drawtools").find(".menuTwo").hide(); $(this).siblings().removeClass('active'); $(this).addClass('active'); hqChart.ClearChartDrawPicture(); $(".subTolls").css("display", "none"); }); } else { $('#' + this.ID + " .first-" + menuOne[i].HTML.ID).click( //一层菜单类名是:“first-”+item.HTML.ID { // DrawName: menuOne[i].Name, //把画法名字传进去 CurrentIndex:i }, function (event) { $(".drawtools").find(".menuTwo").hide(); $(this).siblings().removeClass('active'); $(this).addClass('active'); hqChart.CreateChartDrawPicture(menuOne[event.data.CurrentIndex].Name); } ); for (var j in TOOL_LIST[i]) { var itemTwo = TOOL_LIST[i][j]; let classname = itemTwo.HTML.IClass; //闭包问题 $('#' + this.ID + ' .' + itemTwo.HTML.ID).hover(function(event){ event.stopPropagation(); $(this).closest('.icon-image').find(".contentArrow").addClass("trans"); }); $('#' + this.ID + ' .' + itemTwo.HTML.ID).click(//二层菜单 { DrawName: itemTwo.Name, //把画法名字传进去 CurrentIndex:i, CurrentData:itemTwo }, function (event) { event.stopPropagation(); $(this).closest('.icon-image').find(".contentArrow").hide(); $(this).siblings().removeClass("current"); $(this).addClass("current"); $(this).closest('.icon-image').children('i').eq(0).removeClass().addClass(classname,"active").attr('title',event.data.CurrentData.HTML.Title); menuOne.splice(event.data.CurrentIndex,1,event.data.CurrentData); $(this).parent().hide(); hqChart.CreateChartDrawPicture(event.data.DrawName); } ); } } } } var curID = this.ID; $(document).click(function(event){ if(!($("#"+curID).is(event.target)) && ($("#"+curID).has(event.target).length === 0)){ $("#"+curID+" .menuTwo").hide(); $("#"+curID+" .contentArrow").hide(); } }); var scrollPos = GetScrollPosition(); var pixelRatio=GetDevicePixelRatio(); // var left=this.ChartBorder.GetChartWidth()-this.Right-this.ToolsWidth; var left=ToFixedPoint(this.ChartBorder.GetRight()+this.Left); // var top = this.Top+this.ChartBorder.UIElement.getBoundingClientRect().top+scrollPos.Top; var top = this.ChartBorder.GetTop(); this.ToolsDiv.style.left = left/pixelRatio + "px"; this.ToolsDiv.style.top = top/pixelRatio + "px"; this.ToolsDiv.style.width = (this.Width-5)/pixelRatio + "px"; this.ToolsDiv.style.height = 'auto'; this.ToolsDiv.style.position = "absolute"; this.ToolsDiv.style.display = "block"; // this.ToolsDiv.style.paddingLeft = "10px"; this.SizeChange == true; } } //弹幕数据 { X:X偏移, Y:Y偏移, Text:内容, Color:颜色 } function BarrageList() { this.PlayList=[]; //正在播放队列 this.Cache=[]; //没有播放的弹幕数据 this.MinLineHeight=40*GetDevicePixelRatio(); this.Height; //高度 this.Step=1; //{Canves:画布, Right:右边坐标, Left:左边坐标, Font:默认字体 } this.GetPlayList=function(obj) { var canves=obj.Canves; var right=obj.Right; var left=obj.Left; var width=right-left; var isMoveStep=obj.IsMoveStep; var list=[]; var yOffset=0; for(var i=0;ithis.MinLineHeight) lineHeight=ary.Height; var bAddNewItem=true; //是否需要加入新弹幕 var bRemoveFirst=false; //是否删除第1个数据 for(var j=0;j0) //最后一个数据了 判断是否需要增加弹幕 { bAddNewItem=false; if (!item.TextWidth) { if (item.Font && item.Font.Name) canves.font=item.Font.Name; else canves.font=obj.Font; item.TextWidth=canves.measureText(playItem.Text+'擎擎').width; } if (item.X>=item.TextWidth) bAddNewItem=true; } else if (j==0) { bRemoveFirst=false; if (!item.TextWidth) { if (item.Font && item.Font.Name) canves.font=item.Font.Name; else canves.font=obj.Font; item.TextWidth=canves.measureText(playItem.Text+'擎擎').width; } if (item.X>width+item.TextWidth) bRemoveFirst=true; } item.X+=this.Step; } if(isMoveStep && bAddNewItem && this.Cache.length>0) //最后一个数据了 判断是否需要增加弹幕 { var cacheItem=this.Cache.shift(); var newItem={ X:0, Text:cacheItem.Text, Color:cacheItem.Color , Font:cacheItem.Font, Info:cacheItem.Info }; ary.Data.push(newItem); } if (isMoveStep && bRemoveFirst && ary.Data.length>0) { var removeItem=ary.Data.shift(); this.OnItemPlayEnd(obj.HQChart,removeItem); } yOffset+=lineHeight; } return list; } //根据高度计算播放队列个数 this.CacluatePlayLine=function(height) { this.Height=height; var lineCount=parseInt(height/this.MinLineHeight); if (this.PlayList.lengthlineCount) { var removeCount=this.PlayList.length-lineCount; for(var i=0;i0) this.BarrageList.Step=option.Step; if (option.MinLineHeight) this.Barrage.MinLineHeight=option.MinLineHeight; } } this.DrawHScreen=function() { var height=this.ChartBorder.GetWidth(); var left=this.ChartBorder.GetTop(); var right=this.ChartBorder.GetBottom(); var top=this.ChartBorder.GetRightEx(); var wdith=this.ChartBorder.GetChartWidth(); if (height!=this.BarrageList.Height) this.BarrageList.CacluatePlayLine(height); this.Canvas.textBaseline="middle"; this.Canvas.textAlign="left"; var play=this.BarrageList.GetPlayList({Canves:this.Canvas, Right:right, Left:left, Font:this.Font, IsMoveStep:this.IsMoveStep, HQChart:this.HQChart}); this.IsMoveStep=false; if (!play) return; this.Canvas.save(); this.Canvas.translate(this.ChartBorder.GetChartHeight(), 0); this.Canvas.rotate(90 * Math.PI / 180); for(var i=0;i0) fontHeight=item.Font.Height; var yOffset=item.Y+parseInt((item.Height-fontHeight)/2); this.Canvas.fillText(item.Text, right-item.X,top+yOffset); } this.Canvas.restore(); } this.Draw=function() { if (this.ChartFrame.IsHScreen) { this.DrawHScreen(); return; } var left=this.ChartBorder.GetLeft(); var right=this.ChartBorder.GetRight(); var top=this.ChartBorder.GetTopEx(); var height=this.ChartBorder.GetHeight(); if (height!=this.BarrageList.Height) this.BarrageList.CacluatePlayLine(height); this.Canvas.textBaseline="middle"; this.Canvas.textAlign="left"; var play=this.BarrageList.GetPlayList({Canves:this.Canvas, Right:right, Left:left, Font:this.Font, IsMoveStep:this.IsMoveStep, HQChart:this.HQChart}); this.IsMoveStep=false; if (!play) return; for(var i=0;i0) fontHeight=item.Font.Height; var yOffset=item.Y+parseInt((item.Height-fontHeight)/2); this.Canvas.fillText(item.Text, right-item.X,top+yOffset); } } } ///////////////////////////////////////////////////////////////////////////////////////////////////// //坐标分割 // // //////////////////////////////////////////////////////////////////////////////////////////////////// function IFrameSplitOperator() { this.ChartBorder; //边框信息 this.Frame; //框架信息 this.FrameSplitData; //坐标轴分割方法 this.SplitCount=5; //刻度个数 this.StringFormat=0; //刻度字符串格式 this.IsShowLeftText=true; //显示左边刻度 this.IsShowRightText=true; //显示右边刻度 this.LanguageID=JSCHART_LANGUAGE_ID.LANGUAGE_CHINESE_ID; ////////////////////// // data.Min data.Max data.Interval data.Count // this.IntegerCoordinateSplit=function(data) { var splitItem=this.FrameSplitData.Find(data.Interval); if (!splitItem) return false; if (data.Interval==splitItem.FixInterval) return true; //调整到整数倍数,不能整除的 +1 var fixMax=parseInt((data.Max/(splitItem.FixInterval)+0.5).toFixed(0))*splitItem.FixInterval; var fixMin=parseInt((data.Min/(splitItem.FixInterval)-0.5).toFixed(0))*splitItem.FixInterval; if (data.Min==0) fixMin=0; //最小值是0 不用调整了. if (fixMin<0 && data.Min>0) fixMin=0; //都是正数的, 最小值最小调整为0 var count=0; for(var i=fixMin;(i-fixMax)<0.00000001;i+=splitItem.FixInterval) { ++count; } data.Interval=splitItem.FixInterval; data.Max=fixMax; data.Min=fixMin; data.Count=count; return true; } this.Filter = function (aryInfo,keepZero) { if (this.SplitCount <= 0 || aryInfo.length <= 0 || aryInfo.length < this.SplitCount) return aryInfo; //分割线比预设的多, 过掉一些 var filter = parseInt(aryInfo.length / this.SplitCount); if (filter <= 1) filter = 2; var data = []; for (var i = 0; i < aryInfo.length; i += filter) { if (i + filter >= aryInfo.length && i != aryInfo.length - 1) //最后一个数据放进去 { data.push(aryInfo[aryInfo.length - 1]); } else { data.push(aryInfo[i]); } } if (this.SplitCount == 2 && data.length>2) //之显示第1个和最后一个刻度 { for(var i=1;i= '1' && char <= '9') return false; } return true; } } //字符串格式化 千分位分割 IFrameSplitOperator.FormatValueThousandsString=function(value,floatPrecision) { if (value==null || isNaN(value)) { if (floatPrecision>0) { var nullText='-.'; for(var i=0;i0){ var numFloat = num.split('.')[1]; var numM = num.split('.')[0]; while (numM.length > 3) { result = ',' + numM.slice(-3) + result; numM = numM.slice(0, numM.length - 3); } if (numM) { result = numM + result + '.' + numFloat; } }else{ while (num.length > 3) { result = ',' + num.slice(-3) + result; num = num.slice(0, num.length - 3); } if (num) { result = num + result; } } return result; } //数据输出格式化 floatPrecision=小数位数 IFrameSplitOperator.FormatValueString=function(value, floatPrecision,languageID) { if (value==null || isNaN(value)) { if (floatPrecision>0) { var nullText='-.'; for(var i=0;i-0.00000000001) { return "0"; } var absValue = Math.abs(value); if (languageID===JSCHART_LANGUAGE_ID.LANGUAGE_ENGLISH_ID) { if (absValue < 10000) return value.toFixed(floatPrecision); else if (absValue < 1000000) return (value/1000).toFixed(floatPrecision)+"K"; else if (absValue < 1000000000) return (value/1000000).toFixed(floatPrecision)+"M"; else if (absValue < 1000000000000) return (value/1000000000).toFixed(floatPrecision)+"B"; else return (value/1000000000000).toFixed(floatPrecision)+"T"; } else { if (absValue < 10000) return value.toFixed(floatPrecision); else if (absValue < 100000000) return (value/10000).toFixed(floatPrecision)+"万"; else if (absValue < 1000000000000) return (value/100000000).toFixed(floatPrecision)+"亿"; else return (value/1000000000000).toFixed(floatPrecision)+"万亿"; } return ''; } //整形输出格式化 floatPrecision=小数位数 IFrameSplitOperator.FromatIntegerString=function(value, floatPrecision,languageID) { if (value<10000 && IFrameSplitOperator.IsInteger(value)) floatPrecision=0; //<10000的整形 去掉小数位数 return IFrameSplitOperator.FormatValueString(value, floatPrecision,languageID); } IFrameSplitOperator.NumberToString=function(value) { if (value<10) return '0'+value.toString(); return value.toString(); } IFrameSplitOperator.FormatDateString=function(value,format) { var year=parseInt(value/10000); var month=parseInt(value/100)%100; var day=value%100; switch(format) { case 'MM-DD': return IFrameSplitOperator.NumberToString(month) + '-' + IFrameSplitOperator.NumberToString(day); default: return year.toString() + '-' + IFrameSplitOperator.NumberToString(month) + '-' + IFrameSplitOperator.NumberToString(day); } } IFrameSplitOperator.FormatTimeString=function(value) { if (value<10000) { var hour=parseInt(value/100); var minute=value%100; return IFrameSplitOperator.NumberToString(hour)+':'+ IFrameSplitOperator.NumberToString(minute); } else { var hour=parseInt(value/10000); var minute=parseInt((value%10000)/100); var second=value%100; return IFrameSplitOperator.NumberToString(hour)+':'+ IFrameSplitOperator.NumberToString(minute) + ':' + IFrameSplitOperator.NumberToString(second); } } //报告格式化 IFrameSplitOperator.FormatReportDateString=function(value) { var year=parseInt(value/10000); var month=parseInt(value/100)%100; var monthText; switch(month) { case 3: monthText="一季度报"; break; case 6: monthText="半年报"; break; case 9: monthText="三季度报"; break; case 12: monthText="年报"; break; } return year.toString()+ monthText; } IFrameSplitOperator.FormatDateTimeString=function(value,isShowDate) { var aryValue=value.split(' '); if (aryValue.length<2) return ""; var time=parseInt(aryValue[1]); var minute=time%100; var hour=parseInt(time/100); var text=(hour<10? ('0'+hour.toString()):hour.toString()) + ':' + (minute<10?('0'+minute.toString()):minute.toString()); if (isShowDate==true) { var date=parseInt(aryValue[0]); var year=parseInt(date/10000); var month=parseInt(date%10000/100); var day=date%100; text=year.toString() +'-'+ (month<10? ('0'+month.toString()) :month.toString()) +'-'+ (day<10? ('0'+day.toString()):day.toString()) +" " +text; } return text; } //字段颜色格式化 IFrameSplitOperator.FormatValueColor = function (value, value2) { if (value != null && value2 == null) //只传一个值的 就判断value正负 { if (value == 0) return 'PriceNull'; else if (value > 0) return 'PriceUp'; else return 'PriceDown'; } //2个数值对比 返回颜色 if (value == null || value2 == null) return 'PriceNull'; if (value == value2) return 'PriceNull'; else if (value > value2) return 'PriceUp'; else return 'PriceDown'; } IFrameSplitOperator.IsNumber=function(value) { if (value==null) return false; if (isNaN(value)) return false; return true; } //判断是否是正数 IFrameSplitOperator.IsPlusNumber=function(value) { if (value==null) return false; if (isNaN(value)) return false; return value>0; } //是否是整形 IFrameSplitOperator.IsInteger=function(x) { return (typeof x === 'number') && (x % 1 === 0); } //判断字段是否存在 IFrameSplitOperator.IsObjectExist=function(obj) { if (obj===undefined) return false; if (obj==null) return false; return true; } function FrameSplitKLinePriceY() { this.newMethod=IFrameSplitOperator; //派生 this.newMethod(); delete this.newMethod; this.CoordinateType=0; //坐标类型 0=普通坐标 1=百分比坐标 (右边坐标刻度) this.Symbol; this.Data; //K线数据 (计算百分比坐标) this.FrameSplitData2; //坐标轴分割方法(计算百分比刻度) this.FloatPrecision=null; //小数位数 (设置了就使用这个位数,否则使用品种对应的小数位数) this.Period; //周期 this.KLineChart; this.Custom=[]; //[{Type:0}]; 定制刻度 0=显示最后的价格刻度 this.Operator=function() { var splitData={}; splitData.Max=this.Frame.HorizontalMax; splitData.Min=this.Frame.HorizontalMin; splitData.Count=this.SplitCount; splitData.Interval=(splitData.Max-splitData.Min)/(splitData.Count-1); var pixelTatio = GetDevicePixelRatio(); //获取设备的分辨率 var width=this.Frame.ChartBorder.GetChartWidth(); //画布的宽度 var isPhoneModel=width<450*pixelTatio; var defaultfloatPrecision=GetfloatPrecision(this.Symbol); if (isPhoneModel && MARKET_SUFFIX_NAME.IsSHSZIndex(this.Symbol)) defaultfloatPrecision = 0; //手机端指数不显示小数位数,太长了 if (this.FloatPrecision!=null) defaultfloatPrecision=this.FloatPrecision; console.log(`[FrameSplitKLinePriceY] Max=${splitData.Max} Min=${splitData.Min} Count=${splitData.Count} isPhoneModel=${isPhoneModel} defaultfloatPrecision=${defaultfloatPrecision} `); if (ChartData.IsTickPeriod(this.Period)) { this.SplitTickData(splitData,defaultfloatPrecision); } else { switch(this.CoordinateType) { case 1: this.SplitPercentage(splitData,defaultfloatPrecision); break; default: this.SplitDefault(splitData,defaultfloatPrecision); break; } } this.Frame.HorizontalInfo = this.Filter(this.Frame.HorizontalInfo,false); this.Frame.HorizontalMax=splitData.Max; this.Frame.HorizontalMin=splitData.Min; console.log(`[FrameSplitKLinePriceY] fixed . Max=${splitData.Max} Min=${splitData.Min} Count=${splitData.Count}`); } this.SplitTickData=function(splitData,floatPrecision) { var aryPrice=this.KLineChart.GetAllPrice(); this.Frame.HorizontalInfo=[]; for(var i in aryPrice) { var value=aryPrice[i]; this.Frame.HorizontalInfo[i]= new CoordinateInfo(); this.Frame.HorizontalInfo[i].Value=value; if (this.IsShowLeftText) this.Frame.HorizontalInfo[i].Message[0]=value.toFixed(floatPrecision); if (this.IsShowRightText) this.Frame.HorizontalInfo[i].Message[1]=value.toFixed(floatPrecision); } } this.SplitPercentage=function(splitData,floatPrecision) //百分比坐标 { var firstOpenPrice=this.GetFirstOpenPrice(); splitData.Max=(splitData.Max-firstOpenPrice)/firstOpenPrice; splitData.Min=(splitData.Min-firstOpenPrice)/firstOpenPrice; splitData.Interval=(splitData.Max-splitData.Min)/(splitData.Count-1); this.IntegerCoordinateSplit2(splitData); this.Frame.HorizontalInfo=[]; for(var i=0,value=splitData.Min;ilatestItem.Open) info.LineColor=g_JSChartResource.FrameLatestPrice.UpBarColor; else if (latestItem.Close0) fixMin=0; //都是正数的, 最小值最小调整为0 var count=0; for(var i=fixMin;(i-fixMax)<0.00000001;i+=splitItem.FixInterval) { ++count; } data.Interval=splitItem.FixInterval; data.Max=fixMax; data.Min=fixMin; data.Count=count; return true; } } function FrameSplitY() { this.newMethod=IFrameSplitOperator; //派生 this.newMethod(); delete this.newMethod; this.SplitCount=3; //刻度个数 this.FloatPrecision = 2; //坐标小数位数(默认2) this.FLOATPRECISION_RANGE=[1,0.1,0.01,0.001,0.0001]; this.GetFloatPrecision=function(value,floatPrecision) { if (value>this.FLOATPRECISION_RANGE[0]) return floatPrecision; if (floatPrecision<0) return 2; for(;floatPrecisionthis.FLOATPRECISION_RANGE[floatPrecision]) break; } return floatPrecision; } this.Operator=function() { var splitData={}; splitData.Max=this.Frame.HorizontalMax; splitData.Min=this.Frame.HorizontalMin; if(this.Frame.YSpecificMaxMin) { splitData.Count=this.Frame.YSpecificMaxMin.Count; splitData.Interval=(splitData.Max-splitData.Min)/(splitData.Count-1); } else { splitData.Count=this.SplitCount; splitData.Interval=(splitData.Max-splitData.Min)/(splitData.Count-1); this.IntegerCoordinateSplit(splitData); } this.Frame.HorizontalInfo=[]; if (this.Frame.YSplitScale) //固定坐标 { for(var i in this.Frame.YSplitScale) { var value=this.Frame.YSplitScale[i]; var coordinate=new CoordinateInfo(); coordinate.Value=value; var absValue=Math.abs(value); if (absValue<0.0000000001) { coordinate.Message[1]=0; } else if (absValue 1000) floatPrecision=0; this.Frame.HorizontalInfo[i].Message[1]=IFrameSplitOperator.FormatValueString(value,floatPrecision,this.LanguageID); } else { var absValue=Math.abs(value); if (absValue<0.0000000001) { this.Frame.HorizontalInfo[i].Message[1]=0; } else if (absValue0 && splitData.Min<0)); this.RemoveZero(this.Frame.HorizontalInfo); this.Frame.HorizontalMax=splitData.Max; this.Frame.HorizontalMin=splitData.Min; } } function FrameSplitKLineX() { this.newMethod=IFrameSplitOperator; //派生 this.newMethod(); delete this.newMethod; this.ShowText=true; //是否显示坐标信息 this.Period; //周期 this.Symbol; //股票代码 this.MinTextDistance=50*GetDevicePixelRatio(); this.SplitDateTime=function() //根据时间分割 { this.Frame.VerticalInfo=[]; var itemWidth=this.Frame.DistanceWidth+this.Frame.DataWidth; var xOffset=this.Frame.Data.DataOffset; var xPointCount=this.Frame.XPointCount; var lastYear=null, lastMonth=null; var textDistance=0; for(var i=0, index=xOffset; ithis.MinTextDistance) { var time=IFrameSplitOperator.FormatTimeString(this.Frame.Data.Data[index].Time); infoData={Value:index-xOffset, Text:time}; } if (infoData) { var info= new CoordinateInfo(); info.Value=infoData.Value; if (this.ShowText) info.Message[0]=infoData.Text; this.Frame.VerticalInfo.push(info); textDistance=0; if (i==0) textDistance=-(this.MinTextDistance/2); } } } this.SplitDate=function() //根据日期分割 { this.Frame.VerticalInfo=[]; var xOffset=this.Frame.Data.DataOffset; var xPointCount=this.Frame.XPointCount; var lastYear=null, lastMonth=null; var minDistance=12; for(var i=0, index=xOffset, distance=minDistance;ivalue) min=value; } if (this.AverageData) { for(var i in this.AverageData.Data) { if (this.AverageData.Data[i]==null) continue; if (maxthis.AverageData.Data[i]) min=this.AverageData.Data[i]; } } for(var i in this.OverlayChartPaint) { var item=this.OverlayChartPaint[i]; //if (item.Status!=OVERLAY_STATUS_ID.STATUS_FINISHED_ID) continue; var range=item.GetMaxMin(); if (range.Max && range.Max>max) max=range.Max; if (range.Min && range.Minthis.LimitPrice.Min) min=this.LimitPrice.Min; } return { Max:max, Min:min }; } this.USASplit=function(range) { var max=range.Max; var min=range.Min; if (max==min) { max=max+max*0.1; min=min-min*0.1; } else { var pixelTatio = GetDevicePixelRatio(); //获取设备的分辨率 var height=this.Frame.ChartBorder.GetHeight(); //画布的高度 var spacePrice=5*pixelTatio*(max-min)/height; max+=spacePrice; min-=spacePrice; } var showCount=this.SplitCount; var distance=(max-min)/(showCount-1); const minDistance=[1, 0.1, 0.01, 0.001, 0.0001]; var defaultfloatPrecision=GetfloatPrecision(this.Symbol); if (distance0) coordinate.TextColor=g_JSChartResource.UpTextColor; else if (per<0) coordinate.TextColor=g_JSChartResource.DownTextColor; if (this.IsShowRightText) coordinate.Message[1]=IFrameSplitOperator.FormatValueString(per,2)+'%'; //百分比 } this.Frame.HorizontalInfo.push(coordinate); } if (this.YClose>min && this.YClose0? xcoordinateData.MiddleCount: parseInt(minuteCount/2); var xcoordinate = xcoordinateData.Data; this.Frame.XPointCount=minuteCount*this.DayCount; this.Frame.MinuteCount=minuteCount; this.Frame.VerticalInfo=[]; if (this.DayCount<=1) { var beforeDataCount=14; if (this.IsBeforeData) //增加盘前的数据个数 { this.Frame.XPointCount=minuteCount+beforeDataCount; this.Frame.MinuteCount=minuteCount+beforeDataCount; } for(var i in xcoordinate) { var info=new CoordinateInfo(); info.Value=xcoordinate[i][0]; if (this.IsBeforeData) info.Value+=beforeDataCount; if (this.ShowText) info.Message[0]=xcoordinate[i][3]; this.Frame.VerticalInfo[i]=info; } } else { for(var i=this.DayData.length-1,j=0;i>=0;--i,++j) { var info=new CoordinateInfo(); info.Value=j*minuteCount+minuteMiddleCount; info.LineType=-1; //线段不画 if (this.ShowText) info.Message[0]=IFrameSplitOperator.FormatDateString(this.DayData[i].Date, this.ShowFormate==0?'YYYY-MM-DD':'MM-DD'); this.Frame.VerticalInfo.push(info); var info=new CoordinateInfo(); info.Value=(j+1)*minuteCount; this.Frame.VerticalInfo.push(info); } } } } function FrameSplitXData() { this.newMethod=IFrameSplitOperator; //派生 this.newMethod(); delete this.newMethod; this.ShowText=true; //是否显示坐标信息 this.Operator=function() { if (this.Frame.Data==null || this.Frame.XData==null) return; this.Frame.VerticalInfo=[]; var xOffset=this.Frame.Data.DataOffset; var xPointCount=this.Frame.XPointCount; for(var i=0, index=xOffset; i= data.Data.length) dataIndex = data.Data.length - 1; if (dataIndex < 0) return null; var klineData = data.Data[dataIndex]; if (!klineData) return null; this.Close=klineData.Close; var yPoint = this.Frame.GetYFromData(this.Close); return yPoint; } this.Draw=function() { if (!this.LastPoint) return; this.Close=null; var x=this.LastPoint.X; var y=this.LastPoint.Y; var isInClient=false; this.Canvas.beginPath(); this.Canvas.rect(this.Frame.ChartBorder.GetLeft(),this.Frame.ChartBorder.GetTop(),this.Frame.ChartBorder.GetWidth(),this.Frame.ChartBorder.GetHeight()); isInClient=this.Canvas.isPointInPath(x,y); this.PointY=null; this.PointY==null; if (!isInClient) return; if (this.Frame.IsHScreen===true) { this.HScreenDraw(); return; } var left=this.Frame.ChartBorder.GetLeft(); var right=this.Frame.ChartBorder.GetRight(); var top=this.Frame.ChartBorder.GetTopTitle(); var bottom=this.Frame.ChartBorder.GetBottom(); var rightWidth=this.Frame.ChartBorder.Right; var chartRight=this.Frame.ChartBorder.GetChartWidth(); if (this.IsOnlyDrawKLine) //手机端 十字只能画在K线上 { x=this.Frame.GetXFromIndex(this.CursorIndex); if (this.IsShowClose) { var yPoint = this.GetCloseYPoint(this.CursorIndex); if (yPoint != null) y=yPoint; } } this.PointY=[[left,y],[right,y]]; this.PointX=[[x,top],[x,bottom]]; //十字线 if (this.IsShowCorss) { this.Canvas.save(); this.Canvas.strokeStyle=this.PenColor; this.Canvas.setLineDash([3,2]); //虚线 //this.Canvas.lineWidth=0.5 this.Canvas.beginPath(); this.Canvas.moveTo(left,ToFixedPoint(y)); this.Canvas.lineTo(right,ToFixedPoint(y)); if (this.Frame.SubFrame.length>0) { for(var i in this.Frame.SubFrame) { var frame=this.Frame.SubFrame[i].Frame; top=frame.ChartBorder.GetTopTitle(); bottom=frame.ChartBorder.GetBottom(); this.Canvas.moveTo(ToFixedPoint(x),top); this.Canvas.lineTo(ToFixedPoint(x),bottom); } } else { this.Canvas.moveTo(ToFixedPoint(x),top); this.Canvas.lineTo(ToFixedPoint(x),bottom); } this.Canvas.stroke(); this.Canvas.restore(); } var xValue=this.Frame.GetXData(x); var yValueExtend={}; var yValue=this.Frame.GetYData(y,yValueExtend); if (this.IsShowClose && this.Close != null) yValue=this.Close; this.StringFormatX.Value=xValue; this.StringFormatY.Value=yValue; this.StringFormatY.FrameID=yValueExtend.FrameID; //Y轴 if ( ((this.ShowTextMode.Left==1 && this.Frame.ChartBorder.Left>=30) || this.ShowTextMode.Left==2 || (this.ShowTextMode.Right==1 && this.Frame.ChartBorder.Right>=30) || this.ShowTextMode.Right==2 ) && this.StringFormatY.Operator() ) { var text=this.StringFormatY.Text; this.Canvas.font=this.Font; var textWidth=this.Canvas.measureText(text).width+4; //前后各空2个像素 if (this.Frame.ChartBorder.Left>=30 && this.ShowTextMode.Left==1) { this.Canvas.fillStyle=this.TextBGColor; if (left=30 && this.ShowTextMode.Right==1) { var isOverlayIndex=false; //是否有叠加子坐标 var overlayIndexInterval=null; //子坐标间距 if (yValueExtend.FrameID>=0) { var frame=this.Frame.SubFrame[yValueExtend.FrameID]; isOverlayIndex=frame.OverlayIndex.length>0; overlayIndexInterval=frame.Interval; } this.Canvas.fillStyle=this.TextBGColor; if (isOverlayIndex && textWidth>overlayIndexInterval) //大于子坐标宽度 { var drawRight=right+overlayIndexInterval; if (drawRight>chartRight) drawRight=chartRight; this.Canvas.fillRect(drawRight-2-textWidth,y-this.TextHeight/2,textWidth,this.TextHeight); this.Canvas.textAlign="right"; this.Canvas.textBaseline="middle"; this.Canvas.fillStyle=this.TextColor; this.Canvas.fillText(text,drawRight-4,y,textWidth); } else if (rightWidth=right) { this.Canvas.fillRect(right-textWidth,bottom+2,textWidth,this.TextHeight); this.Canvas.textAlign="right"; this.Canvas.textBaseline="middle"; this.Canvas.fillStyle=this.TextColor; this.Canvas.fillText(text,right-2,yCenter,textWidth); } else { this.Canvas.fillRect(x-textWidth/2,bottom+2,textWidth,this.TextHeight); this.Canvas.textAlign="center"; this.Canvas.textBaseline="middle"; this.Canvas.fillStyle=this.TextColor; this.Canvas.fillText(text,x,yCenter,textWidth); } } //子坐标Y轴 if (yValueExtend.FrameID>=0) { var frame=this.Frame.SubFrame[yValueExtend.FrameID]; var overlayLeft=right; this.Canvas.font=this.Font; for(var i in frame.OverlayIndex) { var item=frame.OverlayIndex[i]; if (item.Frame.IsShow===false) continue; overlayLeft+=frame.Interval; if (overlayLeft+30>chartRight) break; var yValue=item.Frame.GetYData(y); for(var i=2;i>=0;--i) { var text=IFrameSplitOperator.FormatValueString(yValue,i); var textWidth=this.Canvas.measureText(text).width+4; //前后各空2个像素 if (textWidth0) { for(var i in this.Frame.SubFrame) { var frame=this.Frame.SubFrame[i].Frame; this.Canvas.moveTo(frame.ChartBorder.GetLeft(),ToFixedPoint(y)); this.Canvas.lineTo(frame.ChartBorder.GetRightTitle(),ToFixedPoint(y)); } } else { this.Canvas.moveTo(left,ToFixedPoint(y)); this.Canvas.lineTo(right,ToFixedPoint(y)); } this.Canvas.stroke(); this.Canvas.restore(); } var xValue=this.Frame.GetXData(y); var yValueExtend={}; var yValue=this.Frame.GetYData(x,yValueExtend); this.StringFormatX.Value=xValue; this.StringFormatY.Value=yValue; this.StringFormatY.FrameID=yValueExtend.FrameID; if ( ((this.ShowTextMode.Left==1 && this.Frame.ChartBorder.Top>=30) || this.ShowTextMode.Left==2 || (this.ShowTextMode.Right==1 && this.Frame.ChartBorder.Bottom>=30) || this.ShowTextMode.Right==2) && this.StringFormatY.Operator() ) { var text=this.StringFormatY.Text; this.Canvas.font=this.Font; var textWidth=this.Canvas.measureText(text).width+4; //前后各空2个像素 if (this.Frame.ChartBorder.Top>=30 && this.ShowTextMode.Left==1) { var xText=x; var yText=top; this.Canvas.save(); this.Canvas.translate(xText, yText); this.Canvas.rotate(90 * Math.PI / 180); //数据和框子旋转180度 this.Canvas.fillStyle=this.TextBGColor; if (top>=textWidth) { this.Canvas.fillRect(0,-(this.TextHeight/2),-textWidth,this.TextHeight); this.Canvas.textAlign="right"; this.Canvas.textBaseline="middle"; this.Canvas.fillStyle=this.TextColor; this.Canvas.fillText(text,-2,0,textWidth); } else { this.Canvas.fillRect((textWidth-top),-(this.TextHeight/2),-textWidth,this.TextHeight); this.Canvas.textAlign="right"; this.Canvas.textBaseline="middle"; this.Canvas.fillStyle=this.TextColor; this.Canvas.fillText(text,(textWidth-top)-2,0,textWidth); } this.Canvas.restore(); } else if (this.ShowTextMode.Left==2) { var xText=x; var yText=top; this.Canvas.save(); this.Canvas.translate(xText, yText); this.Canvas.rotate(90 * Math.PI / 180); //数据和框子旋转180度 this.Canvas.fillStyle=this.TextBGColor; this.Canvas.fillRect(0,-(this.TextHeight/2),textWidth,this.TextHeight); this.Canvas.textAlign="left"; this.Canvas.textBaseline="middle"; this.Canvas.fillStyle=this.TextColor; this.Canvas.fillText(text,2,0,textWidth); this.Canvas.restore(); } if (this.Frame.ChartBorder.Bottom>=30 && this.ShowTextMode.Right==1) { var xText=x; var yText=bottom; this.Canvas.save(); this.Canvas.translate(xText, yText); this.Canvas.rotate(90 * Math.PI / 180); //数据和框子旋转180度 this.Canvas.fillStyle=this.TextBGColor; if (bottomWidth>textWidth) { this.Canvas.fillRect(0,-(this.TextHeight/2),textWidth,this.TextHeight); this.Canvas.textAlign="left"; this.Canvas.textBaseline="middle"; this.Canvas.fillStyle=this.TextColor; this.Canvas.fillText(text,2,0,textWidth); } else { this.Canvas.fillRect((bottomWidth-textWidth),-(this.TextHeight/2),textWidth,this.TextHeight); this.Canvas.textAlign="left"; this.Canvas.textBaseline="middle"; this.Canvas.fillStyle=this.TextColor; this.Canvas.fillText(text,(bottomWidth-textWidth)+2,0,textWidth); } this.Canvas.restore(); } else if (this.ShowTextMode.Right==2) { var xText=x; var yText=bottom; this.Canvas.save(); this.Canvas.translate(xText, yText); this.Canvas.rotate(90 * Math.PI / 180); //数据和框子旋转180度 this.Canvas.fillStyle=this.TextBGColor; this.Canvas.fillRect(0,-(this.TextHeight/2),-textWidth,this.TextHeight); this.Canvas.textAlign="right"; this.Canvas.textBaseline="middle"; this.Canvas.fillStyle=this.TextColor; this.Canvas.fillText(text,-2,0,textWidth); this.Canvas.restore(); } } if (this.ShowTextMode.Bottom===1 && this.StringFormatX.Operator()) { var text=this.StringFormatX.Text; this.Canvas.font=this.Font; this.Canvas.fillStyle=this.TextBGColor; var textWidth=this.Canvas.measureText(text).width+4; //前后各空2个像素 if (y-textWidth/2<3) //左边位置不够了, 顶着左边画 { var xText=left; var yText=y; this.Canvas.save(); this.Canvas.translate(xText, yText); this.Canvas.rotate(90 * Math.PI / 180); //数据和框子旋转180度 this.Canvas.fillRect(0,0,textWidth,this.TextHeight); this.Canvas.textAlign="left"; this.Canvas.textBaseline="middle"; this.Canvas.fillStyle=this.TextColor; this.Canvas.fillText(text,0,this.TextHeight/2,textWidth); this.Canvas.restore(); } else { var xText=left; var yText=y; this.Canvas.save(); this.Canvas.translate(xText, yText); this.Canvas.rotate(90 * Math.PI / 180); //数据和框子旋转180度 this.Canvas.fillRect(-textWidth/2,0,textWidth,this.TextHeight); this.Canvas.textAlign="center"; this.Canvas.textBaseline="middle"; this.Canvas.fillStyle=this.TextColor; this.Canvas.fillText(text,0,this.TextHeight/2,textWidth); this.Canvas.restore(); } } } } //////////////////////////////////////////////////////////////////////////////// // 等待提示 function ChartSplashPaint() { this.Frame; this.Canvas; //画布 this.Font=g_JSChartResource.DefaultTextFont; //字体 this.TextColor=g_JSChartResource.DefaultTextColor; //文本颜色 this.IsEnableSplash=false; this.SplashTitle='数据加载中'; this.Draw=function() { if (!this.IsEnableSplash) return; if (this.Frame.IsHScreen===true) { this.HScreenDraw(); return; } var xCenter = (this.Frame.ChartBorder.GetLeft() + this.Frame.ChartBorder.GetRight()) / 2; var yCenter = (this.Frame.ChartBorder.GetTop() + this.Frame.ChartBorder.GetBottom()) / 2; this.Canvas.textAlign='center'; this.Canvas.textBaseline='middle'; this.Canvas.fillStyle=this.TextColor; this.Canvas.font=this.Font; this.Canvas.fillText(this.SplashTitle,xCenter,yCenter); } this.HScreenDraw=function() //横屏 { var xCenter = (this.Frame.ChartBorder.GetLeft() + this.Frame.ChartBorder.GetRight()) / 2; var yCenter = (this.Frame.ChartBorder.GetTop() + this.Frame.ChartBorder.GetBottom()) / 2; this.Canvas.save(); this.Canvas.translate(xCenter, yCenter); this.Canvas.rotate(90 * Math.PI / 180); //数据和框子旋转180度 this.Canvas.textAlign='center'; this.Canvas.textBaseline='middle'; this.Canvas.fillStyle=this.TextColor; this.Canvas.font=this.Font; this.Canvas.fillText(this.SplashTitle,0,0); this.Canvas.restore(); } } ///////////////////////////////////////////////////////////////////////////////// // function IChangeStringFormat() { this.Data; this.Value; //数据 this.Text; //输出字符串 this.Operator=function() { return false; } } function HQPriceStringFormat() { this.newMethod=IChangeStringFormat; //派生 this.newMethod(); delete this.newMethod; this.Symbol; this.FrameID; this.LanguageID=JSCHART_LANGUAGE_ID.LANGUAGE_CHINESE_ID; this.YClose; //收盘价 this.PercentageText; //百分比 this.Operator=function() { if (!this.Value) return false; this.PercentageText=null; var defaultfloatPrecision=2; //价格小数位数 if (this.FrameID==0) //第1个窗口显示原始价格 { var defaultfloatPrecision=GetfloatPrecision(this.Symbol); this.Text=this.Value.toFixed(defaultfloatPrecision); if (this.YClose>0) this.PercentageText=((this.Value-this.YClose)*100/this.YClose).toFixed(2); //走势图右边坐标显示百分比 } else { this.Text=IFrameSplitOperator.FormatValueString(this.Value,defaultfloatPrecision,this.LanguageID); } return true; } } function HQDateStringFormat() { this.newMethod=IChangeStringFormat; //派生 this.newMethod(); delete this.newMethod; this.Operator=function() { if (!IFrameSplitOperator.IsNumber(this.Value)) return false; if (!this.Data) return false; var index=this.Value; index=parseInt(index.toFixed(0)); if (this.Data.DataOffset+index>=this.Data.Data.length) return false; var currentData = this.Data.Data[this.Data.DataOffset+index]; this.Text=IFrameSplitOperator.FormatDateString(currentData.Date); if (ChartData.IsMinutePeriod(this.Data.Period,true)) // 分钟周期 { var time = IFrameSplitOperator.FormatTimeString(currentData.Time); this.Text = this.Text + " " + time; } else if (ChartData.IsTickPeriod(this.Data.Period)) //分笔 { var time = IFrameSplitOperator.FormatTimeString(currentData.Time); this.Text = this.Text + " " + time; } return true; } } function HQMinuteTimeStringFormat() { this.newMethod=IChangeStringFormat; //派生 this.newMethod(); delete this.newMethod; this.Frame; this.Symbol; this.IsBeforeData=false; //是否显示盘前数据 this.Operator=function() { if (this.Value==null || isNaN(this.Value)) return false; var index=Math.abs(this.Value); index=parseInt(index.toFixed(0)); var showIndex=index; if (this.Frame && this.Frame.MinuteCount) showIndex=index%this.Frame.MinuteCount; var timeStringData=g_MinuteTimeStringData; var timeData=timeStringData.GetTimeData(this.Symbol); if (!timeData) return false; if (this.IsBeforeData) //增加盘前数据时间刻度 { var allTimeData=[915,916,917,918,919,920,921,922,923,924,925,926,927,928,929] for(var i in timeData) { if (timeData[i]==925) continue; allTimeData.push(timeData[i]) } timeData=allTimeData; } if (showIndex<0) showIndex=0; else if (showIndex>timeData.length) showIndex=timeData.length-1; if (this.Frame && index>=this.Frame.XPointCount) showIndex=timeData.length-1; var time=timeData[showIndex]; this.Text=IFrameSplitOperator.FormatTimeString(time); return true; } } //行情tooltip提示信息格式 var WEEK_NAME=["日","一","二","三","四","五","六"]; function HistoryDataStringFormat() { this.newMethod=IChangeStringFormat; //派生 this.newMethod(); delete this.newMethod; this.Symbol; this.UpColor=g_JSChartResource.UpTextColor; this.DownColor=g_JSChartResource.DownTextColor; this.UnchagneColor=g_JSChartResource.UnchagneTextColor; this.VolColor=g_JSChartResource.DefaultTextColor; this.AmountColor=g_JSChartResource.DefaultTextColor; this.LanguageID=JSCHART_LANGUAGE_ID.LANGUAGE_CHINESE_ID; this.LineCount=0; //一共几行 this.Operator=function() { var data=this.Value.Data; if (!data) return false; var date=new Date(parseInt(data.Date/10000),(data.Date/100%100-1),data.Date%100); var strDate=IFrameSplitOperator.FormatDateString(data.Date); var title2=g_JSChartLocalization.GetText(WEEK_NAME[date.getDay()],this.LanguageID); if (ChartData.IsMinutePeriod(this.Value.ChartPaint.Data.Period,true)) // 分钟周期 { var hour=parseInt(data.Time/100); var minute=data.Time%100; var strHour=hour>=10?hour.toString():"0"+hour.toString(); var strMinute=minute>=10?minute.toString():"0"+minute.toString(); title2 = strHour + ":" + strMinute; } var defaultfloatPrecision=GetfloatPrecision(this.Symbol);//价格小数位数 var increase=null; if (data.YClose>0) increase=(data.Close-data.YClose)/data.YClose*100; var strText= ""+strDate+"  "+title2+""+ ""+g_JSChartLocalization.GetText('DivTooltip-Open',this.LanguageID)+""+ ""+data.Open.toFixed(defaultfloatPrecision)+"
"+ ""+g_JSChartLocalization.GetText('DivTooltip-High',this.LanguageID)+""+ ""+data.High.toFixed(defaultfloatPrecision)+"
"+ ""+g_JSChartLocalization.GetText('DivTooltip-Low',this.LanguageID)+""+ ""+data.Low.toFixed(defaultfloatPrecision)+"
"+ ""+g_JSChartLocalization.GetText('DivTooltip-Close',this.LanguageID)+""+ ""+data.Close.toFixed(defaultfloatPrecision)+"
"+ //" 前收: "+IFrameSplitOperator.FormatValueString(data.YClose,2)+"
"+ ""+g_JSChartLocalization.GetText('DivTooltip-Vol',this.LanguageID)+""+ ""+IFrameSplitOperator.FormatValueString(data.Vol,2,this.LanguageID)+"
"+ ""+g_JSChartLocalization.GetText('DivTooltip-Amount',this.LanguageID)+""+ ""+IFrameSplitOperator.FormatValueString(data.Amount,2,this.LanguageID)+"
"+ ""+g_JSChartLocalization.GetText('DivTooltip-Increase',this.LanguageID)+""+ (increase==null? ""+'--'+"
" : ""+increase.toFixed(2)+'%'+"
"); this.LineCount=8; if(MARKET_SUFFIX_NAME.IsSHSZStockA(this.Symbol) && data.FlowCapital>0) //换手率 { var value=data.Vol/data.FlowCapital*100; strText+= ""+g_JSChartLocalization.GetText('DivTooltip-Exchange',this.LanguageID)+""+ ""+value.toFixed(2)+'%'+"
"; ++this.LineCount; } //叠加股票 if (this.Value.ChartPaint.Name=="Overlay-KLine") { var title=""+this.Value.ChartPaint.Title+""; strText=title+strText; ++this.LineCount; } this.Text=strText; return true; } this.GetColor=function(price,yclse) { if(price>yclse) return this.UpColor; else if (price"; if(infoList.length > 8) { var strBox="
共"+infoList.length+"条
"; html+=strBox; } this.Text=html; return true; } this.DefaultFormat=function(item) { var strDate=IFrameSplitOperator.FormatDateString(item.Date); var strText=""+strDate+"   "+item.Title+""; return strText; } //大宗交易 this.BlockTradingFormat=function(item) { var showPriceInfo = item.ExtendData; var strDate=IFrameSplitOperator.FormatDateString(item.Date); var strText=""+strDate+"  成交价: "+showPriceInfo.Price.toFixed(2)+"收盘价: "+showPriceInfo.ClosePrice.toFixed(2)+ "
溢折价率: "+ showPriceInfo.Premium.toFixed(2)+"%成交量(万股): "+showPriceInfo.Vol.toFixed(2)+"
"; return strText; } //龙虎榜 this.TradeDetailFormat=function(item) { /*var detail= [ "日价格涨幅偏离值达到9.89%", "日价格涨幅偏离值达格涨幅偏离值达格涨幅偏离值达到9.89%" ] */ var detail=item.ExtendData.Detail; //格式:日期 上榜原因: detail[0].TypeExplain // detail[1].TypeExplain // 一周后涨幅: xx 四周后涨幅: xx var strDate=IFrameSplitOperator.FormatDateString(item.Date); var reasons = []; for(var i in detail) { reasons += ""+detail[i].TypeExplain+"
" // reasons += detail[i] + "
" } var strText= ""+strDate+"   上榜原因:  "+reasons+"
一周后涨幅: "+ item.ExtendData.FWeek.Week1.toFixed(2)+ "%   四周后涨幅: "+ item.ExtendData.FWeek.Week4.toFixed(2)+"%
"; return strText; } //调研 this.ResearchFormat=function(item) { var levels=item.ExtendData.Level; var recPerson=''; if(levels.length==0) { recPerson = "一般调研" } else { for(var j in levels) { if(levels[j]==0) recPerson+="证券代表   "; else if(levels[j]==1) recPerson+="董秘   "; else if(levels[j]==2) recPerson+="总经理   "; else if(levels[j]==3) recPerson+="董事长   "; } recPerson='接待:   '+recPerson; } var researchType=''; if (item.ExtendData.Type && item.ExtendData.Type!='其他') { researchType='   '+''+item.ExtendData.Type+''; if (levels.length==0) recPerson=''; } var strDate=IFrameSplitOperator.FormatDateString(item.Date); var strText=""+strDate+"   "+researchType+recPerson+""; return strText; } //业绩预测 this.PerformanceForecastFormat=function(item) { var reportDate=item.ExtendData.ReportDate; var year=parseInt(reportDate/10000); //年份 var day=reportDate%10000; //比较 这个去掉年份的日期 var reportType; if(day == 1231){ reportType = "年报" }else if(day == 331){ reportType = "一季度报" }else if(day == 630){ reportType = "半年度报" }else if(day == 930){ reportType = "三季度报" } var weekData=""; if (item.ExtendData.FWeek) { if (item.ExtendData.FWeek.Week1!=null) weekData+="一周后涨幅:"+ item.ExtendData.FWeek.Week1.toFixed(2)+"%"; if (item.ExtendData.FWeek.Week4!=null) weekData+=" 四周后涨幅:"+ item.ExtendData.FWeek.Week4.toFixed(2)+"%"; if (weekData.length>0) weekData="
  "+weekData+""; } var strDate=IFrameSplitOperator.FormatDateString(item.Date); var strText=""+strDate+"  "+year+reportType+item.Title+" "+weekData+""; return strText; } this.GetColor=function(price) { if(price>0) return this.UpColor; else if (price<0) return this.DownColor; else return this.UnchagneColor; } } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // 标题 // // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function IChartTitlePainting() { this.Frame; this.Data=new Array(); this.Canvas; //画布 this.IsDynamic=false; //是否是动态标题 this.Position=0; //标题显示位置 0 框架里的标题 1 框架上面 this.CursorIndex; //数据索引 this.Font=g_JSChartResource.TitleFont; this.Title; //固定标题(可以为空) this.TitleColor=g_JSChartResource.DefaultTextColor; } var PERIOD_NAME=["日线","周线","月线","年线","1分","5分","15分","30分","60分","季线","分笔", "2小时","4小时","","",""]; var RIGHT_NAME=['不复权','前复权','后复权']; function DynamicKLineTitlePainting() { this.newMethod=IChartTitlePainting; //派生 this.newMethod(); delete this.newMethod; this.IsDynamic=true; this.IsShow=true; //是否显示 this.UpColor=g_JSChartResource.UpTextColor; this.DownColor=g_JSChartResource.DownTextColor; this.UnchagneColor=g_JSChartResource.UnchagneTextColor; this.VolColor=g_JSChartResource.DefaultTextColor; this.AmountColor=g_JSChartResource.DefaultTextColor; this.DateTimeColor=g_JSChartResource.DefaultTextColor; this.NameColor = g_JSChartResource.DefaultTextColor; this.Symbol; this.Name; this.SpaceWidth=2*GetDevicePixelRatio(); //获取设备的分辨率; this.OverlayChartPaint; //叠加画法 this.IsShowName=true; //是否显示股票名称 this.IsShowSettingInfo=true; //是否显示设置信息(周期 复权) this.IsShowDateTime=true; //是否显示日期 this.LanguageID=JSCHART_LANGUAGE_ID.LANGUAGE_CHINESE_ID; this.OnDrawEvent; this.GetCurrentKLineData=function() //获取当天鼠标位置所在的K线数据 { if (this.CursorIndex==null || !this.Data) return null; if (this.Data.length<=0) return null; var index=this.CursorIndex; index=parseInt(index.toFixed(0)); var dataIndex=this.Data.DataOffset+index; if (dataIndex>=this.Data.Data.length) dataIndex=this.Data.Data.length-1; if (dataIndex<0) return null; var item=this.Data.Data[dataIndex]; return item; } this.DrawItem=function(item) { var isHScreen=this.Frame.IsHScreen===true; var left=this.Frame.ChartBorder.GetLeft(); var bottom=this.Frame.ChartBorder.GetTop()-this.Frame.ChartBorder.Top/2; var right=this.Frame.ChartBorder.GetRight(); var defaultfloatPrecision=GetfloatPrecision(this.Symbol);//价格小数位数 if (isHScreen) { if (this.Frame.ChartBorder.Right<5) return; var left=2; var bottom=this.Frame.ChartBorder.Right/2; //上下居中显示 var right=this.Frame.ChartBorder.GetHeight(); var xText=this.Frame.ChartBorder.GetChartWidth(); var yText=this.Frame.ChartBorder.GetTop(); this.Canvas.translate(xText, yText); this.Canvas.rotate(90 * Math.PI / 180); } else { if (this.Frame.ChartBorder.Top<5*GetDevicePixelRatio()) return; } this.Canvas.textAlign="left"; this.Canvas.textBaseline="middle"; this.Canvas.font=this.Font; var position = { Left: left, Bottom: bottom, IsHScreen: isHScreen }; if (this.IsShowName) { if (!this.DrawText(this.Name,this.UnchagneColor,position)) return; } if (this.IsShowSettingInfo) { this.Canvas.fillStyle=this.NameColor; var periodName=''; if (this.Data.Period>CUSTOM_MINUTE_PERIOD_START && this.Data.Period<=CUSTOM_MINUTE_PERIOD_END) periodName=(this.Data.Period-CUSTOM_MINUTE_PERIOD_START)+g_JSChartLocalization.GetText('自定义分钟',this.LanguageID); else if (this.Data.Period>CUSTOM_DAY_PERIOD_START && this.Data.Period<=CUSTOM_DAY_PERIOD_END) periodName=(this.Data.Period-CUSTOM_DAY_PERIOD_START)+g_JSChartLocalization.GetText('自定义日线',this.LanguageID); else periodName=g_JSChartLocalization.GetText(PERIOD_NAME[this.Data.Period],this.LanguageID); var rightName=g_JSChartLocalization.GetText(RIGHT_NAME[this.Data.Right],this.LanguageID); var text="("+periodName+" "+rightName+")"; var isStock=MARKET_SUFFIX_NAME.IsSHSZStockA(this.Symbol); //是否是指数 if(item.Time!=null || !isStock) text="("+periodName+")"; //分钟K线 指数 没有复权 if (!this.DrawText(text,this.NameColor,position)) return; } if (this.IsShowDateTime) //是否显示日期 { this.Canvas.fillStyle=this.DateTimeColor; var text=IFrameSplitOperator.FormatDateString(item.Date); if (!this.DrawText(text,this.DateTimeColor,position)) return; } if(item.Time!=null && !isNaN(item.Time) && item.Time>0) { var text=IFrameSplitOperator.FormatTimeString(item.Time); if (!this.DrawText(text,this.UnchagneColor,position)) return; } var color=this.GetColor(item.Open,item.YClose); var text=g_JSChartLocalization.GetText('KTitle-Open',this.LanguageID)+item.Open.toFixed(defaultfloatPrecision); if (!this.DrawText(text,color,position)) return; var color=this.GetColor(item.High,item.YClose); var text=g_JSChartLocalization.GetText('KTitle-High',this.LanguageID)+item.High.toFixed(defaultfloatPrecision); if (!this.DrawText(text,color,position)) return; var color=this.GetColor(item.Low,item.YClose); var text=g_JSChartLocalization.GetText('KTitle-Low',this.LanguageID)+item.Low.toFixed(defaultfloatPrecision); if (!this.DrawText(text,color,position)) return; var color=this.GetColor(item.Close,item.YClose); var text=g_JSChartLocalization.GetText('KTitle-Close',this.LanguageID)+item.Close.toFixed(defaultfloatPrecision); if (!this.DrawText(text,color,position)) return; var value=(item.Close-item.YClose)/item.YClose*100; var color = this.GetColor(value, 0); var text = g_JSChartLocalization.GetText('KTitle-Increase',this.LanguageID) + value.toFixed(2)+'%'; if (!this.DrawText(text,color,position)) return; var text=g_JSChartLocalization.GetText('KTitle-Vol',this.LanguageID)+IFrameSplitOperator.FromatIntegerString(item.Vol,2,this.LanguageID); if (!this.DrawText(text,this.VolColor,position)) return; if (IFrameSplitOperator.IsNumber(item.Amount)) { var text=g_JSChartLocalization.GetText('KTitle-Amount',this.LanguageID)+IFrameSplitOperator.FormatValueString(item.Amount,2,this.LanguageID); if (!this.DrawText(text,this.AmountColor,position)) return; } if (MARKET_SUFFIX_NAME.IsSHSZStockA(this.Symbol) && item.FlowCapital>0) //A股有换手率 { var value=item.Vol/item.FlowCapital*100; //成交量/流通A股*100 var text=g_JSChartLocalization.GetText('KTitle-Exchange',this.LanguageID)+IFrameSplitOperator.FormatValueString(value,2,this.LanguageID)+'%'; if (!this.DrawText(text,this.AmountColor,position)) return; } //叠加股票的名字 for(var i in this.OverlayChartPaint) { var item=this.OverlayChartPaint[i]; if (!item.Symbol || !item.Title) continue; var name=item.Title; var clrText=item.Color; var text='['+name+']'; if (!this.DrawText(text,clrText,position)) return; } } this.Draw=function() { if (!this.IsShow) return; if (this.CursorIndex==null || !this.Data || this.Data.length<=0) { this.OnDrawEventCallback(null); return; } this.Canvas.font=this.Font; this.SpaceWidth = this.Canvas.measureText('0').width; var index=this.CursorIndex; index=parseInt(index.toFixed(0)); var dataIndex=this.Data.DataOffset+index; if (dataIndex>=this.Data.Data.length) dataIndex=this.Data.Data.length-1; if (dataIndex<0) { this.OnDrawEventCallback(null); return; } var item=this.Data.Data[dataIndex]; this.OnDrawEventCallback(item); this.Canvas.save(); this.DrawItem(item); this.Canvas.restore(); } this.OnDrawEventCallback=function(drawData) { if (!this.OnDrawEvent || !this.OnDrawEvent.Callback) return; var data={ Draw: drawData, Name:'DynamicKLineTitlePainting'}; this.OnDrawEvent.Callback(this.OnDrawEvent,data,this); } this.GetColor=function(price,yclse) { if(price>yclse) return this.UpColor; else if (price right) return false; this.Canvas.fillText(title, position.Left, position.Bottom, textWidth); position.Left += textWidth + this.SpaceWidth; return true; } } function DynamicMinuteTitlePainting() { this.newMethod=DynamicKLineTitlePainting; //派生 this.newMethod(); delete this.newMethod; this.SpaceWidth=1*GetDevicePixelRatio(); this.YClose; this.IsShowDate=false; //标题是否显示日期 this.IsShowName=true; //标题是否显示股票名字 this.OverlayChartPaint; //叠加画法 this.LanguageID=JSCHART_LANGUAGE_ID.LANGUAGE_CHINESE_ID; this.LastShowData; //保存最后显示的数据 给tooltip用 this.OnDrawEvent; this.GetCurrentKLineData=function() //获取当天鼠标位置所在的K线数据 { if (this.LastShowData) return this.LastShowData; if (this.CursorIndex==null || !this.Data) return null; if (this.Data.length<=0) return null; var index=Math.abs(this.CursorIndex-0.5); index=parseInt(index.toFixed(0)); var dataIndex=this.Data.DataOffset+index; if (dataIndex>=this.Data.Data.length) dataIndex=this.Data.Data.length-1; if (dataIndex<0) return null; var item=this.Data.Data[dataIndex]; return item; } this.DrawItem=function(item) { var isHScreen=this.Frame.IsHScreen===true; var left=this.Frame.ChartBorder.GetLeft(); var bottom=this.Frame.ChartBorder.GetTop()-this.Frame.ChartBorder.Top/2; var right=this.Frame.ChartBorder.GetRight(); var defaultfloatPrecision=GetfloatPrecision(this.Symbol);//价格小数位数 if (isHScreen) { if (this.Frame.ChartBorder.Right<5) return; var left=2; var bottom=this.Frame.ChartBorder.Right/2; //上下居中显示 var right=this.Frame.ChartBorder.GetHeight(); var xText=this.Frame.ChartBorder.GetChartWidth(); var yText=this.Frame.ChartBorder.GetTop(); this.Canvas.translate(xText, yText); this.Canvas.rotate(90 * Math.PI / 180); } else { if (this.Frame.ChartBorder.Top<5) return; } this.Canvas.textAlign="left"; this.Canvas.textBaseline="middle"; this.Canvas.font=this.Font; var position = { Left: left, Bottom: bottom, IsHScreen: isHScreen }; if(this.IsShowName) { if (!this.DrawText(this.Name,this.UnchagneColor,position)) return; } var text=IFrameSplitOperator.FormatDateTimeString(item.DateTime,this.IsShowDate); if (!this.DrawText(text,this.UnchagneColor,position)) return; var close=item.Close; var increase=item.Increase; var vol=item.Vol; var amount=item.Amount; if (item.Before) //读取盘前数据 { close=item.Before.Close; increase=item.Before.Increase; vol=item.Before.Vol; amount=item.Before.Amount; } if (close) { var color=this.GetColor(close,this.YClose); var text=g_JSChartLocalization.GetText('MTitle-Close',this.LanguageID)+close.toFixed(defaultfloatPrecision); if (!this.DrawText(text,color,position)) return; } if (increase!=null) { var color=this.GetColor(increase,0); var text=g_JSChartLocalization.GetText('MTitle-Increase',this.LanguageID)+increase.toFixed(2)+'%'; if (!this.DrawText(text,color,position)) return; } if (item.AvPrice) { var color=this.GetColor(item.AvPrice,this.YClose); var text=g_JSChartLocalization.GetText('MTitle-AvPrice',this.LanguageID)+item.AvPrice.toFixed(defaultfloatPrecision); if (!this.DrawText(text,color,position)) return; } var text=g_JSChartLocalization.GetText('MTitle-Vol',this.LanguageID)+IFrameSplitOperator.FromatIntegerString(vol,2); if (!this.DrawText(text,this.VolColor,position)) return; if (IFrameSplitOperator.IsNumber(amount)) { var text=g_JSChartLocalization.GetText('MTitle-Amount',this.LanguageID)+IFrameSplitOperator.FormatValueString(amount,2); if (!this.DrawText(text,this.AmountColor,position)) return; } //叠加股票的名字 for(var i in this.OverlayChartPaint) { var item=this.OverlayChartPaint[i]; if (!item.Symbol || !item.Title) continue; var name=item.Title; var clrText=item.Color; var text='['+name+']'; if (!this.DrawText(text,clrText,position)) return; } } this.Draw=function() { this.LastShowData=null; if (!this.IsShow) return; if (this.CursorIndex==null || !this.Data || !this.Data.Data) return; if (this.Data.Data.length<=0) return; this.Canvas.font=this.Font; this.SpaceWidth = this.Canvas.measureText('0').width; //var index=Math.abs(this.CursorIndex-0.5); var index=this.CursorIndex; index=parseInt(index.toFixed(0)); var dataIndex=index+this.Data.DataOffset; if (dataIndex>=this.Data.Data.length) dataIndex=this.Data.Data.length-1; var item=this.Data.Data[dataIndex]; this.LastShowData=item; this.Canvas.save(); this.DrawItem(item); this.Canvas.restore(); } } //字符串输出格式 var STRING_FORMAT_TYPE = { DEFAULT: 1, //默认 2位小数 单位自动转化 (万 亿) ORIGINAL:2, //原始数据 INTEGER:3, //整形数据输出 如果不是整形使用 DEFAULT THOUSANDS:21, //千分位分割 }; function DynamicTitleData(data,name,color) { this.Data=data; this.Name=name; this.Color=color; //字体颜色 this.DataType; //数据类型 this.StringFormat=STRING_FORMAT_TYPE.DEFAULT; //字符串格式 this.FloatPrecision=2; //小数位数 } function DynamicChartTitlePainting() { this.newMethod=IChartTitlePainting; //派生 this.newMethod(); delete this.newMethod; this.IsDynamic=true; this.Data=new Array(); this.Explain; this.ColorIndex; //五彩K线名字 {Name:'名字'} this.TradeIndex; //专家系统名字{Name:'名字'} this.OverlayIndex=new Map(); //叠加指标 key=Identify value={ Data:数据, Title:标题, Identify:标识} this.LanguageID=JSCHART_LANGUAGE_ID.LANGUAGE_CHINESE_ID; this.FormatValue=function(value,item) { if (item.StringFormat==STRING_FORMAT_TYPE.DEFAULT) return IFrameSplitOperator.FormatValueString(value,item.FloatPrecision,this.LanguageID); else if (item.StringFormat==STRING_FORMAT_TYPE.THOUSANDS) return IFrameSplitOperator.FormatValueThousandsString(value,item.FloatPrecision); else if (item.StringFormat==STRING_FORMAT_TYPE.ORIGINAL) return value.toFixed(item.FloatPrecision).toString(); else if (item.StringFormat==STRING_FORMAT_TYPE.INTEGER) return IFrameSplitOperator.FromatIntegerString(value,item.FloatPrecision,this.LanguageID); } this.FormatMultiReport=function(data,format) { var text=""; for(var i in data) { var item = data[i]; let quarter=item.Quarter; let year=item.Year; let value=item.Value; if (text.length>0) text+=','; text+=year.toString(); switch(quarter) { case 1: text+='一季报 '; break; case 2: text+='半年报 '; break; case 3: text+='三季报 '; break; case 4: text+='年报 '; break; } text+=this.FormatValue(value,format); } return text; } this.Draw=function() { if (this.CursorIndex==null ) return; if (!this.Data) return; if (this.Frame.ChartBorder.TitleHeight<5) return; if (this.Frame.IsHScreen===true) { this.Canvas.save(); this.HScreenDraw(); this.Canvas.restore(); return; } var left=this.Frame.ChartBorder.GetLeft()+1; var bottom=this.Frame.ChartBorder.GetTop()+this.Frame.ChartBorder.TitleHeight/2; //上下居中显示 var right=this.Frame.ChartBorder.GetRight(); this.Canvas.textAlign="left"; this.Canvas.textBaseline="middle"; this.Canvas.font=this.Font; if (this.Title) { this.Canvas.fillStyle=this.TitleColor; var textWidth=this.Canvas.measureText(this.Title).width+2; this.Canvas.fillText(this.Title,left,bottom,textWidth); left+=textWidth; } var lockRect=this.Frame.GetLockRect(); if (lockRect) //指标上锁区域不显示动态标题 { var index=Math.abs(this.CursorIndex-0.5); var x=this.Frame.GetXFromIndex(index.toFixed(0)); if (x>=lockRect.Left) return; } for(var i in this.Data) { var item=this.Data[i]; if (!item || !item.Data || !item.Data.Data || !item.Name) continue; if (item.Data.Data.length<=0) continue; var value=null; var valueText=null; if (item.DataType=="StraightLine") //直线只有1个数据 { value=item.Data.Data[0]; valueText=this.FormatValue(value,item); } else { var index=Math.abs(this.CursorIndex-0.5); index=parseInt(index.toFixed(0)); var dataIndex=item.Data.DataOffset+index; if (dataIndex>=item.Data.Data.length) dataIndex=item.Data.Data.length-1; if (dataIndex<0) continue; //if (item.Data.DataOffset+index>=item.Data.Data.length) continue; value=item.Data.Data[dataIndex]; if (value==null) continue; if (item.DataType=="HistoryData-Vol") { value=value.Vol; valueText=this.FormatValue(value,item); } else if (item.DataType=="MultiReport") { valueText=this.FormatMultiReport(value,item); } else { valueText=this.FormatValue(value,item); } } this.Canvas.fillStyle=item.Color; var text=item.Name+":"+valueText; var textWidth=this.Canvas.measureText(text).width+2; //后空2个像素 this.Canvas.fillText(text,left,bottom,textWidth); left+=textWidth; } if (this.Explain) //说明信息 { this.Canvas.fillStyle=this.TitleColor; var text="说明:"+this.Explain; var textWidth=this.Canvas.measureText(text).width+2; if (left+textWidthright) return; var spaceWidth=5*GetDevicePixelRatio(); var drawLeft=left; for(item of this.OverlayIndex) { left+=spaceWidth; var overlayItem=item[1]; if (overlayItem.Title) { this.Canvas.fillStyle=this.TitleColor; var textWidth=this.Canvas.measureText(overlayItem.Title).width+2; drawLeft=left; left+=textWidth; if (left>right) break; this.Canvas.fillText(overlayItem.Title,drawLeft,bottom,textWidth); } for(var i in overlayItem.Data) { var item=overlayItem.Data[i]; if (!item || !item.Data || !item.Data.Data || !item.Name) continue; if (item.Data.Data.length<=0) continue; var value=null; var valueText=null; if (item.DataType=="StraightLine") //直线只有1个数据 { value=item.Data.Data[0]; valueText=this.FormatValue(value,item); } else { var index=Math.abs(this.CursorIndex-0.5); index=parseInt(index.toFixed(0)); var dataIndex=item.Data.DataOffset+index; if (dataIndex>=item.Data.Data.length) dataIndex=item.Data.Data.length-1; if (dataIndex<0) continue; value=item.Data.Data[dataIndex]; if (value==null) continue; if (item.DataType=="HistoryData-Vol") { value=value.Vol; valueText=this.FormatValue(value,item); } else if (item.DataType=="MultiReport") { valueText=this.FormatMultiReport(value,item); } else { valueText=this.FormatValue(value,item); } } this.Canvas.fillStyle=item.Color; var text=item.Name+":"+valueText; var textWidth=this.Canvas.measureText(text).width+2; //后空2个像素 drawLeft=left; left+=textWidth; if (left>right) break; this.Canvas.fillText(text,drawLeft,bottom,textWidth); } if (left>right) break; } } this.HScreenDraw=function() { var xText=this.Frame.ChartBorder.GetRightTitle(); var yText=this.Frame.ChartBorder.GetTop(); this.Canvas.translate(xText, yText); this.Canvas.rotate(90 * Math.PI / 180); var left=1; var bottom=-this.Frame.ChartBorder.TitleHeight/2; //上下居中显示 var right=this.Frame.ChartBorder.GetHeight(); this.Canvas.textAlign="left"; this.Canvas.textBaseline="middle"; this.Canvas.font=this.Font; if (this.Title) { this.Canvas.fillStyle=this.TitleColor; var textWidth=this.Canvas.measureText(this.Title).width+2; this.Canvas.fillText(this.Title,left,bottom,textWidth); left+=textWidth; } var lockRect=this.Frame.GetLockRect(); if (lockRect) //指标上锁区域不显示动态标题 { var index=Math.abs(this.CursorIndex-0.5); var x=this.Frame.GetXFromIndex(index.toFixed(0)); if (x>=lockRect.Top) return; } for(var i in this.Data) { var item=this.Data[i]; if (!item || !item.Data || !item.Data.Data || !item.Name) continue; if (item.Data.Data.length<=0) continue; var value=null; var valueText=null; if (item.DataType=="StraightLine") //直线只有1个数据 { value=item.Data.Data[0]; valueText=this.FormatValue(value,item); } else { var index=Math.abs(this.CursorIndex-0.5); index=parseInt(index.toFixed(0)); var dataIndex=item.Data.DataOffset+index; if (dataIndex>=item.Data.Data.length) dataIndex=item.Data.Data.length-1; if (dataIndex<0) continue; value=item.Data.Data[dataIndex]; if (value==null) continue; if (item.DataType=="HistoryData-Vol") { value=value.Vol; valueText=this.FormatValue(value,item); } else if (item.DataType=="MultiReport") { valueText=this.FormatMultiReport(value,item); } else { valueText=this.FormatValue(value,item); } } this.Canvas.fillStyle=item.Color; var text=item.Name+":"+valueText; var textWidth=this.Canvas.measureText(text).width+2; //后空2个像素 this.Canvas.fillText(text,left,bottom,textWidth); left+=textWidth; } if (this.Explain) //说明信息 { this.Canvas.fillStyle=this.TitleColor; var text="说明:"+this.Explain; var textWidth=this.Canvas.measureText(text).width+2; if (left+textWidth Value this.PointToValue=function() { if (!this.Frame) return false; var data=this.Frame.Data; if (!data) return false; for(var i in this.Point) { var item=this.Point[i]; var xValue=parseInt(this.Frame.GetXData(item.X))+data.DataOffset; var yValue=this.Frame.GetYData(item.Y); this.Value[i]={}; this.Value[i].XValue=xValue; this.Value[i].YValue=yValue; } return true; } this.IsPointIn=function(x,y) { return false; } //Value => Point this.ValueToPoint=function() { if (!this.Frame) return false; var data=this.Frame.Data; if (!data) return false; this.Point=[]; for(var i in this.Value) { var item=this.Value[i]; var pt=new Point(); pt.X=this.Frame.GetXFromIndex(item.XValue-data.DataOffset); pt.Y=this.Frame.GetYFromData(item.YValue); this.Point[i]=pt; } } //xStep,yStep 移动的偏移量 this.Move=function(xStep,yStep) { if (this.Status!=20) return fasle; if (!this.Frame) return false; var data=this.Frame.Data; if (!data) return false; if (this.MovePointIndex==null) return false; var index=parseInt(this.MovePointIndex); if (index===100) //整体移动 { for(var i in this.Point) { this.Point[i].X+=xStep; this.Point[i].Y+=yStep; } } else if (index===0 || index===1 || index===2 || index===3 || index===4 || index===5) { if (index=showCount) ++invaildX; var pt=new Point(); pt.X=this.Frame.GetXFromIndex(item.XValue-data.DataOffset,false); pt.Y=this.Frame.GetYFromData(item.YValue,false); drawPoint.push(pt); } if (option && option.IsCheckX===true) { if (invaildX==this.Value.length) return null; } } else { drawPoint=this.Point; } return drawPoint; } this.IsYValueInFrame=function(yValue) { if (!this.Frame) return false; if (yValue>this.Frame.HorizontalMax || yValue0) { var b2=bottom-ptStart.Y; var a2=a*b2/b; var pt=new Point(); pt.X=ptStart.X+a2; pt.Y=bottom; result.End=pt; var b2=ptEnd.Y-top; var a2=a*b2/b; var pt2=new Point(); pt2.Y=top; pt2.X=ptEnd.X-a2; result.Start=pt2; } else { var b2=bottom-ptStart.Y; var a2=Math.abs(a)*b2/b; var pt=new Point(); pt.X=ptStart.X-a2;; pt.Y=bottom; result.End=pt; var b2=ptEnd.Y-top; var a2=Math.abs(a)*b2/b; var pt2=new Point(); pt2.Y=top; pt2.X=ptEnd.X+a2; result.Start=pt2; } return result; } //坐标是否在点上 返回在第几个点上 this.IsPointInXYValue=function(x,y) { if (!this.Frame) return -1; var data=this.Frame.Data; if (!data) return -1; if (!this.Value) return -1; for(var i=0;i=0) return value; value=this.IsPointInLine(x,y); if (value>=0) return 100; return -1; } this.DrawLine=function(ptStart,ptEnd,isDottedline) { if (isDottedline) this.Canvas.setLineDash([5,10]); this.Canvas.strokeStyle=this.LineColor; this.Canvas.beginPath(); this.Canvas.moveTo(ptStart.X,ptStart.Y); this.Canvas.lineTo(ptEnd.X,ptEnd.Y); this.Canvas.stroke(); if (isDottedline) this.Canvas.setLineDash([]); } this.CreateLineData=function(ptStart,ptEnd) { var line={Start:new Point(), End:new Point()}; line.Start.Y=ptStart.Y; line.Start.X=ptStart.X; line.End.Y=ptEnd.Y; line.End.X=ptEnd.X; return line; } //导出成存储格式 this.ExportStorageData=function() { var storageData= { ClassName:this.ClassName, Symbol:this.Symbol, Guid:this.Guid, Period:this.Period,Value:[] , FrameID:this.Frame.Identify, LineColor:this.LineColor, AreaColor:this.AreaColor }; for(var i in this.Value) { var item=this.Value[i]; storageData.Value.push({XValue:item.XValue, YValue:item.YValue}); } if (this.Text) storageData.Text=this.Text; //如果有文本, 也导出 if (this.FontOption) storageData.FontOption=this.FontOption; //字体也导出 return storageData; } } IChartDrawPicture.ColorToRGBA=function(color,opacity) { return "rgba(" + parseInt("0x" + color.slice(1, 3)) + "," + parseInt("0x" + color.slice(3, 5)) + "," + parseInt("0x" + color.slice(5, 7)) + "," + opacity + ")"; } IChartDrawPicture.CreateChartDrawPrictrue=function(obj) //创建画图工具 { const MAP_CREATE=new Map( [ ['ChartDrawPictureLine', { Create:function() { return new ChartDrawPictureLine(); }}], ['ChartDrawPictureHaflLine', { Create:function() { return new ChartDrawPictureHaflLine(); }}], ['ChartDrawPictureHorizontalLine', { Create:function() { return new ChartDrawPictureHorizontalLine(); }}], ['ChartDrawPictureTrendLine', { Create:function() { return new ChartDrawPictureTrendLine(); }}], ['ChartDrawPictureRect', { Create:function() { return new ChartDrawPictureRect(); }}], ['ChartDrawPictureArc', { Create:function() { return new ChartDrawPictureArc(); }}], ['ChartDrawPictureWaveMW', { Create:function() { return new ChartDrawPictureWaveMW(); }}], ['ChartDrawPictureParallelLines', { Create:function() { return new ChartDrawPictureParallelLines(); }}], ['ChartDrawPictureParallelChannel', { Create:function() { return new ChartDrawPictureParallelChannel(); }}], ['ChartDrawPicturePriceChannel', { Create:function() { return new ChartDrawPicturePriceChannel(); }}], ['ChartDrawPictureText', { Create:function() { return new ChartDrawPictureText(); }}], ['ChartDrawPictureGannFan', { Create:function() { return new ChartDrawPictureGannFan(); }}], ['ChartDrawPictureResistanceLine', { Create:function() { return new ChartDrawPictureResistanceLine(); }}], ['ChartDrawPictureGoldenSection', { Create:function() { return new ChartDrawPictureGoldenSection(); }}], ['ChartDrawPicturePercentage', { Create:function() { return new ChartDrawPicturePercentage(); }}], ['ChartDrawPictureWaveBand', { Create:function() { return new ChartDrawPictureWaveBand(); }}], ['ChartDrawPictureTriangle', { Create:function() { return new ChartDrawPictureTriangle(); }}], ['ChartDrawPictureSymmetryAngle', { Create:function() { return new ChartDrawPictureSymmetryAngle(); }}], ['ChartDrawPictureCircle', { Create:function() { return new ChartDrawPictureCircle(); }}], ['ChartDrawPictureQuadrangle', { Create:function() { return new ChartDrawPictureQuadrangle(); }}], ['ChartDrawPictureFibonacci', { Create:function() { return new ChartDrawPictureFibonacci(); }}], ['ChartDrawPictureIconFont', { Create:function() { return new ChartDrawPictureIconFont(); }}] ]); if (!MAP_CREATE.has(obj.ClassName)) return null; var item=MAP_CREATE.get(obj.ClassName); var chartDraw=item.Create(); if (obj.Period>=0) chartDraw.Period=obj.Period; if (obj.Guid) chartDraw.Guid=obj.Guid; if (obj.Symbol) chartDraw.Symbol=obj.Symbol; if (obj.Value) chartDraw.Value=obj.Value; if (obj.Text) chartDraw.Text=obj.Text; if (obj.LineColor) chartDraw.LineColor=obj.LineColor; if (obj.AreaColor) chartDraw.AreaColor=obj.AreaColor; if (obj.FontOption) chartDraw.FontOption=obj.FontOption; return chartDraw; } //画图工具-线段 function ChartDrawPictureLine() { this.newMethod=IChartDrawPicture; //派生 this.newMethod(); delete this.newMethod; this.ClassName='ChartDrawPictureLine'; this.IsPointIn=this.IsPointIn_XYValue_Line; this.Draw=function() { this.LinePoint=[]; var drawPoint=this.CalculateDrawPoint( {IsCheckX:true, IsCheckY:true} ); if (!drawPoint) return; if (drawPoint.length!=2) return; this.ClipFrame(); var ptStart=drawPoint[0]; var ptEnd=drawPoint[1]; this.Canvas.strokeStyle=this.LineColor; this.Canvas.beginPath(); this.Canvas.moveTo(ptStart.X,ptStart.Y); this.Canvas.lineTo(ptEnd.X,ptEnd.Y); this.Canvas.stroke(); var line={Start:ptStart, End:ptEnd}; this.LinePoint.push(line); this.DrawPoint(drawPoint); //画点 this.Canvas.restore(); } } //画图工具-射线 function ChartDrawPictureHaflLine() { this.newMethod=IChartDrawPicture; //派生 this.newMethod(); delete this.newMethod; this.ClassName='ChartDrawPictureHaflLine'; this.IsPointIn=this.IsPointIn_XYValue_Line; this.Draw=function() { this.LinePoint=[]; var drawPoint=this.CalculateDrawPoint({IsCheckX:true, IsCheckY:true}); if (!drawPoint || drawPoint.length!=2) return; var ptStart=drawPoint[0]; var ptEnd=drawPoint[1]; this.ClipFrame(); this.Canvas.strokeStyle=this.LineColor; this.Canvas.beginPath(); this.Canvas.moveTo(drawPoint[0].X,drawPoint[0].Y); this.Canvas.lineTo(drawPoint[1].X,drawPoint[1].Y); var endPoint=this.CalculateEndPoint(drawPoint); this.Canvas.lineTo(endPoint.X,endPoint.Y); this.Canvas.stroke(); var line={Start:ptStart, End:ptEnd}; this.LinePoint.push(line); this.DrawPoint(drawPoint); //画点 this.Canvas.restore(); } this.CalculateEndPoint=function(aryPoint) { var left=this.Frame.ChartBorder.GetLeft(); var right=this.Frame.ChartBorder.GetRight(); var a=aryPoint[1].X-aryPoint[0].X; var b=aryPoint[1].Y-aryPoint[0].Y; if (a>0) { var a1=right-aryPoint[0].X; var b1=a1*b/a; var y=b1+aryPoint[0].Y; var pt=new Point(); pt.X=right; pt.Y=y; return pt; } else { var a1=aryPoint[0].X-left; var b1=a1*b/Math.abs(a); var y=b1+aryPoint[0].Y; var pt=new Point(); pt.X=left; pt.Y=y; return pt; } } } // 画图工具-水平线 function ChartDrawPictureHorizontalLine() { this.newMethod=IChartDrawPicture; //派生 this.newMethod(); delete this.newMethod; this.PointCount=1; this.ClassName='ChartDrawPictureHorizontalLine'; this.IsPointIn=this.IsPointIn_XYValue_Line; this.Font=16*GetDevicePixelRatio() +"px 微软雅黑"; this.Draw=function() { this.LinePoint=[]; var drawPoint=this.CalculateDrawPoint(); if (!drawPoint || drawPoint.length!=1) return; if (!this.Frame) return; if (this.Value.length!=1) return; if (!this.IsYValueInFrame(this.Value[0].YValue)) return null; var left=this.Frame.ChartBorder.GetLeft(); var right=this.Frame.ChartBorder.GetRight(); this.ClipFrame(); this.Canvas.strokeStyle=this.LineColor; this.Canvas.beginPath(); this.Canvas.moveTo(left,drawPoint[0].Y); this.Canvas.lineTo(right,drawPoint[0].Y); this.Canvas.stroke(); var line={Start:new Point(), End:new Point()}; line.Start.X=left; line.Start.Y=drawPoint[0].Y; line.End.X=right; line.End.Y=drawPoint[0].Y; this.LinePoint.push(line); //显示价格 var yValue=this.Frame.GetYData(drawPoint[0].Y); this.Canvas.fillStyle=this.LineColor; this.Canvas.textAlign="let"; this.Canvas.textBaseline="bottom"; this.Canvas.font=this.Font; this.Canvas.fillText(yValue.toFixed(2),left,drawPoint[0].Y); this.DrawPoint(drawPoint); this.Canvas.restore(); } } //趋势线 function ChartDrawPictureTrendLine() { this.newMethod=IChartDrawPicture; //派生 this.newMethod(); delete this.newMethod; this.ClassName='ChartDrawPictureTrendLine'; this.IsPointIn=this.IsPointIn_XYValue_Line; this.Draw=function() { this.LinePoint=[]; var drawPoint=this.CalculateDrawPoint({IsCheckX:true, IsCheckY:true}); if (!drawPoint || drawPoint.length!=2) return; var ptStart=drawPoint[0]; var ptEnd=drawPoint[1]; var extendLine=this.CalculateExtendLinePoint(ptStart,ptEnd); this.ClipFrame(); this.Canvas.strokeStyle=this.LineColor; this.Canvas.beginPath(); this.Canvas.moveTo(extendLine.Start.X,extendLine.Start.Y); this.Canvas.lineTo(extendLine.End.X,extendLine.End.Y); this.Canvas.stroke(); var line={Start:ptStart, End:ptEnd}; this.LinePoint.push(line); this.DrawPoint(drawPoint); //画点 this.Canvas.restore(); } } //画图工具-矩形 function ChartDrawPictureRect() { this.newMethod=IChartDrawPicture; //派生 this.newMethod(); delete this.newMethod; this.ClassName='ChartDrawPictureRect'; this.Draw=function() { var drawPoint=this.CalculateDrawPoint({IsCheckX:true, IsCheckY:true}); if (!drawPoint || drawPoint.length!=2) return; this.AreaColor=IChartDrawPicture.ColorToRGBA(this.LineColor,0.3); this.ClipFrame(); this.Canvas.strokeStyle=this.LineColor; this.Canvas.beginPath(); this.Canvas.rect(drawPoint[0].X,drawPoint[0].Y,drawPoint[1].X-drawPoint[0].X,drawPoint[1].Y-drawPoint[0].Y); this.Canvas.stroke(); //透明背景 this.Canvas.fillStyle=this.AreaColor; this.Canvas.beginPath(); this.Canvas.fillRect(drawPoint[0].X,drawPoint[0].Y,drawPoint[1].X-drawPoint[0].X,drawPoint[1].Y-drawPoint[0].Y); this.Canvas.restore(); //画点 this.DrawPoint(drawPoint); } //0-10 鼠标对应的点索引 100=鼠标在正个图形上 -1 鼠标不在图形上 this.IsPointIn=function(x,y) { if (!this.Frame || this.Status!=10) return -1; var data=this.Frame.Data; if (!data) return -1; //是否在点上 var aryPoint=new Array(); for(var i in this.Value) { var item=this.Value[i]; var pt=new Point(); pt.X=this.Frame.GetXFromIndex(item.XValue-data.DataOffset); pt.Y=this.Frame.GetYFromData(item.YValue); this.Canvas.beginPath(); this.Canvas.arc(pt.X,pt.Y,5,0,360); //console.log('['+i+']'+'x='+x+' y='+y+' dataX='+pt.X+" dataY="+pt.Y); if (this.Canvas.isPointInPath(x,y)) return i; aryPoint.push(pt); } //是否在矩形边框上 var linePoint=[ {X:aryPoint[0].X,Y:aryPoint[0].Y},{X:aryPoint[1].X,Y:aryPoint[0].Y}]; if (this.IsPointInLine(linePoint,x,y)) return 100; linePoint=[ {X:aryPoint[1].X,Y:aryPoint[0].Y},{X:aryPoint[1].X,Y:aryPoint[1].Y}]; if (this.IsPointInLine2(linePoint,x,y)) return 100; linePoint=[ {X:aryPoint[1].X,Y:aryPoint[1].Y},{X:aryPoint[0].X,Y:aryPoint[1].Y}]; if (this.IsPointInLine(linePoint,x,y)) return 100; linePoint=[ {X:aryPoint[0].X,Y:aryPoint[1].Y},{X:aryPoint[0].X,Y:aryPoint[0].Y}]; if (this.IsPointInLine2(linePoint,x,y)) return 100; return -1; } //点是否在线段上 水平线段 this.IsPointInLine=function(aryPoint,x,y) { this.Canvas.beginPath(); this.Canvas.moveTo(aryPoint[0].X,aryPoint[0].Y+5); this.Canvas.lineTo(aryPoint[0].X,aryPoint[0].Y-5); this.Canvas.lineTo(aryPoint[1].X,aryPoint[1].Y-5); this.Canvas.lineTo(aryPoint[1].X,aryPoint[1].Y+5); this.Canvas.closePath(); if (this.Canvas.isPointInPath(x,y)) return true; } //垂直线段 this.IsPointInLine2=function(aryPoint,x,y) { this.Canvas.beginPath(); this.Canvas.moveTo(aryPoint[0].X-5,aryPoint[0].Y); this.Canvas.lineTo(aryPoint[0].X+5,aryPoint[0].Y); this.Canvas.lineTo(aryPoint[1].X+5,aryPoint[1].Y); this.Canvas.lineTo(aryPoint[1].X-5,aryPoint[1].Y); this.Canvas.closePath(); if (this.Canvas.isPointInPath(x,y)) return true; } } //画图工具-弧形 function ChartDrawPictureArc() { this.newMethod=IChartDrawPicture; //派生 this.newMethod(); delete this.newMethod; this.ClassName='ChartDrawPictureArc'; this.Draw=function() { var drawPoint=this.CalculateDrawPoint(); if (!drawPoint || drawPoint.length!=2) return; this.ClipFrame(); //this.Canvas.beginPath(); //this.Canvas.rect(drawPoint[0].X,drawPoint[0].Y,drawPoint[1].X-drawPoint[0].X,drawPoint[1].Y-drawPoint[0].Y); if (drawPoint[0].X < drawPoint[1].X && drawPoint[0].Y > drawPoint[1].Y) // 第一象限 { var a = drawPoint[1].X - drawPoint[0].X; var b = drawPoint[0].Y - drawPoint[1].Y; var step = (a > b) ? 1/a : 1 / b; var xcenter = drawPoint[0].X; var ycenter = drawPoint[1].Y; this.Canvas.beginPath(); this.Canvas.moveTo(drawPoint[0].X, drawPoint[0].Y); for (var i = 1.5*Math.PI; i < 2*Math.PI; i+=step) { this.Canvas.lineTo(xcenter+a*Math.cos(i), ycenter+b*Math.sin(i)*-1); } for (var j = 0; j <= 0.5*Math.PI; j += step) { this.Canvas.lineTo(xcenter+a*Math.cos(j), ycenter+b*Math.sin(j)*-1); } } else if (drawPoint[0].X > drawPoint[1].X && drawPoint[0].Y > drawPoint[1].Y) // 第二象限 { var a = drawPoint[0].X - drawPoint[1].X; var b = drawPoint[0].Y - drawPoint[1].Y; var step = (a > b) ? 1/a:1/b; var xcenter = drawPoint[1].X; var ycenter = drawPoint[0].Y; this.Canvas.beginPath(); this.Canvas.moveTo(drawPoint[0].X, drawPoint[0].Y); for (var i = 0; i <= Math.PI; i += step) { this.Canvas.lineTo(xcenter + a*Math.cos(i), ycenter + b*Math.sin(i)*-1); } } else if (drawPoint[0].X > drawPoint[1].X && drawPoint[0].Y < drawPoint[1].Y) // 第三象限 { var a = drawPoint[0].X - drawPoint[1].X; var b = drawPoint[1].Y - drawPoint[0].Y; var step = (a > b) ? 1/a:1/b; var xcenter = drawPoint[0].X; var ycenter = drawPoint[1].Y; this.Canvas.beginPath(); this.Canvas.moveTo(drawPoint[0].X, drawPoint[0].Y); for (var i = 0.5*Math.PI; i <= 1.5*Math.PI; i += step) { this.Canvas.lineTo(xcenter + a*Math.cos(i), ycenter + b*Math.sin(i)*-1); } } else if (drawPoint[0].X < drawPoint[1].X && drawPoint[0].Y < drawPoint[1].Y) // 第四象限 { var a = drawPoint[1].X - drawPoint[0].X; var b = drawPoint[1].Y - drawPoint[0].Y; var step = (a > b) ? 1/a : 1/b; var xcenter = drawPoint[1].X; var ycenter = drawPoint[0].Y; this.Canvas.beginPath(); this.Canvas.moveTo(drawPoint[0].X, drawPoint[0].Y); for (var i = Math.PI; i <= 2*Math.PI; i += step) { this.Canvas.lineTo(xcenter+a*Math.cos(i), ycenter + b*Math.sin(i)*-1); } } this.Canvas.strokeStyle=this.LineColor; this.Canvas.stroke(); //this.Canvas.closePath(); this.Canvas.restore(); //画点 this.DrawPoint(drawPoint); } //0-10 鼠标对应的点索引 100=鼠标在正个图形上 -1 鼠标不在图形上 this.IsPointIn=function(x,y) { if (!this.Frame || this.Status!=10) return -1; var data=this.Frame.Data; if (!data) return -1; //是否在点上 var aryPoint=new Array(); for(var i in this.Value) { var item=this.Value[i]; var pt=new Point(); pt.X=this.Frame.GetXFromIndex(item.XValue-data.DataOffset); pt.Y=this.Frame.GetYFromData(item.YValue); this.Canvas.beginPath(); this.Canvas.arc(pt.X,pt.Y,5,0,360); //console.log('['+i+']'+'x='+x+' y='+y+' dataX='+pt.X+" dataY="+pt.Y); if (this.Canvas.isPointInPath(x,y)) return i; aryPoint.push(pt); } //是否在弧线上 var ArcPoint=[ {X:aryPoint[0].X,Y:aryPoint[0].Y},{X:aryPoint[1].X,Y:aryPoint[1].Y}]; if (this.IsPointInArc(ArcPoint, x, y)) return 100; return -1; } this.IsPointInArc=function(aryPoint,x,y) { if (aryPoint.length != 2) return false; if (aryPoint[0].X < aryPoint[1].X && aryPoint[0].Y > aryPoint[1].Y) // 第一象限 { var a = aryPoint[1].X - aryPoint[0].X; var b = aryPoint[0].Y - aryPoint[1].Y; var step = (a > b) ? 1/a : 1 / b; var ainer = a * 0.8; var biner = b * 0.8; var stepiner = (ainer > biner) ? 1/ainer : 1/biner; var xcenter = aryPoint[0].X; var ycenter = aryPoint[1].Y; this.Canvas.beginPath(); this.Canvas.moveTo(aryPoint[0].X, aryPoint[0].Y); for (var i = 1.5*Math.PI; i < 2*Math.PI; i+=step) { this.Canvas.lineTo(xcenter+a*Math.cos(i), ycenter+b*Math.sin(i)*-1); } for (var j = 0; j <= 0.5*Math.PI; j += step) { this.Canvas.lineTo(xcenter+a*Math.cos(j), ycenter+b*Math.sin(j)*-1); } for (var k = 0.5*Math.PI; k >= 0; k -= stepiner) { this.Canvas.lineTo(xcenter+ainer*Math.cos(k), ycenter + biner*Math.sin(j)*-1); } for (var l = 2*Math.PI; l >= 1.5*Math.PI; l -= stepiner) { this.Canvas.lineTo(xcenter + ainer*Math.cos(l), ycenter + biner*Math.sin(l)*-1); } this.Canvas.closePath(); } else if (aryPoint[0].X > aryPoint[1].X && aryPoint[0].Y > aryPoint[1].Y) // 第二象限 { var a = aryPoint[0].X - aryPoint[1].X; var b = aryPoint[0].Y - aryPoint[1].Y; var step = (a > b) ? 1/a:1/b; var ainer = a * 0.8; var biner = b * 0.8; var stepiner = (ainer > biner) ? 1 / ainer : 1 / biner; var xcenter = aryPoint[1].X; var ycenter = aryPoint[0].Y; this.Canvas.beginPath(); this.Canvas.moveTo(aryPoint[0].X, aryPoint[0].Y); for (var i = 0; i <= Math.PI; i += step) { this.Canvas.lineTo(xcenter + a*Math.cos(i), ycenter + b*Math.sin(i)*-1); } for (var j = Math.PI; j >= 0; j -= stepiner) { this.Canvas.lineTo(xcenter + ainer * Math.cos(j), ycenter + biner*Math.sin(j)*-1); } this.Canvas.closePath(); } else if (aryPoint[0].X > aryPoint[1].X && aryPoint[0].Y < aryPoint[1].Y) // 第三象限 { var a = aryPoint[0].X - aryPoint[1].X; var b = aryPoint[1].Y - aryPoint[0].Y; var step = (a > b) ? 1/a:1/b; var ainer = a * 0.8; var biner = b * 0.8; var stepiner = (ainer > biner) ? 1/ainer : 1/biner; var xcenter = aryPoint[0].X; var ycenter = aryPoint[1].Y; this.Canvas.beginPath(); this.Canvas.moveTo(aryPoint[0].X, aryPoint[0].Y); for (var i = 0.5*Math.PI; i <= 1.5*Math.PI; i += step) { this.Canvas.lineTo(xcenter + a*Math.cos(i), ycenter + b*Math.sin(i)*-1); } for (var j = 1.5*Math.PI; j >= 0.5*Math.PI; j -= stepiner) { this.Canvas.lineTo(xcenter + ainer * Math.cos(j), ycenter + biner*Math.sin(j)*-1); } this.Canvas.closePath(); } else if (aryPoint[0].X < aryPoint[1].X && aryPoint[0].Y < aryPoint[1].Y) // 第四象限 { var a = aryPoint[1].X - aryPoint[0].X; var b = aryPoint[1].Y - aryPoint[0].Y; var step = (a > b) ? 1/a : 1/b; var ainer = a * 0.8; var biner = b * 0.8; var stepiner = (ainer > biner) ? 1/ainer : 1/biner; var xcenter = aryPoint[1].X; var ycenter = aryPoint[0].Y; this.Canvas.beginPath(); this.Canvas.moveTo(aryPoint[0].X, aryPoint[0].Y); for (var i = Math.PI; i <= 2*Math.PI; i += step) { this.Canvas.lineTo(xcenter+a*Math.cos(i), ycenter + b*Math.sin(i)*-1); } for (var j = 2*Math.PI; j >= Math.PI; j -= stepiner) { this.Canvas.lineTo(xcenter + ainer*Math.cos(j), ycenter + biner*Math.sin(j)*-1); } this.Canvas.closePath(); } if (this.Canvas.isPointInPath(x,y)) return true; else return false; } } //M头W底 function ChartDrawPictureWaveMW() { this.newMethod=IChartDrawPicture; //派生 this.newMethod(); delete this.newMethod; this.ClassName='ChartDrawPictureWaveMW'; this.PointCount=2; this.IsPointIn=this.IsPointIn_XYValue_Line; this.Draw=function() { this.LinePoint=[]; var drawPoint=this.CalculateDrawPoint({IsCheckX:true, IsCheckY:true}); if (!drawPoint) return; //var points=drawPoint.slice(0); this.AreaColor=IChartDrawPicture.ColorToRGBA(this.LineColor,0.3); this.ClipFrame(); this.CalculateLines(drawPoint); for(var i in this.LinePoint) { var item=this.LinePoint[i]; this.DrawLine(item.Start,item.End); } this.DrawPoint(drawPoint); //画点 this.Canvas.restore(); } this.CalculateLines=function(points) { if (!this.Frame) return; if (points.length<2) return; if (this.Status==2) { var line={Start:new Point(), End:new Point()}; line.Start.Y=points[0].Y; line.Start.X=points[0].X; line.End.Y=points[1].Y; line.End.X=points[1].X; this.LinePoint.push(line); var xMove=points[1].X-points[0].X; line={Start:new Point(), End:new Point()}; line.Start.Y=points[1].Y; line.Start.X=points[1].X; line.End.Y=points[0].Y; line.End.X=points[1].X+xMove; this.LinePoint.push(line); var ptStart=line.End; var newPt=new Point(); newPt.X=ptStart.X; newPt.Y=ptStart.Y; this.Point[2]=newPt; line={Start:new Point(), End:new Point()}; line.Start.Y=ptStart.Y; line.Start.X=ptStart.X; line.End.Y=points[1].Y; line.End.X=ptStart.X+xMove; this.LinePoint.push(line); var ptStart=line.End; var newPt=new Point(); newPt.X=ptStart.X; newPt.Y=ptStart.Y; this.Point[3]=newPt; line={Start:new Point(), End:new Point()}; line.Start.Y=ptStart.Y; line.Start.X=ptStart.X; line.End.Y=points[0].Y; line.End.X=ptStart.X+xMove; this.LinePoint.push(line); var ptStart=line.End; var newPt=new Point(); newPt.X=ptStart.X; newPt.Y=ptStart.Y; this.Point[4]=newPt; this.PointCount=this.Point.length; } else if (points.length==5) { var line={Start:new Point(), End:new Point()}; line.Start.Y=points[0].Y; line.Start.X=points[0].X; line.End.Y=points[1].Y; line.End.X=points[1].X; this.LinePoint.push(line); var line={Start:new Point(), End:new Point()}; line.Start.Y=points[1].Y; line.Start.X=points[1].X; line.End.Y=points[2].Y; line.End.X=points[2].X; this.LinePoint.push(line); var line={Start:new Point(), End:new Point()}; line.Start.Y=points[2].Y; line.Start.X=points[2].X; line.End.Y=points[3].Y; line.End.X=points[3].X; this.LinePoint.push(line); var line={Start:new Point(), End:new Point()}; line.Start.Y=points[3].Y; line.Start.X=points[3].X; line.End.Y=points[4].Y; line.End.X=points[4].X; this.LinePoint.push(line); } } } //平行线 function ChartDrawPictureParallelLines() { this.newMethod=IChartDrawPicture; //派生 this.newMethod(); delete this.newMethod; this.ClassName='ChartDrawPictureParallelLines'; this.IsPointIn=this.IsPointIn_XYValue_Line; this.PointCount=3; this.LastPoint; this.Draw=function() { this.LinePoint=[]; var drawPoint=this.CalculateDrawPoint({IsCheckX:true, IsCheckY:true}); if (!drawPoint) return; this.AreaColor=IChartDrawPicture.ColorToRGBA(this.LineColor,0.3); var points=drawPoint.slice(0); this.CalculateLines(points); this.ClipFrame(); for(var i in this.LinePoint) { var item=this.LinePoint[i]; this.DrawLine(item.Start,item.End); } this.DrawArea(); this.DrawPoint(points); //画点 this.Canvas.restore(); } this.SetLastPoint=function(obj) { this.LastPoint={X:obj.X,Y:obj.Y}; } this.DrawArea=function() { if (this.LinePoint.length!=2) return; this.Canvas.fillStyle=this.AreaColor; this.Canvas.beginPath(); this.Canvas.moveTo(this.LinePoint[0].Start.X,this.LinePoint[0].Start.Y); this.Canvas.lineTo(this.LinePoint[0].End.X,this.LinePoint[0].End.Y); this.Canvas.lineTo(this.LinePoint[1].End.X,this.LinePoint[1].End.Y); this.Canvas.lineTo(this.LinePoint[1].Start.X,this.LinePoint[1].Start.Y); this.Canvas.closePath(); this.Canvas.fill(); } this.CalculateLines=function(points) { if (this.PointStatus==2 && this.LastPoint) { var pt=new Point(); pt.X=this.LastPoint.X; pt.Y=this.LastPoint.Y; points[2]=pt; } if (points.length==2) { var linePoint=this.CalculateExtendLinePoint(points[0],points[1]); this.LinePoint.push(linePoint); } else if (points.length==3) { var linePoint=this.CalculateExtendLinePoint(points[0],points[1]); this.LinePoint.push(linePoint); //计算平行线 var xMove=points[2].X-points[1].X; var yMove=points[2].Y-points[1].Y; var ptStart=new Point(); var ptEnd=new Point(); ptStart.X=points[0].X+xMove; ptStart.Y=points[0].Y+yMove; ptEnd.X=points[1].X+xMove; ptEnd.Y=points[1].Y+yMove; linePoint=this.CalculateExtendLinePoint(ptStart,ptEnd); this.LinePoint.push(linePoint); } } } //价格通道线 function ChartDrawPicturePriceChannel() { this.newMethod=ChartDrawPictureParallelLines; //派生 this.newMethod(); delete this.newMethod; this.ClassName='ChartDrawPicturePriceChannel'; this.CalculateLines=function(points) { if (this.PointStatus==2 && this.LastPoint) { var pt=new Point(); pt.X=this.LastPoint.X; pt.Y=this.LastPoint.Y; points[2]=pt; } if (points.length==2) { var linePoint=this.CalculateExtendLinePoint(points[0],points[1]); this.LinePoint.push(linePoint); } else if (points.length==3) { var linePoint=this.CalculateExtendLinePoint(points[0],points[1]); this.LinePoint.push(linePoint); //计算平行线 var xMove=points[2].X-points[1].X; var yMove=points[2].Y-points[1].Y; var ptStart=new Point(); var ptEnd=new Point(); ptStart.X=points[0].X+xMove; ptStart.Y=points[0].Y+yMove; ptEnd.X=points[1].X+xMove; ptEnd.Y=points[1].Y+yMove; linePoint=this.CalculateExtendLinePoint(ptStart,ptEnd); this.LinePoint.push(linePoint); var ptStart=new Point(); var ptEnd=new Point(); ptStart.X=points[0].X-xMove; ptStart.Y=points[0].Y-yMove; ptEnd.X=points[1].X-xMove; ptEnd.Y=points[1].Y-yMove; linePoint=this.CalculateExtendLinePoint(ptStart,ptEnd); this.LinePoint.push(linePoint); } } this.DrawArea=function() { if (this.LinePoint.length!=3) return; this.Canvas.fillStyle=this.AreaColor; this.Canvas.beginPath(); this.Canvas.moveTo(this.LinePoint[1].Start.X,this.LinePoint[1].Start.Y); this.Canvas.lineTo(this.LinePoint[1].End.X,this.LinePoint[1].End.Y); this.Canvas.lineTo(this.LinePoint[2].End.X,this.LinePoint[2].End.Y); this.Canvas.lineTo(this.LinePoint[2].Start.X,this.LinePoint[2].Start.Y); this.Canvas.closePath(); this.Canvas.fill(); } } //平行通道 function ChartDrawPictureParallelChannel() { this.newMethod=IChartDrawPicture; //派生 this.newMethod(); delete this.newMethod; this.ClassName='ChartDrawPictureParallelChannel'; this.ChannelWidth=50; this.AreaColor='rgba(25,25,25,0.4)'; this.LinePoint=[]; //计算需要画的点的坐标 this.CalculateDrawPoint=function() { if (this.Status<2) return null; if(!this.Point.length || !this.Frame) return null; var data=this.Frame.Data; if (!data) return null; var drawPoint=[]; if (this.Status==10) //完成 { for(var i=0; i<2; ++i) { var item=this.Value[i]; var pt=new Point(); pt.X=this.Frame.GetXFromIndex(item.XValue-data.DataOffset); pt.Y=this.Frame.GetYFromData(item.YValue); drawPoint.push(pt); } } else { for(var i=0; i=2) { var linePoint={Start:new Point(), End:new Point() }; linePoint.Start.X=drawPoint[0].X; linePoint.Start.Y=drawPoint[0].Y; linePoint.End.X=drawPoint[1].X; linePoint.End.Y=drawPoint[1].Y; this.LinePoint.push(linePoint); if (drawPoint.length==3 || this.Status==10) { var x=linePoint.End.X-linePoint.Start.X; var y=linePoint.End.Y-linePoint.Start.Y; var angle=Math.atan(Math.abs(x/y)); var yMove=this.ChannelWidth/Math.sin(angle); //console.log('[ChartDrawPictureParallelChannel::CalculateDrawPoint]',xMove); linePoint={Start:new Point(), End:new Point() }; linePoint.Start.X=drawPoint[0].X; linePoint.Start.Y=drawPoint[0].Y-yMove; linePoint.End.X=drawPoint[1].X; linePoint.End.Y=drawPoint[1].Y-yMove; this.LinePoint.push(linePoint); var ptCenter=new Point(); ptCenter.X=linePoint.Start.X+(linePoint.End.X-linePoint.Start.X)/2; ptCenter.Y=linePoint.Start.Y+(linePoint.End.Y-linePoint.Start.Y)/2; drawPoint[3]=ptCenter; this.Point[2]=ptCenter; var xValue=parseInt(this.Frame.GetXData(ptCenter.X))+data.DataOffset; var yValue=this.Frame.GetYData(ptCenter.Y); this.Value[2]={XValue:xValue,YValue:yValue}; this.PointCount=this.Point.length; //完成以后是3个点 } } return drawPoint; } this.DrawLine=function(ptStart,ptEnd) { this.Canvas.strokeStyle=this.LineColor; this.Canvas.beginPath(); this.Canvas.moveTo(ptStart.X,ptStart.Y); this.Canvas.lineTo(ptEnd.X,ptEnd.Y); this.Canvas.stroke(); } this.DrawArea=function(pt,pt2,pt3,pt4) { this.Canvas.fillStyle=this.AreaColor; this.Canvas.beginPath(); this.Canvas.moveTo(pt.X,pt.Y); this.Canvas.lineTo(pt2.X,pt2.Y); this.Canvas.lineTo(pt3.X,pt3.Y); this.Canvas.lineTo(pt4.X,pt4.Y); this.Canvas.closePath(); this.Canvas.fill(); } this.Draw=function() { this.LinePoint=[]; var drawPoint=this.CalculateDrawPoint(); if (!drawPoint) return; this.AreaColor=IChartDrawPicture.ColorToRGBA(this.LineColor,0.3); this.ClipFrame(); for(var i in this.LinePoint) { var item=this.LinePoint[i]; this.DrawLine(item.Start,item.End); } if (this.LinePoint.length==2) { this.DrawArea(this.LinePoint[0].Start,this.LinePoint[0].End,this.LinePoint[1].End,this.LinePoint[1].Start); } this.Canvas.restore(); this.DrawPoint(drawPoint); //画点 } //xStep,yStep 移动的偏移量 this.Move=function(xStep,yStep) { if (this.Status!=20) return fasle; if (!this.Frame) return false; var data=this.Frame.Data; if (!data) return false; if (this.MovePointIndex==100) //整体移动 { for(var i in this.Point) { this.Point[i].X+=xStep; this.Point[i].Y+=yStep; } } else if (this.MovePointIndex==0 || this.MovePointIndex==1) { if (this.MovePointIndex=this.Point.length) continue; pt.X=this.Point[i].X; pt.Y=this.Point[i].Y; } this.Canvas.beginPath(); this.Canvas.arc(pt.X,pt.Y,5,0,360); if (this.Canvas.isPointInPath(x,y)) return i; } //是否在线段上 for(var i in this.LinePoint) { var item=this.LinePoint[i]; var ptStart=item.Start; var ptEnd=item.End; this.Canvas.beginPath(); this.Canvas.moveTo(ptStart.X,ptStart.Y+5); this.Canvas.lineTo(ptStart.X,ptStart.Y-5); this.Canvas.lineTo(ptEnd.X,ptEnd.Y-5); this.Canvas.lineTo(ptEnd.X,ptEnd.Y+5); this.Canvas.closePath(); if (this.Canvas.isPointInPath(x,y)) return 100; } return -1; } } //文本 function ChartDrawPictureText() { this.newMethod=IChartDrawPicture; //派生 this.newMethod(); delete this.newMethod; this.ClassName='ChartDrawPictureText'; this.Text='文本'; this.PointCount=1; this.FontOption={ Family:'微软雅黑', Size:20, Weight:null, Style:null }; //Weight(bold 粗体), Style(italic) //矢量图片 //this.Text="\ue606"; //this.FontOption={ Family:'iconfont', Size:20, Weight:null, Style:null }; //Weight(bold 粗体), Style(italic) this.TextRect=null; //文字区域 this.IsInitialized=false; //是否初始化了 this.SettingMenu; this.HQChart; this.Draw=function(textFont) { this.TextRect=null; var drawPoint=this.CalculateDrawPoint({IsCheckX:true, IsCheckY:true}); if (!drawPoint || drawPoint.length!=1) return; this.ClipFrame(); this.Canvas.fillStyle=this.LineColor; this.Canvas.textAlign="center"; this.Canvas.textBaseline="bottom"; this.Canvas.font=this.GetTextFont(); this.Canvas.fillText(this.Text,drawPoint[0].X,drawPoint[0].Y); var textWidth=this.Canvas.measureText(this.Text).width; this.TextRect={}; this.TextRect.Left=drawPoint[0].X-textWidth/2; this.TextRect.Top=drawPoint[0].Y-this.FontOption.Size; this.TextRect.Width=textWidth; this.TextRect.Height=this.FontOption.Size; //this.Canvas.strokeRect(this.TextRect.Left,this.TextRect.Top,this.TextRect.Width,this.TextRect.Height); this.Canvas.restore(); if (this.IsInitialized===false) { this.SetTextOption(); this.IsInitialized=true; } } //根据设置动态生成字体 this.GetTextFont=function() { const defaultFont=16*GetDevicePixelRatio() +"px 微软雅黑"; if (!this.FontOption || !this.FontOption.Family || this.FontOption.Size<=0) return defaultFont; var font=''; if (this.FontOption.Color) font+=this.FontOption.Color+' '; if (this.FontOption.Style) font+=this.FontOption.Style+' '; if (this.FontOption.Weight) font+=this.FontOption.Weight+' '; if (this.FontOption.Size>=0) font+=this.FontOption.Size*GetDevicePixelRatio()+'px '; font+=this.FontOption.Family; return font; } this.SetTextOption=function() { console.log('[ChartDrawPictureText::SetTextOption]'); //创建div设置窗口 if (!this.SettingMenu) this.SettingMenu=new ChartPictureTextSettingMenu(this.Frame.ChartBorder.UIElement.parentNode); this.SettingMenu.ChartPicture=this; this.SettingMenu.HQChart=this.HQChart; this.SettingMenu.Position={Left:this.TextRect.Left+this.TextRect.Width,Top:this.TextRect.Top}; this.SettingMenu.DoModal(); } this.IsPointIn=function(x,y) { if (!this.Frame || this.Status!=10) return -1; var data=this.Frame.Data; if (!data) return -1; if (!this.TextRect) return -1; this.Canvas.beginPath(); this.Canvas.rect(this.TextRect.Left,this.TextRect.Top,this.TextRect.Width,this.TextRect.Height); if (this.Canvas.isPointInPath(x,y)) return 100; return -1; } } //iconfont 图片 function ChartDrawPictureIconFont() { this.newMethod=IChartDrawPicture; //派生 this.newMethod(); delete this.newMethod; this.ClassName='ChartDrawPictureIconFont'; this.PointCount=1; //矢量图片 this.Text="\ue606"; this.FontOption={ Family:'iconfont', Size:24}; //Weight(bold 粗体), Style(italic) this.TextRect=null; //文字区域 this.SettingMenu; this.Draw=function() { this.TextRect=null; var drawPoint=this.CalculateDrawPoint({IsCheckX:true, IsCheckY:true}); if (!drawPoint || drawPoint.length!=1) return; var font=this.GetTextFont(); if (!font) return; this.ClipFrame(); this.Canvas.fillStyle=this.LineColor; this.Canvas.textAlign="center"; this.Canvas.textBaseline="bottom"; this.Canvas.font=font; this.Canvas.fillText(this.Text,drawPoint[0].X,drawPoint[0].Y); var textWidth=this.Canvas.measureText(this.Text).width; this.TextRect={}; this.TextRect.Left=drawPoint[0].X-textWidth/2; this.TextRect.Top=drawPoint[0].Y-this.FontOption.Size; this.TextRect.Width=textWidth; this.TextRect.Height=this.FontOption.Size; //this.Canvas.strokeRect(this.TextRect.Left,this.TextRect.Top,this.TextRect.Width,this.TextRect.Height); this.Canvas.restore(); } //根据设置动态生成字体 this.GetTextFont=function() { if (!this.FontOption || !this.FontOption.Family || this.FontOption.Size<=0) return null; var font=''; if (this.FontOption.Size>=0) font+=this.FontOption.Size*GetDevicePixelRatio()+'px '; font+=this.FontOption.Family; return font; } this.IsPointIn=function(x,y) { if (!this.Frame || this.Status!=10) return -1; var data=this.Frame.Data; if (!data) return -1; if (!this.TextRect) return -1; this.Canvas.beginPath(); this.Canvas.rect(this.TextRect.Left,this.TextRect.Top,this.TextRect.Width,this.TextRect.Height); if (this.Canvas.isPointInPath(x,y)) return 100; return -1; } } //江恩角度线(Gann Fan),亦又称作甘氏线的 function ChartDrawPictureGannFan() { this.newMethod=IChartDrawPicture; //派生 this.newMethod(); delete this.newMethod; this.ClassName='ChartDrawPictureGannFan'; this.IsPointIn=this.IsPointIn_XYValue_Line; this.LinePoint=[]; this.Font=16*GetDevicePixelRatio() +"px 微软雅黑"; this.Draw=function() { this.LinePoint=[]; var drawPoint=this.CalculateDrawPoint({IsCheckX:true, IsCheckY:true}); if (!drawPoint) return; if (drawPoint.length!=2) return; this.AreaColor=IChartDrawPicture.ColorToRGBA(this.LineColor,0.3); this.ClipFrame(); var quadrant=this.GetQuadrant(drawPoint[0],drawPoint[1]); if (quadrant===1 || quadrant===4) { this.CalculateLines(drawPoint[0],drawPoint[1],quadrant); this.DrawArea(); for(var i in this.LinePoint) { var item=this.LinePoint[i]; this.DrawLine(item.Start,item.End,item.IsDottedLine); } for(var i in this.LinePoint) { var item =this.LinePoint[i]; if (item.Text && item.PtEnd) this.DrawTitle(item.PtEnd,item.Text); } } else { this.DrawLine(drawPoint[0],drawPoint[1],false); } this.Canvas.restore(); this.DrawPoint(drawPoint); //画点 } //获取在第几象限 this.GetQuadrant=function(ptStart,ptEnd) { if (ptStart.XptEnd.Y) return 1; else if (ptStart.XptEnd.Y) return 2; else if (ptStart.X < ptEnd.X && ptStart.Y< ptEnd.Y) return 4; else return 3; } //isDotline 是否是虚线 this.DrawLine=function(ptStart,ptEnd,isDottedline) { if (isDottedline) this.Canvas.setLineDash([5,10]); this.Canvas.strokeStyle=this.LineColor; this.Canvas.beginPath(); this.Canvas.moveTo(ptStart.X,ptStart.Y); this.Canvas.lineTo(ptEnd.X,ptEnd.Y); this.Canvas.stroke(); if (isDottedline) this.Canvas.setLineDash([]); } this.DrawTitle=function(pt,text) { this.Canvas.fillStyle=this.LineColor; this.Canvas.textAlign="left"; this.Canvas.textBaseline="bottom"; this.Canvas.font=this.Font; this.Canvas.fillText(text,pt.X,pt.Y); } this.DrawArea=function() { var lineStart=null,lineEnd=null; for(var i in this.LinePoint) { var item=this.LinePoint[i]; if (item.Text=='1:8') lineStart=this.LinePoint[i]; else if (item.Text=='8:1') lineEnd=this.LinePoint[i]; } if (!lineStart || !lineEnd) return; this.Canvas.fillStyle=this.AreaColor; this.Canvas.beginPath(); this.Canvas.moveTo(lineStart.End.X,lineStart.End.Y); this.Canvas.lineTo(lineStart.Start.X,lineStart.Start.Y); this.Canvas.lineTo(lineEnd.End.X,lineEnd.End.Y); this.Canvas.closePath(); this.Canvas.fill(); } //计算线段 this.CalculateLines=function(ptStart,ptEnd,quadrant) { if (!this.Frame) return false; var top=this.Frame.ChartBorder.GetTopEx(); var right=this.Frame.ChartBorder.GetRight(); var bottom=this.Frame.ChartBorder.GetBottom(); const SPLIT_LINE_VALUE=[0.5, 1.0/3, 0.25, 0.125, 2.0/3]; const SPLIT_LINE_X_TITLE=["1:2","1:3","1:4","1:8","2:3"]; const SPLIT_LINE_Y_TITLE=["2:1","3:1","4:1","8:1","3:2"]; var ptLineStart=new Point(); var ptLineEnd=new Point(); ptLineStart.X=ptStart.X; ptLineStart.Y=ptStart.Y; ptLineEnd.X=ptEnd.X; ptLineEnd.Y=ptEnd.Y; var lineWidth=Math.abs(ptStart.X-ptEnd.X); var lineHeight=Math.abs(ptStart.Y-ptEnd.Y); if (quadrant===1) { /* var line={Start:ptLineStart, End:new Point(), IsDottedLine:false}; line.End.X=ptStart.X; line.End.Y=top; this.LinePoint.push(line); line={Start:ptLineStart, End:new Point(), IsDottedLine:false}; line.End.X=right; line.End.Y=ptStart.Y; this.LinePoint.push(line); */ var extendLine=this.CalculateExtendLinePoint(ptStart,ptEnd); var line={Start:ptLineStart, End:extendLine.Start, IsDottedLine:false,PtEnd:ptLineEnd, Text:'1:1'}; this.LinePoint.push(line); for(var i in SPLIT_LINE_VALUE) { if (lineWidth>5) { line={Start:ptLineStart, End:null, IsDottedLine:false,PtEnd:new Point(),Text:SPLIT_LINE_X_TITLE[i]}; line.PtEnd.Y=ptEnd.Y; line.PtEnd.X=ptStart.X+lineWidth*SPLIT_LINE_VALUE[i]; var extendLine=this.CalculateExtendLinePoint(line.Start,line.PtEnd); line.End=extendLine.Start; this.LinePoint.push(line); } if (lineHeight>5) { line={Start:ptLineStart, End:null, IsDottedLine:false,PtEnd:new Point(), Text:SPLIT_LINE_Y_TITLE[i]}; line.PtEnd.Y=ptStart.Y-lineHeight*SPLIT_LINE_VALUE[i]; line.PtEnd.X=ptEnd.X; var extendLine=this.CalculateExtendLinePoint(line.Start,line.PtEnd); line.End=extendLine.Start; this.LinePoint.push(line); } } } else if (quadrant==4) { /* var line={Start:ptLineStart, End:new Point(), IsDottedLine:false}; line.End.X=ptStart.X; line.End.Y=bottom; this.LinePoint.push(line); line={Start:ptLineStart, End:new Point(), IsDottedLine:false}; line.End.X=right; line.End.Y=ptStart.Y; this.LinePoint.push(line); */ var extendLine=this.CalculateExtendLinePoint(ptStart,ptEnd); var line={Start:ptLineStart, End:extendLine.End, IsDottedLine:false,PtEnd:ptLineEnd, Text:'1:1'}; this.LinePoint.push(line); for(var i in SPLIT_LINE_VALUE) { if (lineWidth>5) { line={Start:ptLineStart, End:null, IsDottedLine:false,PtEnd:new Point(),Text:SPLIT_LINE_X_TITLE[i]}; line.PtEnd.Y=ptEnd.Y; line.PtEnd.X=ptStart.X+lineWidth*SPLIT_LINE_VALUE[i]; var extendLine=this.CalculateExtendLinePoint(line.Start,line.PtEnd); line.End=extendLine.End; this.LinePoint.push(line); } if (lineHeight>5) { line={Start:ptLineStart, End:null, IsDottedLine:false,PtEnd:new Point(), Text:SPLIT_LINE_Y_TITLE[i]}; line.PtEnd.Y=ptStart.Y+lineHeight*SPLIT_LINE_VALUE[i]; line.PtEnd.X=ptEnd.X; var extendLine=this.CalculateExtendLinePoint(line.Start,line.PtEnd); line.End=extendLine.End; this.LinePoint.push(line); } } } else return false; return true; } } //阻速线 (高 3等份) function ChartDrawPictureResistanceLine() { this.newMethod=ChartDrawPictureGannFan; //派生 this.newMethod(); delete this.newMethod; this.ClassName='ChartDrawPictureResistanceLine'; //计算线段 this.CalculateLines=function(ptStart,ptEnd,quadrant) { if (!this.Frame) return false; var top=this.Frame.ChartBorder.GetTopEx(); var right=this.Frame.ChartBorder.GetRight(); var bottom=this.Frame.ChartBorder.GetBottom(); const SPLIT_LINE_VALUE=[1.0/3, 2.0/3]; const SPLIT_LINE_Y_TITLE=["3:1","3:2"]; var ptLineStart=new Point(); var ptLineEnd=new Point(); ptLineStart.X=ptStart.X; ptLineStart.Y=ptStart.Y; ptLineEnd.X=ptEnd.X; ptLineEnd.Y=ptEnd.Y; var lineWidth=Math.abs(ptStart.X-ptEnd.X); var lineHeight=Math.abs(ptStart.Y-ptEnd.Y); if (quadrant===1) { var extendLine=this.CalculateExtendLinePoint(ptStart,ptEnd); var line={Start:ptLineStart, End:extendLine.Start, IsDottedLine:false,PtEnd:ptLineEnd, Text:'1:1'}; this.LinePoint.push(line); for(var i in SPLIT_LINE_VALUE) { if (lineHeight>5) { line={Start:ptLineStart, End:null, IsDottedLine:false,PtEnd:new Point(), Text:SPLIT_LINE_Y_TITLE[i]}; line.PtEnd.Y=ptStart.Y-lineHeight*SPLIT_LINE_VALUE[i]; line.PtEnd.X=ptEnd.X; var extendLine=this.CalculateExtendLinePoint(line.Start,line.PtEnd); line.End=extendLine.Start; this.LinePoint.push(line); } } } else if (quadrant==4) { var extendLine=this.CalculateExtendLinePoint(ptStart,ptEnd); var line={Start:ptLineStart, End:extendLine.End, IsDottedLine:false,PtEnd:ptLineEnd, Text:'1:1'}; this.LinePoint.push(line); for(var i in SPLIT_LINE_VALUE) { if (lineHeight>5) { line={Start:ptLineStart, End:null, IsDottedLine:false,PtEnd:new Point(), Text:SPLIT_LINE_Y_TITLE[i]}; line.PtEnd.Y=ptStart.Y+lineHeight*SPLIT_LINE_VALUE[i]; line.PtEnd.X=ptEnd.X; var extendLine=this.CalculateExtendLinePoint(line.Start,line.PtEnd); line.End=extendLine.End; this.LinePoint.push(line); } } } else return false; return true; } this.DrawArea=function() { var lineStart=null,lineEnd=null; for(var i in this.LinePoint) { var item=this.LinePoint[i]; if (item.Text=='1:1') lineStart=this.LinePoint[i]; else if (item.Text=='3:1') lineEnd=this.LinePoint[i]; } if (!lineStart || !lineEnd) return; this.Canvas.fillStyle=this.AreaColor; this.Canvas.beginPath(); this.Canvas.moveTo(lineStart.End.X,lineStart.End.Y); this.Canvas.lineTo(lineStart.Start.X,lineStart.Start.Y); this.Canvas.lineTo(lineEnd.End.X,lineEnd.End.Y); this.Canvas.closePath(); this.Canvas.fill(); } } //黄金分割线 function ChartDrawPictureGoldenSection() { this.newMethod=IChartDrawPicture; //派生 this.newMethod(); delete this.newMethod; this.ClassName='ChartDrawPictureGoldenSectionLine'; this.IsPointIn=this.IsPointIn_XYValue_Line; this.Font=14*GetDevicePixelRatio() +"px 微软雅黑"; this.GetSectionData=function() { const GOLDEN_SECTION_DATA= [0,0.236,0.382,0.5,0.618,0.80,1,1.236,1.382,1.5,1.618,1.8,2]; return GOLDEN_SECTION_DATA; } this.Draw=function() { this.LinePoint=[]; var drawPoint=this.CalculateDrawPoint(); if (!drawPoint) return; if (drawPoint.length!=2) return; this.AreaColor=IChartDrawPicture.ColorToRGBA(this.LineColor,0.3); this.CalculateLines(drawPoint[0],drawPoint[1]); this.ClipFrame(); for(var i in this.LinePoint) { var item=this.LinePoint[i]; this.DrawLine(item.Start,item.End,item.IsDottedLine); } for(var i in this.LinePoint) { var item =this.LinePoint[i]; if (item.Text) this.DrawTitle(item.Start,item.Text); } this.DrawPoint(drawPoint); //画点 this.Canvas.restore(); } this.CalculateLines=function(ptStart,ptEnd) { var sectionData=this.GetSectionData(); var left=this.Frame.ChartBorder.GetLeft(); var right=this.Frame.ChartBorder.GetRight(); var lineHeight=ptStart.Y-ptEnd.Y; for(var i=0;i=0) return value; if (this.CircleData && this.CircleData.R>8) { var triangleX=this.CircleData.X-x; var triangleY=this.CircleData.Y-y; var r=Math.sqrt(triangleX*triangleX+triangleY*triangleY); //计算直径 if (rthis.CircleData.R-8) return 100; } return -1; } } //四边形 function ChartDrawPictureQuadrangle() { this.newMethod=IChartDrawPicture; //派生 this.newMethod(); delete this.newMethod; this.ClassName='ChartDrawPictureQuadrangle'; this.IsPointIn=this.IsPointIn_XYValue_Line; this.PointCount=3; this.LastPoint; this.Draw=function() { this.LinePoint=[]; var drawPoint=this.CalculateDrawPoint({IsCheckX:true, IsCheckY:true}); if (!drawPoint) return; this.AreaColor=IChartDrawPicture.ColorToRGBA(this.LineColor,0.3); var points=drawPoint.slice(0); this.CalculateLines(points); this.ClipFrame(); for(var i in this.LinePoint) { var item=this.LinePoint[i]; this.DrawLine(item.Start,item.End); } this.DrawArea(); this.DrawPoint(points); //画点 this.Canvas.restore(); } this.SetLastPoint=function(obj) { this.LastPoint={X:obj.X,Y:obj.Y}; } this.DrawArea=function() { if (this.LinePoint.length!=4) return; this.Canvas.fillStyle=this.AreaColor; this.Canvas.beginPath(); this.Canvas.moveTo(this.LinePoint[0].Start.X,this.LinePoint[0].Start.Y); this.Canvas.lineTo(this.LinePoint[0].End.X,this.LinePoint[0].End.Y); this.Canvas.lineTo(this.LinePoint[1].End.X,this.LinePoint[1].End.Y); this.Canvas.lineTo(this.LinePoint[2].End.X,this.LinePoint[2].End.Y); this.Canvas.closePath(); this.Canvas.fill(); } this.CalculateLines=function(points) { if (this.PointStatus==2 && this.LastPoint) { var pt=new Point(); pt.X=this.LastPoint.X; pt.Y=this.LastPoint.Y; points[2]=pt; } if (points.length==2) { var linePoint=this.CreateLineData(points[0],points[1]); this.LinePoint.push(linePoint); } else if (points.length==3) { var linePoint=this.CreateLineData(points[0],points[1]); this.LinePoint.push(linePoint); var linePoint=this.CreateLineData(points[1],points[2]); this.LinePoint.push(linePoint); //计算平行线 var xMove=points[2].X-points[1].X; var yMove=points[2].Y-points[1].Y; var pt4=new Point(); //第4个点的坐标 pt4.X=points[0].X+xMove; pt4.Y=points[0].Y+yMove; var linePoint=this.CreateLineData(points[2],pt4); this.LinePoint.push(linePoint); var linePoint=this.CreateLineData(pt4,points[0]); this.LinePoint.push(linePoint); } } } //斐波那契周期线 function ChartDrawPictureFibonacci() { this.newMethod=IChartDrawPicture; //派生 this.newMethod(); delete this.newMethod; this.ClassName='ChartDrawPictureFibonacci'; this.PointCount=1; this.Font=14*GetDevicePixelRatio() +"px 微软雅黑"; this.IsPointIn=this.IsPointIn_XYValue_Line; this.Draw=function() { this.LinePoint=[]; var drawPoint=this.CalculateDrawPoint(); if (!drawPoint) return; this.CalculateLines(); if (this.LinePoint.length<=0) return; this.ClipFrame(); for(var i in this.LinePoint) { var item=this.LinePoint[i]; this.DrawLine(item.Start,item.End); this.DrawTitle(item.Start,item.Title); } this.DrawPoint(drawPoint); //画点 this.Canvas.restore(); } this.DrawTitle=function(pt,text) { this.Canvas.fillStyle=this.LineColor; this.Canvas.textAlign="left"; this.Canvas.textBaseline="top"; this.Canvas.font=this.Font; this.Canvas.fillText(text,pt.X+2,pt.Y+10); } this.CalculateLines=function() { if (this.Status<2) return; if (!this.Frame) return; var data=this.Frame.Data; if (!data) return; var xStart=null; if (this.Status==10) { if (this.Value.length!=1) return; xStart=this.Value[0].XValue; } else { if (this.Point.length!=1) return; xStart=parseInt(this.Frame.GetXData(this.Point[0].X))+data.DataOffset; } var top=this.Frame.ChartBorder.GetTopEx(); var bottom=this.Frame.ChartBorder.GetBottom(); var showCount=this.Frame.XPointCount; const LINE_DATA=[1,2,3,5,8,13,21,34,55,89,144,233]; for(var i=0;i=showCount) continue; var x=this.Frame.GetXFromIndex(xValue-data.DataOffset,false); var line={Start:new Point(), End:new Point(), Title:LINE_DATA[i]}; line.Start.Y=top; line.Start.X=x; line.End.Y=bottom; line.End.X=x; this.LinePoint.push(line); } } } function ChartDrawStorage() { this.DrawData=new Map(); //画图工具数据 key=symbol-Period, value=Map() Key:Guid, Value:{Guid, Symbol, Period, ClassName, Value} this.StorageKey; this.Load=function(key) //从本地读取画图工具 { if (!key) return; this.StorageKey=key; var cacheValue = localStorage[this.StorageKey]; console.log(`[ChartDrawStorage::Save] Load to localStorage, key=${this.StorageKey}, cache=${cacheValue}`); if (!cacheValue) return; if (typeof(cacheValue) != "string") return; var saveData=JSON.parse(cacheValue); for(var i in saveData) { var item=saveData[i]; var drawMap=new Map(); for(var j in item.Value) { var drawItem=item.Value[j]; drawMap.set(drawItem.Key, drawItem.Value); } this.DrawData.set(item.Key,drawMap); } } this.Save=function() //把数据保存到本地 { if (!this.StorageKey) return; var saveData=[]; for(var stock of this.DrawData) { var key=stock[0]; var value=stock[1]; var itemData={ Key:key, Value:[]}; for(var drawItem of value) { itemData.Value.push({Key:drawItem[0], Value:drawItem[1]}); } saveData.push(itemData) } console.log(`[ChartDrawStorage::Save] save to localStorage, key=${this.StorageKey}`); var strData=JSON.stringify(saveData); localStorage[this.StorageKey]=strData; } this.SaveDrawData=function(drawPicture) //保存一个画图工具 { var strKey=drawPicture.Symbol+'-'+drawPicture.Period; var data=drawPicture.ExportStorageData(); if (!data) return; if (this.DrawData.has(strKey)) //更新 { console.log('[ChartDrawStorage::SaveDrawData] Upate: key, drawPicture, data', strKey, drawPicture,data); this.DrawData.get(strKey).set(data.Guid, data); } else //新增 { console.log('[ChartDrawStorage::SaveDrawData] Insert: key, drawPicture, data', strKey, drawPicture,data); var newData=new Map(); newData.set(data.Guid, data); this.DrawData.set(strKey,newData); } console.log('[ChartDrawStorage::SaveDrawData] All draw data: ', this.DrawData); this.Save(); } this.DeleteDrawData=function(drawPicture) //删除一个画图工具 { var strKey=drawPicture.Symbol+'-'+drawPicture.Period; if (!this.DrawData.has(strKey)) return; this.DrawData.delete(strKey); this.Save(); } this.Clear=function() { this.DrawData=new Map(); this.Save(); } this.GetDrawData=function(obj) //获取已有的画图工具数据{Symbol: , Period:, } { var data=[]; var strKey=obj.Symbol+'-'+obj.Period; if (!this.DrawData.has(strKey)) return data; var stockData=this.DrawData.get(strKey); for(var item of stockData) { data.push(item[1]); } return data; } } ///////////////////////////////////////////////////////////////////////////////////////////////////////// // 数据分割 // [0]=Start起始 [1]=End结束 [2]=FixInterval修正的间隔 [3]=Increase // function SplitData() { this.Data=[ [0.000001, 0.000002, 0.000001, 0.0000001], [0.000002, 0.000004, 0.000002, 0.0000002], [0.000004, 0.000005, 0.000004, 0.0000001], [0.000005, 0.00001, 0.000005, 0.0000005], [0.00001, 0.00002, 0.00001, 0.000001], [0.00002, 0.00004, 0.00002, 0.000002], [0.00004, 0.00005, 0.00004, 0.000001], [0.00005, 0.0001, 0.00005, 0.000005], [0.0001, 0.0002, 0.0001, 0.00001], [0.0002, 0.0004, 0.0002, 0.00002], [0.0004, 0.0005, 0.0004, 0.00001], [0.0005, 0.001, 0.0005, 0.00005], [0.001, 0.002, 0.001, 0.0001], [0.002, 0.004, 0.002, 0.0002], [0.004, 0.005, 0.004, 0.0001], [0.005, 0.01, 0.005, 0.0005], [0.01, 0.02, 0.01, 0.001], [0.02, 0.04, 0.02, 0.002], [0.04, 0.05, 0.04, 0.001], [0.05, 0.1, 0.05, 0.005], [0.1, 0.2, 0.1, 0.01], [0.2, 0.4, 0.2, 0.02], [0.4, 0.5, 0.4, 0.01], [0.5, 1, 0.5, 0.05], [1, 2, 0.5, 0.05], [2, 4, 0.5, 0.05], [4, 5, 0.5, 0.05], [5, 10, 0.5, 0.05], [10, 12, 10, 2], [20, 40, 20, 5], [40, 50, 40, 2], [50, 100, 50, 10], [100, 200, 100, 10], [200, 400, 200, 20], [400, 500, 400, 10], [500, 1000, 500, 50], [1000, 2000, 1000, 50], [2000, 4000, 2000, 50], [4000, 5000, 4000, 50], [5000, 10000, 5000, 100], [10000, 20000, 10000, 1000], [20000, 40000, 10000, 1000], [40000, 50000, 10000, 1000], [50000, 100000, 10000, 1000], [100000, 200000, 100000, 10000], [200000, 400000, 100000, 10000], [400000, 500000, 100000, 10000], [500000, 1000000, 100000, 10000], [1000000, 2000000, 1000000, 100000], [2000000, 4000000, 1000000, 100000], [4000000, 5000000, 1000000, 100000], [5000000, 10000000, 1000000, 100000], [10000000, 20000000, 10000000, 1000000], [20000000, 40000000, 10000000, 1000000], [40000000, 50000000, 10000000, 1000000], [50000000, 100000000, 10000000, 1000000], [100000000, 200000000, 100000000, 10000000], [200000000, 400000000, 100000000, 10000000], [400000000, 500000000, 100000000, 10000000], [500000000, 1000000000, 100000000, 10000000], [1000000000, 2000000000, 1000000000, 100000000], [2000000000, 4000000000, 1000000000, 100000000], [4000000000, 5000000000, 1000000000, 100000000], [5000000000, 10000000000, 1000000000, 100000000] ]; this.Find=function(interval) { for(var i in this.Data) { var item =this.Data[i]; if (interval>item[0] && interval<=item[1]) { var result={}; result.FixInterval=item[2]; result.Increase=item[3]; return result; } } return null; } } function PriceSplitData() { this.newMethod=SplitData; //派生 this.newMethod(); delete this.newMethod; this.Data=[ [0.000001, 0.000002, 0.000001, 0.0000001], [0.000002, 0.000004, 0.000002, 0.0000002], [0.000004, 0.000005, 0.000004, 0.0000001], [0.000005, 0.00001, 0.000005, 0.0000005], [0.00001, 0.00002, 0.00001, 0.000001], [0.00002, 0.00004, 0.00002, 0.000002], [0.00004, 0.00005, 0.00004, 0.000001], [0.00005, 0.0001, 0.00005, 0.000005], [0.0001, 0.0002, 0.0001, 0.00001], [0.0002, 0.0004, 0.0002, 0.00002], [0.0004, 0.0005, 0.0004, 0.00001], [0.0005, 0.001, 0.0005, 0.00005], [0.001, 0.002, 0.001, 0.0001], [0.002, 0.004, 0.002, 0.0001], [0.004, 0.005, 0.004, 0.0001], [0.005, 0.01, 0.005, 0.0005], [0.01, 0.02, 0.01, 0.001], [0.02, 0.04, 0.02, 0.001], [0.04, 0.05, 0.04, 0.001], [0.05, 0.1, 0.05, 0.001], [0.1, 0.2, 0.1, 0.01], [0.2, 0.4, 0.2, 0.01], [0.4, 0.5, 0.2, 0.01], [0.5, 0.8, 0.2, 0.01], [0.8, 1, 0.5, 0.01], [1, 2, 0.5, 0.05], [2, 4, 0.5, 0.05], [4, 5, 0.5, 0.05], [5, 10, 0.5, 0.05], [10, 12, 10, 2], [20, 40, 20, 5], [40, 50, 40, 2], [50, 100, 50, 10], [100, 200, 100, 10], [200, 400, 200, 20], [400, 500, 400, 10], [500, 1000, 500, 50], [1000, 2000, 1000, 50], [2000, 4000, 2000, 50], [4000, 5000, 4000, 50], [5000, 10000, 5000, 100], [10000, 20000, 10000, 1000], [20000, 40000, 20000, 2000], [40000, 50000, 40000, 1000], [50000, 100000, 50000, 5000], [100000, 200000, 100000, 10000], [200000, 400000, 200000, 20000], [400000, 500000, 400000, 10000], [500000, 1000000, 500000, 50000], [1000000, 2000000, 1000000, 100000], [2000000, 4000000, 2000000, 200000], [4000000, 5000000, 4000000, 100000], [5000000, 10000000, 5000000, 500000], [10000000, 20000000, 10000000, 1000000], [20000000, 40000000, 20000000, 2000000], [40000000, 50000000, 40000000, 1000000], [50000000, 100000000, 50000000, 5000000], [100000000, 200000000, 100000000, 10000000], [200000000, 400000000, 200000000, 20000000], [400000000, 500000000, 400000000, 10000000], [500000000, 1000000000, 500000000, 50000000], [1000000000, 2000000000, 1000000000, 100000000], [2000000000, 4000000000, 2000000000, 200000000], [4000000000, 5000000000, 4000000000, 100000000], [5000000000, 10000000000, 5000000000, 500000000] ]; } ///////////////////////////////////////////////////////////////////////////// // 全局配置颜色 // // function JSChartResource() { this.TooltipBGColor="rgb(255, 255, 255)"; //背景色 this.TooltipAlpha=0.92; //透明度 this.SelectRectBGColor="rgba(1,130,212,0.06)"; //背景色 // this.SelectRectAlpha=0.06; //透明度 this.UpBarColor="rgb(238,21,21)"; this.DownBarColor="rgb(25,158,0)"; this.UnchagneBarColor="rgb(0,0,0)"; this.Minute={}; this.Minute.VolBarColor="rgb(238,127,9)"; this.Minute.PriceColor="rgb(50,171,205)"; this.Minute.AreaPriceColor='rgba(50,171,205,0.1)'; //价格的面积图 this.Minute.AvPriceColor="rgb(238,127,9)"; this.Minute.BeforeBGColor='rgba(240,240,240,0.7)'; //分钟 集合竞价背景 this.DefaultTextColor="rgb(43,54,69)"; this.DefaultTextFont=14*GetDevicePixelRatio() +'px 微软雅黑'; this.TitleFont=13*GetDevicePixelRatio() +'px 微软雅黑'; this.UpTextColor="rgb(238,21,21)"; this.DownTextColor="rgb(25,158,0)"; this.UnchagneTextColor="rgb(0,0,0)"; this.CloseLineColor='rgb(0,191,255)'; this.CloseLineAreaColor=['rgba(0,191,255,0.8)','rgba(0,191,255,0.2)']; this.FrameBorderPen="rgb(225,236,242)"; this.FrameSplitPen="rgb(225,236,242)"; //分割线 this.FrameDotSplitPen='rgb(105,105,105)'; //分割虚线 this.FrameSplitTextColor="rgb(117,125,129)"; //刻度文字颜色 this.FrameSplitTextFont=14*GetDevicePixelRatio() +"px 微软雅黑"; //坐标刻度文字字体 this.FrameTitleBGColor="rgb(246,251,253)"; //标题栏背景色 this.FrameLatestPrice = { TextColor:'rgb(255,255,255)', //最新价格文字颜色 UpBarColor:"rgb(238,21,21)", //上涨 DownBarColor:"rgb(25,158,0)", //下跌 UnchagneBarColor:"rgb(0,0,0)", //平盘 BGAlpha:0.6 }; this.OverlayFrame={ BolderPen:'rgb(190,190,190)', TitleColor:'rgb(105,105,105)', TitleFont:11*GetDevicePixelRatio() +'px arial', }; this.CorssCursorBGColor="rgb(43,54,69)"; //十字光标背景 this.CorssCursorTextColor="rgb(255,255,255)"; this.CorssCursorTextFont=14*GetDevicePixelRatio() +"px 微软雅黑"; this.CorssCursorPenColor="rgb(130,130,130)"; //十字光标线段颜色 this.LockBGColor = "rgb(220, 220, 220)"; this.LockTextColor = "rgb(210, 34, 34)"; this.Domain="https://opensource.zealink.com"; //API域名 this.CacheDomain="https://opensourcecache.zealink.com"; //缓存域名 this.PyIndexDomain='https://py.zealink.com'; //py指标计算域名 this.KLine={ MaxMin: {Font:12*GetDevicePixelRatio() +'px 微软雅黑',Color:'rgb(43,54,69)'}, //K线最大最小值显示 Info: //信息地雷 { Investor: { ApiUrl:'https://opensource.zealink.com/API/NewsInteract', //互动易 IconFont: { Family:'iconfont', Text:'\ue631' , HScreenText:'\ue684', Color:'#1c65db'} //SVG 文本 }, Announcement: //公告 { ApiUrl:'https://opensource.zealink.com/API/ReportList', IconFont: { Family:'iconfont', Text:'\ue633', HScreenText:'\ue685', Color:'#f5a521' }, //SVG 文本 IconFont2: { Family:'iconfont', Text:'\ue634', HScreenText:'\ue686', Color:'#ed7520' } //SVG 文本 //季报 }, Pforecast: //业绩预告 { ApiUrl:'https://opensource.zealink.com/API/StockHistoryDay', IconFont: { Family:'iconfont', Text:'\ue62e', HScreenText:'\ue687', Color:'#986cad' } //SVG 文本 }, Research: //调研 { ApiUrl:'https://opensource.zealink.com/API/InvestorRelationsList', IconFont: { Family:'iconfont', Text:'\ue632', HScreenText:'\ue688', Color:'#19b1b7' } //SVG 文本 }, BlockTrading: //大宗交易 { ApiUrl:'https://opensource.zealink.com/API/StockHistoryDay', IconFont: { Family:'iconfont', Text:'\ue630', HScreenText:'\ue689', Color:'#f39f7c' } //SVG 文本 }, TradeDetail: //龙虎榜 { ApiUrl:'https://opensource.zealink.com/API/StockHistoryDay', IconFont: { Family:'iconfont', Text:'\ue62f', HScreenText:'\ue68a' ,Color:'#b22626' } //SVG 文本 } }, NumIcon: { Color:'rgb(251,80,80)',Family:'iconfont', Text:[ '\ue649', '\ue63b','\ue640','\ue63d','\ue63f','\ue645','\ue641','\ue647','\ue648','\ue646','\ue636', '\ue635','\ue637','\ue638','\ue639','\ue63a','\ue63c','\ue63e','\ue642','\ue644','\ue643' ] }, TradeIcon: //交易指标 图标 { Family:'iconfont', Buy: { Color:'rgb(255,15,4)', Text:'\ue683', HScreenText:'\ue682'}, Sell: { Color:'rgb(64,122,22)', Text:'\ue681',HScreenText:'\ue680'}, } }; this.Index={}; //指标线段颜色 this.Index.LineColor= [ "rgb(255,174,0)", "rgb(25,199,255)", "rgb(175,95,162)", "rgb(236,105,65)", "rgb(68,114,196)", "rgb(229,0,79)", "rgb(0,128,255)", "rgb(252,96,154)", "rgb(42,230,215)", "rgb(24,71,178)", ]; this.OverlaySymbol={ Random:0 }; //Random 颜色的随机数 this.OverlaySymbol.Color= //叠加股票颜色 [ "rgb(38,198,218)", "rgb(103,58,183)", "rgb(0,191,165)", "rgb(130,177,255)", ]; //历史数据api this.Index.StockHistoryDayApiUrl="https://opensource.zealink.com/API/StockHistoryDay"; //市场多空 this.Index.MarketLongShortApiUrl="https://opensource.zealink.com/API/FactorTiming"; //市场关注度 this.Index.MarketAttentionApiUrl="https://opensource.zealink.com/API/MarketAttention"; //行业,指数热度 this.Index.MarketHeatApiUrl="https://opensource.zealink.com/API/MarketHeat"; //自定义指数热度 this.Index.CustomIndexHeatApiUrl="https://opensource.zealink.com/API/QuadrantCalculate"; //指标不支持信息 this.Index.NotSupport={Font:"14px 微软雅黑", TextColor:"rgb(52,52,52)"}; //画图工具 this.DrawPicture={}; this.DrawPicture.LineColor= [ "rgb(30,144,255)", ]; this.DrawPicture.PointColor= [ "rgb(105,105,105)", ]; this.KLineTrain = { Font:'bold 14px arial', LastDataIcon: {Color:'rgb(0,0,205)',Text:'⬇'}, BuyIcon: {Color:'rgb(0,205,102 )',Text:'B'}, SellIcon: {Color:'rgb(255,127,36 )',Text:'S'}, IconFont: { Family:'iconfont', Buy:{ Text:'\ue64a', HScreenText:'\ue68a' ,Color:'rgb(255,140,0)' }, Sell:{ Text:'\ue64b', HScreenText:'\ue68a' ,Color:'rgb(6,79,18)' }, Last:{ Text:'\ue681', HScreenText:'\ue68a' ,Color:'rgb(55,0,255)' }, } }; //手机端tooltip this.TooltipPaint = { BGColor:'rgba(250,250,250,0.8)', //背景色 BorderColor:'rgb(120,120,120)', //边框颜色 TitleColor:'rgb(120,120,120)', //标题颜色 TitleFont:13*GetDevicePixelRatio() +'px 微软雅黑' //字体 }; //弹幕 this.Barrage= { Font:16*GetDevicePixelRatio() +'px 微软雅黑', //字体 Height:20, Color:'RGB(109,109,109)' } //走势图 信息地雷 this.MinuteInfo={ TextColor: 'rgb(84,143,255)', Font: 14*GetDevicePixelRatio() +'px 微软雅黑', PointColor:'rgb(38,113,254)', LineColor:'rgb(120,167,255)', TextBGColor:'rgba(255,255,255,0.8)' } //自定义风格 this.SetStyle=function(style) { if (style.TooltipBGColor) this.TooltipBGColor = style.TooltipBGColor; if (style.TooltipAlpha) this.TooltipAlpha = style.TooltipAlpha; if (style.SelectRectBGColor) this.SelectRectBGColor = style.SelectRectBGColor; if (style.UpBarColor) this.UpBarColor = style.UpBarColor; if (style.DownBarColor) this.DownBarColor = style.DownBarColor; if (style.UnchagneBarColor) this.UnchagneBarColor = style.UnchagneBarColor; if (style.Minute) { if (style.Minute.VolBarColor) this.Minute.VolBarColor = style.Minute.VolBarColor; if (style.Minute.PriceColor) this.Minute.PriceColor = style.Minute.PriceColor; if (style.Minute.AvPriceColor) this.Minute.AvPriceColor = style.Minute.AvPriceColor; if (style.Minute.AreaPriceColor) this.Minute.AreaPriceColor = style.Minute.AreaPriceColor; } if (style.DefaultTextColor) this.DefaultTextColor = style.DefaultTextColor; if (style.DefaultTextFont) this.DefaultTextFont = style.DefaultTextFont; if (style.TitleFont) this.TitleFont = style.TitleFont; if (style.UpTextColor) this.UpTextColor = style.UpTextColor; if (style.DownTextColor) this.DownTextColor = style.DownTextColor; if (style.UnchagneTextColor) this.UnchagneTextColor = style.UnchagneTextColor; if (style.CloseLineColor) this.CloseLineColor = style.CloseLineColor; if (style.CloseLineAreaColor) this.CloseLineAreaColor = style.CloseLineAreaColor; if (style.FrameBorderPen) this.FrameBorderPen = style.FrameBorderPen; if (style.FrameSplitPen) this.FrameSplitPen = style.FrameSplitPen; if (style.FrameDotSplitPen) this.FrameDotSplitPen = style.FrameDotSplitPen; if (style.FrameSplitTextColor) this.FrameSplitTextColor = style.FrameSplitTextColor; if (style.FrameSplitTextFont) this.FrameSplitTextFont = style.FrameSplitTextFont; if (style.FrameTitleBGColor) this.FrameTitleBGColor = style.FrameTitleBGColor; if (style.FrameLatestPrice) { if (style.FrameLatestPrice.TextColor) this.FrameLatestPrice.TextColor = style.FrameLatestPrice.TextColor; if (style.FrameLatestPrice.UpBarColor) this.FrameLatestPrice.UpBarColor = style.FrameLatestPrice.UpBarColor; if (style.FrameLatestPrice.DownBarColor) this.FrameLatestPrice.DownBarColor = style.FrameLatestPrice.DownBarColor; if (style.FrameLatestPrice.UnchagneBarColor) this.FrameLatestPrice.UnchagneBarColor = style.FrameLatestPrice.UnchagneBarColor; if (style.FrameLatestPrice.BGAlpha) this.FrameLatestPrice.BGAlpha = style.FrameLatestPrice.BGAlpha; } if (style.CorssCursorBGColor) this.CorssCursorBGColor = style.CorssCursorBGColor; if (style.CorssCursorTextColor) this.CorssCursorTextColor = style.CorssCursorTextColor; if (style.CorssCursorTextFont) this.CorssCursorTextFont = style.CorssCursorTextFont; if (style.CorssCursorPenColor) this.CorssCursorPenColor = style.CorssCursorPenColor; if (style.KLine) this.KLine = style.KLine; if (style.Index) { if (style.Index.LineColor) this.Index.LineColor = style.Index.LineColor; if (style.Index.NotSupport) this.Index.NotSupport = style.Index.NotSupport; } if (style.ColorArray) this.ColorArray = style.ColorArray; if (style.DrawPicture) { this.DrawPicture.LineColor = style.DrawPicture.LineColor; this.DrawPicture.PointColor = style.DrawPicture.PointColor; } if (style.TooltipPaint) { if (style.TooltipPaint.BGColor) this.TooltipPaint.BGColor=style.TooltipPaint.BGColor; if (style.TooltipPaint.BorderColor) this.TooltipPaint.BorderColor=style.TooltipPaint.BorderColor; if (style.TooltipPaint.TitleColor) this.TooltipPaint.TitleColor=style.TooltipPaint.TitleColor; if (style.TooltipPaint.TitleFont) this.TooltipPaint.TitleFont=style.TooltipPaint.TitleFont; } if (style.MinuteInfo) { if (style.MinuteInfo.TextColor) this.MinuteInfo.TextColor=style.MinuteInfo.TextColor; if (style.MinuteInfo.Font) this.MinuteInfo.Font=style.MinuteInfo.Font; if (style.MinuteInfo.PointColor) this.MinuteInfo.PointColor=style.MinuteInfo.PointColor; if (style.MinuteInfo.LineColor) this.MinuteInfo.LineColor=style.MinuteInfo.LineColor; if (style.MinuteInfo.TextBGColor) this.MinuteInfo.TextBGColor=style.MinuteInfo.TextBGColor; } } } var g_JSChartResource=new JSChartResource(); ///////////////////////////////////////////////////////////////////////////////// // // // var JSCHART_LANGUAGE_ID= { LANGUAGE_CHINESE_ID:0, LANGUAGE_ENGLISH_ID:1 }; function JSChartLocalization() { this.TextResource=new Map([ //内部tooltip ['Tooltip-Open', {CN:'开:', EN:'O:'}], ['Tooltip-High', {CN:'高:', EN:'H:'}], ['Tooltip-Low', {CN:'低:', EN:'L:'}], ['Tooltip-Close', {CN:'收:', EN:'C:'}], ['Tooltip-Increase', {CN:'幅:', EN:'I:'}], ['Tooltip-Vol', {CN:'量:', EN:'V:'}], ['Tooltip-Amount', {CN:'额:', EN:'A:'}], ['Tooltip-AvPrice', {CN:'均:', EN:'AP:'}], ['Tooltip-Price', {CN:'价:', EN:'P:'}], ['Tooltip-Exchange', {CN:'换:', EN:'E:'}], ['DivTooltip-Open', {CN:'开盘:', EN:'Open:'}], ['DivTooltip-High', {CN:'最高:', EN:'High:'}], ['DivTooltip-Low', {CN:'最低:', EN:'Low:'}], ['DivTooltip-Close', {CN:'收盘:', EN:'Close:'}], ['DivTooltip-Increase', {CN:'涨幅:', EN:'Increase:'}], ['DivTooltip-Vol', {CN:'数量:', EN:'Volume:'}], ['DivTooltip-Amount', {CN:'金额:', EN:'Amount:'}], ['DivTooltip-Exchange', {CN:'换手:', EN:'Exchange:'}], //K线动态标题 ['KTitle-Open', {CN:'开:', EN:'O:'}], ['KTitle-High', {CN:'高:', EN:'H:'}], ['KTitle-Low', {CN:'低:', EN:'L:'}], ['KTitle-Close', {CN:'收:', EN:'C:'}], ['KTitle-Increase', {CN:'幅:', EN:'I:'}], ['KTitle-Vol', {CN:'量:', EN:'V:'}], ['KTitle-Amount', {CN:'额:', EN:'A:'}], ['KTitle-Exchange', {CN:'换:', EN:'E:'}], //走势图动态标题 ['MTitle-Close', {CN:'价:', EN:'C:'}], ['MTitle-AvPrice', {CN:'均:', EN:'AC:'}], ['MTitle-Increase', {CN:'幅:', EN:'I:'}], ['MTitle-Vol', {CN:'量:', EN:'V:'}], ['MTitle-Amount', {CN:'额:', EN:'A:'}], //周期 ['日线', {CN:'日线', EN:'1D'}], ['周线', {CN:'周线', EN:'1W'}], ['月线', {CN:'月线', EN:'1M'}], ['年线', {CN:'年线', EN:'1Y'}], ['1分', {CN:'1分', EN:'1Min'}], ['5分', {CN:'5分', EN:'5Min'}], ['15分', {CN:'15分', EN:'15Min'}], ['30分', {CN:'30', EN:'30Min'}], ['60分', {CN:'60分', EN:'60Min'}], ['季线', {CN:'季线', EN:'1Q'}], ['分笔', {CN:'分笔', EN:'Tick'}], ['2小时', {CN:'2小时', EN:'2H'}], ['4小时', {CN:'4小时', EN:'4H'}], //复权 ['不复权', {CN:'不复权', EN:'No Right'}], ['前复权', {CN:'前复权', EN:'Pro Right'}], ['后复权', {CN:'后复权', EN:'Post Right'}], //week ['日', {CN:'日', EN:'Sun.'}], ['一', {CN:'一', EN:'Mon.'}], ['二', {CN:'二', EN:'Tues.'}], ['三', {CN:'三', EN:'Wed.'}], ['四', {CN:'四', EN:'Thur.'}], ['五', {CN:'五', EN:'Fri.'}], ['六', {CN:'六', EN:'Sat.'}], ['1月', {CN:'1月', EN:'Jan'}], ['2月', {CN:'2月', EN:'Feb'}], ['3月', {CN:'3月', EN:'Mar'}], ['4月', {CN:'4月', EN:'Apr'}], ['5月', {CN:'5月', EN:'May'}], ['6月', {CN:'6月', EN:'Jun'}], ['7月', {CN:'7月', EN:'Jul'}], ['8月', {CN:'8月', EN:'Aug'}], ['9月', {CN:'9月', EN:'Sept'}], ['10月', {CN:'10月', EN:'Oct'}], ['11月', {CN:'11月', EN:'Nov'}], ['12月', {CN:'12月', EN:'Dec'}], ['自定义分钟', {CN:'分', EN:'Min'}], ['自定义日线', {CN:'日', EN:'D'}] ]); this.GetText=function(key,language) { var item=this.TextResource.get(key); if (!item) return ''; switch(language) { case JSCHART_LANGUAGE_ID.LANGUAGE_CHINESE_ID: return item.CN; case JSCHART_LANGUAGE_ID.LANGUAGE_ENGLISH_ID: return item.EN; default: return item.CN; } } this.SetTextResource=function(key,value) { this.TextResource.set(key,value) } }; var g_JSChartLocalization=new JSChartLocalization(); /* 指标列表 指标信息都在这里,不够后面再加字段 */ function JSIndexMap() { } JSIndexMap.Get=function(id) { var indexMap=new Map( [ //公司自己的指标 ["市场多空", {IsMainIndex:false, Create:function(){ return new MarketLongShortIndex()} }], ["市场择时", {IsMainIndex:false, Create:function(){ return new MarketTimingIndex()} }], ["市场关注度", {IsMainIndex:false, Create:function(){ return new MarketAttentionIndex()} }], ["指数热度", {IsMainIndex:false, Create:function(){ return new MarketHeatIndex()} }], ["财务粉饰", {IsMainIndex:false, Create:function(){ return new BenfordIndex()} }], ["自定义指数热度", {IsMainIndex:false, Create:function(){ return new CustonIndexHeatIndex()} , Name:'自定义指数热度'} ], //能图指标 ["能图-趋势", {IsMainIndex:false, Create:function(){ return new LighterIndex1()}, Name:'大盘/个股趋势' }], ["能图-位置研判", {IsMainIndex:false, Create:function(){ return new LighterIndex2()}, Name:'位置研判' }], ["能图-点位研判", {IsMainIndex:false, Create:function(){ return new LighterIndex3()}, Name:'点位研判' }] ] ); return indexMap.get(id); } //////////////////////////////////////////////////////////////////////////////////////////////// // 指标计算方法 // // // function HQIndexFormula() { } //指数平均数指标 EMA(close,10) HQIndexFormula.EMA=function(data,dayCount) { var result = []; var offset=0; if (offset>=data.length) return result; //取首个有效数据 for(;offsetdata.length) return result; var max=-10000; for(var i=n,j=0;idata[max]) max = j; } } result[i] = data[max]; } return result; } HQIndexFormula.LLV=function(data,n) { var result = []; if (n>data.length) return result; var min=-10000; for(var i=n;idata[min]?min:i; } else { for(var j=(min=i-n+1)+1;j<=i;++j) { if(data[j]=data.length) return result; result=data.slice(0,data.length-n); for(var i=0;idata2比较 返回 0/1 数组 HQIndexFormula.ARRAY_GT=function(data,data2) { var result=[]; var IsNumber=typeof(data2)=="number"; if (IsNumber) { for(var i in data) { result[i]=(data[i]>data2 ? 1:0); } } else { var count=Math.max(data.length,data2.length) for(var i=0;idata2[i] ? 1:0; else result[i]=null; } } return result; } //数组 data>=data2比较 返回 0/1 数组 HQIndexFormula.ARRAY_GTE=function(data,data2) { var result=[]; var IsNumber=typeof(data2)=="number"; if (IsNumber) { for(var i in data) { result[i]=(data[i]>=data2 ? 1:0); } } else { var count=Math.max(data.length,data2.length) for(var i=0;i=data2[i] ? 1:0; else result[i]=null; } } return result; } //数组 data=data.length) return result; var i=dayCount; for(;i=data.length) return result; var index=0; for(;indexdata2[index]&&data[index-1]0) step=obj.Step; if(this.DataMove(step*this.StepPixel,isLeft)) //每次移动一个数据 { this.UpdataDataoffset(); this.UpdatePointByCursorIndex(); this.UpdateFrameMaxMin(); this.ResetFrameXYSplit(); this.Draw(); } } else if (id===JSCHART_OPERATOR_ID.OP_ZOOM_IN || id===JSCHART_OPERATOR_ID.OP_ZOOM_OUT) //缩放 { var cursorIndex={}; cursorIndex.Index=parseInt(Math.abs(this.CursorIndex-0.5).toFixed(0)); if (id===JSCHART_OPERATOR_ID.OP_ZOOM_IN) { if (!this.Frame.ZoomUp(cursorIndex)) return; } else { if (!this.Frame.ZoomDown(cursorIndex)) return; } this.CursorIndex=cursorIndex.Index; this.UpdataDataoffset(); this.UpdatePointByCursorIndex(); this.UpdateFrameMaxMin(); this.Draw(); } else if (id===JSCHART_OPERATOR_ID.OP_GOTO_HOME) { var hisData=null; if (!this.Frame.Data) hisData=this.Frame.Data; else hisData=this.Frame.SubFrame[0].Frame.Data; if (!hisData) return; //数据还没有到达 var showCount=this.PageSize; var pageSize = this.GetMaxMinPageSize(); if (pageSize.Max < showCount) showCount = pageSize.Max; else if (pageSize.Min>showCount) showCount=pageSize.Min; for(var i in this.Frame.SubFrame) //设置一屏显示的数据个数 { var item =this.Frame.SubFrame[i].Frame; item.XPointCount=showCount; } var index=hisData.Data.length-showCount; hisData.DataOffset=index; this.CursorIndex=0.6; this.LastPoint.X=null; this.LastPoint.Y=null; console.log(`[KLineChartContainer::ChartOperator] OP_GOTO_HOME, dataOffset=${hisData.DataOffset} CursorIndex=${this.CursorIndex} PageSize=${showCount}`); this.UpdataDataoffset(); //更新数据偏移 this.UpdateFrameMaxMin(); //调整坐标最大 最小值 this.Frame.SetSizeChage(true); this.Draw(); this.UpdatePointByCursorIndex(); //更新十字光标位子 } } this.OnWheel=function(e) { console.log('[KLineChartContainer::OnWheel]',e); var x = e.clientX-this.UIElement.getBoundingClientRect().left; var y = e.clientY-this.UIElement.getBoundingClientRect().top; var isInClient=false; this.Canvas.beginPath(); this.Canvas.rect(this.Frame.ChartBorder.GetLeft(),this.Frame.ChartBorder.GetTop(),this.Frame.ChartBorder.GetWidth(),this.Frame.ChartBorder.GetHeight()); isInClient=this.Canvas.isPointInPath(x,y); if (isInClient && e.wheelDelta<0) //缩小 { var cursorIndex={}; cursorIndex.Index=parseInt(Math.abs(this.CursorIndex-0.5).toFixed(0)); if (this.Frame.ZoomDown(cursorIndex)) { this.CursorIndex=cursorIndex.Index; this.UpdataDataoffset(); this.UpdatePointByCursorIndex(); this.UpdateFrameMaxMin(); this.Draw(); } } else if (isInClient && e.wheelDelta>0) //放大 { var cursorIndex={}; cursorIndex.Index=parseInt(Math.abs(this.CursorIndex-0.5).toFixed(0)); if (this.Frame.ZoomUp(cursorIndex)) { this.CursorIndex=cursorIndex.Index; this.UpdatePointByCursorIndex(); this.UpdataDataoffset(); this.UpdateFrameMaxMin(); this.Draw(); } } if(e.preventDefault) e.preventDefault(); else e.returnValue = false; } //创建 //windowCount 窗口个数 this.Create=function(windowCount) { this.UIElement.JSChartContainer=this; //创建十字光标 this.ChartCorssCursor=new ChartCorssCursor(); this.ChartCorssCursor.Canvas=this.Canvas; this.ChartCorssCursor.StringFormatX=new HQDateStringFormat(); this.ChartCorssCursor.StringFormatY=new HQPriceStringFormat(); this.ChartCorssCursor.StringFormatY.LanguageID=this.LanguageID; //创建等待提示 this.ChartSplashPaint = new ChartSplashPaint(); this.ChartSplashPaint.Canvas = this.Canvas; //创建框架容器 this.Frame=new HQTradeFrame(); this.Frame.ChartBorder=new ChartBorder(); this.Frame.ChartBorder.UIElement=this.UIElement; this.Frame.ChartBorder.Top=30; this.Frame.ChartBorder.Left=5; this.Frame.ChartBorder.Bottom=20; this.Frame.Canvas=this.Canvas; this.ChartCorssCursor.Frame=this.Frame; //十字光标绑定框架 this.ChartSplashPaint.Frame = this.Frame; this.CreateChildWindow(windowCount); this.CreateMainKLine(); //子窗口动态标题 for(var i in this.Frame.SubFrame) { var titlePaint=new DynamicChartTitlePainting(); titlePaint.Frame=this.Frame.SubFrame[i].Frame; titlePaint.Canvas=this.Canvas; titlePaint.LanguageID=this.LanguageID; this.TitlePaint.push(titlePaint); } this.UIElement.addEventListener("keydown", OnKeyDown, true); //键盘消息 this.UIElement.addEventListener("wheel", OnWheel, true); //上下滚动消息 } //创建子窗口 this.CreateChildWindow=function(windowCount) { for(var i=0;i=hisData.Data.length) this.CursorIndex=hisData.Data.length-1-dataOffset; if (this.CursorIndex<0) this.CursorIndex=0; //不一定对啊 if (this.CustomShow) //定制显示 1次有效 { this.SetCustomShow(this.CustomShow,hisData); this.CustomShow=null; } } this.UpdateMainData=function(hisData, lastDataCount) { var frameHisdata=null; if (!this.Frame.Data) frameHisdata=this.Frame.Data; else if (this.Frame.SubFrame && this.Frame.SubFrame[0]) frameHisdata=this.Frame.SubFrame[0].Frame.Data; if (!frameHisdata) return; var newDataCount=0; if (lastDataCount>0 && hisData.Data.length>lastDataCount) { newDataCount=hisData.Data.length-lastDataCount; console.log(`[KLineChartContainer::UpdateMainData] [count=${lastDataCount}->${hisData.Data.length}], [newDataCount=${newDataCount}]`); } this.ChartPaint[0].Data=hisData; this.ChartPaint[0].Symbol=this.Symbol; this.ChartPaint[0].Data.DataOffset=frameHisdata.DataOffset+newDataCount; //加上数据增加的个数 for(var i in this.Frame.SubFrame) { var item =this.Frame.SubFrame[i].Frame; item.Data=this.ChartPaint[0].Data; } this.TitlePaint[0].Data=this.ChartPaint[0].Data; //动态标题 this.TitlePaint[0].Symbol=this.Symbol; this.TitlePaint[0].Name=this.Name; this.ChartCorssCursor.StringFormatX.Data=this.ChartPaint[0].Data; //十字光标 this.Frame.Data=this.ChartPaint[0].Data; for(var i in this.OverlayChartPaint) //主图股票数据绑定到叠加股票上 { var item=this.OverlayChartPaint[i]; item.MainData=this.ChartPaint[0].Data; } this.ChartCorssCursor.StringFormatY.Symbol=this.Symbol; } this.SetCustomShow=function(customShow,hisData) { if (!customShow || !customShow.Date || customShow.Date<20000101) return; var firstDate=customShow.Date; var index=null; for(var i =0;i=firstDate) { index=i; break; } } if (index===null) { console.log(`[KLineChartContainer::SetCustomShow] Can't find first date=${firstDate}`); return; } var count=hisData.Data.length-index; if (customShow.PageSize>0) count=customShow.PageSize; var customShowCount=count; var pageSize=this.GetMaxMinPageSize(); if (count>pageSize.Max) customShowCount=pageSize.Max; else if (count0 && !this.IsApiPeriod) //复权 { var rightData=bindData.GetRightDate(bindData.Right); bindData.Data=rightData; } if (ChartData.IsDayPeriod(bindData.Period,false) && !this.IsApiPeriod) //周期数据 { var periodData=bindData.GetPeriodData(bindData.Period); bindData.Data=periodData; } //绑定数据 this.SourceData=sourceData; this.Symbol=data.symbol; this.Name=data.name; this.BindMainData(bindData,this.PageSize); this.Frame.SetSizeChage(true); this.BindInstructionIndexData(bindData); //执行指示脚本 var firstSubFrame; for(var i=0; i0 && bindData.Period<=3) //复权(日线数据才复权) { var rightData=bindData.GetRightDate(bindData.Right); bindData.Data=rightData; } if (ChartData.IsDayPeriod(bindData.Period,false) || ChartData.IsMinutePeriod(bindData.Period,false)) //周期数据 (0= 日线,4=1分钟线 不需要处理) { var periodData=bindData.GetPeriodData(bindData.Period); bindData.Data=periodData; } //绑定数据 this.UpdateMainData(bindData,lastDataCount); this.BindInstructionIndexData(bindData); //执行指示脚本 for(var i=0; i0 && ChartData.IsDayPeriod(bindData.Period,false)) //复权(日线数据才复权) { var rightData=bindData.GetRightDate(bindData.Right); bindData.Data=rightData; } if (ChartData.IsDayPeriod(bindData.Period,false) || ChartData.IsMinutePeriod(bindData.Period,false)) //周期数据 (0= 日线,4=1分钟线 不需要处理) { var periodData=bindData.GetPeriodData(bindData.Period); bindData.Data=periodData; } //绑定数据 this.UpdateMainData(bindData,lastDataCount); this.BindInstructionIndexData(bindData); //执行指示脚本 for(var i=0; i0 && ChartData.IsDayPeriod(bindData.Period,true)) //复权(日线数据才复权) { var rightData=bindData.GetRightDate(bindData.Right); bindData.Data=rightData; } if (ChartData.IsDayPeriod(bindData.Period,false) || ChartData.IsMinutePeriod(bindData.Period,false)) //周期数据 (0= 日线,4=1分钟线 不需要处理) { var periodData=bindData.GetPeriodData(bindData.Period); bindData.Data=periodData; } this.UpdateMainData(bindData,lastDataCount);//更新主图数据 this.UpdateOverlayRealtimeData(data); //更新叠加股票数据 this.BindInstructionIndexData(bindData); //执行指示脚本 for(var i=0; i0 && MARKET_SUFFIX_NAME.IsSHSZStockA(data.symbol)) //复权数据 ,A股才有有复权 { var rightData=bindData.GetRightDate(bindData.Right); bindData.Data=rightData; } var aryOverlayData=this.SourceData.GetOverlayData(bindData.Data); //和主图数据拟合以后的数据 bindData.Data=aryOverlayData; if (ChartData.IsDayPeriod(bindData.Period,false)) //周期数据 { var periodData=bindData.GetPeriodData(bindData.Period); bindData.Data=periodData; } item.Data=bindData; } } this.RequestMinuteRealtimeData=function() { var self=this; var arySymbol=[self.Symbol]; for(var i in this.OverlayChartPaint) //叠加的股票更新 { var item=this.OverlayChartPaint[i]; if (!item.Symbol) continue; if (!item.MainData) continue; //等待主图股票数据未下载完 if (item.Status!=OVERLAY_STATUS_ID.STATUS_FINISHED_ID) continue; arySymbol.push(item.Symbol); } if (this.NetworkFilter) { var obj= { Name:'KLineChartContainer::RequestMinuteRealtimeData', //类名:: Explain:'当天1分钟K线数据', Request:{ Url:self.RealtimeApiUrl, Data:{ symbol: arySymbol, field:["name","symbol","price","yclose","minutecount","minute","date","time"] }, Type:'POST' }, Self:this, PreventDefault:false }; this.NetworkFilter(obj, function(data) { self.RecvMinuteRealtimeData(data); self.AutoUpdate(); }); if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求 } JSNetwork.HttpRequest({ url: this.RealtimeApiUrl, data: { "field": ["name","symbol","price","yclose","minutecount","minute","date","time"], "symbol": arySymbol, "start": -1 }, type:"post", dataType: "json", async:true, success: function (data) { self.RecvMinuteRealtimeData(data); self.AutoUpdate(); } }); } this.RecvMinuteRealtimeDataV2=function(data) //新版本的 { if (this.IsOnTouch==true) return; //正在操作中不更新数据 var aryMinuteData=KLineChartContainer.JsonDataToMinuteHistoryData(data); if (!aryMinuteData || aryMinuteData.length<=0) return; var lastDataCount=this.GetHistoryDataCount(); //保存下上一次的数据个数 if (!this.SourceData.MergeMinuteData(aryMinuteData)) return; console.log(`[KLineChartContainer::RecvMinuteRealtimeDataV2] update kline by 1 minute data [${lastDataCount}->${this.SourceData.Data.length}]`); var bindData=new ChartData(); bindData.Data=this.SourceData.Data; bindData.Period=this.Period; bindData.Right=this.Right; bindData.DataType=this.SourceData.DataType; bindData.Symbol=this.Symbol; if (bindData.Right>0 && ChartData.IsDayPeriod(bindData.Period,true) && !this.IsApiPeriod) //复权(日线数据才复权) { var rightData=bindData.GetRightDate(bindData.Right); bindData.Data=rightData; } if ((ChartData.IsDayPeriod(bindData.Period,false) || ChartData.IsMinutePeriod(bindData.Period,false)) && !this.IsApiPeriod) //周期数据 (0= 日线,4=1分钟线 不需要处理) { var periodData=bindData.GetPeriodData(bindData.Period); bindData.Data=periodData; } //绑定数据 this.UpdateMainData(bindData,lastDataCount); this.BindInstructionIndexData(bindData); //执行指示脚本 for(var i=0; i${this.SourceData.Data.length}]`); var bindData=new ChartData(); bindData.Data=this.SourceData.Data; bindData.Period=this.Period; bindData.Right=this.Right; bindData.DataType=this.SourceData.DataType; bindData.Symbol=this.Symbol; if (bindData.Right>0 && ChartData.IsDayPeriod(bindData.Period,true)) //复权(日线数据才复权) { var rightData=bindData.GetRightDate(bindData.Right); bindData.Data=rightData; } if (ChartData.IsDayPeriod(bindData.Period,false) || ChartData.IsMinutePeriod(bindData.Period,false)) //周期数据 (0= 日线,4=1分钟线 不需要处理) { var periodData=bindData.GetPeriodData(bindData.Period); bindData.Data=periodData; } //绑定数据 this.UpdateMainData(bindData,lastDataCount); this.UpdateOverlayMinuteRealtimeData(data); //更新叠加股票数据 this.BindInstructionIndexData(bindData); //执行指示脚本 for(var i=0; iresult.MaxRequestDataCount) result.MaxRequestDataCount=lCount; } else if (ChartData.IsMinutePeriod(this.Period,true)) { var date; var lCount=0; for(var i in this.SourceData.Data) { var item=this.SourceData.Data[i]; if (item.Date!=date) ++lCount; date=item.Date; } if (lCount>result.MaxRequestMinuteDayCount) result.MaxRequestMinuteDayCount=lCount; } return result; } //分笔数据 this.RequestTickData=function() { var self=this; self.ChartSplashPaint.IsEnableSplash = true; self.Draw(); //下载缓存文件 var cacheUrl=g_JSChartResource.CacheDomain+'/cache/dealday/today/'+self.Symbol+'.json' if (this.NetworkFilter) { var obj= { Name:'KLineChartContainer::RequestTickData', //类名:: Explain:'当天分笔数据', Request:{ Url:cacheUrl, Data:{ symbol: self.Symbol }, Type:'GET' }, Self:this, PreventDefault:false }; this.NetworkFilter(obj, function(data) { self.ChartSplashPaint.IsEnableSplash=false; self.RecvTickData(data); self.AutoUpdate(); }); if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求 } /* $.ajax({ url: self.TickApiUrl, data:{"symbol":self.Symbol}, type:"post", dataType: "json", async:true, success: function (data) { self.ChartSplashPaint.IsEnableSplash=false; self.RecvTickData(data); self.AutoUpdate(); } }); */ JSNetwork.HttpRequest({ url: cacheUrl, data:{"symbol":self.Symbol}, type:"get", dataType: "json", async:true, success: function (data) { self.ChartSplashPaint.IsEnableSplash=false; self.RecvTickData(data); self.AutoUpdate(1); }, error: function(http,e) { self.ChartSplashPaint.IsEnableSplash=false; self.AutoUpdate(); //self.RecvError(http,e,param);; } }); } this.RecvTickData=function(data) { var aryDayData=KLineChartContainer.JsonDataToTickData(data); //原始数据 var sourceData=new ChartData(); sourceData.Data=aryDayData; sourceData.DataType=2; //0=日线数据 1=分钟数据 2=分笔数据 //显示的数据 var bindData=new ChartData(); bindData.Data=aryDayData; bindData.Right=this.Right; bindData.Period=this.Period; bindData.DataType=2; //绑定数据 this.SourceData=sourceData; this.Symbol=data.symbol; this.Name=data.name; this.BindMainData(bindData,this.PageSize); this.BindInstructionIndexData(bindData); //执行指示脚本 var firstSubFrame; for(var i=0; i0) lastTime=source[source.length-1].Time; var newCount=0; for(var i in aryDayData) { var item=aryDayData[i]; if (item.Time<=lastTime) continue; source.push(item); ++newCount; } if (newCount<=0) return; //显示的数据 var bindData=new ChartData(); bindData.Data=source; bindData.Right=this.Right; bindData.Period=this.Period; bindData.DataType=2; //绑定数据 this.Symbol=data.symbol; this.Name=data.name; this.UpdateMainData(bindData,lastDataCount); this.BindInstructionIndexData(bindData); //执行指示脚本 for(var i=0; iCUSTOM_DAY_PERIOD_START && period<=CUSTOM_DAY_PERIOD_START) { if (this.SourceData.DataType!=0) isDataTypeChange=true; } else if (period>CUSTOM_MINUTE_PERIOD_START && period<=CUSTOM_MINUTE_PERIOD_END) { if (this.SourceData.DataType!=1) isDataTypeChange=true; } else { switch(period) { case 0: //日线 case 1: //周 case 2: //月 case 3: //年 case 9: //季线 if (this.SourceData.DataType!=0) isDataTypeChange=true; break; case 4: //1分钟 case 5: //5分钟 case 6: //15分钟 case 7: //30分钟 case 8: //60分钟 case 11: //2小时 case 12: //4小时 if (this.SourceData.DataType!=1) isDataTypeChange=true; break; case 10: //分笔线 if (this.SourceData.DataType!=2) isDataTypeChange=true; break; } } this.Period=period; this.ReloadChartDrawPicture(); //切换周期了 清空画图工具 if (isDataTypeChange==false && !this.IsApiPeriod) { this.Update(); return; } if (ChartData.IsDayPeriod(this.Period,true)) { this.CancelAutoUpdate(); //先停止定时器 this.AutoUpdateEvent(false,'KLineChartContainer::ChangePeriod'); //切换周期先停止更新 this.ResetOverlaySymbolStatus(); this.RequestHistoryData(); //请求日线数据 this.ReqeustKLineInfoData(); } else if (ChartData.IsMinutePeriod(this.Period,true)) { this.CancelAutoUpdate(); //先停止定时器 this.AutoUpdateEvent(false,'KLineChartContainer::ChangePeriod'); //切换周期先停止更新 this.ResetOverlaySymbolStatus(); this.ReqeustHistoryMinuteData(); //请求分钟数据 } else if (ChartData.IsTickPeriod(this.Period)) { this.CancelAutoUpdate(); //先停止定时器 this.AutoUpdateEvent(false,'KLineChartContainer::ChangePeriod'); this.RequestTickData(); //请求分笔数据 } } //复权切换 this.ChangeRight=function(right) { if (!MARKET_SUFFIX_NAME.IsSHSZStockA(this.Symbol)) return; //A股股票有复权 if (ChartData.IsTickPeriod(this.Period)) return; //分笔没有复权 var upperSymbol=this.Symbol.toUpperCase(); if (MARKET_SUFFIX_NAME.IsBIT(upperSymbol)) return; if (right<0 || right>2) return; if (this.Right==right) return; this.Right=right; this.Update(); } //设置第1屏的起始日期 this.SetFirstShowDate=function(obj) { if (!obj || !obj.Date) return; console.log('[KLineChartContainer::SetFirstShowDate] obj=', obj); var hisData=null; if (!this.Frame.Data) hisData=this.Frame.Data; else hisData=this.Frame.SubFrame[0].Frame.Data; if (!hisData) return; //数据还没有到达 var index=null; for(var i=0;i=obj.Date) { index=i; break; } } if (index===null) { console.log(`[KLineChartContainer::SetFirstShowDate] an't find first date=${obj.Date}`, obj); return; } var count=hisData.Data.length-index; var customShowCount=count; if (obj.PageSize>0) customShowCount=obj.PageSize; var pageSize = this.GetMaxMinPageSize(); if (pageSize.Max < customShowCount) customShowCount = pageSize.Max; else if (pageSize.Min>customShowCount) customShowCount=pageSize.Min; for(var i in this.Frame.SubFrame) //设置一屏显示的数据个数 { var item =this.Frame.SubFrame[i].Frame; item.XPointCount=customShowCount; } hisData.DataOffset=index; this.CursorIndex=0.6; this.LastPoint.X=null; this.LastPoint.Y=null; console.log(`[KLineChartContainer::SetFirstShowDate] dataOffset=${hisData.DataOffset} CursorIndex=${this.CursorIndex} PageSize=${customShowCount}`); this.UpdataDataoffset(); //更新数据偏移 this.UpdateFrameMaxMin(); //调整坐标最大 最小值 this.Frame.SetSizeChage(true); this.Draw(); this.UpdatePointByCursorIndex(); //更新十字光标位子 } //删除某一个窗口的指标 this.DeleteIndexPaint=function(windowIndex) { let paint=new Array(); //踢出当前窗口的指标画法 for(let i in this.ChartPaint) { let item=this.ChartPaint[i]; if (i==0 || item.ChartFrame!=this.Frame.SubFrame[windowIndex].Frame) paint.push(item); } this.Frame.SubFrame[windowIndex].Frame.YSpecificMaxMin=null; //清空指定最大最小值 this.Frame.SubFrame[windowIndex].Frame.IsLocked=false; //解除上锁 this.Frame.SubFrame[windowIndex].Frame.YSplitScale = null; //清空固定刻度 this.ChartPaint=paint; //清空东条标题 var titleIndex=windowIndex+1; this.TitlePaint[titleIndex].Data=[]; this.TitlePaint[titleIndex].Title=null; } //显示隐藏主图K线 this.ShowKLine=function(isShow) { if (this.ChartPaint.length<=0 || !this.ChartPaint[0]) return; this.ChartPaint[0].IsShow=isShow; } this.SetInstructionData=function(type,instructionData) { if (this.ChartPaint.length<=0 || !this.ChartPaint[0]) return; var title=this.TitlePaint[1]; if (type==2) //五彩K线 { this.ChartPaint[0].ColorData=instructionData.Data; if (title) title.ColorIndex={Name:instructionData.Name}; } else if (type==1) //专家指示 { this.ChartPaint[0].TradeData={Sell:instructionData.Sell, Buy:instructionData.Buy}; if (title) title.TradeIndex={Name:instructionData.Name} } } this.ChangeInstructionIndex=function(indexName) { let scriptData = new JSIndexScript(); let indexInfo = scriptData.Get(indexName); if (!indexInfo) return; if(indexInfo.InstructionType!=1 && indexInfo.InstructionType!=2) return; indexInfo.ID=indexName; this.ChangeInstructionScriptIndex(indexInfo); } this.ChangeInstructionScriptIndex=function(indexData) { if (indexData.InstructionType==1) //交易系统 { this.TradeIndex=new ScriptIndex(indexData.Name,indexData.Script,indexData.Args,indexData); //脚本执行 } else if (indexData.InstructionType==2) //五彩K线 { this.ColorIndex=new ScriptIndex(indexData.Name,indexData.Script,indexData.Args,indexData); //脚本执行 } else { return; } var bindData=this.ChartPaint[0].Data; this.BindInstructionIndexData(bindData); this.UpdataDataoffset(); //更新数据偏移 this.UpdateFrameMaxMin(); //调整坐标最大 最小值 this.Draw(); } this.CancelInstructionIndex=function() //取消指示数据 { if (this.ChartPaint.length<=0 || !this.ChartPaint[0]) return; this.ColorIndex=null; this.TradeIndex=null; this.ChartPaint[0].ColorData=null; //五彩K线数据取消掉 this.ChartPaint[0].TradeData=null; //交易系统数据取消 var title=this.TitlePaint[1]; if (title) { title.TradeIndex=null; title.ColorIndex=null; } this.UpdataDataoffset(); //更新数据偏移 this.UpdateFrameMaxMin(); //调整坐标最大 最小值 this.Draw(); } //切换成 脚本指标 this.ChangeScriptIndex=function(windowIndex,indexData) { this.DeleteIndexPaint(windowIndex); this.WindowIndex[windowIndex]=new ScriptIndex(indexData.Name,indexData.Script,indexData.Args,indexData); //脚本执行 var bindData=this.ChartPaint[0].Data; this.BindIndexData(windowIndex,bindData); //执行脚本 this.UpdataDataoffset(); //更新数据偏移 this.UpdateFrameMaxMin(); //调整坐标最大 最小值 this.Draw(); } //切换指标 指定切换窗口指标 this.ChangeIndex=function(windowIndex,indexName,option) { var indexItem=JSIndexMap.Get(indexName); if (!indexItem) { //查找系统指标 let scriptData = new JSIndexScript(); let indexInfo = scriptData.Get(indexName); if (!indexInfo) return; if (indexInfo.IsMainIndex) { windowIndex = 0; //主图指标只能在主图显示 } else { if (windowIndex == 0) windowIndex = 1; //幅图指标,不能再主图显示 } let indexData = { Name:indexInfo.Name, Script:indexInfo.Script, Args: indexInfo.Args, ID:indexName , //扩展属性 可以是空 KLineType:indexInfo.KLineType, YSpecificMaxMin:indexInfo.YSpecificMaxMin, YSplitScale:indexInfo.YSplitScale, FloatPrecision:indexInfo.FloatPrecision, Condition:indexInfo.Condition, StringFormat:indexInfo.StringFormat }; if (option) { if (option.FloatPrecision>=0) indexData.FloatPrecision=option.FloatPrecision; if (option.StringFormat>0) indexData.StringFormat=option.StringFormat; if (option.Args) indexData.Args=option.Args; } return this.ChangeScriptIndex(windowIndex, indexData); } //主图指标 if (indexItem.IsMainIndex) { if (windowIndex>0) windowIndex=0; //主图指标只能在主图显示 } else { if (windowIndex==0) windowIndex=1; //幅图指标,不能再主图显示 } var paint=new Array(); //踢出当前窗口的指标画法 for(var i in this.ChartPaint) { var item=this.ChartPaint[i]; if (i==0 || item.ChartFrame!=this.Frame.SubFrame[windowIndex].Frame) paint.push(item); } this.Frame.SubFrame[windowIndex].Frame.YSpecificMaxMin=null; //清空指定最大最小值 this.Frame.SubFrame[windowIndex].Frame.IsLocked=false; //解除上锁 this.Frame.SubFrame[windowIndex].Frame.YSplitScale = null; //清空固定刻度 this.ChartPaint=paint; //清空东条标题 var titleIndex=windowIndex+1; this.TitlePaint[titleIndex].Data=[]; this.TitlePaint[titleIndex].Title=null; this.WindowIndex[windowIndex]=indexItem.Create(); this.CreateWindowIndex(windowIndex); var bindData=this.ChartPaint[0].Data; this.BindIndexData(windowIndex,bindData); this.UpdataDataoffset(); //更新数据偏移 this.UpdateFrameMaxMin(); //调整坐标最大 最小值 this.Draw(); } this.ChangePyScriptIndex=function(windowIndex,indexData) { this.DeleteIndexPaint(windowIndex); this.WindowIndex[windowIndex]=new PyScriptIndex(indexData.Name,indexData.Script,indexData.Args,indexData); //脚本执行 var bindData=this.ChartPaint[0].Data; this.BindIndexData(windowIndex,bindData); //执行脚本 this.UpdataDataoffset(); //更新数据偏移 this.UpdateFrameMaxMin(); //调整坐标最大 最小值 this.Draw(); } this.AddOverlayIndex=function(obj) { var overlay=this.CreateOverlayWindowsIndex(obj); if (!overlay) return; var bindData=this.ChartPaint[0].Data; this.BindOverlayIndexData(overlay,obj.WindowIndex,bindData); this.UpdataDataoffset(); //更新数据偏移 this.UpdateFrameMaxMin(); //调整坐标最大 最小值 this.Draw(); } //创建一个叠加指标 this.CreateOverlayWindowsIndex=function(obj) // {WindowIndex:, IndexName:, Identify:, ShowRightText:} { let indexName=obj.IndexName; let windowIndex=obj.WindowIndex; let scriptData = new JSIndexScript(); let indexInfo = scriptData.Get(indexName); //系统指标 if (!indexInfo) { var indexCustom=JSIndexMap.Get(indexName); //定制指标 if (!indexCustom) { console.warn(`[KLineChartContainer::CreateOverlayIndex] can not find index[${indexName}]`); return null; } } var subFrame=this.Frame.SubFrame[windowIndex]; subFrame.Interval=this.OverlayIndexFrameWidth; var overlayFrame=new OverlayIndexItem(); if (obj.Identify) overlayFrame.Identify=obj.Identify; //由外部指定id var frame= this.ClassName==='KLineChartHScreenContainer' ? new OverlayKLineHScreenFrame() : new OverlayKLineFrame(); frame.Canvas=this.Canvas; frame.MainFrame=subFrame.Frame; frame.ChartBorder=subFrame.Frame.ChartBorder; if (obj.ShowRightText===true) frame.IsShow=true; else if (obj.ShowRightText===false) frame.IsShow=false; frame.YSplitOperator=new FrameSplitY(); frame.YSplitOperator.LanguageID=this.LanguageID; frame.YSplitOperator.FrameSplitData=this.FrameSplitData.get('double'); frame.YSplitOperator.Frame=frame; frame.YSplitOperator.ChartBorder=frame.ChartBorder; frame.YSplitOperator.SplitCount=subFrame.Frame.YSplitOperator.SplitCount; overlayFrame.Frame=frame; if (indexInfo) { let indexData = { Name:indexInfo.Name, Script:indexInfo.Script, Args: indexInfo.Args, ID:indexName , //扩展属性 可以是空 KLineType:indexInfo.KLineType, YSpecificMaxMin:indexInfo.YSpecificMaxMin, YSplitScale:indexInfo.YSplitScale, FloatPrecision:indexInfo.FloatPrecision, Condition:indexInfo.Condition, }; var scriptIndex=new OverlayScriptIndex(indexData.Name,indexData.Script,indexData.Args,indexData); //脚本执行 scriptIndex.OverlayIndex={ IsOverlay:true, Identify:overlayFrame.Identify, WindowIndex:windowIndex, Frame:overlayFrame }; //叠加指标信息 overlayFrame.Script=scriptIndex; } else { var scriptIndex=indexCustom.Create(); scriptIndex.OverlayIndex={ IsOverlay:true, Identify:overlayFrame.Identify, WindowIndex:windowIndex, Frame:overlayFrame }; //叠加指标信息 scriptIndex.Create(this,windowIndex); overlayFrame.Script=scriptIndex; } subFrame.OverlayIndex.push(overlayFrame); return overlayFrame; } this.DeleteOverlayWindowsIndex=function(identify) //删除叠加指标 { var findIndex=null; for(var i in this.Frame.SubFrame) { var item=this.Frame.SubFrame[i]; for(var j in item.OverlayIndex) { var overlayItem=item.OverlayIndex[j]; if (overlayItem.Identify===identify) { item.OverlayIndex.splice(j, 1); findIndex=parseInt(i); break; } } } if (findIndex==null) { console.warn(`[KLineChartContainer::DeleteOverlayWindowsIndex] can't find overlay index. [identify=${identify}]`); return; } var windowsIndex=findIndex+1; var titlePaint=this.TitlePaint[windowsIndex]; if (titlePaint.OverlayIndex.has(identify)) titlePaint.OverlayIndex.delete(identify); this.Draw(); } this.ChangeKLineDrawType=function(drawType) { if (this.KLineDrawType==drawType) return; this.KLineDrawType=drawType; for(var i in this.ChartPaint) { var item=this.ChartPaint[i]; if (i==0) item.DrawType=this.KLineDrawType; else if (item.ClassName=='ChartVolStick') item.KLineDrawType=this.KLineDrawType } for(var i in this.OverlayChartPaint) //叠加K线样式修改 { var item=this.OverlayChartPaint[i]; item.DrawType=this.KLineDrawType; } this.Draw(); } //修改坐标类型 this.ChangeCoordinateType=function(type) { if (!this.Frame && !this.Frame.SubFrame) return; if (!this.Frame.SubFrame.length) return; if (type==2) //反转坐标 { this.Frame.SubFrame[0].Frame.CoordinateType=1; } else if(type==1) { this.Frame.SubFrame[0].Frame.YSplitOperator.CoordinateType=type; } else if (type==0) { this.Frame.SubFrame[0].Frame.CoordinateType=0; this.Frame.SubFrame[0].Frame.YSplitOperator.CoordinateType=0; } else { return; } this.UpdateFrameMaxMin(); //调整坐标最大 最小值 this.Frame.SetSizeChage(true); this.Draw(); } //设置指标窗口个数 this.ChangeIndexWindowCount=function(count) { if (count<=0) return; if (this.Frame.SubFrame.length==count) return; var currentLength=this.Frame.SubFrame.length; if (currentLength>count) { for(var i=currentLength-1;i>=count;--i) { this.DeleteIndexPaint(i); this.Frame.SubFrame[i].Frame.ClearToolbar(); } this.Frame.SubFrame.splice(count,currentLength-count); this.WindowIndex.splice(count,currentLength-count); //最后一个显示X轴坐标 for(var i=0;icount) { for(var i=currentLength-1;i>=count;--i) { this.Frame.SubFrame[i].Frame.ClearToolbar(); } this.Frame.SubFrame.splice(count,currentLength-count); this.WindowIndex.splice(count,currentLength-count); } else { for(var i=currentLength;i=this.Frame.SubFrame.length) return; var delFrame=this.Frame.SubFrame[id].Frame; this.DeleteIndexPaint(id); this.Frame.SubFrame[id].Frame.ClearToolbar(); this.Frame.SubFrame.splice(id,1); this.WindowIndex.splice(id,1); this.TitlePaint.splice(id+1,1); //删除对应的动态标题 for(var i=0;i0) { var aryDrawPicture=[]; for(var i in this.ChartDrawPicture) { var item=this.ChartDrawPicture[i]; if (item.Frame==delFrame) continue; aryDrawPicture.push(item); } this.ChartDrawPicture=aryDrawPicture; } this.Frame.SetSizeChage(true); this.UpdateFrameMaxMin(); this.ResetFrameXYSplit(); this.Draw(); } //获取当前的显示的指标 this.GetIndexInfo=function() { var aryIndex=[]; for(var i in this.WindowIndex) { var item=this.WindowIndex[i]; var info={Name:item.Name}; if (item.ID) info.ID=item.ID; aryIndex.push(info); } return aryIndex; } this.CreateExtendChart=function(name, option) //创建扩展图形 { var chart; switch(name) { case '筹码分布': chart=new StockChip(); chart.Canvas=this.Canvas; chart.ChartBorder=this.Frame.ChartBorder; chart.ChartFrame=this.Frame; chart.HQChart=this; chart.Left=this.Frame.ChartBorder.Right; //左边间距使用当前框架间距 chart.SetOption(option); this.ExtendChartPaint.push(chart); this.Frame.ChartBorder.Right+=chart.Width; //创建筹码需要增加右边的间距 return chart; case '画图工具': chart=new DrawToolsButton(); chart.Canvas=this.Canvas; chart.ChartBorder=this.Frame.ChartBorder; chart.ChartFrame=this.Frame; chart.HQChart=this; chart.Left=this.Frame.ChartBorder.Right; //左边间距使用当前框架间距 chart.SetOption(option); this.ExtendChartPaint.push(chart); this.Frame.ChartBorder.Right+=chart.Width; //创建筹码需要增加右边的间距 return chart; case 'KLineTooltip': chart=new KLineTooltipPaint(); chart.Canvas=this.Canvas; chart.ChartBorder=this.Frame.ChartBorder; chart.ChartFrame=this.Frame; chart.HQChart=this; option.LanguageID=this.LanguageID; chart.SetOption(option); this.ExtendChartPaint.push(chart); return chart; default: return null; } } this.OnTouchFinished=function() { if (this.CorssCursorTouchEnd===true) //手势离开十字光标消失 { if (this.TouchDrawCount>0) this.DrawDynamicInfo(); return; } for(var i in this.ExtendChartPaint) { var item=this.ExtendChartPaint[i]; if (item.ClassName==='KLineTooltipPaint') { this.DrawDynamicInfo(); } } } this.GetExtendChartByClassName=function(name) { for(var i in this.ExtendChartPaint) { var item=this.ExtendChartPaint[i]; if (item.ClassName==name) return { Index:i, Chart:item }; } return null } this.DeleteExtendChart=function(data) { if (data.Index>=this.ExtendChartPaint.length) return; if (this.ExtendChartPaint[data.Index]!=data.Chart) return; if (typeof(data.Chart.Clear)=='function') data.Chart.Clear(); this.ExtendChartPaint.splice(data.Index,1); } //锁|解锁指标 { Index:指标名字,IsLocked:是否要锁上,Callback:回调 } this.LockIndex=function(lockData) { if (!lockData) return; if (!lockData.IndexName) return; for(let i in this.WindowIndex) { let item=this.WindowIndex[i]; if (!item) conintue; if (item.Name==lockData.IndexName) { item.SetLock(lockData); this.Update(); break; } } } this.TryClickLock=function(x,y) { for(let i in this.Frame.SubFrame) { var item=this.Frame.SubFrame[i]; if (!item.Frame.IsLocked) continue; if (!item.Frame.LockPaint) continue; var tooltip=new TooltipData(); if (!item.Frame.LockPaint.GetTooltipData(x,y,tooltip)) continue; tooltip.HQChart=this; if (tooltip.Data.Callback) tooltip.Data.Callback(tooltip); return true; } return false; } this.SetSizeChage=function(bChanged) { this.Frame.SetSizeChage(bChanged); for(var i in this.ExtendChartPaint) { var item=this.ExtendChartPaint[i]; item.SizeChange=bChanged; } } this.Update=function() { if (!this.SourceData) return; var bindData=new ChartData(); bindData.Data=this.SourceData.Data; bindData.Period=this.Period; bindData.Right=this.Right; bindData.DataType=this.SourceData.DataType; bindData.Symbol=this.Symbol; if (bindData.Right>0 && ChartData.IsDayPeriod(bindData.Period,true)) //复权(日线数据才复权) { var rightData=bindData.GetRightDate(bindData.Right); bindData.Data=rightData; } if (ChartData.IsDayPeriod(bindData.Period,false) || ChartData.IsMinutePeriod(bindData.Period,false)) //周期数据 (0= 日线,4=1分钟线 不需要处理) { var periodData=bindData.GetPeriodData(bindData.Period); bindData.Data=periodData; } //绑定数据 this.BindMainData(bindData,this.PageSize); for(var i=0; i0 && MARKET_SUFFIX_NAME.IsSHSZStockA(item.Symbol)) //复权数据 { var rightData=bindData.GetRightDate(bindData.Right); bindData.Data=rightData; } var aryOverlayData=this.SourceData.GetOverlayData(bindData.Data); //和主图数据拟合以后的数据 bindData.Data=aryOverlayData; if (ChartData.IsDayPeriod(bindData.Period,false)) //周期数据 { var periodData=bindData.GetPeriodData(bindData.Period); bindData.Data=periodData; } item.Data=bindData; } } this.ReqeustKLineInfoData(); this.CreateChartDrawPictureByStorage(); //创建画图工具 //刷新画图 this.UpdataDataoffset(); //更新数据偏移 this.UpdatePointByCursorIndex(); //更新十字光标位子 this.UpdateFrameMaxMin(); //调整坐标最大 最小值 this.Frame.SetSizeChage(true); this.Draw(); //叠加指标 for(var i=0;i0) { var klinePaint=this.ChartPaint[0]; klinePaint.InfoData=new Map(); } //信息地雷信息 for(var i in this.ChartInfo) { this.ChartInfo[i].RequestData(this); } } //设置K线信息地雷 this.SetKLineInfo=function(aryInfo,bUpdate) { this.ChartInfo=[]; //先清空 for(var i in aryInfo) { var infoItem=JSKLineInfoMap.Get(aryInfo[i]); if (!infoItem) continue; var item=infoItem.Create(); item.MaxReqeustDataCount=this.MaxReqeustDataCount; this.ChartInfo.push(item); } if (bUpdate==true) this.ReqeustKLineInfoData(); } //添加信息地雷 this.AddKLineInfo=function(infoName,bUpdate) { var classInfo=JSKLineInfoMap.GetClassInfo(infoName); if (!classInfo) { console.warn("[KLineChartContainer::AddKLineInfo] can't find infoname=", infoName); return; } for(var i in this.ChartInfo) { var item=this.ChartInfo[i]; if (item.ClassName==classInfo.ClassName) //已经存在 return; } var infoItem=JSKLineInfoMap.Get(infoName); if (!infoItem) return; var item=infoItem.Create(); item.MaxReqeustDataCount=this.MaxReqeustDataCount; this.ChartInfo.push(item); if (bUpdate==true) { item.RequestData(this); //信息地雷信息 } } //删除信息地理 this.DeleteKLineInfo=function(infoName) { var classInfo=JSKLineInfoMap.GetClassInfo(infoName); if (!classInfo) { console.warn("[KLineChartContainer::DeleteKLineInfo] can't find infoname=", infoName); return; } for(var i in this.ChartInfo) { var item=this.ChartInfo[i]; if (item.ClassName==classInfo.ClassName) { this.ChartInfo.splice(i,1); this.UpdataChartInfo(); this.Draw(); break; } } } //清空所有的信息地理 this.ClearKLineInfo=function() { if (!this.ChartInfo || this.ChartInfo.length<=0) return; this.ChartInfo=[]; var klinePaint=this.ChartPaint[0]; klinePaint.InfoData=null; this.Draw(); } //增加叠加股票 只支持日线数据 this.OverlaySymbol=function(symbol,option) { for(var i in this.OverlayChartPaint) { var item=this.OverlayChartPaint[i]; if (item.Symbol===symbol) { console.warn(`[KLineChartContainer::OverlaySymbol] overlay symbol=${symbol} exist.`) return false; } } var paint=new ChartOverlayKLine(); paint.Canvas=this.Canvas; paint.ChartBorder=this.Frame.SubFrame[0].Frame.ChartBorder; paint.ChartFrame=this.Frame.SubFrame[0].Frame; paint.Name="Overlay-KLine"; paint.DrawType=this.KLineDrawType; paint.Symbol=symbol; paint.Color=g_JSChartResource.OverlaySymbol.Color[g_JSChartResource.OverlaySymbol.Random%g_JSChartResource.OverlaySymbol.Color.length]; paint.SetOption(option); ++g_JSChartResource.OverlaySymbol.Random; if (this.ChartPaint[0] && this.ChartPaint[0].Data && this.SourceData) paint.MainData=this.ChartPaint[0].Data; //绑定主图数据 this.OverlayChartPaint.push(paint); if (ChartData.IsDayPeriod(this.Period, true)) this.RequestOverlayHistoryData(); //请求日线数据 else if (ChartData.IsMinutePeriod(this.Period,true)) this.RequestOverlayHistoryMinuteData(); //请求分钟历史数据 return true; } this.RequestOverlayHistoryData=function() { if (!this.OverlayChartPaint.length) return; if (!this.SourceData || !this.SourceData.Data) return; //主图数据还没有到完 var self = this; var dataCount=this.GetRequestDataCount(); var firstDate=this.SourceData.Data[0].Date; for(var i in this.OverlayChartPaint) { let item=this.OverlayChartPaint[i]; if (!item.MainData) continue; //等待主图股票数据未下载完 if (item.Status!=OVERLAY_STATUS_ID.STATUS_NONE_ID) continue; let symbol=item.Symbol; if (!symbol) continue; item.Status=OVERLAY_STATUS_ID.STATUS_REQUESTDATA_ID; if (this.NetworkFilter) { var obj= { Name:'KLineChartContainer::RequestOverlayHistoryData', //类名:: Explain:'叠加股票日K线数据', Request:{ Url:self.KLineApiUrl, Data: { symbol: symbol, count: dataCount.MaxRequestDataCount,"first":{ date: firstDate }, field:["name","symbol","yclose","open","price","high",'vol','amount'] }, Type:'POST' }, Self:this, PreventDefault:false }; this.NetworkFilter(obj, function(data) { item.Status=OVERLAY_STATUS_ID.STATUS_RECVDATA_ID; self.RecvOverlayHistoryData(data,item); }); if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求 } //请求数据 JSNetwork.HttpRequest({ url: this.KLineApiUrl, data: { "field": ["name","symbol","yclose","open","price","high"], "symbol": symbol, "start": -1, "count": dataCount.MaxRequestDataCount }, type:"post", dataType: "json", async:true, success: function (data) { item.Status=OVERLAY_STATUS_ID.STATUS_RECVDATA_ID; self.RecvOverlayHistoryData(data,item); } }); } } this.RecvOverlayHistoryData=function(data,paint) { if (paint.IsDelete) return; var aryDayData=KLineChartContainer.JsonDataToHistoryData(data); //原始叠加数据 var sourceData=new ChartData(); sourceData.Data=aryDayData; sourceData.DataType=0; var bindData=new ChartData(); bindData.Data=aryDayData; bindData.Period=this.Period; bindData.Right=this.Right; bindData.DataType=0; if (bindData.Right>0 && MARKET_SUFFIX_NAME.IsSHSZStockA(data.symbol)) //复权数据 ,A股才有有复权 { var rightData=bindData.GetRightDate(bindData.Right); bindData.Data=rightData; } var aryOverlayData=this.SourceData.GetOverlayData(bindData.Data); //和主图数据拟合以后的数据 bindData.Data=aryOverlayData; if (ChartData.IsDayPeriod(bindData.Period,false)) //周期数据 { var periodData=bindData.GetPeriodData(bindData.Period); bindData.Data=periodData; } paint.Data=bindData; paint.SourceData=sourceData; paint.Title=data.name; paint.Symbol=data.symbol; paint.Status=OVERLAY_STATUS_ID.STATUS_FINISHED_ID; this.Frame.SubFrame[0].Frame.YSplitOperator.CoordinateType=1; //调整为百份比坐标 this.UpdataDataoffset(); //更新数据偏移 this.UpdateFrameMaxMin(); //调整坐标最大 最小值 this.Frame.SetSizeChage(true); this.Draw(); } this.RequestOverlayHistoryMinuteData=function() { if (!this.OverlayChartPaint.length) return; if (!this.SourceData || !this.SourceData.Data) return; //主图数据还没有到完 var self = this; var dataCount=this.GetRequestDataCount(); var firstDate=this.SourceData.Data[0].Date; var firstTime=this.SourceData.Data[0].Time; for(var i in this.OverlayChartPaint) { let item=this.OverlayChartPaint[i]; if (!item.MainData) continue; //等待主图股票数据未下载完 if (item.Status!=OVERLAY_STATUS_ID.STATUS_NONE_ID) continue; let symbol=item.Symbol; if (!symbol) continue; item.Status=OVERLAY_STATUS_ID.STATUS_REQUESTDATA_ID; if (this.NetworkFilter) { var obj= { Name:'KLineChartContainer::RequestOverlayHistoryMinuteData', //类名:: Explain:'叠加股票分钟K线数据', Request:{ Url:self.MinuteKLineApiUrl, Data: { symbol: symbol, count: dataCount.MaxRequestMinuteDayCount,"first":{ date: firstDate, time:firstTime }, field:["name","symbol","yclose","open","price","high",'vol','amount'] }, Type:'POST' }, Self:this, PreventDefault:false }; this.NetworkFilter(obj, function(data) { item.Status=OVERLAY_STATUS_ID.STATUS_RECVDATA_ID; self.RecvOveralyHistoryMinuteData(data,item); }); if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求 } //请求数据 JSNetwork.HttpRequest({ url: this.MinuteKLineApiUrl, data: { "field": ["name","symbol","yclose","open","price","high",'vol','amount'], "symbol": symbol, "start": -1, "count": dataCount.MaxRequestMinuteDayCount }, type:"post", dataType: "json", async:true, success: function (data) { item.Status=OVERLAY_STATUS_ID.STATUS_RECVDATA_ID; self.RecvOveralyHistoryMinuteData(data,item); } }); } } this.RecvOveralyHistoryMinuteData=function(data,paint) { var aryDayData=KLineChartContainer.JsonDataToMinuteHistoryData(data); if (!aryDayData) return; //原始叠加数据 var sourceData=new ChartData(); sourceData.Data=aryDayData; sourceData.DataType=1; //0=日线数据 1=分钟数据 var bindData=new ChartData(); bindData.Data=aryDayData; bindData.Period=this.Period; bindData.Right=this.Right; bindData.DataType=1; var aryOverlayData=this.SourceData.GetOverlayMinuteData(bindData.Data); //和主图数据拟合以后的数据 bindData.Data=aryOverlayData; if (ChartData.IsMinutePeriod(bindData.Period,false)) //周期数据 { var periodData=bindData.GetPeriodData(bindData.Period); bindData.Data=periodData; } paint.Data=bindData; paint.SourceData=sourceData; paint.Title=data.name; paint.Symbol=data.symbol; paint.Status=OVERLAY_STATUS_ID.STATUS_FINISHED_ID; //数据下载完成 this.Frame.SubFrame[0].Frame.YSplitOperator.CoordinateType=1; //调整为百份比坐标 this.UpdataDataoffset(); //更新数据偏移 this.UpdateFrameMaxMin(); //调整坐标最大 最小值 this.Frame.SetSizeChage(true); this.Draw(); } this.ResetOverlaySymbolStatus=function() { for(var i in this.OverlayChartPaint) { var item=this.OverlayChartPaint[i]; item.Status=OVERLAY_STATUS_ID.STATUS_NONE_ID; } } //取消叠加股票 this.ClearOverlaySymbol=function() { for(var i in this.OverlayChartPaint) { var item=this.OverlayChartPaint[i]; item.IsDelete=true; } this.OverlayChartPaint=[]; this.TitlePaint[0].OverlayChartPaint=this.OverlayChartPaint; //绑定叠加 this.Frame.SubFrame[0].Frame.YSplitOperator.CoordinateType=0; //调整一般坐标 this.UpdateFrameMaxMin(); this.Draw(); } //删除一个叠加股票 this.DeleteOverlaySymbol=function(symbol) { for(var i in this.OverlayChartPaint) { var item=this.OverlayChartPaint[i]; if (item.Symbol===symbol) { item.IsDelete=true; this.OverlayChartPaint.splice(i,1); if (this.OverlayChartPaint.length<=0) this.Frame.SubFrame[0].Frame.YSplitOperator.CoordinateType=0; //调整一般坐标 this.UpdateFrameMaxMin(); this.Draw(); return true; } } console.warn(`[KLineChartContainer::DeleteOverlaySymbol] overlay symbol=${symbol} not exist.`) return false; } this.RequestFlowCapitalData=function() { if (!this.Symbol) return; if (this.FlowCapitalReady==true) return; if (MARKET_SUFFIX_NAME.IsBIT(this.Symbol)) //数字货币不需要下载流通股本 { console.log(`[KLineChartContainer::RequestFlowCapitalData] symbol=${this.Symbol} not need download data.`); this.FlowCapitalReady=true; return; } var self = this; let fieldList=["name","date","symbol","capital.a"]; if (this.NetworkFilter) { var obj= { Name:'KLineChartContainer::RequestFlowCapitalData', //类名:: Explain:'流通股本数据', Request:{ Url:self.StockHistoryDayApiUrl, Data: { symbol: [this.Symbol], orderfield:'date',field:fieldList }, Type:'POST' }, Self:this, PreventDefault:false }; this.NetworkFilter(obj, function(data) { self.RecvFlowCapitalData(data); }); if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求 } //请求数据 JSNetwork.HttpRequest({ url: this.StockHistoryDayApiUrl, data: { "field": fieldList, "symbol": [this.Symbol], "orderfield":"date" }, type:"post", dataType: "json", async:true, success: function (recvData) { self.RecvFlowCapitalData(recvData); } }); } this.RecvFlowCapitalData=function(data) { if (!data.stock || data.stock.length!=1) return; let stock=data.stock[0]; var aryData=new Array(); for(let i in stock.stockday) { var item=stock.stockday[i]; let indexData=new SingleData(); indexData.Date=item.date; var financeData=item.capital; if (!financeData) continue; if (financeData.a>0) { indexData.Value=financeData.a; //流通股本(股) aryData.push(indexData); } } if (ChartData.IsMinutePeriod(this.Period,true)) //分钟数据 { var aryFixedData=this.SourceData.GetMinuteFittingFinanceData(aryData); for(let i in this.SourceData.Data) { var item=this.SourceData.Data[i]; item.FlowCapital=aryFixedData[i].Value; } var bindData=this.ChartPaint[0].Data; var newBindData=new ChartData(); newBindData.Data=this.SourceData.Data; if (ChartData.IsMinutePeriod(bindData.Period,false)) //周期数据 { var periodData=newBindData.GetPeriodData(bindData.Period); newBindData.Data=periodData; } bindData.Data=newBindData.Data; } else { var aryFixedData=this.SourceData.GetFittingFinanceData(aryData); for(let i in this.SourceData.Data) { var item=this.SourceData.Data[i]; item.FlowCapital=aryFixedData[i].Value; } var bindData=this.ChartPaint[0].Data; var newBindData=new ChartData(); newBindData.Data=this.SourceData.Data; if (bindData.Right>0) //复权 { var rightData=newBindData.GetRightDate(bindData.Right); newBindData.Data=rightData; } if (ChartData.IsDayPeriod(bindData.Period,false)) //周期数据 { var periodData=newBindData.GetPeriodData(bindData.Period); newBindData.Data=periodData; } bindData.Data=newBindData.Data; } this.FlowCapitalReady=true; var bDraw=false; for(var i in this.ExtendChartPaint) { var item=this.ExtendChartPaint[i]; if (item.ClassName=='StockChip') { bDraw=true; break; } } if (bDraw) this.Draw(); } //创建画图工具 this.CreateChartDrawPicture=function(name, callback) { var drawPicture=null; switch(name) { case "线段": drawPicture=new ChartDrawPictureLine(); break; case "射线": drawPicture=new ChartDrawPictureHaflLine(); break; case '水平线': drawPicture=new ChartDrawPictureHorizontalLine(); break; case '趋势线': drawPicture=new ChartDrawPictureTrendLine(); break; case "矩形": drawPicture=new ChartDrawPictureRect(); break; case "圆弧线": drawPicture=new ChartDrawPictureArc(); break; case 'M头W底': drawPicture=new ChartDrawPictureWaveMW(); break; case '平行线': drawPicture=new ChartDrawPictureParallelLines(); break; case '平行通道': drawPicture=new ChartDrawPictureParallelChannel(); break; case '价格通道线': drawPicture=new ChartDrawPicturePriceChannel(); break; case '文本': drawPicture=new ChartDrawPictureText(); drawPicture.HQChart=this; break; case '江恩角度线': drawPicture=new ChartDrawPictureGannFan(); break; case '阻速线': drawPicture=new ChartDrawPictureResistanceLine() break; case '黄金分割': drawPicture=new ChartDrawPictureGoldenSection() break; case '百分比线': drawPicture=new ChartDrawPicturePercentage(); break; case '波段线': drawPicture=new ChartDrawPictureWaveBand(); break; case '三角形': drawPicture=new ChartDrawPictureTriangle(); break; case '对称角度': drawPicture=new ChartDrawPictureSymmetryAngle(); break; case '圆': drawPicture=new ChartDrawPictureCircle(); break; case '平行四边形': drawPicture=new ChartDrawPictureQuadrangle(); break; case '斐波那契周期线': drawPicture=new ChartDrawPictureFibonacci(); break; default: { //iconfont 图标 const ICONFONT_LIST=new Map( [ ["icon-arrow_up", { Text:'\ue683', Color:'#318757'}], ["icon-arrow_down", { Text:'\ue681', Color:'#db563e'}], ["icon-arrow_right", { Text:'\ue680', Color:'#318757'}], ["icon-arrow_left", { Text:'\ue682', Color:'#318757'}], ] ); if (ICONFONT_LIST.has(name)) { var item=ICONFONT_LIST.get(name); drawPicture=new ChartDrawPictureIconFont(); drawPicture.FontOption.Family='iconfont'; drawPicture.Text=item.Text; if (item.Color) drawPicture.LineColor=item.Color; break; } } return false; } drawPicture.Canvas=this.Canvas; drawPicture.Status=0; drawPicture.Symbol=this.Symbol; drawPicture.Period=this.Period; if (callback) drawPicture.FinishedCallback=callback; //完成通知上层回调 self=this; drawPicture.Update=function() //更新回调函数 { self.DrawDynamicInfo(); }; this.CurrentChartDrawPicture=drawPicture; //console.log("[KLineChartContainer::CreateChartDrawPicture] ", name,this.CurrentChartDrawPicture); return true; } this.SetChartDrawPictureFirstPoint=function(x,y) { var drawPicture=this.CurrentChartDrawPicture; if (!drawPicture) return false; if (!this.Frame.SubFrame || this.Frame.SubFrame.length<=0) return false; //相对坐标 var xFixed=x-this.UIElement.getBoundingClientRect().left; var yFixed=y-this.UIElement.getBoundingClientRect().top; for(var i in this.Frame.SubFrame) { var frame=this.Frame.SubFrame[i].Frame; var left=frame.ChartBorder.GetLeft(); var top=frame.ChartBorder.GetTopEx(); var height=frame.ChartBorder.GetHeight(); var width=frame.ChartBorder.GetWidth(); this.Canvas.beginPath(); this.Canvas.rect(left,top,width,height); if (this.Canvas.isPointInPath(xFixed,yFixed)) { drawPicture.Frame=frame; break; } } if (!drawPicture.Frame) return false; drawPicture.Point[0]=new Point(); drawPicture.Point[0].X=x-this.UIElement.getBoundingClientRect().left; drawPicture.Point[0].Y=y-this.UIElement.getBoundingClientRect().top; drawPicture.Status=1; //第1个点完成 } this.SetChartDrawPictureSecondPoint=function(x,y) { var drawPicture=this.CurrentChartDrawPicture; if (!drawPicture) return false; drawPicture.Point[1]=new Point(); drawPicture.Point[1].X=x-this.UIElement.getBoundingClientRect().left; drawPicture.Point[1].Y=y-this.UIElement.getBoundingClientRect().top; drawPicture.Status=2; //设置第2个点 } //设置第3个点 this.SetChartDrawPictureThirdPoint=function(x,y) { var drawPicture=this.CurrentChartDrawPicture; if (!drawPicture) return false; drawPicture.Point[2]=new Point(); drawPicture.Point[2].X=x-this.UIElement.getBoundingClientRect().left; drawPicture.Point[2].Y=y-this.UIElement.getBoundingClientRect().top; drawPicture.Status=3; //设置第3个点 } //xStep,yStep 移动的偏移量 this.MoveChartDrawPicture=function(xStep,yStep) { var drawPicture=this.CurrentChartDrawPicture; if (!drawPicture) return false; //console.log("xStep="+xStep+" yStep="+yStep); drawPicture.Move(xStep,yStep); return true; } this.FinishChartDrawPicturePoint=function() { var drawPicture=this.CurrentChartDrawPicture; if (!drawPicture) return false; if (drawPicture.PointCount!=drawPicture.Point.length) return false; drawPicture.Status=10; //完成 drawPicture.PointToValue(); this.ChartDrawPicture.push(drawPicture); this.CurrentChartDrawPicture=null; //通知上层画好了 if (drawPicture.FinishedCallback) drawPicture.FinishedCallback(drawPicture); if (this.ChartDrawStorage) this.ChartDrawStorage.SaveDrawData(drawPicture); return true; } //注册鼠标右键事件 this.OnRightMenu=function(x,y,e) { if (this.RightMenu) { var frameId=this.Frame.PtInFrame(x,y); e.data={ Chart:this, FrameID:frameId }; this.RightMenu.DoModal(e); } var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_CONTEXT_MENU); if (event) { var frameId=this.Frame.PtInFrame(x,y); var data={ X:x, Y:y, Event:e, FrameID:frameId }; event.Callback(event,data,this); } } this.FinishMoveChartDrawPicture=function() { var drawPicture=this.CurrentChartDrawPicture; if (!drawPicture) return false; if (drawPicture.PointCount!=drawPicture.Point.length) return false; drawPicture.Status=10; //完成 drawPicture.PointToValue(); if (this.ChartDrawStorage) this.ChartDrawStorage.SaveDrawData(drawPicture); this.CurrentChartDrawPicture=null; return true; } //清空所有的画线工具 this.ClearChartDrawPicture=function(drawPicture) { if (!drawPicture) { this.ChartDrawPicture=[]; if (this.ChartDrawStorage) this.ChartDrawStorage.Clear(); this.Draw(); } else { for(var i in this.ChartDrawPicture) { if (this.ChartDrawPicture[i]==drawPicture) { if (this.ChartDrawStorage) this.ChartDrawStorage.DeleteDrawData(drawPicture); this.ChartDrawPicture.splice(i,1); this.Draw(); } } } } //重新加载画图工具(切换股票|周期) this.ReloadChartDrawPicture=function() { this.ChartDrawPicture=[]; this.ChartDrawStorageCache; if (this.ChartDrawStorage) { this.ChartDrawStorageCache=this.ChartDrawStorage.GetDrawData( {Symbol:this.Symbol, Period:this.Period} ); } } this.CreateChartDrawPictureByStorage=function() //把缓存(this.ChartDrawStorageCache) 画图工具创建出来 { if (!this.ChartDrawStorageCache || this.ChartDrawStorageCache.length<=0) return; for(var i in this.ChartDrawStorageCache) { var item=this.ChartDrawStorageCache[i]; if (item.FrameID<0 || !this.Frame.SubFrame || this.Frame.SubFrame.length=0; --info.TempID) //信息地雷是倒叙排的 { var infoItem=infoData[info.TempID]; if (infoItem.Date>kItem.Date) break; //信息地雷日期0) //复权 { var rightData=bindData.GetRightDate(bindData.Right); bindData.Data=rightData; } if (ChartData.IsDayPeriod(bindData.Period,false) || ChartData.IsMinutePeriod(bindData.Period,false)) //周期数据 { var periodData=bindData.GetPeriodData(bindData.Period); bindData.Data=periodData; } if (typeof(this.WindowIndex[index].ExecuteScript)=='function') { var hisData=this.ChartPaint[0].Data; this.WindowIndex[index].ExecuteScript(this,index,hisData); } else { this.WindowIndex[index].BindData(this,index,bindData); } this.UpdataDataoffset(); //更新数据偏移 this.UpdateFrameMaxMin(); //调整坐标最大 最小值 this.Draw(); } //修改参数指标 this.ChangeWindowIndexParam=function(index) { this.WindowIndex[index].Index[0].Param+=1; this.WindowIndex[index].Index[1].Param+=1; this.UpdateWindowIndex(index); } this.OnDoubleClick=function(x,y,e) { var event=null; if (this.mapEvent.has(JSCHART_EVENT_ID.DBCLICK_KLINE)) event=this.mapEvent.get(JSCHART_EVENT_ID.DBCLICK_KLINE); if (!this.MinuteDialog && !event) return; var tooltip=new TooltipData(); for(var i in this.ChartPaint) { var item=this.ChartPaint[i]; if (item.GetTooltipData(x,y,tooltip)) { break; } } if (!tooltip.Data) return; if (event) { var data={ Tooltip:tooltip, Stock:{Symbol:this.Symbol, Name:this.Name } } event.Callback(event,data,this); } if (this.MinuteDialog) { e.data={Chart:this,Tooltip:tooltip}; this.MinuteDialog.DoModal(e); } } //选中画图工具 出现单个图形设置菜单 this.OnSelectChartPicture=function(chart) { console.log('[KLineChartContainer::OnSelectChartPicture',chart); if (!this.ChartPictureMenu) this.ChartPictureMenu=new ChartPictureSettingMenu(this.UIElement.parentNode); var event={ data: { ChartPicture:chart, HQChart:this}}; this.ChartPictureMenu.DoModal(event); } this.CancelAutoUpdate=function() //关闭停止更新 { if (typeof (this.AutoUpdateTimer) == 'number') { clearTimeout(this.AutoUpdateTimer); this.AutoUpdateTimer = undefined; } } //数据自动更新 this.AutoUpdate=function(waitTime) //waitTime 更新时间 { this.CancelAutoUpdate(); if (!this.IsAutoUpdate) return; if (!this.Symbol) return; var self = this; var marketStatus=MARKET_SUFFIX_NAME.GetMarketStatus(this.Symbol); if (marketStatus==0 || marketStatus==3) return; //闭市,盘后 var frequency=this.AutoUpdateFrequency; if (marketStatus==1) //盘前 { setTimeout(function() { self.AutoUpdate(); },frequency); } else if (marketStatus==2) //盘中 { setTimeout(function() { if (ChartData.IsDayPeriod(self.Period,true)) { self.RequestRealtimeData(); //更新最新行情 //self.ReqeustKLineInfoData(); } else if (ChartData.IsMinutePeriod(self.Period,true)) { self.RequestMinuteRealtimeData(); //请求分钟数据 } else if (ChartData.IsTickPeriod(self.Period)) { self.RequestTickRealtimeData(); //请求最新分笔 } },frequency); } } this.GetMaxMinPageSize = function () { let pageSize={}; let width = this.Frame.ChartBorder.GetWidth(); let barWidth = (ZOOM_SEED[ZOOM_SEED.length - 1][0] + ZOOM_SEED[ZOOM_SEED.length - 1][1]); pageSize.Max=parseInt(width / barWidth) - 2; barWidth= (ZOOM_SEED[0][0] + ZOOM_SEED[0][1]); pageSize.Min=parseInt(width / barWidth) - 2; console.log(`[KLineChartContainer::GetMaxMinPageSize] Max=${pageSize.Max} Min=${pageSize.Min}`); return pageSize; } //获取图形控件的状态 this.GetChartStatus=function() { var subFrame=this.Frame.SubFrame[0].Frame; if (!subFrame) return null; var hisData=subFrame.Data; if (!hisData) return null; var status={ KLine:{ }, Zoom:{} }; status.KLine.Count=hisData.Data.length; status.KLine.Offset=hisData.DataOffset; status.KLine.PageSize=subFrame.XPointCount; status.Zoom.Index=subFrame.ZoomIndex; status.Zoom.Max=ZOOM_SEED.length; return status; } //数据拖拽下载 this.DragDownloadData=function() { var data=null; if (!this.Frame.Data) data=this.Frame.Data; else data=this.Frame.SubFrame[0].Frame.Data; if (!data) return false; if (data.DataOffset>0) return; if (ChartData.IsMinutePeriod(this.Period,true)) //下载分钟数据 { console.log(`[KLineChartContainer.DragDownloadData] Minute:[Enable=${this.DragDownload.Minute.Enable}, IsEnd=${this.DragDownload.Minute.IsEnd}, Status=${this.DragDownload.Minute.Status}]`); if (!this.DragDownload.Minute.Enable) return; if (this.DragDownload.Minute.IsEnd) return; //全部下载完了 if (this.DragDownload.Minute.Status!=0) return; this.RequestDragMinuteData(); } else if (ChartData.IsDayPeriod(this.Period,true)) { console.log(`[KLineChartContainer.DragDownloadData] Day:[Enable=${this.DragDownload.Minute.Enable}, IsEnd=${this.DragDownload.Minute.IsEnd}, Status=${this.DragDownload.Minute.Status}]`); if (!this.DragDownload.Day.Enable) return; if (this.DragDownload.Day.IsEnd) return; //全部下载完了 if (this.DragDownload.Day.Status!=0) return; this.RequestDragDayData(); } } this.RequestDragMinuteData=function() { var self=this; this.AutoUpdateEvent(false,'KLineChartContainer::RequestDragMinuteData'); //停止自动更新 this.CancelAutoUpdate(); var download=this.DragDownload.Minute; download.Status=1; var firstItem=this.SourceData.Data[0]; //最新的一条数据 var postData= { "field": ["name","symbol", "yclose","open","price","high","low","vol"], "symbol": self.Symbol, "enddate": firstItem.Date, "endtime" :firstItem.Time, "count": self.MaxRequestMinuteDayCount, "first":{ date: firstItem.Date, time:firstItem.Time } }; if (this.NetworkFilter) { var obj= { Name:'KLineChartContainer::RequestDragMinuteData', //类名::函数 Explain:'拖拽1分钟K线数据下载', Request:{ Url:this.DragMinuteKLineApiUrl, Type:'POST' , Data: postData }, DragDownload:download, Self:this, PreventDefault:false }; this.NetworkFilter(obj, function(data) { self.RecvDragMinuteData(data); download.Status=0; self.AutoUpdateEvent(true,'KLineChartContainer::RequestDragMinuteData'); //自动更新 self.AutoUpdate(); }); if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求 } JSNetwork.HttpRequest({ url: this.DragMinuteKLineApiUrl, data:postData, type:"post", dataType: "json", async:true, success: function(data) { self.RecvDragMinuteData(data); download.Status=0; self.AutoUpdateEvent(true,'KLineChartContainer::RequestDragMinuteData'); //自动更新 self.AutoUpdate(); } }); } this.RecvDragMinuteData=function(data) { var aryDayData=KLineChartContainer.JsonDataToMinuteHistoryData(data); var lastDataCount=this.GetHistoryDataCount(); //保存下上一次的数据个数 for(var i in aryDayData) //数据往前插 { var item=aryDayData[i]; this.SourceData.Data.splice(i,0,item); } var bindData=new ChartData(); bindData.Data=this.SourceData.Data; bindData.Period=this.Period; bindData.Right=this.Right; bindData.DataType=this.SourceData.DataType; bindData.Symbol=this.Symbol; if (ChartData.IsDayPeriod(bindData.Period,false) || ChartData.IsMinutePeriod(bindData.Period,false)) //周期数据 (0= 日线,4=1分钟线 不需要处理) { var periodData=bindData.GetPeriodData(bindData.Period); bindData.Data=periodData; } //绑定数据 this.UpdateMainData(bindData,lastDataCount); this.BindInstructionIndexData(bindData); //执行指示脚本 for(var i=0; i0) preClose=jsData.price; aryMinuteData[i]=item; } return aryMinuteData; } //API 返回数据 转化为array[] KLineChartContainer.JsonDataToMinuteHistoryData=function(data) { var upperSymbol=null; if (data.symbol) upperSymbol=data.symbol.toUpperCase(); var isSHSZ=false; if (upperSymbol) isSHSZ=MARKET_SUFFIX_NAME.IsSHSZ(upperSymbol); 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) { var item = new 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]; if (isSHSZ) item.Vol = list[i][vol]/100; //原始单位股 else 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(var 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(var 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; } KLineChartContainer.JsonDataToTickData=function(data) { /* 历史分笔数据格式 var aryDayData=[]; if (!data.deal || !data.day) return aryDayData; var time=data.deal.time; if (!time) return aryDayData; var date=data.date; var amount=data.deal.amount; var flag=data.deal.flag; var price=data.deal.price; var vol=data.deal.vol; var yClose=data.day.yclose; for(var i in time) { var item = new HistoryData(); item.Date = date; item.Low=item.High=item.Close=item.Open = price[i]; item.YClose = yClose; item.Vol = vol[i]; //原始单位股 item.Amount = amount[i]; item.Flag=flag[i]; item.Time=time[i]; if (isNaN(item.Open) || item.Open<=0) continue; //停牌的数据剔除 yClose=item.Close; aryDayData.push(item); } return aryDayData; */ var aryDayData=[]; if (!data.detail) return aryDayData; var date=data.date; var yClose=data.yclose; for(var i in data.detail) { var item = new HistoryData(); var tick=data.detail[i]; if (!tick) continue; item.Date = date; item.Time=tick[0]; item.Low=item.High=item.Close=item.Open = tick[1]; item.YClose = yClose; item.Vol = tick[2]; //原始单位股 item.Amount = tick[3]; item.Flag=tick[4]; if (isNaN(item.Open) || item.Open<=0) continue; //停牌的数据剔除 yClose=item.Close; aryDayData.push(item); } return aryDayData; } /////////////////////////////////////////////////////////////////////////////////////////// // 走势图 // function MinuteChartContainer(uielement) { this.newMethod=JSChartContainer; //派生 this.newMethod(uielement); delete this.newMethod; this.ClassName='MinuteChartContainer'; this.WindowIndex=new Array(); this.Symbol; this.Name; this.SourceData; //原始的历史数据 this.IsAutoUpdate=true; //是否自动更新行情数据 this.AutoUpdateFrequency=30000; //30秒更新一次数据 this.AutoUpdateTimer; //自动更新定时器 this.TradeDate=0; //行情交易日期 this.DayCount=1; //显示几天的数据 this.DayData; //多日分钟数据 this.LimitPrice; //涨停价格 { Max:null, Min:null }; this.IsShowBeforeData=false; //是否显示盘前数据 (当日) this.BeforeData=null; //盘前数据 this.IsBeforeData=false; //是否支持显示盘前数据 this.IsShowLead=true; //指数是否显示领先指标 this.MinuteApiUrl=g_JSChartResource.Domain+"/API/Stock"; this.HistoryMinuteApiUrl=g_JSChartResource.Domain+'/API/StockMinuteData'; //历史分钟数据 this.StopAutoUpdate=function() { this.CancelAutoUpdate(); if (!this.IsAutoUpdate) return; this.IsAutoUpdate=false; } //手机拖拽 uielement.ontouchstart=function(e) { if(!this.JSChartContainer) return; if(this.JSChartContainer.DragMode==0) return; this.JSChartContainer.IsOnTouch=true; this.JSChartContainer.PhonePinch=null; var jsChart=this.JSChartContainer; if (jsChart.EnableScrollUpDown==false) e.preventDefault(); //上下拖动图形不能阻止事件 if (jsChart.IsPhoneDragging(e)) { var drag= { "Click":{}, "LastMove":{}, //最后移动的位置 }; var touches=jsChart.GetToucheData(e,jsChart.IsForceLandscape); drag.Click.X=touches[0].clientX; drag.Click.Y=touches[0].clientY; drag.LastMove.X=touches[0].clientX; drag.LastMove.Y=touches[0].clientY; var self=this; var T_ShowCorssCursor=function() //临时函数(Temp_) T_开头 { if (jsChart.ChartCorssCursor.IsShow === true) //移动十字光标 { var pixelTatio = GetDevicePixelRatio(); var x = drag.Click.X-self.getBoundingClientRect().left*pixelTatio; var y = drag.Click.Y-self.getBoundingClientRect().top*pixelTatio; jsChart.OnMouseMove(x, y, e); } } if (jsChart.EnableScrollUpDown==true) { this.DragTimer=setTimeout(function() { if (drag.Click.X==drag.LastMove.X && drag.Click.Y==drag.LastMove.Y) { var mouseDrag=jsChart.MouseDrag; jsChart.MouseDrag=null; T_ShowCorssCursor(); jsChart.PreventTouchEvent(e) } }, 800); } this.JSChartContainer.MouseDrag=drag; document.JSChartContainer=this.JSChartContainer; this.JSChartContainer.SelectChartDrawPicture=null; if (jsChart.EnableScrollUpDown==false) T_ShowCorssCursor(); //移动十字光标 } uielement.ontouchmove=function(e) { if(!this.JSChartContainer) return; var touches=jsChart.GetToucheData(e,this.JSChartContainer.IsForceLandscape); if (jsChart.IsPhoneDragging(e)) { var drag=this.JSChartContainer.MouseDrag; if ((drag==null && jsChart.EnableScrollUpDown==true) || (drag && jsChart.EnableScrollUpDown==false)) { var pixelTatio = GetDevicePixelRatio(); var x = touches[0].clientX-this.getBoundingClientRect().left*pixelTatio; var y = touches[0].clientY-this.getBoundingClientRect().top*pixelTatio; this.JSChartContainer.OnMouseMove(x,y,e); } } if (jsChart.EnableScrollUpDown==false) { e.preventDefault(); } else { if (drag==null) { jsChart.PreventTouchEvent(e); //十字光标出来了,阻止消息 } else { clearTimeout(this.DragTimer); //上下推动图片,停止定时器,消息传递下去 this.DragTimer=null; } } }; uielement.ontouchend=function(e) { console.log('[MinuteChartContainer::uielement.ontouchend]',e); this.JSChartContainer.IsOnTouch = false; this.JSChartContainer.OnTouchFinished(); clearTimeout(this.DragTimer); } } //键盘左右移动十字光标 this.OnKeyDown=function(e) { var keyID = e.keyCode ? e.keyCode :e.which; switch(keyID) { case 37: //left this.CursorIndex=parseInt(this.CursorIndex); if (this.CursorIndex<=0.99999) { if (!this.DataMoveLeft()) break; this.UpdataDataoffset(); this.UpdatePointByCursorIndex(); this.UpdateFrameMaxMin(); this.Draw(); } else { --this.CursorIndex; this.UpdatePointByCursorIndex(); this.DrawDynamicInfo(); } break; case 39: //right var xPointcount=0; if (this.Frame.XPointCount) xPointcount=this.Frame.XPointCount; else xPointcount=this.Frame.SubFrame[0].Frame.XPointCount; this.CursorIndex=parseInt(this.CursorIndex); if (this.CursorIndex+1>=xPointcount) { if (!this.DataMoveRight()) break; this.UpdataDataoffset(); this.UpdatePointByCursorIndex(); this.UpdateFrameMaxMin(); this.Draw(); } else { //判断是否在最后一个数据上 var data=null; if (this.Frame.Data) data=this.Frame.Data; else data=this.Frame.SubFrame[0].Frame.Data; if (!data) break; if (this.CursorIndex+data.DataOffset+1>=data.Data.length) break; ++this.CursorIndex; this.UpdatePointByCursorIndex(); this.DrawDynamicInfo(); } break; default: return; } //不让滚动条滚动 if(e.preventDefault) e.preventDefault(); else e.returnValue = false; } //注册鼠标右键事件 this.OnRightMenu=function(x,y,e) { if (this.RightMenu) { var frameId=this.Frame.PtInFrame(x,y); e.data={ Chart:this, FrameID:frameId }; this.RightMenu.DoModal(e); } var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_CONTEXT_MENU); if (event) { var frameId=this.Frame.PtInFrame(x,y); var data={ X:x, Y:y, Event:e, FrameID:frameId }; event.Callback(event,data,this); } } this.UpdatePointByCursorIndex=function() { this.LastPoint.X=this.Frame.GetXFromIndex(this.CursorIndex); var index=this.CursorIndex; index=parseInt(index.toFixed(0)); var data=this.Frame.SourceData; if (data.DataOffset+index>=data.Data.length) { return; } var item=data.Data[data.DataOffset+index]; var close=null; if (item.Before) close=item.Before.Close; else close=item.Close this.LastPoint.Y=this.Frame.GetYFromData(close); } //创建 //windowCount 窗口个数 this.Create=function(windowCount) { this.UIElement.JSChartContainer=this; //创建十字光标 this.ChartCorssCursor=new ChartCorssCursor(); this.ChartCorssCursor.Canvas=this.Canvas; this.ChartCorssCursor.StringFormatX=new HQMinuteTimeStringFormat(); this.ChartCorssCursor.StringFormatY=new HQPriceStringFormat(); this.ChartCorssCursor.StringFormatY.LanguageID=this.LanguageID; //创建等待提示 this.ChartSplashPaint = new ChartSplashPaint(); this.ChartSplashPaint.Canvas = this.Canvas; //创建框架容器 this.Frame=new HQTradeFrame(); this.Frame.ChartBorder=new ChartBorder(); this.Frame.ChartBorder.UIElement=this.UIElement; this.Frame.ChartBorder.Top=25; this.Frame.ChartBorder.Left=50; this.Frame.ChartBorder.Bottom=20; this.Frame.Canvas=this.Canvas; this.ChartCorssCursor.Frame=this.Frame; //十字光标绑定框架 this.ChartSplashPaint.Frame = this.Frame; this.CreateChildWindow(windowCount); this.CreateMainKLine(); //子窗口动态标题 for(var i in this.Frame.SubFrame) { var titlePaint=new DynamicChartTitlePainting(); titlePaint.Frame=this.Frame.SubFrame[i].Frame; titlePaint.Canvas=this.Canvas; titlePaint.LanguageID=this.LanguageID; this.TitlePaint.push(titlePaint); } this.ChartCorssCursor.StringFormatX.Frame=this.Frame.SubFrame[0].Frame; this.UIElement.addEventListener("keydown", OnKeyDown, true); //键盘消息 } //创建子窗口 this.CreateChildWindow=function(windowCount) { for(var i=0;i=this.Frame.SubFrame.length) windowIndex=2; let indexData = { Name:indexInfo.Name, Script:indexInfo.Script, Args: indexInfo.Args, ID:indexName , //扩展属性 可以是空 KLineType:indexInfo.KLineType, YSpecificMaxMin:indexInfo.YSpecificMaxMin, YSplitScale:indexInfo.YSplitScale, FloatPrecision:indexInfo.FloatPrecision, Condition:indexInfo.Condition,StringFormat:indexInfo.StringFormat }; if (option) { if (option.FloatPrecision>=0) indexData.FloatPrecision=option.FloatPrecision; if (option.StringFormat>0) indexData.StringFormat=option.StringFormat; if (option.Args) indexData.Args=option.Args; } return this.ChangeScriptIndex(windowIndex, indexData); } //设置指标窗口个数 this.ChangeIndexWindowCount=function(count) { if (count<2) return; //1,2个窗口固定的不能动 if (this.Frame.SubFrame.length==count) return; var currentLength=this.Frame.SubFrame.length; if (currentLength>count) { for(var i=currentLength-1;i>=count;--i) { this.DeleteIndexPaint(i); var item=this.Frame.SubFrame[i].Frame; if (item.ClearToolbar) item.ClearToolbar(); } this.Frame.SubFrame.splice(count,currentLength-count); this.WindowIndex.splice(count,currentLength-count); } else { //创建新的指标窗口 for(var i=currentLength;i10) return; this.DayCount=count; this.ResetOverlaySymbolStatus(); this.RequestData(); } //叠加股票 只支持日线数据 this.OverlaySymbol=function(symbol) { for(var i in this.OverlayChartPaint) { var item=this.OverlayChartPaint[i]; if (item.Symbol==symbol) { console.warn(`[MinuteChartContainer::OverlaySymbol] overlay symbol=${symbol} exist.`); return false; } } var paint=new ChartOverlayMinutePriceLine(); paint.Canvas=this.Canvas; paint.ChartBorder=this.Frame.SubFrame[0].Frame.ChartBorder; paint.ChartFrame=this.Frame.SubFrame[0].Frame; paint.Name="Overlay-Minute"; paint.Symbol=symbol; paint.Color=g_JSChartResource.OverlaySymbol.Color[g_JSChartResource.OverlaySymbol.Random%g_JSChartResource.OverlaySymbol.Color.length]; ++g_JSChartResource.OverlaySymbol.Random; if (this.ChartPaint[0].YClose>0 && this.ChartPaint[0].Data) //绑定主图数据 { paint.MainData=this.ChartPaint[0].Data; paint.MainYClose=this.ChartPaint[0].YClose; } this.OverlayChartPaint.push(paint); if (this.DayCount<=1) this.RequestOverlayMinuteData(); //请求数据 else this.RequestOverlayHistoryMinuteData(); return true; } this.ResetOverlaySymbolStatus=function() { for(var i in this.OverlayChartPaint) { var item=this.OverlayChartPaint[i]; item.Status=OVERLAY_STATUS_ID.STATUS_NONE_ID; } } //删除一个叠加股票 this.DeleteOverlaySymbol=function(symbol) { for(var i in this.OverlayChartPaint) { var item=this.OverlayChartPaint[i]; if (item.Symbol===symbol) { item.IsDelete=true; this.OverlayChartPaint.splice(i,1); this.UpdateFrameMaxMin(); this.Draw(); return true; } } console.warn(`[MinuteChartContainer::DeleteOverlaySymbol] overlay symbol=${symbol} not exist.`) return false; } //取消叠加股票 this.ClearOverlaySymbol=function() { for(var i in this.OverlayChartPaint) { var item=this.OverlayChartPaint[i]; item.IsDelete=true; } this.OverlayChartPaint=[]; this.Frame.SubFrame[0].Frame.YSplitOperator.OverlayChartPaint=this.OverlayChartPaint; this.TitlePaint[0].OverlayChartPaint=this.OverlayChartPaint; //绑定叠加 this.UpdateFrameMaxMin(); this.Draw(); } this.ShowBeforeData=function(isShow) { if (this.IsShowBeforeData==isShow) return; this.IsShowBeforeData=isShow; this.RequestData(); } this.RequestData=function() { if (this.DayCount<=1) this.RequestMinuteData(); else this.RequestHistoryMinuteData(); } this.ChangeDrawType=function(type) { if (this.ChartPaint.length<=0) return; if (type==0) this.ChartPaint[0].IsDrawArea=true; else if (type==1) this.ChartPaint[0].IsDrawArea=false; else return; this.Draw(); } //请求历史分钟数据 this.RequestHistoryMinuteData=function() { var self=this; this.IsBeforeData=false; this.ChartSplashPaint.IsEnableSplash = true; this.Draw(); if (this.NetworkFilter) { var obj= { Name:'MinuteChartContainer::RequestHistoryMinuteData', //类名:: Explain:'多日分时数据', Request:{ Url:self.HistoryMinuteApiUrl, Data:{daycount:self.DayCount, symbol:self.Symbol}, Type:'POST' }, Self:this, PreventDefault:false }; this.NetworkFilter(obj, function(data) { self.ChartSplashPaint.IsEnableSplash=false; self.RecvHistoryMinuteData(data); }); if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求 } JSNetwork.HttpRequest({ url: self.HistoryMinuteApiUrl, data: { "symbol": self.Symbol, "daycount": self.DayCount }, type:"post", dataType: "json", async:true, success: function (data) { self.ChartSplashPaint.IsEnableSplash=false; self.RecvHistoryMinuteData(data); } }); } this.RecvHistoryMinuteData=function(data) { this.DayData=MinuteChartContainer.JsonDataToMinuteDataArray(data); this.Symbol=data.symbol; this.Name=data.name; this.CaclutateLimitPrice(this.DayData[0].YClose, data.data[0].limitprice); //计算涨停价格 this.UpdateHistoryMinuteUI(); this.RequestOverlayHistoryMinuteData(); this.AutoUpdate(); } this.UpdateHistoryMinuteUI=function() { var allMinuteData=this.HistoryMinuteDataToArray(this.DayData); //原始数据 var sourceData=new ChartData(); sourceData.Data=allMinuteData; this.SourceData=sourceData; this.TradeDate=this.DayData[0].Date; this.BindMainData(sourceData,this.DayData[0].YClose); if (MARKET_SUFFIX_NAME.IsChinaFutures(this.Symbol)) this.ChartPaint[1].Data=null; //期货均线暂时不用 if (this.Frame.SubFrame.length>2) { var bindData=new ChartData(); bindData.Data=allMinuteData; for(var i=2; i=0;--i) { var item=data[i]; for(var j in item.Data) { result.push(item.Data[j]); } } return result; } this.UpdateLatestMinuteData=function(data,date) { for(var i in this.DayData) { var item=this.DayData[i]; if (item.Date===date) { item.Data=data; break; } } } //请求分钟数据 this.RequestMinuteData=function() { var self=this; var fields= [ "name","symbol", "yclose","open","price","high","low", "vol","amount", "date","time", "minute","minutecount" ]; var upperSymbol=this.Symbol.toUpperCase(); if (MARKET_SUFFIX_NAME.IsChinaFutures(upperSymbol)) { //期货的需要加上结算价 fields.push("clearing"); fields.push("yclearing"); } // 盘前数据(A股) this.IsBeforeData=false; if (this.IsShowBeforeData && this.DayCount===1 && MARKET_SUFFIX_NAME.IsSHSZStockA(self.Symbol)) { this.IsBeforeData=true; fields.push('before'); } if (this.NetworkFilter) { var obj= { Name:'MinuteChartContainer::RequestMinuteData', //类名::函数名 Explain:'最新分时数据', Request:{ Url:self.MinuteApiUrl, Data:{field:fields, symbol:[self.Symbol]}, Type:'POST' }, Self:this, PreventDefault:false }; this.NetworkFilter(obj, function(data) { self.ChartSplashPaint.IsEnableSplash=false; self.RecvMinuteData(data); }); if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求 } JSNetwork.HttpRequest({ url: self.MinuteApiUrl, data: { "field": fields, "symbol": [self.Symbol], "start": -1 }, type:"post", dataType: "json", async:true, success: function (data) { self.ChartSplashPaint.IsEnableSplash=false; self.RecvMinuteData(data); } }); } this.RecvMinuteData=function(data) { if (this.IsBeforeData) var aryMinuteData=MinuteChartContainer.JsonDataToMinuteData2(data); else var aryMinuteData=MinuteChartContainer.JsonDataToMinuteData(data); if (this.DayCount>1) //多日走势图 { this.UpdateLatestMinuteData(aryMinuteData,data.stock[0].date); this.UpdateHistoryMinuteUI(); this.RequestOverlayMinuteData(); //请求叠加数据 (主数据下载完再下载) this.AutoUpdate(); return; } //原始数据 var sourceData=new ChartData(); sourceData.Data=aryMinuteData; this.TradeDate=data.stock[0].date; this.SourceData=sourceData; this.Symbol=data.stock[0].symbol; this.Name=data.stock[0].name; var yClose=data.stock[0].yclose; var upperSymbol=this.Symbol.toUpperCase(); if (data.stock[0].yclearing && MARKET_SUFFIX_NAME.IsChinaFutures(upperSymbol)) yClose=data.stock[0].yclearing; //期货使用前结算价 this.CaclutateLimitPrice(yClose, data.stock[0].limitprice); //计算涨停价格 this.BindMainData(sourceData,yClose); if (this.Frame.SubFrame.length>2) { var bindData=new ChartData(); bindData.Data=aryMinuteData; for(var i=2; i0 && limitData.min>0) //API里带涨停价格 直接使用 { this.LimitPrice={ Max:limitData.max, Min:limitData.min }; return; } var range=MARKET_SUFFIX_NAME.GetLimitPriceRange(this.Symbol, this.Name); //通过规则获取涨停价格 if (!range) { console.log(`[MinuteChartContainer::CaclutateLimitPrice] ${this.Symbol} no limit price.`) return; } //var yClose=data.stock[0].yclose; if (yClose<=0) return; this.LimitPrice={ Max:yClose*(1+range.Max), Min:yClose*(1+range.Min) }; console.log(`[MinuteChartContainer::CaclutateLimitPrice] ${this.Symbol} yClose:${yClose} max:${this.LimitPrice.Max} min:${this.LimitPrice.Min}`); this.LimitPrice.Max=parseFloat(this.LimitPrice.Max.toFixed(2)); this.LimitPrice.Min=parseFloat(this.LimitPrice.Min.toFixed(2)); console.log(`[MinuteChartContainer::CaclutateLimitPrice] ${this.Symbol} tofixed(2) max:${this.LimitPrice.Max} min:${this.LimitPrice.Min}`); } //请求叠加数据 (主数据下载完再下载)) this.RequestOverlayMinuteData=function() { var self = this; var date=this.TradeDate; //最后一个交易日期 for(var i in this.OverlayChartPaint) { let item=this.OverlayChartPaint[i]; if (!item.MainData || !(item.MainYClose>0) ) continue; if (item.Status!=OVERLAY_STATUS_ID.STATUS_NONE_ID) continue; var symbol=item.Symbol; if (!symbol) return; item.Status=OVERLAY_STATUS_ID.STATUS_REQUESTDATA_ID; if (this.NetworkFilter) { var obj= { Name:'MinuteChartContainer::RequestOverlayMinuteData', //类名::函数名 Explain:'叠加股票最新分时数据', Request:{ Url:self.HistoryMinuteApiUrl, Data:{days:[date], symbol:symbol}, Type:'POST' }, Self:this, PreventDefault:false }; this.NetworkFilter(obj, function(data) { item.Status=OVERLAY_STATUS_ID.STATUS_RECVDATA_ID; self.RecvOverlayMinuteData(data,item); }); if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求 } //请求数据 JSNetwork.HttpRequest({ url: self.HistoryMinuteApiUrl, data: { "symbol":symbol, "days": [date], }, type:"post", dataType: "json", async:true, success: function (data) { item.Status=OVERLAY_STATUS_ID.STATUS_RECVDATA_ID; self.RecvOverlayMinuteData(data,item); } }); } } this.RecvOverlayMinuteData=function(data,paint) { if (paint.IsDelete) return; var aryMinuteData=MinuteChartContainer.JsonDataToMinuteDataArray(data); var sourceData=null; var yClose; if (this.DayCount>1) //多日数据 { if (aryMinuteData.length<=0) return; var minuteData=aryMinuteData[0]; for(var i in paint.SourceData) { var item=paint.SourceData[i]; if (item.Date==minuteData.Date) { paint.SourceData[i]=minuteData; var allMinuteData=this.HistoryMinuteDataToArray(paint.SourceData); var sourceData=new ChartData(); sourceData.Data=allMinuteData; yClose=minuteData.YClose; break; } } if (sourceData==null) return; } else { if (aryMinuteData.length>0) sourceData=aryMinuteData[0]; else sourceData=new ChartData(); yClose=sourceData.YClose; } paint.Data=sourceData; paint.Title=data.name; paint.Symbol=data.symbol; paint.YClose=yClose; paint.Status=OVERLAY_STATUS_ID.STATUS_FINISHED_ID; this.UpdateFrameMaxMin(); //调整坐标最大 最小值 this.Frame.SetSizeChage(true); this.Draw(); } this.RequestOverlayHistoryMinuteData=function() { var self = this; var days=[]; for(var i in this.DayData) { var item=this.DayData[i]; days.push(item.Date); } if (days.length<=0) return; for(var i in this.OverlayChartPaint) { let item=this.OverlayChartPaint[i] var symbol=item.Symbol; if (!symbol) return; if (item.Status!=OVERLAY_STATUS_ID.STATUS_NONE_ID) continue; item.Status=OVERLAY_STATUS_ID.STATUS_REQUESTDATA_ID; if (this.NetworkFilter) { var obj= { Name:'MinuteChartContainer::RequestOverlayHistoryMinuteData', //类名::函数名 Explain:'叠加股票多日分时数据', Request:{ Url:self.HistoryMinuteApiUrl, Data:{days:days, symbol:symbol}, Type:'POST' }, Self:this, PreventDefault:false }; this.NetworkFilter(obj, function(data) { item.Status=OVERLAY_STATUS_ID.STATUS_RECVDATA_ID; self.RecvOverlayHistoryMinuteData(data,item); }); if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求 } JSNetwork.HttpRequest({ url: self.HistoryMinuteApiUrl, data:{ "symbol": symbol, "days": days }, type:"post", dataType: "json", async:true, success: function (data) { item.Status=OVERLAY_STATUS_ID.STATUS_RECVDATA_ID; self.RecvOverlayHistoryMinuteData(data,item); } }); } } this.RecvOverlayHistoryMinuteData=function(data,paint) //叠加历史的分钟数据 { var dayData=MinuteChartContainer.JsonDataToMinuteDataArray(data); var overlayDayData=[]; for(var i in this.DayData) { var item=this.DayData[i]; var bFind=false; for(var j in dayData) { if (item.Date==dayData[j].Date) { overlayDayData.push(dayData[i]); bFind=true; break; } } if (!bFind) //当天不存在叠加数据, 存空 { var empytData=new ChartData(); empytData.Date=item.Date; } } paint.SourceData=overlayDayData; var allMinuteData=this.HistoryMinuteDataToArray(overlayDayData); var yClose=overlayDayData[0].YClose; //取最近一个交易日前收盘最为中轴线 //原始数据 var sourceData=new ChartData(); sourceData.Data=allMinuteData; paint.Data=sourceData; paint.Title=data.name; paint.Symbol=data.symbol; paint.YClose=yClose; paint.Status=OVERLAY_STATUS_ID.STATUS_FINISHED_ID; this.UpdateFrameMaxMin(); //调整坐标最大 最小值 this.Frame.SetSizeChage(true); this.Draw(); } this.CancelAutoUpdate=function() //关闭停止更新 { if (typeof (this.AutoUpdateTimer) == 'number') { clearTimeout(this.AutoUpdateTimer); this.AutoUpdateTimer = undefined; } } //数据自动更新 this.AutoUpdate=function() { this.CancelAutoUpdate(); if (!this.IsAutoUpdate) return; if (!this.Symbol) return; var self = this; var marketStatus=MARKET_SUFFIX_NAME.GetMarketStatus(this.Symbol); if (marketStatus==0 || marketStatus==3) return; //闭市,盘后 var frequency=this.AutoUpdateFrequency; if (marketStatus==1) //盘前 { this.AutoUpdateTimer=setTimeout(function() { self.AutoUpdate(); },frequency); } else if (marketStatus==2) //盘中 { this.AutoUpdateTimer=setTimeout(function() { self.ResetOverlaySymbolStatus(); self.RequestMinuteData(); },frequency); } } this.BindIndexData=function(windowIndex,hisData) { if (!this.WindowIndex[windowIndex]) return; if (typeof(this.WindowIndex[windowIndex].RequestData)=="function") //数据需要另外下载的. { this.WindowIndex[windowIndex].RequestData(this,windowIndex,hisData); return; } if (typeof(this.WindowIndex[windowIndex].ExecuteScript)=='function') { this.WindowIndex[windowIndex].ExecuteScript(this,windowIndex,hisData); return; } this.WindowIndex[windowIndex].BindData(this,windowIndex,hisData); } //绑定分钟数据 this.BindMainData=function(minuteData,yClose) { //分钟数据 var bindData=new ChartData(); bindData.Data=minuteData.GetClose(); this.ChartPaint[0].Data=bindData; this.ChartPaint[0].YClose=yClose; this.ChartPaint[0].NotSupportMessage=null; this.ChartPaint[0].SourceData=this.IsBeforeData ? minuteData:null; this.ChartPaint[0].IsShowLead=false; this.ChartPaint[0].LeadData=null; if (MARKET_SUFFIX_NAME.IsSHSZIndex(this.Symbol) && this.DayCount==1 && this.IsShowLead) //指数显示领先指标 { var bindLeadData=new ChartData(); bindLeadData.Data=minuteData.GetLead(); this.ChartPaint[0].LeadData=bindLeadData; this.ChartPaint[0].IsShowLead=true; } this.Frame.SubFrame[0].Frame.YSplitOperator.YClose=yClose; this.Frame.SubFrame[0].Frame.YSplitOperator.Data=bindData; this.Frame.Data=this.ChartPaint[0].Data; this.Frame.SourceData=minuteData; //均线 bindData=new ChartData(); bindData.Data=minuteData.GetMinuteAvPrice(); this.ChartPaint[1].Data=bindData; this.Frame.SubFrame[0].Frame.YSplitOperator.AverageData=bindData; this.Frame.SubFrame[0].Frame.YSplitOperator.SourceData=this.IsBeforeData ? minuteData:null; this.Frame.SubFrame[0].Frame.YSplitOperator.OverlayChartPaint=this.OverlayChartPaint; this.Frame.SubFrame[0].Frame.YSplitOperator.LimitPrice=this.LimitPrice; //成交量 this.ChartPaint[2].Data=minuteData; this.ChartPaint[2].YClose=yClose; this.TitlePaint[0].Data=this.SourceData; //动态标题 this.TitlePaint[0].Symbol=this.Symbol; this.TitlePaint[0].Name=this.Name; this.TitlePaint[0].YClose=yClose; if (this.ChartCorssCursor && this.ChartCorssCursor.StringFormatY) this.ChartCorssCursor.StringFormatY.YClose=yClose; if (this.ExtendChartPaint[0]) { this.ExtendChartPaint[0].Symbol=this.Symbol; this.ExtendChartPaint[0].Name=this.Name; } var beforeDataCount=0; var isBeforeData=this.IsBeforeData; if (this.DayCount>1) isBeforeData=false; if (isBeforeData) beforeDataCount=15; for(var i in this.OverlayChartPaint) { var item=this.OverlayChartPaint[i]; item.MainData=this.ChartPaint[0].Data; //叠加股票 item.MainYClose=yClose; item.BeforeDataCount=beforeDataCount; //只是集合竞价数据 item.IsBeforeData=isBeforeData; } } //获取子窗口的所有画法 this.GetChartPaint=function(windowIndex) { var paint=new Array(); for(var i in this.ChartPaint) { if (i<3) continue; //分钟 均线 成交量 3个线不能改 var item=this.ChartPaint[i]; if (item.ChartFrame==this.Frame.SubFrame[windowIndex].Frame) paint.push(item); } return paint; } //创建指定窗口指标 this.CreateWindowIndex=function(windowIndex) { this.WindowIndex[windowIndex].Create(this,windowIndex); } //获取当前的显示的指标 this.GetIndexInfo=function() { var aryIndex=[]; for(var i in this.WindowIndex) { var item=this.WindowIndex[i]; var info={Name:item.Name}; if (item.ID) info.ID=item.ID; aryIndex.push(info); } return aryIndex; } this.OnTouchFinished=function() { if (this.CorssCursorTouchEnd===true) //手势离开十字光标消失 { this.DrawDynamicInfo(); return; } /* 以后放日线的tooltip for(var i in this.ExtendChartPaint) { var item=this.ExtendChartPaint[i]; if (item.ClassName==='KLineTooltipPaint') { this.DrawDynamicInfo(); } } */ } this.CreateExtendChart=function(name, option) //创建扩展图形 { var chart; switch(name) { case 'MinuteTooltip': chart=new MinuteTooltipPaint(); chart.Canvas=this.Canvas; chart.ChartBorder=this.Frame.ChartBorder; chart.ChartFrame=this.Frame; chart.HQChart=this; option.LanguageID=this.LanguageID; chart.SetOption(option); this.ExtendChartPaint.push(chart); return chart; default: return null; } } this.SetMinuteInfo=function(aryInfo,bUpdate) { this.ChartInfo=[]; //先清空 for(var i in aryInfo) { var infoItem=JSMinuteInfoMap.Get(aryInfo[i]); if (!infoItem) continue; var item=infoItem.Create(); this.ChartInfo.push(item); } if (bUpdate==true) this.RequestMinuteInfoData(); } this.GetChartMinuteInfo=function() { return this.ChartInfoPaint; } this.CreateMinuteInfo=function(option) //在Create()以后 在调用 { var chart=new ChartMinuteInfo(); chart.Canvas=this.Canvas; chart.ChartBorder=this.Frame.SubFrame[0].Frame.ChartBorder; chart.ChartFrame=this.Frame.SubFrame[0].Frame; chart.HQChartBorder=this.Frame.ChartBorder; chart.ChartMinutePrice=this.ChartPaint[0]; if (option && chart.SetOption) chart.SetOption(option); this.ChartInfoPaint=chart; return chart; } //信息地雷数据请求 this.RequestMinuteInfoData=function() { if (this.ChartInfo.length<=0) return; var chart=this.GetChartMinuteInfo(); if (!chart) chart=this.CreateMinuteInfo(null); //不存在就创建 chart.SourceData=this.SourceData; //信息地雷信息 for(var i in this.ChartInfo) { this.ChartInfo[i].RequestData(this); } } //更新信息地雷 this.UpdataChartInfo=function() { var chart=this.GetChartMinuteInfo(); if (!chart) return; var infoMap=new Map(); for(var i in this.ChartInfo) { var infoData=this.ChartInfo[i].Data; for(var j in infoData) { var item=infoData[j]; var dateTime=`${item.Date} ${item.Time}`; if (infoMap.has(dateTime)) { infoMap.get(dateTime).Data.push(item); } else { infoMap.set(dateTime,{Data:new Array(item)}); } } } chart.Data=infoMap; } } // 分钟走势图数据 带盘前数据 MinuteChartContainer.JsonDataToMinuteData2=function(data) { var symbol=data.stock[0].symbol; var preClose=data.stock[0].yclose; //前一个数据价格 var preAvPrice=data.stock[0].yclose; //前一个均价 var yClose=data.stock[0].yclose; var aryMinuteData=[]; var stockData=data.stock[0]; var date=stockData.date; //日期 for(var i in stockData.before) { var item=new MinuteData(); var jsData=stockData.before[i]; var time=jsData[0]; item.Before={}; item.Before.Close=jsData[1]; if (!item.Before.Close) item.Before.Close=preClose; else preClose=item.Before.Close; item.Before.Vol=jsData[2]/100; //沪深股票原始单位股 item.Before.Amount=jsData[3]; item.DateTime=date.toString()+" "+time.toString(); item.Date=date; item.Time=time; if (yClose && item.Before.Close) item.Before.Increase=(item.Before.Close-yClose)/yClose*100; //涨幅 (最新价格-昨收)/昨收*100; aryMinuteData.push(item); } for(var i in stockData.minute) { var jsData=stockData.minute[i]; var item=new MinuteData(); if (jsData.price) preClose=jsData.price; if (jsData.avprice) preAvPrice=jsData.avprice; if (jsData.time==925) continue; //去掉9:25的数据 item.Close=jsData.price; item.Open=jsData.open; item.High=jsData.high; item.Low=jsData.low; item.Amount=jsData.amount; item.Vol=jsData.vol/100; //沪深股票原始单位股 item.DateTime=data.stock[0].date.toString()+" "+jsData.time.toString(); item.Date=data.stock[0].date; item.Time=jsData.time; item.Increase=jsData.increase; item.Risefall=jsData.risefall; item.AvPrice=jsData.avprice; //当前没有价格 使用上一个价格填充 if (!item.Close) item.Open=item.High=item.Low=item.Close=preClose; if (!item.AvPrice) item.AvPrice=preAvPrice; if (yClose && item.Close) item.Increase=(item.Close-yClose)/yClose*100; //涨幅 (最新价格-昨收)/昨收*100; aryMinuteData.push(item); } return aryMinuteData; } //API 返回数据 转化为array[] MinuteChartContainer.JsonDataToMinuteData=function(data,isBeforeData) { var symbol=data.stock[0].symbol; var upperSymbol=symbol.toUpperCase(); var isSHSZ=MARKET_SUFFIX_NAME.IsSHSZ(upperSymbol); var isFutures=MARKET_SUFFIX_NAME.IsChinaFutures(upperSymbol); var aryMinuteData=new Array(); var preClose=data.stock[0].yclose; //前一个数据价格 var preAvPrice=data.stock[0].yclose; //前一个均价 var yClose=data.stock[0].yclose; if (isFutures && data.stock[0].yclearing) yClose=preClose=preAvPrice=data.stock[0].yclearing; //期货使用昨结算价 var date=data.stock[0].date; //默认使用外部日期, 但跨天的 走势图使用内部的日期 for(var i in data.stock[0].minute) { var jsData=data.stock[0].minute[i]; var item=new MinuteData(); item.Close=jsData.price; item.Open=jsData.open; item.High=jsData.high; item.Low=jsData.low; if (isSHSZ) item.Vol=jsData.vol/100; //沪深股票原始单位股 else item.Vol=jsData.vol; item.Amount=jsData.amount; if (jsData.date>0) date=jsData.date; //分钟数据中有日期 优先使用 item.DateTime=date.toString()+" "+jsData.time.toString(); item.Date=date; item.Time=jsData.time; if (i==0) { item.IsFristData=true; if(isSHSZ) { item.DateTime=data.stock[0].date.toString() + " 0925"; //沪深股票 第1个数据 写死9:25 item.Time=925; } } item.Increase=jsData.increase; item.Risefall=jsData.risefall; item.AvPrice=jsData.avprice; if (IFrameSplitOperator.IsNumber(jsData.lead)) item.Lead=jsData.lead; //领先指标 指数才有 if (!item.Close) //当前没有价格 使用上一个价格填充 { item.Close=preClose; item.Open=item.High=item.Low=item.Close; } if (!item.AvPrice) item.AvPrice=preAvPrice; //价格是0的 都用空 if (item.Open<=0) item.Open=null; if (item.Close<=0) item.Close=null; if (item.AvPrice<=0) item.AvPrice=null; if (item.High<=0) item.High=null; if (item.Low<=0) item.Low=null; //if (isFutures) item.AvPrice=null; //期货均价暂时没有 if (yClose && item.Close) item.Increase=(item.Close-yClose)/yClose*100; //涨幅 (最新价格-昨收)/昨收*100; //均价太大 可能是后台算错了 var checkValue=Math.abs(item.AvPrice-item.Close); //console.log(`[MinuteChartContainer::JsonDataToMinuteData] checkValue=${checkValue}, ${item.Close*0.13} `) if (isSHSZ && checkValue>item.Close*0.13 ) item.AvPrice=preAvPrice; //上次价格 if (jsData.price>0) preClose=jsData.price; if (jsData.avprice>0 && item.AvPrice===jsData.avprice) preAvPrice=jsData.avprice; aryMinuteData[i]=item; } return aryMinuteData; } //多日日线数据API 转化成array[]; MinuteChartContainer.JsonDataToMinuteDataArray=function(data) { var symbol=data.symbol; var upperSymbol=symbol.toUpperCase(); var isSHSZ=MARKET_SUFFIX_NAME.IsSHSZ(upperSymbol); var isFutures=MARKET_SUFFIX_NAME.IsChinaFutures(upperSymbol); var result=[]; for(var i in data.data) { var minuteData=[]; var dayData=data.data[i]; var date=dayData.date; var yClose=dayData.yclose; //前收盘 计算涨幅 var preClose=yClose; //前一个数据价格 var preAvPrice=null; //上一个均价 //var preAvPrice=data.stock[0].yclose; //前一个均价 for(var j in dayData.minute) { var jsData=dayData.minute[j]; if (jsData[2]) preClose=jsData[2]; //保存上一个收盘数据 var item=new MinuteData(); item.Close=jsData[2]; item.Open=jsData[1]; item.High=jsData[3]; item.Low=jsData[4]; item.Vol=jsData[5]/100; //原始单位股 item.Amount=jsData[6]; if (70) item.AvPrice=jsData[7]; //均价 item.DateTime=date.toString()+" "+jsData[0].toString(); item.Date=date; item.Time=jsData[0]; if (!item.Close) //当前没有价格 使用上一个价格填充 { item.Close=preClose; item.Open=item.High=item.Low=item.Close; } if (!item.AvPrice && preAvPrice) item.AvPrice=preAvPrice; if (item.Close && yClose) item.Increase = (item.Close - yClose)/yClose*100; else item.Increase=null; if (j==0) //第1个数据 写死9:25 { if (isSHSZ) { item.DateTime=date.toString()+" 0925"; item.Time=925; } item.IsFristData=true; } //价格是0的 都用空 if (item.Open<=0) item.Open=null; if (item.Close<=0) item.Close=null; if (item.AvPrice<=0) item.AvPrice=null; if (item.High<=0) item.High=null; if (item.Low<=0) item.Low=null; if (item.AvPrice<=0) item.AvPrice=null; //均价太大 可能是后台算错了 if (item.AvPrice && isSHSZ) { var checkValue=Math.abs(item.AvPrice-item.Close); if (checkValue>item.Close*0.13 ) item.AvPrice=preAvPrice; } if (jsData.length>7 && jsData[7]>0 && item.AvPrice===jsData[7]) preAvPrice=jsData[7]; minuteData[j]=item; } var newData=new ChartData(); newData.Data=minuteData; newData.YClose=yClose; newData.Close=dayData.close; newData.Date=date; result.push(newData); } return result; } /* 历史分钟走势图 */ function HistoryMinuteChartContainer(uielement) { this.newMethod=MinuteChartContainer; //派生 this.newMethod(uielement); delete this.newMethod; this.HistoryMinuteApiUrl="https://opensourcecache.zealink.com/cache/minuteday/day/"; this.ClassName='HistoryMinuteChartContainer'; //创建主图K线画法 this.CreateMainKLine=function() { //分钟线 var minuteLine=new ChartMinutePriceLine(); minuteLine.Canvas=this.Canvas; minuteLine.ChartBorder=this.Frame.SubFrame[0].Frame.ChartBorder; minuteLine.ChartFrame=this.Frame.SubFrame[0].Frame; minuteLine.Name="Minute-Line"; minuteLine.Color=g_JSChartResource.Minute.PriceColor; this.ChartPaint[0]=minuteLine; //分钟线均线 var averageLine=new ChartLine(); averageLine.Canvas=this.Canvas; averageLine.ChartBorder=this.Frame.SubFrame[0].Frame.ChartBorder; averageLine.ChartFrame=this.Frame.SubFrame[0].Frame; averageLine.Name="Minute-Average-Line"; averageLine.Color=g_JSChartResource.Minute.AvPriceColor; this.ChartPaint[1]=averageLine; var averageLine=new ChartMinuteVolumBar(); averageLine.Color=g_JSChartResource.Minute.VolBarColor; averageLine.Canvas=this.Canvas; averageLine.ChartBorder=this.Frame.SubFrame[1].Frame.ChartBorder; averageLine.ChartFrame=this.Frame.SubFrame[1].Frame; averageLine.Name="Minute-Vol-Bar"; this.ChartPaint[2]=averageLine; this.TitlePaint[0]=new DynamicMinuteTitlePainting(); this.TitlePaint[0].Frame=this.Frame.SubFrame[0].Frame; this.TitlePaint[0].Canvas=this.Canvas; this.TitlePaint[0].IsShowDate=true; /* //主图叠加画法 var paint=new ChartOverlayKLine(); paint.Canvas=this.Canvas; paint.ChartBorder=this.Frame.SubFrame[0].Frame.ChartBorder; paint.ChartFrame=this.Frame.SubFrame[0].Frame; paint.Name="Overlay-KLine"; this.OverlayChartPaint[0]=paint; */ } //设置交易日期 this.ChangeTradeDate=function(trdateDate) { if (!trdateDate) return; this.TradeDate=trdateDate; this.RequestData(); //更新数据 } this.RequestData=function() { var date=new Date(); var nowDate=date.getFullYear()*10000+(date.getMonth()+1)*100+date.getDate(); if (nowDate==this.TradeDate) this.RequestMinuteData(); else this.RequestHistoryMinuteData(); } //请求分钟数据 this.RequestHistoryMinuteData=function() { var self=this; var url=this.HistoryMinuteApiUrl+this.TradeDate.toString()+"/"+this.Symbol+".json"; JSNetwork.HttpRequest({ url: url, type:"get", dataType: "json", async:true, success: function (data) { self.ChartSplashPaint.IsEnableSplash=false; self.RecvHistoryMinuteData(data); }, error:function(reqeust) { self.ChartSplashPaint.IsEnableSplash=false; self.RecvHistoryMinuteError(reqeust); } }); } this.RecvHistoryMinuteError=function(reqeust) { if (reqeust.status!=404) return; var sourceData=new ChartData(); this.SourceData=sourceData; for(var i in this.ChartPaint) { this.ChartPaint[i].Data=sourceData; if (i==0) this.ChartPaint[i].NotSupportMessage='没有权限访问!'; } this.TitlePaint[0].Data=this.SourceData; //动态标题 this.TitlePaint[0].Symbol=this.Symbol; this.TitlePaint[0].Name=null; this.Draw(); } this.RecvHistoryMinuteData=function(data) { var aryMinuteData=HistoryMinuteChartContainer.JsonDataToMinuteData(data); //原始数据 var sourceData=new ChartData(); sourceData.Data=aryMinuteData; this.TradeDate=data.date; this.SourceData=sourceData; this.Symbol=data.symbol; this.Name=data.name; this.BindMainData(sourceData,data.day.yclose); if (this.Frame.SubFrame.length>2) { var bindData=new ChartData(); bindData.Data=aryMinuteData; for(var i=2; i0) //当前这一分钟价格为空,使用上一分钟的数据 { item.Close=aryMinuteData[i-1].Close; item.Open=aryMinuteData[i-1].Close; item.High=item.Close; item.Low=item.Close; item.Vol=data.minute.vol[i]; //原始单位股 item.Amount=data.minute.amount[i]; item.DateTime=data.date.toString()+" "+data.minute.time[i].toString(); //item.Increate=jsData.increate; //item.Risefall=jsData.risefall; item.AvPrice=aryMinuteData[i-1].AvPrice; } else { item.Close=data.minute.price[i]; item.Open=data.minute.open[i]; item.High=data.minute.high[i]; item.Low=data.minute.low[i]; item.Vol=data.minute.vol[i]; //原始单位股 item.Amount=data.minute.amount[i]; item.DateTime=data.date.toString()+" "+data.minute.time[i].toString(); //item.Increate=jsData.increate; //item.Risefall=jsData.risefall; item.AvPrice=data.minute.avprice[i]; } //价格是0的 都用空 if (item.Open<=0) item.Open=null; if (item.Close<=0) item.Close=null; if (item.AvPrice<=0) item.AvPrice=null; if (item.High<=0) item.High=null; if (item.Low<=0) item.Low=null; aryMinuteData[i]=item; } return aryMinuteData; } ///////////////////////////////////////////////////////////////////////////// // 自定义指数 // function CustomKLineChartContainer(uielement) { this.newMethod=KLineChartContainer; //派生 this.newMethod(uielement); delete this.newMethod; this.ClassName='CustomKLineChartContainer'; this.CustomKLineApiUrl=g_JSChartResource.Domain+"/API/IndexCalculate"; //自定义指数计算地址 this.CustomStock; //成分 this.QueryDate={Start:20180101,End:20180627} ; //计算时间区间 this.RequestHistoryData=function() { var self=this; this.ChartSplashPaint.IsEnableSplash = true; this.Draw(); JSNetwork.HttpRequest({ url: this.CustomKLineApiUrl, data: { "stock": self.CustomStock, "Name": self.Symbol, "date": { "startdate":self.QueryDate.Start,"enddate":self.QueryDate.End } }, type:"post", dataType: "json", async:true, success: function (data) { self.ChartSplashPaint.IsEnableSplash = false; self.RecvHistoryData(data); } }); } this.RecvHistoryData=function(data) { var aryDayData=KLineChartContainer.JsonDataToHistoryData(data); //原始数据 var sourceData=new ChartData(); sourceData.Data=aryDayData; sourceData.DataType=0; //0=日线数据 1=分钟数据 //显示的数据 var bindData=new ChartData(); bindData.Data=aryDayData; bindData.Right=this.Right; bindData.Period=this.Period; bindData.DataType=0; if (bindData.Right>0) //复权 { var rightData=bindData.GetRightDate(bindData.Right); bindData.Data=rightData; } if (ChartData.IsDayPeriod(this.Period,false)) //周期数据 { var periodData=sourceData.GetPeriodData(bindData.Period); bindData.Data=periodData; } //绑定数据 this.SourceData=sourceData; this.Name=data.name; this.BindMainData(bindData,this.PageSize); for(var i=0; i1) //十字光标只能在当前屏移动 { --this.CursorIndex; this.UpdatePointByCursorIndex(); this.DrawDynamicInfo(); this.ShowTooltipByKeyDown(); } break; case 39: //right var xPointcount=0; if (this.Frame.XPointCount) xPointcount=this.Frame.XPointCount; else xPointcount=this.Frame.SubFrame[0].Frame.XPointCount; if (this.CursorIndex+1=data.Data.length) break; ++this.CursorIndex; this.UpdatePointByCursorIndex(); this.DrawDynamicInfo(); this.ShowTooltipByKeyDown(); } break; case 38: //up var cursorIndex={}; cursorIndex.Index=parseInt(Math.abs(this.CursorIndex-0.5).toFixed(0)); if (!this.Frame.ZoomUp(cursorIndex)) break; this.CursorIndex=cursorIndex.Index; this.UpdatePointByCursorIndex(); this.UpdataDataoffset(); this.UpdateFrameMaxMin(); this.Draw(); this.ShowTooltipByKeyDown(); break; case 40: //down var cursorIndex={}; cursorIndex.Index=parseInt(Math.abs(this.CursorIndex-0.5).toFixed(0)); if (!this.Frame.ZoomDown(cursorIndex)) break; this.CursorIndex=cursorIndex.Index; this.UpdataDataoffset(); this.UpdatePointByCursorIndex(); this.UpdateFrameMaxMin(); this.Draw(); this.ShowTooltipByKeyDown(); break; } //不让滚动条滚动 if(e.preventDefault) e.preventDefault(); else e.returnValue = false; } //手机拖拽 uielement.ontouchstart=function(e) { if(!this.JSChartContainer) return; this.JSChartContainer.PhonePinch=null; e.preventDefault(); var jsChart=this.JSChartContainer; if (jsChart.IsPhoneDragging(e)) { var drag= { "Click":{}, "LastMove":{} //最后移动的位置 }; var touches=jsChart.GetToucheData(e,false); drag.Click.X=touches[0].clientX; drag.Click.Y=touches[0].clientY; drag.LastMove.X=touches[0].clientX; drag.LastMove.Y=touches[0].clientY; if (drag.Click.X==drag.LastMove.X && drag.Click.Y==drag.LastMove.Y) //手指没有移动,出现十字光标 { var mouseDrag=jsChart.MouseDrag; jsChart.MouseDrag=null; //移动十字光标 var pixelTatio = GetDevicePixelRatio(); var x = drag.Click.X-uielement.getBoundingClientRect().left*pixelTatio; var y = drag.Click.Y-uielement.getBoundingClientRect().top*pixelTatio; jsChart.OnMouseMove(x,y,e); } document.JSChartContainer=this.JSChartContainer; this.JSChartContainer.SelectChartDrawPicture=null; } else if (jsChart.IsPhonePinching(e)) { var phonePinch= { "Start":{}, "Last":{} }; var touches=jsChart.GetToucheData(e,false); phonePinch.Start={"X":touches[0].pageX,"Y":touches[0].pageY,"X2":touches[1].pageX,"Y2":touches[1].pageY}; phonePinch.Last={"X":touches[0].pageX,"Y":touches[0].pageY,"X2":touches[1].pageX,"Y2":touches[1].pageY}; this.JSChartContainer.PhonePinch=phonePinch; document.JSChartContainer=this.JSChartContainer; this.JSChartContainer.SelectChartDrawPicture=null; } uielement.ontouchmove=function(e) { if(!this.JSChartContainer) return; e.preventDefault(); var touches=jsChart.GetToucheData(e,false); if (jsChart.IsPhoneDragging(e)) { var drag=this.JSChartContainer.MouseDrag; if (drag==null) { var pixelTatio = GetDevicePixelRatio(); var x = touches[0].clientX-this.getBoundingClientRect().left*pixelTatio; var y = touches[0].clientY-this.getBoundingClientRect().top*pixelTatio; this.JSChartContainer.OnMouseMove(x,y,e); } else { } }else if (jsChart.IsPhonePinching(e)) { phonePinch.Last={"X":touches[0].pageX,"Y":touches[0].pageY,"X2":touches[1].pageX,"Y2":touches[1].pageY}; } }; uielement.ontouchend=function(e) { clearTimeout(timeout); } } this.CreateBuySellPaint=function() //在主窗口建立以后 创建买卖点 { var chart=new ChartBuySell(); chart.Canvas=this.Canvas; chart.ChartBorder=this.Frame.SubFrame[0].Frame.ChartBorder; chart.ChartFrame=this.Frame.SubFrame[0].Frame; chart.Name="KLine-Train-BuySell"; this.ChartPaintEx[0]=chart; } this.BindMainData=function(hisData,showCount) //数据到达绑定主图K线数据 { this.ChartPaint[0].Data=hisData; for(var i in this.Frame.SubFrame) { var item =this.Frame.SubFrame[i].Frame; item.XPointCount=showCount; item.Data=this.ChartPaint[0].Data; } this.TitlePaint[0].Data=this.ChartPaint[0].Data; //动态标题 this.TitlePaint[0].Symbol=this.Symbol; this.TitlePaint[0].Name=this.Name; this.ChartCorssCursor.StringFormatX.Data=this.ChartPaint[0].Data; //十字光标 this.Frame.Data=this.ChartPaint[0].Data; if (!this.ChartPaintEx[0]) this.CreateBuySellPaint(); this.ChartPaintEx[0].Data=this.ChartPaint[0].Data; for(var i in this.OverlayChartPaint ) { var item=this.OverlayChartPaint[i]; item.MainData=this.ChartPaint[0].Data; //K线叠加 } var dataOffset=hisData.Data.length-showCount-this.TrainDataCount-20; //随机选一段数据进行训练 if (dataOffset<0) dataOffset=0; this.ChartPaint[0].Data.DataOffset=dataOffset; this.CursorIndex=showCount; if (this.CursorIndex+dataOffset>=hisData.Data.length) this.CursorIndex=dataOffset; this.TrainDataIndex=this.CursorIndex; this.TrainStartEnd.Start=hisData.Data[this.TrainDataIndex+dataOffset-1]; } this.Run=function() { if (this.AutoRunTimer) return; if (this.TrainDataCount<=0) return; var self=this; this.AutoRunTimer=setInterval(function() { if (!self.MoveNextKLineData()) clearInterval(self.AutoRunTimer); }, 1000); } this.MoveNextKLineData=function() { if (this.TrainDataCount<=0) return false; var xPointcount=0; if (this.Frame.XPointCount) xPointcount=this.Frame.XPointCount; //数据个数 if (this.TrainDataIndex+1>=xPointcount) { this.CursorIndex=this.TrainDataIndex; if (!this.DataMoveRight()) return false; this.UpdataDataoffset(); this.UpdatePointByCursorIndex(); this.UpdateFrameMaxMin(); this.Draw(); ++this.TrainDataIndex; --this.TrainDataCount; if (this.TrainDataCount<=0) { this.FinishTrainData(); this.UpdateTrainUICallback(); return false; } this.UpdateTrainUICallback(); return true; } return false; } this.UpdateTrainUICallback=function() { var buySellPaint=this.ChartPaintEx[0]; var lastData=buySellPaint.LastData.Data; this.TrainStartEnd.End=lastData; //老接口 以后会不用 if (this.TrainCallback) this.TrainCallback(this); //新的监听事件 if (!this.mapEvent.has(JSCHART_EVENT_ID.RECV_TRAIN_MOVE_STEP)) return; var item=this.mapEvent.get(JSCHART_EVENT_ID.RECV_TRAIN_MOVE_STEP); if (!item.Callback) return; //Operator 0=买 1卖 var data={TrainDataCount:this.TrainDataCount, BuySellData:this.BuySellData, Operator:this.GetOperator() , KLine:this.TrainStartEnd}; item.Callback(item,data,this); } this.FinishTrainData=function() { var buySellPaint=this.ChartPaintEx[0]; if (buySellPaint && this.BuySellData.length) //取最后1条数据 看是否卖了 { var lastData=buySellPaint.LastData.Data; var item=this.BuySellData[this.BuySellData.length-1]; if (!item.Sell) { item.Sell={Price:lastData.Close,Date:lastData.Date}; buySellPaint.BuySellData.set(lastData.Date,{Op:1}); } } } this.GetLastBuySellData=function() //取最后1条数据 { var buySellPaint=this.ChartPaintEx[0]; if (!buySellPaint) return null; if (this.BuySellData.length) { var item=this.BuySellData[this.BuySellData.length-1]; return item; } return null; } this.GetOperator=function() //获取当前是卖/买 { var buySellData=this.GetLastBuySellData(); if (buySellData && buySellData.Buy && !buySellData.Sell) return 1; return 0; } this.Stop=function() { if (this.AutoRunTimer!=null) clearInterval(this.AutoRunTimer); this.AutoRunTimer=null; } this.BuyOrSell=function() //模拟买卖 { var buySellPaint=this.ChartPaintEx[0]; var lastData=buySellPaint.LastData.Data; var buySellData=this.GetLastBuySellData(); if (buySellData && buySellData.Buy && !buySellData.Sell) { buySellData.Sell={Price:lastData.Close,Date:lastData.Date}; buySellPaint.BuySellData.set(lastData.Date,{Op:1}); this.MoveNextKLineData(); return; } this.BuySellData.push({ Buy:{Price:lastData.Close,Date:lastData.Date}, Sell:null }); buySellPaint.BuySellData.set(lastData.Date,{Op:0}); this.MoveNextKLineData(); } } //////////////////////////////////////////////////////////////////////////////// // K线横屏显示 // function KLineChartHScreenContainer(uielement) { this.newMethod=KLineChartContainer; //派生 this.newMethod(uielement); delete this.newMethod; this.ClassName='KLineChartHScreenContainer'; this.OnMouseMove=function(x,y,e) { this.LastPoint.X=x; this.LastPoint.Y=y; this.CursorIndex=this.Frame.GetXData(y); this.DrawDynamicInfo(); } uielement.onmousedown=function(e) //鼠标拖拽 { if(!this.JSChartContainer) return; if(this.JSChartContainer.DragMode==0) return; var pixelTatio = GetDevicePixelRatio(); if (this.JSChartContainer.TryClickLock) { var x = (e.clientX-this.getBoundingClientRect().left)*pixelTatio; var y = (e.clientY-this.getBoundingClientRect().top)*pixelTatio; if (this.JSChartContainer.TryClickLock(x,y)) return; } var drag= { "Click":{}, "LastMove":{} //最后移动的位置 }; drag.Click.X=e.clientX; drag.Click.Y=e.clientY; drag.LastMove.X=e.clientX; drag.LastMove.Y=e.clientY; this.JSChartContainer.MouseDrag=drag; document.JSChartContainer=this.JSChartContainer; this.JSChartContainer.SelectChartDrawPicture=null; uielement.ondblclick=function(e) { var x = e.clientX-this.getBoundingClientRect().left; var y = e.clientY-this.getBoundingClientRect().top; if(this.JSChartContainer) this.JSChartContainer.OnDoubleClick(x,y,e); } document.onmousemove=function(e) { if(!this.JSChartContainer) return; //加载数据中,禁用鼠标事件 if (this.JSChartContainer.ChartSplashPaint && this.JSChartContainer.ChartSplashPaint.IsEnableSplash == true) return; var drag=this.JSChartContainer.MouseDrag; if (!drag) return; var moveSetp=Math.abs(drag.LastMove.Y-e.clientY); if (this.JSChartContainer.DragMode==1) //数据左右拖拽 { if (moveSetp<5) return; var isLeft=true; if (drag.LastMove.Y0) //放大 { var cursorIndex={}; cursorIndex.Index=parseInt(Math.abs(this.JSChartContainer.CursorIndex-0.5).toFixed(0)); if (!this.JSChartContainer.Frame.ZoomUp(cursorIndex)) return; this.JSChartContainer.CursorIndex=cursorIndex.Index; this.JSChartContainer.UpdatePointByCursorIndex(); this.JSChartContainer.UpdataDataoffset(); this.JSChartContainer.UpdateFrameMaxMin(); this.JSChartContainer.Draw(); this.JSChartContainer.ShowTooltipByKeyDown(); } else //缩小 { var cursorIndex={}; cursorIndex.Index=parseInt(Math.abs(this.JSChartContainer.CursorIndex-0.5).toFixed(0)); if (!this.JSChartContainer.Frame.ZoomDown(cursorIndex)) return; this.JSChartContainer.CursorIndex=cursorIndex.Index; this.JSChartContainer.UpdataDataoffset(); this.JSChartContainer.UpdatePointByCursorIndex(); this.JSChartContainer.UpdateFrameMaxMin(); this.JSChartContainer.Draw(); this.JSChartContainer.ShowTooltipByKeyDown(); } phonePinch.Last={"X":touches[0].pageX,"Y":touches[0].pageY,"X2":touches[1].pageX,"Y2":touches[1].pageY}; } }; uielement.ontouchend=function(e) { this.JSChartContainer.IsOnTouch = false; this.JSChartContainer.OnTouchFinished(); clearTimeout(timeout); } } //创建 //windowCount 窗口个数 this.Create=function(windowCount) { this.UIElement.JSChartContainer=this; //创建十字光标 this.ChartCorssCursor=new ChartCorssCursor(); this.ChartCorssCursor.Canvas=this.Canvas; this.ChartCorssCursor.StringFormatX=new HQDateStringFormat(); this.ChartCorssCursor.StringFormatY=new HQPriceStringFormat(); //创建等待提示 this.ChartSplashPaint = new ChartSplashPaint(); this.ChartSplashPaint.Canvas = this.Canvas; //创建框架容器 this.Frame=new HQTradeHScreenFrame(); this.Frame.ChartBorder=new ChartBorder(); this.Frame.ChartBorder.UIElement=this.UIElement; this.Frame.ChartBorder.Top=30; this.Frame.ChartBorder.Left=5; this.Frame.ChartBorder.Bottom=20; this.Frame.Canvas=this.Canvas; this.ChartCorssCursor.Frame=this.Frame; //十字光标绑定框架 this.ChartSplashPaint.Frame = this.Frame; this.CreateChildWindow(windowCount); this.CreateMainKLine(); //子窗口动态标题 for(var i in this.Frame.SubFrame) { var titlePaint=new DynamicChartTitlePainting(); titlePaint.Frame=this.Frame.SubFrame[i].Frame; titlePaint.Canvas=this.Canvas; titlePaint.LanguageID=this.LanguageID; this.TitlePaint.push(titlePaint); } this.UIElement.addEventListener("keydown", OnKeyDown, true); //键盘消息 } //创建子窗口 this.CreateChildWindow=function(windowCount) { for(var i=0;i0) //周期数据 { this.NotSupport(param.HQChart,param.WindowIndex,"不支持周期切换"); param.HQChart.Draw(); return false; } //请求数据 JSNetwork.HttpRequest({ url: g_JSChartResource.Index.MarketLongShortApiUrl, data: { }, type:"post", dataType: "json", async:true, success: function (recvData) { self.RecvData(recvData,param); } }); return true; } this.RecvData=function(recvData,param) { if (recvData.data.length<=0) return; var aryData=new Array(); for(var i in recvData.data) { var item=recvData.data[i]; var indexData=new SingleData(); indexData.Date=item[0]; indexData.Value=item[1]; aryData.push(indexData); } var aryFittingData=param.HistoryData.GetFittingData(aryData); var bindData=new ChartData(); bindData.Data=aryFittingData; bindData.Period=param.HQChart.Period; //周期 bindData.Right=param.HQChart.Right; //复权 this.LongShortData=bindData.GetValue(); this.BindData(param.HQChart,param.WindowIndex,param.HistoryData); param.HQChart.UpdataDataoffset(); //更新数据偏移 param.HQChart.UpdateFrameMaxMin(); //调整坐标最大 最小值 param.HQChart.Draw(); } this.BindData=function(hqChart,windowIndex,hisData) { var paint=null; var isOverlay=this.IsOverlay(); if (isOverlay) paint=this.OverlayIndex.Frame.ChartPaint; else paint=hqChart.GetChartPaint(windowIndex); if (paint.length!=this.Index.length) return false; //paint[0].Data.Data=SWLData; paint[0].Data.Data=this.LongShortData; paint[0].NotSupportMessage=null; paint[1].Data.Data[0]=8; paint[2].Data.Data[0]=1; var titleIndex=windowIndex+1; //指定[0,9] if (isOverlay) { this.OverlayIndex.Frame.Frame.YSpecificMaxMin={Max:9,Min:0,Count:3}; var titlePaint=hqChart.TitlePaint[titleIndex]; var titleInfo={ Data:[], Title:'' }; titlePaint.OverlayIndex.set(this.OverlayIndex.Identify,titleInfo); for(var i in paint) { var titleData=new DynamicTitleData(paint[i].Data,this.Index[i].Name,this.Index[i].LineColor); if (i>0) titleData.DataType="StraightLine"; titlePaint.OverlayIndex.get(this.OverlayIndex.Identify).Data[i]=titleData; } } else { hqChart.Frame.SubFrame[windowIndex].Frame.YSpecificMaxMin={Max:9,Min:0,Count:3}; for(var i in paint) { hqChart.TitlePaint[titleIndex].Data[i]=new DynamicTitleData(paint[i].Data,this.Index[i].Name,this.Index[i].LineColor); if (i>0) hqChart.TitlePaint[titleIndex].Data[i].DataType="StraightLine"; } } return true; } } //市场择时 function MarketTimingIndex() { this.newMethod=BaseIndex; //派生 this.newMethod('Market-Timing'); delete this.newMethod; this.Index=new Array( new IndexInfo("因子择时",null) ); this.TimingData; //择时数据 this.TitleColor=g_JSChartResource.FrameSplitTextColor this.Create=function(hqChart,windowIndex) { var frame=null; var isOverlay=this.IsOverlay(); if (isOverlay) frame=this.OverlayIndex.Frame.Frame; else frame=hqChart.Frame.SubFrame[windowIndex].Frame; for(var i in this.Index) { var paint=new ChartMACD(); paint.Canvas=hqChart.Canvas; paint.Name=this.Name+"-"+i.toString(); paint.ChartBorder=frame.ChartBorder; paint.ChartFrame=frame; if (isOverlay) this.OverlayIndex.Frame.ChartPaint.push(paint); else hqChart.ChartPaint.push(paint); } } //请求数据 this.RequestData=function(hqChart,windowIndex,hisData) { var self = this; var param= { HQChart:hqChart, WindowIndex:windowIndex, HistoryData:hisData }; this.LongShortData=[]; if (param.HQChart.Period>0) //周期数据 { this.NotSupport(param.HQChart,param.WindowIndex,"不支持周期切换"); param.HQChart.Draw(); return false; } //请求数据 JSNetwork.HttpRequest({ url: g_JSChartResource.Index.MarketLongShortApiUrl, data: { }, type:"post", dataType: "json", async:true, success: function (recvData) { self.RecvData(recvData,param); } }); return true; } this.RecvData=function(recvData,param) { if (recvData.data.length<=0) return; var aryData=new Array(); for(var i in recvData.data) { var item=recvData.data[i]; var indexData=new SingleData(); indexData.Date=item[0]; indexData.Value=item[2]; aryData.push(indexData); } var aryFittingData=param.HistoryData.GetFittingData(aryData); var bindData=new ChartData(); bindData.Data=aryFittingData; bindData.Period=param.HQChart.Period; //周期 bindData.Right=param.HQChart.Right; //复权 this.TimingData=bindData.GetValue(); this.BindData(param.HQChart,param.WindowIndex,param.HistoryData); param.HQChart.UpdataDataoffset(); //更新数据偏移 param.HQChart.UpdateFrameMaxMin(); //调整坐标最大 最小值 param.HQChart.Draw(); } this.BindData=function(hqChart,windowIndex,hisData) { var paint=null; var isOverlay=this.IsOverlay(); if (isOverlay) paint=this.OverlayIndex.Frame.ChartPaint; else paint=hqChart.GetChartPaint(windowIndex); if (paint.length!=this.Index.length) return false; //paint[0].Data.Data=SWLData; paint[0].Data.Data=this.TimingData; paint[0].NotSupportMessage=null; var titleIndex=windowIndex+1; if (isOverlay) { var titlePaint=hqChart.TitlePaint[titleIndex]; var titleInfo={ Data:[], Title:'' }; titlePaint.OverlayIndex.set(this.OverlayIndex.Identify,titleInfo); for(var i in paint) { var titleData=new DynamicTitleData(paint[i].Data,this.Index[i].Name,this.Index[i].LineColor); titleData.StringFormat=STRING_FORMAT_TYPE.THOUSANDS; titleData.FloatPrecision=0; titlePaint.OverlayIndex.get(this.OverlayIndex.Identify).Data[i]=titleData; } } else { for(var i in paint) { hqChart.TitlePaint[titleIndex].Data[i]=new DynamicTitleData(paint[i].Data,this.Index[i].Name,this.TitleColor); hqChart.TitlePaint[titleIndex].Data[i].StringFormat=STRING_FORMAT_TYPE.THOUSANDS; hqChart.TitlePaint[titleIndex].Data[i].FloatPrecision=0; } } return true; } } //市场关注度 function MarketAttentionIndex() { this.newMethod=BaseIndex; //派生 this.newMethod('Market-Attention'); delete this.newMethod; this.Index=new Array( new IndexInfo("市场关注度",null) ); this.Data; //关注度数据 this.TitleColor=g_JSChartResource.FrameSplitTextColor; this.ApiUrl=g_JSChartResource.Index.MarketAttentionApiUrl; this.Create=function(hqChart,windowIndex) { var frame=null; var isOverlay=this.IsOverlay(); if (isOverlay) frame=this.OverlayIndex.Frame.Frame; else frame=hqChart.Frame.SubFrame[windowIndex].Frame; for(var i in this.Index) { var paint=new ChartMACD(); //柱子 paint.Canvas=hqChart.Canvas; paint.Name=this.Name+"-"+i.toString(); paint.ChartBorder=frame.ChartBorder; paint.ChartFrame=frame; if (isOverlay) this.OverlayIndex.Frame.ChartPaint.push(paint); else hqChart.ChartPaint.push(paint); } } //调整框架 this.SetFrame=function(hqChart,windowIndex,hisData) { var isOverlay=this.IsOverlay(); if (isOverlay) this.OverlayIndex.Frame.Frame.YSpecificMaxMin={Max:6,Min:0,Count:3}; else hqChart.Frame.SubFrame[windowIndex].Frame.YSpecificMaxMin={Max:6,Min:0,Count:3}; } //请求数据 this.RequestData=function(hqChart,windowIndex,hisData) { var self = this; var param= { HQChart:hqChart, WindowIndex:windowIndex, HistoryData:hisData }; this.Data=[]; if (param.HQChart.Period>0) //周期数据 { this.NotSupport(param.HQChart,param.WindowIndex,"不支持周期切换"); param.HQChart.Draw(); return false; } //请求数据 JSNetwork.HttpRequest({ url: this.ApiUrl, data: { "symbol":param.HQChart.Symbol, "startdate":20100101, }, type:"post", dataType: "json", async:true, success: function (recvData) { self.RecvData(recvData,param); } }); return true; } this.RecvData=function(recvData,param) { if (recvData.date.length<0) return; var aryData=new Array(); for(var i in recvData.date) { var indexData=new SingleData(); indexData.Date=recvData.date[i]; indexData.Value=recvData.value[i]; aryData.push(indexData); } var aryFittingData=param.HistoryData.GetFittingData(aryData); var bindData=new ChartData(); bindData.Data=aryFittingData; bindData.Period=param.HQChart.Period; //周期 bindData.Right=param.HQChart.Right; //复权 this.Data=bindData.GetValue(); this.BindData(param.HQChart,param.WindowIndex,param.HistoryData); this.SetFrame(param.HQChart,param.WindowIndex,param.HistoryData); param.HQChart.UpdataDataoffset(); //更新数据偏移 param.HQChart.UpdateFrameMaxMin(); //调整坐标最大 最小值 param.HQChart.Draw(); } this.BindData=function(hqChart,windowIndex,hisData) { var paint=null; var isOverlay=this.IsOverlay(); if (isOverlay) paint=this.OverlayIndex.Frame.ChartPaint; else paint=hqChart.GetChartPaint(windowIndex); if (paint.length!=this.Index.length) return false; //paint[0].Data.Data=SWLData; paint[0].Data.Data=this.Data; paint[0].NotSupportMessage=null; var titleIndex=windowIndex+1; if (isOverlay) { var titlePaint=hqChart.TitlePaint[titleIndex]; var titleInfo={ Data:[], Title:'' }; titlePaint.OverlayIndex.set(this.OverlayIndex.Identify,titleInfo); for(var i in paint) { var titleData=new DynamicTitleData(paint[i].Data,this.Index[i].Name,this.Index[i].LineColor); titleData.StringFormat=STRING_FORMAT_TYPE.THOUSANDS; titleData.FloatPrecision=0; titlePaint.OverlayIndex.get(this.OverlayIndex.Identify).Data[i]=titleData; } } else { for(var i in paint) { hqChart.TitlePaint[titleIndex].Data[i]=new DynamicTitleData(paint[i].Data,this.Index[i].Name,this.TitleColor); hqChart.TitlePaint[titleIndex].Data[i].StringFormat=STRING_FORMAT_TYPE.THOUSANDS; hqChart.TitlePaint[titleIndex].Data[i].FloatPrecision=0; } } return true; } } /* 行业,指数热度 */ function MarketHeatIndex() { this.newMethod=BaseIndex; //派生 this.newMethod('Market-Heat'); delete this.newMethod; this.Index=new Array( new IndexInfo("热度",5), new IndexInfo('MA',10), new IndexInfo('MA',null) ); this.Data; //关注度数据 this.ApiUrl=g_JSChartResource.Index.MarketHeatApiUrl; this.Index[0].LineColor=g_JSChartResource.FrameSplitTextColor; this.Index[1].LineColor=g_JSChartResource.Index.LineColor[0]; this.Index[2].LineColor=g_JSChartResource.Index.LineColor[1]; this.Create=function(hqChart,windowIndex) { var frame=null; var isOverlay=this.IsOverlay(); if (isOverlay) frame=this.OverlayIndex.Frame.Frame; else frame=hqChart.Frame.SubFrame[windowIndex].Frame; for(var i in this.Index) { var paint=null; if (i==0) { paint=new ChartMACD(); //柱子 } else { paint=new ChartLine(); paint.Color=this.Index[i].LineColor; } paint.Canvas=hqChart.Canvas; paint.Name=this.Name+"-"+i.toString(); paint.ChartBorder=frame.ChartBorder; paint.ChartFrame=frame; if (isOverlay) this.OverlayIndex.Frame.ChartPaint.push(paint); else hqChart.ChartPaint.push(paint); } } //请求数据 this.RequestData=function(hqChart,windowIndex,hisData) { var self = this; var param= { HQChart:hqChart, WindowIndex:windowIndex, HistoryData:hisData }; this.Data=[]; if (param.HQChart.Period>0) //周期数据 { this.NotSupport(param.HQChart,param.WindowIndex,"不支持周期切换"); param.HQChart.Draw(); return false; } //请求数据 JSNetwork.HttpRequest({ url: this.ApiUrl, data: { "symbol":param.HQChart.Symbol, "startdate":20100101, }, type:"post", dataType: "json", async:true, success: function (recvData) { self.RecvData(recvData,param); } }); return true; } this.RecvData=function(recvData,param) { if (recvData.date.length<0) return; var aryData=new Array(); for(var i in recvData.date) { var indexData=new SingleData(); indexData.Date=recvData.date[i]; indexData.Value=recvData.value[i]; aryData.push(indexData); } var aryFittingData=param.HistoryData.GetFittingData(aryData); var bindData=new ChartData(); bindData.Data=aryFittingData; bindData.Period=param.HQChart.Period; //周期 bindData.Right=param.HQChart.Right; //复权 this.Data=bindData.GetValue(); this.BindData(param.HQChart,param.WindowIndex,param.HistoryData); param.HQChart.UpdataDataoffset(); //更新数据偏移 param.HQChart.UpdateFrameMaxMin(); //调整坐标最大 最小值 param.HQChart.Draw(); } this.BindData=function(hqChart,windowIndex,hisData) { var paint=null; var isOverlay=this.IsOverlay(); if (isOverlay) paint=this.OverlayIndex.Frame.ChartPaint; else paint=hqChart.GetChartPaint(windowIndex); if (paint.length!=this.Index.length) return false; paint[0].Data.Data=this.Data; paint[0].NotSupportMessage=null; var MA=HQIndexFormula.MA(this.Data,this.Index[0].Param); paint[1].Data.Data=MA; var MA2=HQIndexFormula.MA(this.Data,this.Index[1].Param); paint[2].Data.Data=MA2; var titleIndex=windowIndex+1; if (isOverlay) { var titlePaint=hqChart.TitlePaint[titleIndex]; var titleInfo={ Data:[], Title:'' }; titlePaint.OverlayIndex.set(this.OverlayIndex.Identify,titleInfo); for(var i in paint) { var name='' if(i==0) name=hqChart.Name+this.Index[i].Name; else name="MA"+this.Index[i-1].Param; var titleData=new DynamicTitleData(paint[i].Data,name,this.Index[i].LineColor); titleData.StringFormat=STRING_FORMAT_TYPE.DEFAULT; titleData.FloatPrecision=2; titlePaint.OverlayIndex.get(this.OverlayIndex.Identify).Data[i]=titleData; } } else { for(var i in paint) { var name=""; //显示的名字特殊处理 if(i==0) name=hqChart.Name+this.Index[i].Name; else name="MA"+this.Index[i-1].Param; hqChart.TitlePaint[titleIndex].Data[i]=new DynamicTitleData(paint[i].Data,name,this.Index[i].LineColor); hqChart.TitlePaint[titleIndex].Data[i].StringFormat=STRING_FORMAT_TYPE.DEFAULT; hqChart.TitlePaint[titleIndex].Data[i].FloatPrecision=2; } } //hqChart.TitlePaint[titleIndex].Explain="热度说明"; return true; } } //自定义指数热度 function CustonIndexHeatIndex() { this.newMethod=BaseIndex; //派生 this.newMethod('Market-Heat'); delete this.newMethod; this.Index=new Array( new IndexInfo('区域',3), new IndexInfo("热度指数",10), new IndexInfo('MA',5), new IndexInfo('MA',10) ); this.Data; //关注度数据 this.ApiUrl=g_JSChartResource.Index.CustomIndexHeatApiUrl; this.Index[1].LineColor=g_JSChartResource.Index.LineColor[1]; this.Index[2].LineColor=g_JSChartResource.Index.LineColor[2]; this.Index[3].LineColor=g_JSChartResource.Index.LineColor[3]; this.Create=function(hqChart,windowIndex) { for(var i in this.Index) { var paint=null; if (i==0) { paint = new ChartStraightArea(); } else { paint=new ChartLine(); paint.Color=this.Index[i].LineColor; } paint.Canvas=hqChart.Canvas; paint.Name=this.Name+"-"+i.toString(); paint.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder; paint.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame; hqChart.ChartPaint.push(paint); } } //请求数据 this.RequestData=function(hqChart,windowIndex,hisData) { var self = this; var param= { HQChart:hqChart, WindowIndex:windowIndex, HistoryData:hisData }; this.Data=[]; if (param.HQChart.Period>0) //周期数据 { this.NotSupport(param.HQChart,param.WindowIndex,"不支持周期切换"); param.HQChart.Draw(); return false; } //请求数据 JSNetwork.HttpRequest({ url: this.ApiUrl, data: { "stock":param.HQChart.CustomStock, "date":{"startdate":param.HQChart.QueryDate.Start,"enddate":param.HQChart.QueryDate.End}, "day":[this.Index[0].Param,this.Index[1].Param], }, type:"post", dataType: "json", async:true, success: function (recvData) { self.RecvData(recvData,param); } }); return true; } this.RecvData=function(recvData,param) { if (recvData.data==null || recvData.data.length<0) return; //console.log(recvData.data); var aryData=new Array(); for(let i in recvData.data) { let item=recvData.data[i]; let indexData=new SingleData(); indexData.Date=item[0]; indexData.Value=item[1]; aryData.push(indexData); } var aryFittingData=param.HistoryData.GetFittingData(aryData); var bindData=new ChartData(); bindData.Data=aryFittingData; bindData.Period=param.HQChart.Period; //周期 bindData.Right=param.HQChart.Right; //复权 this.Data=bindData.GetValue(); this.BindData(param.HQChart,param.WindowIndex,param.HistoryData); param.HQChart.UpdataDataoffset(); //更新数据偏移 param.HQChart.UpdateFrameMaxMin(); //调整坐标最大 最小值 param.HQChart.Draw(); } this.BindData=function(hqChart,windowIndex,hisData) { let paint=hqChart.GetChartPaint(windowIndex); if (paint.length!=this.Index.length) return false; paint[0].NotSupportMessage=null; paint[0].Data.Data= [ { Value: 0, Value2: 0.2, Color: 'rgb(50,205,50)', Title: '热度1', TitleColor:'rgb(245,255 ,250)'}, { Value: 0.2, Value2: 0.4, Color: 'rgb(255,140,0)', Title: '热度2', TitleColor:'rgb(245,255 ,250)'}, { Value: 0.4, Value2: 0.8, Color: 'rgb(255,106,106)', Title: '热度3', TitleColor:'rgb(245,255 ,250)'}, { Value: 0.8, Value2: 1, Color: 'rgb(208, 32 ,144)', Title: '热度4', TitleColor:'rgb(245,255 ,250)'} ]; paint[1].Data.Data = this.Data; let MA=HQIndexFormula.MA(this.Data,this.Index[2].Param); paint[2].Data.Data=MA; let MA2=HQIndexFormula.MA(this.Data,this.Index[3].Param); paint[3].Data.Data=MA2; //指定框架最大最小[0,1] hqChart.Frame.SubFrame[windowIndex].Frame.YSpecificMaxMin = { Max: 1, Min: 0, Count: 3 }; let titleIndex=windowIndex+1; for(let i=1;i下线 , 上线,下线 ,2, 0),COLORRED,LINETHICK2; STICKLINE(下线>上线,上线,下线,2,0),COLORBLUE,LINETHICK2; */ function LighterIndex1() { this.newMethod=BaseIndex; //派生 this.newMethod('Lighter-Trend'); delete this.newMethod; this.Index=new Array( new IndexInfo("STICKLINE",null), new IndexInfo('STICKLINE',null) ); this.Index[0].LineColor='rgb(255,0,0)'; this.Index[1].LineColor='rgb(0,0,255)'; this.Create=function(hqChart,windowIndex) { for(var i in this.Index) { var paint=new ChartStickLine(); paint.Canvas=hqChart.Canvas; paint.Name=this.Name; paint.Name=this.Name+'-'+i.toString(); paint.Color=this.Index[i].LineColor; paint.LineWidth=2; paint.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder; paint.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame; hqChart.ChartPaint.push(paint); } } this.BindData=function(hqChart,windowIndex,hisData) { var paint=hqChart.GetChartPaint(windowIndex); if (paint.length!=2) return false; var closeData=hisData.GetClose(); var upData=HQIndexFormula.SMA(closeData,6.5,1); var downData=HQIndexFormula.SMA(closeData,13.5,1); var stickLine=HQIndexFormula.STICKLINE(HQIndexFormula.ARRAY_GT(upData,downData),upData,downData);; var stickLine2=HQIndexFormula.STICKLINE(HQIndexFormula.ARRAY_GT(downData,upData),upData,downData);; paint[0].Data.Data=stickLine; paint[1].Data.Data=stickLine2; var titleIndex=windowIndex+1; hqChart.TitlePaint[titleIndex].Title="大盘/个股 趋势函数"; return true; } } /* 位置研判函数 N:=34;M:=3; 28,COLORFFFFFF; STICKLINE(C>0,0,2,5,0),COLOR00008A; STICKLINE(C>0,2,5,5,0),COLOR85008A; STICKLINE(C>0,5,10,5,0),COLOR657600; STICKLINE(C>0,10,21.5,5,0),COLOR690079; STICKLINE(C>0,21.5,23,5,0),COLOR79B715; STICKLINE(C>0,23,28,5,0),COLOR00008A; VAR1:=EMA(100*(CLOSE-LLV(LOW,N))/(HHV(HIGH,N)-LLV(LOW,N)),M)/4,COLORFFFF00,LINETHICK2; 财貌双拳:VAR1,COLORFFFF00,LINETHICK2; DRAWTEXT(CURRBARSCOUNT=128,1,'底部区域'),COLOR00FFFF; DRAWTEXT(CURRBARSCOUNT=128,3.5,'介入区域'),COLOR00FFFF; DRAWTEXT(CURRBARSCOUNT=128,7.5,'稳健区域'),COLOR00FFFF; DRAWTEXT(CURRBARSCOUNT=128,16,'高位区域'),COLOR00FFFF; DRAWTEXT(CURRBARSCOUNT=128,22,'风险区域'),COLOR0000FF; DRAWTEXT(CURRBARSCOUNT=128,25.5,'顶部区域'),COLORFF00FF; */ function LighterIndex2() { this.newMethod=BaseIndex; //派生 this.newMethod('位置研判函数'); delete this.newMethod; this.Index=new Array( new IndexInfo("STICKLINE",34), new IndexInfo('STICKLINE',3), new IndexInfo('STICKLINE',null), new IndexInfo('STICKLINE',null), new IndexInfo('STICKLINE',null), new IndexInfo('STICKLINE',null), new IndexInfo('LINE',null), new IndexInfo('TEXT',null) ); this.Index[0].LineColor='rgb(0,0,138)'; this.Index[1].LineColor='rgb(133,0,138)'; this.Index[2].LineColor='rgb(101,118,0)'; this.Index[3].LineColor='rgb(105,0,121)'; this.Index[4].LineColor='rgb(121,183,21)'; this.Index[5].LineColor='rgb(0,0,138)'; this.Index[6].LineColor='rgb(255,0,0)'; this.Create=function(hqChart,windowIndex) { for(var i in this.Index) { var paint=null; if (this.Index[i].Name=='LINE') { paint=new ChartLine(); paint.Color=this.Index[i].LineColor; } else if (this.Index[i].Name=='TEXT') { paint=new ChartText(); } else { paint=new ChartStickLine(); paint.Color=this.Index[i].LineColor; paint.LineWidth=5; } paint.Canvas=hqChart.Canvas; paint.Name=this.Name; paint.Name=this.Name+'-'+i.toString(); paint.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder; paint.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame; hqChart.ChartPaint.push(paint); } } this.BindData=function(hqChart,windowIndex,hisData) { var paint=hqChart.GetChartPaint(windowIndex); if (paint.length!=this.Index.length) return false; var closeData=hisData.GetClose(); var highData=hisData.GetHigh(); var lowData=hisData.GetLow(); paint[0].Data.Data=HQIndexFormula.STICKLINE(HQIndexFormula.ARRAY_GT(closeData,0),0,2); paint[1].Data.Data=HQIndexFormula.STICKLINE(HQIndexFormula.ARRAY_GT(closeData,0),2,5); paint[2].Data.Data=HQIndexFormula.STICKLINE(HQIndexFormula.ARRAY_GT(closeData,0),5,10); paint[3].Data.Data=HQIndexFormula.STICKLINE(HQIndexFormula.ARRAY_GT(closeData,0),10,21.5); paint[4].Data.Data=HQIndexFormula.STICKLINE(HQIndexFormula.ARRAY_GT(closeData,0),21.5,23,5); paint[5].Data.Data=HQIndexFormula.STICKLINE(HQIndexFormula.ARRAY_GT(closeData,0),23,28,5); //VAR1:=EMA(100*(CLOSE-LLV(LOW,N))/(HHV(HIGH,N)-LLV(LOW,N)),M)/4 var lineData=HQIndexFormula.ARRAY_DIVIDE( HQIndexFormula.EMA( HQIndexFormula.ARRAY_MULTIPLY( HQIndexFormula.ARRAY_DIVIDE( HQIndexFormula.ARRAY_SUBTRACT(closeData,HQIndexFormula.LLV(lowData,this.Index[0].Param)), HQIndexFormula.ARRAY_SUBTRACT(HQIndexFormula.HHV(highData,this.Index[0].Param),HQIndexFormula.LLV(lowData,this.Index[0].Param)) ), 100), this.Index[1].Param), 4 ); paint[6].Data.Data=lineData; //DRAWTEXT(CURRBARSCOUNT=128,1,'底部区域'),COLOR00FFFF; //DRAWTEXT(CURRBARSCOUNT=128,3.5,'介入区域'),COLOR00FFFF; //DRAWTEXT(CURRBARSCOUNT=128,7.5,'稳健区域'),COLOR00FFFF; //DRAWTEXT(CURRBARSCOUNT=128,16,'高位区域'),COLOR00FFFF; //DRAWTEXT(CURRBARSCOUNT=128,22,'风险区域'),COLOR0000FF; //DRAWTEXT(CURRBARSCOUNT=128,25.5,'顶部区域'),COLORFF00FF; var TextData=new Array(); TextData[0]={Value:1, Message:'底部区域',Color:'rgb(0,255,255)',Position:'Left'}; TextData[1]={Value:3.5, Message:'介入区域',Color:'rgb(0,255,255)',Position:'Left'}; TextData[2]={Value:7.5, Message:'稳健区域',Color:'rgb(0,255,255)',Position:'Left'}; TextData[3]={Value:16, Message:'高位区域',Color:'rgb(0,255,255)',Position:'Left'}; TextData[4]={Value:22, Message:'风险区域',Color:'rgb(0,0,255)',Position:'Left'}; TextData[5]={Value:25.5,Message:'顶部区域',Color:'rgb(255,0,255)',Position:'Left'}; paint[7].Data.Data=TextData; var titleIndex=windowIndex+1; hqChart.TitlePaint[titleIndex].Data[0]=new DynamicTitleData(paint[6].Data,"财貌双拳",paint[6].Color); hqChart.TitlePaint[titleIndex].Title=this.FormatIndexTitle(); return true; } } /* py指标 服务器端执行 */ function PyScriptIndex(name,script,args,option) { this.newMethod=BaseIndex; //派生 this.newMethod(name); delete this.newMethod; this.Script=script; //脚本 this.Arguments=[]; //参数 this.OutVar=[]; //输出数据 this.ApiUrl=g_JSChartResource.PyIndexDomain+'/hq/code'; if (args) this.Arguments=args; this.RequestData=function(hqChart,windowIndex,hisData) { this.OutVar=[]; var self = this; var param= { HQChart:hqChart, WindowIndex:windowIndex, HistoryData:hisData }; //参数 var strParam=''; for(let i in this.Arguments) { if (strParam.length>0) strParam+=','; var item=this.Arguments[i]; strParam+='"'+item.Name+'"'+':'+item.Value; } strParam='{'+strParam+'}'; var indexParam=JSON.parse(strParam); var data=JSON.stringify( { code:this.Script, //脚本 symbol:param.HQChart.Symbol, //股票代码 period:param.HQChart.Period, //周期 0=日线 1=周线 2=月线 3=年线 4=1分钟 5=5分钟 6=15分钟 7=30分钟 8=60分钟 right:param.HQChart.Right, //复权 0 不复权 1 前复权 2 后复权 params:indexParam, //指标参数 numcount:hqChart.MaxReqeustDataCount, }); //请求数据 JSNetwork.HttpRequest({ url: this.ApiUrl, data:data, type:"post", dataType: "json", contentType:' application/json; charset=utf-8', async:true, success: function (recvData) { self.RecvData(recvData,param); }, complete:function(h) { //console.log(h); }, error: function(http,e) { self.RecvError(http,e,param);; } }); return true; } this.RecvError=function(http,e,param) { console.log("[PyScriptIndex::RecvError] error",e); if (param.HQChart.ScriptErrorCallback) param.HQChart.ScriptErrorCallback(e); } this.RecvData=function(recvData,param) { if (recvData.code!=0) { console.log("[PyScriptIndex::RecvData] failed.", recvData); if (param.HQChart.ScriptErrorCallback) param.HQChart.ScriptErrorCallback(recvData.msg); return; //失败了 } console.log('[PyScriptIndex::RecvData] recv data.',recvData); var aryDate=recvData.date; for(var i in recvData.data) { var item=recvData.data[i]; var indexData=[]; for(var j=0;j=item.data.length) continue; var indexItem=new SingleData(); //单列指标数据 indexItem.Date=aryDate[j]; indexItem.Value=item.data[j]; indexData.push(indexItem); } var aryFittingData=param.HistoryData.GetFittingData(indexData); //数据和主图K线拟合 var bindData=new ChartData(); bindData.Data=aryFittingData; bindData.Period=param.HQChart.Period; //周期 bindData.Right=param.HQChart.Right; //复权 var indexInfo={Name:item.name,Type:item.graph,LineWidth:item.width,Data:bindData.GetValue(),Color:item.color}; this.OutVar.push(indexInfo); } this.BindData(param.HQChart,param.WindowIndex,param.HistoryData); //把数据绑定到图形上 param.HQChart.UpdataDataoffset(); //更新数据偏移 param.HQChart.UpdateFrameMaxMin(); //调整坐标最大 最小值 param.HQChart.Draw(); } this.BindData=function(hqChart,windowIndex,hisData) { hqChart.DeleteIndexPaint(windowIndex); //清空指标图形 for(let i in this.OutVar) { let item=this.OutVar[i]; switch(item.Type) { case 'line': this.CreateLine(hqChart,windowIndex,item,i); break; case 'colorstick': //上下柱子 this.CreateColorStock(hqChart,windowIndex,item,i); break; } } var titleIndex=windowIndex+1; hqChart.TitlePaint[titleIndex].Title=this.Name; //这是指标名称 let indexParam=''; //指标参数 for(let i in this.Arguments) { let item=this.Arguments[i]; if (indexParam.length>0) indexParam+=','; indexParam+=item.Value.toString(); } if (indexParam.length>0) hqChart.TitlePaint[titleIndex].Title=this.Name+'('+indexParam+')'; return true; } this.CreateLine=function(hqChart,windowIndex,varItem,id) { let line=new ChartLine(); line.Canvas=hqChart.Canvas; line.DrawType=1; line.Name=varItem.Name; line.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder; line.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame; if (varItem.Color) line.Color=varItem.Color; else line.Color=this.GetDefaultColor(id); if (varItem.LineWidth>0) line.LineWidth=varItem.LineWidth; if (varItem.IsShow==false) line.IsShow=false; let titleIndex=windowIndex+1; line.Data.Data=varItem.Data; hqChart.TitlePaint[titleIndex].Data[id]=new DynamicTitleData(line.Data,varItem.Name,line.Color); hqChart.ChartPaint.push(line); } this.CreateColorStock=function(hqChart,windowIndex,varItem,id) { let chart=new ChartMACD(); chart.Canvas=hqChart.Canvas; chart.Name=varItem.Name; chart.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder; chart.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame; let titleIndex=windowIndex+1; chart.Data.Data=varItem.Data; hqChart.TitlePaint[titleIndex].Data[id]=new DynamicTitleData(chart.Data,varItem.Name,this.GetDefaultColor(id)); hqChart.ChartPaint.push(chart); } //给一个默认的颜色 this.GetDefaultColor=function(id) { let COLOR_ARRAY= [ "rgb(255,174,0)", "rgb(25,199,255)", "rgb(175,95,162)", "rgb(236,105,65)", "rgb(68,114,196)", "rgb(229,0,79)", "rgb(0,128,255)", "rgb(252,96,154)", "rgb(42,230,215)", "rgb(24,71,178)", ]; let number=parseInt(id); return COLOR_ARRAY[number%(COLOR_ARRAY.length-1)]; } } /* json格式数据指标 用来显示本地数据 */ function JsonDataIndex(name,script,args,option) { this.newMethod=PyScriptIndex; //派生 this.newMethod(name); delete this.newMethod; this.JsonData; //json格式数据 if (option.JsonData) this.JsonData=option.JsonData; this.RequestData=function(hqChart,windowIndex,hisData) { if (!this.JsonData) { console.warn("[PyScriptIndex::RequestData] JsonData is null"); if (param.HQChart.ScriptErrorCallback) param.HQChart.ScriptErrorCallback('json 数据不能为空'); } else { var param= { HQChart:hqChart, WindowIndex:windowIndex, HistoryData:hisData }; this.JsonData.code=0; var recvData=this.JsonData; this.RecvData(recvData,param); } } } //给一个默认的颜色 PyScriptIndex.prototype.GetDefaultColor=function(id) { let COLOR_ARRAY= [ "rgb(255,174,0)", "rgb(25,199,255)", "rgb(175,95,162)", "rgb(236,105,65)", "rgb(68,114,196)", "rgb(229,0,79)", "rgb(0,128,255)", "rgb(252,96,154)", "rgb(42,230,215)", "rgb(24,71,178)", ]; let number=parseInt(id); return COLOR_ARRAY[number%(COLOR_ARRAY.length-1)]; } /* 点位研判函数 HJ_1:=REF(LOW,1); HJ_2:=SMA(ABS(LOW-HJ_1),13,1)/SMA(MAX(LOW-HJ_1,0),13,1)*100; HJ_3:=EMA(IF(CLOSE*1.2,HJ_2*13,HJ_2/13),13); HJ_4:=LLV(LOW,34); HJ_5:=HHV(HJ_3,34); HJ_6:=IF(LLV(LOW,56),1,0); HJ_7:=EMA(IF(LOW<=HJ_4,(HJ_3+HJ_5*2)/2,0),3)/618*HJ_6; HJ_8:=HJ_7>REF(HJ_7,1); HJ_9:=REF(LLV(LOW,100),3); HJ_10:=REFDATE(HJ_9,DATE); HJ_11:=LOW=HJ_10; HJ_12:=HJ_8 AND HJ_11; HJ_13:=HJ_12>REF(HJ_12,1); 启动买点:HJ_13>REF(HJ_13,1),COLORRED,LINETHICK1; */ function LighterIndex3() { this.newMethod=BaseIndex; //派生 this.newMethod('点位研判函数'); delete this.newMethod; this.Index=new Array( new IndexInfo("启动买点",null) ); this.Index[0].LineColor='rgb(255,0,0)'; this.BindData=function(hqChart,windowIndex,hisData) { var paint=hqChart.GetChartPaint(windowIndex); if (paint.length!=this.Index.length) return false; var closeData=hisData.GetClose(); var highData=hisData.GetHigh(); var lowData=hisData.GetLow(); //HJ_1:=REF(LOW,1); var hj_1=HQIndexFormula.REF(lowData,1); //HJ_2:=SMA(ABS(LOW-HJ_1),13,1)/SMA(MAX(LOW-HJ_1,0),13,1)*100; var hj_2=HQIndexFormula.ARRAY_MULTIPLY( HQIndexFormula.ARRAY_DIVIDE( HQIndexFormula.SMA(HQIndexFormula.ABS(HQIndexFormula.ARRAY_SUBTRACT(lowData,hj_1)),13,1), HQIndexFormula.SMA(HQIndexFormula.MAX(HQIndexFormula.ARRAY_SUBTRACT(lowData,hj_1),0),13,1) ), 100 ); //HJ_3:=EMA(IF(CLOSE*1.2,HJ_2*13,HJ_2/13),13); var hj_3=HQIndexFormula.EMA( HQIndexFormula.ARRAY_IF(HQIndexFormula.ARRAY_MULTIPLY(closeData,1.2),HQIndexFormula.ARRAY_MULTIPLY(hj_2,13),HQIndexFormula.ARRAY_DIVIDE(hj_2,13)), 13 ); //HJ_4:=LLV(LOW,34); var hj_4=HQIndexFormula.LLV(lowData,34); //HJ_5:=HHV(HJ_3,34); var hj_5=HQIndexFormula.HHV(hj_3,34); //HJ_6:=IF(LLV(LOW,56),1,0); var hj_6=HQIndexFormula.ARRAY_IF(HQIndexFormula.LLV(lowData,56),1,0); //HJ_7:=EMA(IF(LOW<=HJ_4,(HJ_3+HJ_5*2)/2,0),3)/618*HJ_6; //hj_7_temp=(HJ_3+HJ_5*2)/2,0) 太长了 这部分单独算下 var hj_7_temp=HQIndexFormula.ARRAY_DIVIDE(HQIndexFormula.ARRAY_ADD(hj_3,HQIndexFormula.ARRAY_MULTIPLY(hj_5,2)),2); var hj_7=HQIndexFormula.ARRAY_MULTIPLY( HQIndexFormula.ARRAY_DIVIDE( HQIndexFormula.EMA( HQIndexFormula.ARRAY_IF(HQIndexFormula.ARRAY_LTE(lowData,hj_4),hj_7_temp,0), 3 ), 618 ), hj_6 ); //HJ_8:=HJ_7>REF(HJ_7,1); var hj_8=HQIndexFormula.ARRAY_GT(hj_7,HQIndexFormula.REF(hj_7,1)); //HJ_9:=REF(LLV(LOW,100),3); var hj_9=HQIndexFormula.REF(HQIndexFormula.LLV(lowData,100),3); //HJ_10:=REFDATE(HJ_9,DATE); 用当日的数据 产生数组 var hj_10=HQIndexFormula.REFDATE(hj_9,-1); //HJ_11:=LOW=HJ_10; var hj_11=HQIndexFormula.ARRAY_EQ(lowData,hj_10); //HJ_12:=HJ_8 AND HJ_11; var hj_12=HQIndexFormula.ARRAY_AND(hj_8,hj_11); var buyData=null; paint[0].Data.Data=hj_12; var titleIndex=windowIndex+1; for(var i in paint) { hqChart.TitlePaint[titleIndex].Data[i]=new DynamicTitleData(paint[i].Data,this.Index[i].Name,this.Index[i].LineColor); } hqChart.TitlePaint[titleIndex].Title=this.FormatIndexTitle(); return true; } } /* 信息地雷 */ /* 信息地雷列表 */ function JSKLineInfoMap() { } JSKLineInfoMap.Get=function(id) { var infoMap=new Map( [ ["互动易", {Create:function(){ return new InvestorInfo()} }], ["公告", {Create:function(){ return new AnnouncementInfo()} }], ["业绩预告", {Create:function(){ return new PforecastInfo()} }], ["调研", {Create:function(){ return new ResearchInfo()} }], ["大宗交易", {Create:function(){ return new BlockTrading()} }], ["龙虎榜", {Create:function(){ return new TradeDetail()} }] ] ); return infoMap.get(id); } JSKLineInfoMap.GetClassInfo=function(id) { var infoMap=new Map( [ ["互动易", { ClassName:"InvestorInfo" }], ["公告", { ClassName:"AnnouncementInfo" }], ["业绩预告", { ClassName:"PforecastInfo" } ], ["调研", { ClassName:"ResearchInfo" }], ["大宗交易", { ClassName:"BlockTrading" }], ["龙虎榜", { ClassName:"TradeDetail"} ] ] ); return infoMap.get(id); } JSKLineInfoMap.GetIconUrl=function(type) { switch(type) { case KLINE_INFO_TYPE.INVESTOR: return g_JSChartResource.KLine.Info.Investor.Icon; break; case KLINE_INFO_TYPE.PFORECAST: return g_JSChartResource.KLine.Info.Pforecast.Icon; case KLINE_INFO_TYPE.ANNOUNCEMENT: return g_JSChartResource.KLine.Info.Announcement.Icon; case KLINE_INFO_TYPE.ANNOUNCEMENT_QUARTER_1: case KLINE_INFO_TYPE.ANNOUNCEMENT_QUARTER_2: case KLINE_INFO_TYPE.ANNOUNCEMENT_QUARTER_3: case KLINE_INFO_TYPE.ANNOUNCEMENT_QUARTER_4: return g_JSChartResource.KLine.Info.Announcement.IconQuarter; case KLINE_INFO_TYPE.RESEARCH: return g_JSChartResource.KLine.Info.Research.Icon; case KLINE_INFO_TYPE.BLOCKTRADING: return g_JSChartResource.KLine.Info.BlockTrading.Icon; case KLINE_INFO_TYPE.TRADEDETAIL: return g_JSChartResource.KLine.Info.TradeDetail.Icon; default: return g_JSChartResource.KLine.Info.Announcement.Icon; } } JSKLineInfoMap.GetIconFont=function(type) { switch(type) { case KLINE_INFO_TYPE.INVESTOR: return g_JSChartResource.KLine.Info.Investor.IconFont; break; case KLINE_INFO_TYPE.PFORECAST: return g_JSChartResource.KLine.Info.Pforecast.IconFont; case KLINE_INFO_TYPE.ANNOUNCEMENT: return g_JSChartResource.KLine.Info.Announcement.IconFont; case KLINE_INFO_TYPE.ANNOUNCEMENT_QUARTER_1: case KLINE_INFO_TYPE.ANNOUNCEMENT_QUARTER_2: case KLINE_INFO_TYPE.ANNOUNCEMENT_QUARTER_3: case KLINE_INFO_TYPE.ANNOUNCEMENT_QUARTER_4: return g_JSChartResource.KLine.Info.Announcement.IconFont2; case KLINE_INFO_TYPE.RESEARCH: return g_JSChartResource.KLine.Info.Research.IconFont; case KLINE_INFO_TYPE.BLOCKTRADING: return g_JSChartResource.KLine.Info.BlockTrading.IconFont; case KLINE_INFO_TYPE.TRADEDETAIL: return g_JSChartResource.KLine.Info.TradeDetail.IconFont; default: return g_JSChartResource.KLine.Info.Announcement.IconFont; } } function IKLineInfo() { this.MaxReqeustDataCount=1000; this.StartDate=20160101; this.Data; this.ClassName='IKLineInfo'; this.GetToday=function() { var date=new Date(); var today=date.getFullYear()*10000+(date.getMonth()+1)*100+date.getDate(); return today; } } //互动易 function InvestorInfo() { this.newMethod=IKLineInfo; //派生 this.newMethod(); delete this.newMethod; this.ClassName='InvestorInfo'; this.RequestData=function(hqChart) { var self = this; var param= { HQChart:hqChart, }; this.Data=[]; //请求数据 JSNetwork.HttpRequest({ url: g_JSChartResource.KLine.Info.Investor.ApiUrl, data: { "filed": ["question","answerdate","symbol","id"], "symbol": [param.HQChart.Symbol], "querydate":{"StartDate":this.StartDate,"EndDate":this.GetToday()}, "start":0, "end":this.MaxReqeustDataCount, }, type:"post", dataType: "json", async:true, success: function (recvData) { self.RecvData(recvData,param); } }); return true; } this.RecvData=function(recvData,param) { if (recvData.list.length<=0) return; for(var i in recvData.list) { var item=recvData.list[i]; var infoData=new KLineInfoData(); infoData.Date=item.answerdate; infoData.Title=item.question; infoData.InfoType=KLINE_INFO_TYPE.INVESTOR; this.Data.push(infoData); } param.HQChart.UpdataChartInfo(); param.HQChart.Draw(); } } //公告 function AnnouncementInfo() { this.newMethod=IKLineInfo; //派生 this.newMethod(); delete this.newMethod; this.ClassName='AnnouncementInfo'; this.ApiType=1; //0=读API 1=读OSS缓存文件 this.RequestData=function(hqChart) { var self = this; var param= { HQChart:hqChart, }; this.Data=[]; if (this.ApiType==1) //取缓存文件 { var url=`${g_JSChartResource.CacheDomain}/cache/analyze/shszreportlist/${param.HQChart.Symbol}.json`; JSNetwork.HttpRequest({ url: url, type:"get", dataType: "json", async:true, success: function (recvData) { self.RecvData(recvData,param); }, error: function(http,e) { self.RecvError(http,e,param);; } }); } else //取api { //请求数据 JSNetwork.HttpRequest({ url: g_JSChartResource.KLine.Info.Announcement.ApiUrl, data: { "filed": ["title","releasedate","symbol","id"], "symbol": [param.HQChart.Symbol], "querydate":{"StartDate":this.StartDate,"EndDate":this.GetToday()}, "start":0, "end":this.MaxReqeustDataCount, }, type:"post", dataType: "json", async:true, success: function (recvData) { self.RecvData(recvData,param); }, error: function(http,e) { self.RecvError(http,e,param);; } }); } } this.RecvData=function(recvData,param) { if (recvData.report.length<=0) return; for(var i in recvData.report) { var item=recvData.report[i]; var infoData=new KLineInfoData(); infoData.Date=item.releasedate; infoData.Title=item.title; infoData.InfoType=KLINE_INFO_TYPE.ANNOUNCEMENT; for(var j in item.type) { var typeItem=item.type[j]; switch(typeItem) { case "一季度报告": infoData.InfoType=KLINE_INFO_TYPE.ANNOUNCEMENT_QUARTER_1; break; case "半年度报告": infoData.InfoType=KLINE_INFO_TYPE.ANNOUNCEMENT_QUARTER_2; break; case "三季度报告": infoData.InfoType=KLINE_INFO_TYPE.ANNOUNCEMENT_QUARTER_3; break; case "年度报告": infoData.InfoType=KLINE_INFO_TYPE.ANNOUNCEMENT_QUARTER_4; break; } } this.Data.push(infoData); } param.HQChart.UpdataChartInfo(); param.HQChart.Draw(); } this.RecvError=function(http,e,param) { console.warn("[AnnouncementInfo::RecvError] error, http ",e, http); //if (param.HQChart.ScriptErrorCallback) param.HQChart.ScriptErrorCallback(e); } } //业绩预告 function PforecastInfo() { this.newMethod=IKLineInfo; //派生 this.newMethod(); delete this.newMethod; this.ClassName='PforecastInfo'; this.RequestData=function(hqChart) { var self = this; var param= { HQChart:hqChart, }; this.Data=[]; //请求数据 JSNetwork.HttpRequest({ url: g_JSChartResource.KLine.Info.Pforecast.ApiUrl, data: { "field": ["pforecast.type","pforecast.reportdate","fweek"], "condition": [ {"item":["pforecast.reportdate","int32","gte",this.StartDate]} ], "symbol": [param.HQChart.Symbol], "start":0, "end":this.MaxReqeustDataCount, }, type:"post", dataType: "json", async:true, success: function (recvData) { self.RecvData(recvData,param); } }); return true; } this.RecvData=function(recvData,param) { if (recvData.stock.length!=1) return; if (recvData.stock[0].stockday.length<=0) return; for(var i in recvData.stock[0].stockday) { var item=recvData.stock[0].stockday[i]; if (item.pforecast.length>0) { var dataItem=item.pforecast[0]; var infoData=new KLineInfoData(); infoData.Date= item.date; infoData.Title=dataItem.type; infoData.InfoType=KLINE_INFO_TYPE.PFORECAST; infoData.ExtendData={ Type:dataItem.type, ReportDate:dataItem.reportdate} if(item.fweek) //未来周涨幅 { infoData.ExtendData.FWeek={}; if (item.fweek.week1!=null) infoData.ExtendData.FWeek.Week1=item.fweek.week1; if (item.fweek.week4!=null) infoData.ExtendData.FWeek.Week4=item.fweek.week4; } this.Data.push(infoData); } } param.HQChart.UpdataChartInfo(); param.HQChart.Draw(); } } //投资者关系 (调研) function ResearchInfo() { this.newMethod=IKLineInfo; //派生 this.newMethod(); delete this.newMethod; this.ClassName='ResearchInfo'; this.RequestData=function(hqChart) { var self = this; var param= { HQChart:hqChart }; this.Data=[]; //请求数据 JSNetwork.HttpRequest({ url: g_JSChartResource.KLine.Info.Research.ApiUrl, data: { "filed": ["releasedate","researchdate","level","symbol","id",'type'], "querydate":{"StartDate":this.StartDate,"EndDate":this.GetToday()}, "symbol": [param.HQChart.Symbol], "start":0, "end":this.MaxReqeustDataCount, }, type:"post", dataType: "json", async:true, success: function (recvData) { self.RecvData(recvData,param); } }); return true; } this.RecvData=function(recvData,param) { if (recvData.list.length<=0) return; for(var i in recvData.list) { var item=recvData.list[i]; var infoData=new KLineInfoData(); infoData.ID=item.id; infoData.Date= item.researchdate; infoData.InfoType=KLINE_INFO_TYPE.RESEARCH; infoData.ExtendData={ Level:item.level , Type:item.type}; this.Data.push(infoData); } param.HQChart.UpdataChartInfo(); param.HQChart.Draw(); } } //大宗交易 function BlockTrading() { this.newMethod=IKLineInfo; //派生 this.newMethod(); delete this.newMethod; this.ClassName='BlockTrading'; this.RequestData=function(hqChart) { var self = this; var param= { HQChart:hqChart }; this.Data=[]; //请求数据 JSNetwork.HttpRequest({ url: g_JSChartResource.KLine.Info.BlockTrading.ApiUrl, data: { "field": ["blocktrading.price","blocktrading.vol","blocktrading.premium","fweek","price"], "condition": [ {"item":["date","int32","gte",this.StartDate]}, {"item":["blocktrading.vol","int32","gte","0"]} ], "symbol": [param.HQChart.Symbol], "start":0, "end":this.MaxReqeustDataCount, }, type:"post", dataType: "json", async:true, success: function (recvData) { self.RecvData(recvData,param); } }); return true; } this.RecvData=function(recvData,param) { if (recvData.stock.length!=1) return; if (recvData.stock[0].stockday.length<=0) return; for(var i in recvData.stock[0].stockday) { var item=recvData.stock[0].stockday[i]; var infoData=new KLineInfoData(); infoData.Date= item.date; infoData.InfoType=KLINE_INFO_TYPE.BLOCKTRADING; infoData.ExtendData= { Price:item.blocktrading.price, //交易价格 Premium:item.blocktrading.premium, //溢价 (百分比%) Vol:item.blocktrading.vol, //交易金额单位(万元) ClosePrice:item.price, //收盘价 }; if(item.fweek) //未来周涨幅 { infoData.ExtendData.FWeek={}; if (item.fweek.week1!=null) infoData.ExtendData.FWeek.Week1=item.fweek.week1; if (item.fweek.week4!=null) infoData.ExtendData.FWeek.Week4=item.fweek.week4; } this.Data.push(infoData); } param.HQChart.UpdataChartInfo(); param.HQChart.Draw(); } } //龙虎榜 function TradeDetail() { this.newMethod=IKLineInfo; //派生 this.newMethod(); delete this.newMethod; this.ClassName='TradeDetail'; this.RequestData=function(hqChart) { var self = this; var param= { HQChart:hqChart }; this.Data=[]; //请求数据 JSNetwork.HttpRequest({ url: g_JSChartResource.KLine.Info.TradeDetail.ApiUrl, data: { "field": ["tradedetail.typeexplain","tradedetail.type","fweek"], "condition": [ {"item":["date","int32","gte",this.StartDate]}, {"item":["tradedetail.type","int32","gte","0"]} ], "symbol": [param.HQChart.Symbol], "start":0, "end":this.MaxReqeustDataCount, }, type:"post", dataType: "json", async:true, success: function (recvData) { self.RecvData(recvData,param); } }); return true; } this.RecvData=function(recvData,param) { if (recvData.stock.length!=1) return; if (recvData.stock[0].stockday.length<=0) return; for(var i in recvData.stock[0].stockday) { var item=recvData.stock[0].stockday[i]; var infoData=new KLineInfoData(); infoData.Date= item.date; infoData.InfoType=KLINE_INFO_TYPE.TRADEDETAIL; infoData.ExtendData={Detail:new Array()}; for(var j in item.tradedetail) { var tradeItem=item.tradedetail[j]; infoData.ExtendData.Detail.push({"Type":tradeItem.type,"TypeExplain":tradeItem.typeexplain}); } if(item.fweek) //未来周涨幅 { infoData.ExtendData.FWeek={}; if (item.fweek.week1!=null) infoData.ExtendData.FWeek.Week1=item.fweek.week1; if (item.fweek.week4!=null) infoData.ExtendData.FWeek.Week4=item.fweek.week4; } this.Data.push(infoData); } param.HQChart.UpdataChartInfo(); param.HQChart.Draw(); } } function JSMinuteInfoMap() { } JSMinuteInfoMap.InfoMap=new Map( [ ["大盘异动", {Create:function(){ return new MarketEventInfo()} }], ]); JSMinuteInfoMap.Get=function(id) { return JSMinuteInfoMap.InfoMap.get(id); } function IMinuteInfo() { this.Data; this.ClassName='IMinuteInfo'; } ////////////////////////////////////////////////////////////////////// // 大盘异动 // 结构 {Date:日期 Time:时间, Title:标题, Type:0 } //////////////////////////////////////////////////////////////////// function MarketEventInfo() { this.newMethod=IMinuteInfo; //派生 this.newMethod(); delete this.newMethod; this.ClassName='MarketEventInfo'; this.RequestData=function(hqChart) { var self = this; this.Data=[]; var param= { HQChart:hqChart }; var url=g_JSChartResource.CacheDomain+'/cache/analyze/shszevent/marketevent/concept/'+hqChart.TradeDate+'.json'; if (hqChart.NetworkFilter) { var obj= { Name:'MarketEventInfo::RequestData', //类名:: Explain:'大盘异动', Request:{ Url:url, Type:'Get', Data: { Date:hqChart.TradeDate, Symbol:hqChart.Symbol } }, Self:this, PreventDefault:false }; hqChart.NetworkFilter(obj, function(data) { self.RecvData(data,param); param.HQChart.UpdataChartInfo(); param.HQChart.Draw(); }); if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求 } //请求数据 JSNetwork.HttpRequest({ url: url, type:"get", dataType: "json", async:true, success: function (recvData) { self.RecvData(recvData,param); }, error: function(http,e) { console.warn("[MarketEventInfo::RequestData] error, http ",e, http); } }); return true; } this.RecvData=function(recvData,param) { for(var i in recvData.event) { var event=recvData.event[i]; for(var j in event.data) { var item=event.data[j]; if (item.length<2) continue; var info={Date:event.date, Time:item[0], Title:item[1], Type:0}; this.Data.push(info); } } param.HQChart.UpdataChartInfo(); param.HQChart.Draw(); } } //注意!!! 这个函数已经不用了 //是否是指数代码 function IsIndexSymbol(symbol) { var upperSymbol=symbol.toUpperCase(); if (upperSymbol.indexOf('.SH')>0) { upperSymbol=upperSymbol.replace('.SH',''); if (upperSymbol.charAt(0)=='0' && parseInt(upperSymbol)<=3000) return true; } else if (upperSymbol.indexOf('.SZ')>0) { upperSymbol=upperSymbol.replace('.SZ',''); if (upperSymbol.charAt(0)=='3' && upperSymbol.charAt(1)=='9') return true; } else if (upperSymbol.indexOf('.CI')>0) //自定义指数 { return true; } return false; } //注意!!! 这个函数已经不用了 //是否是基金代码 function IsFundSymbol(symbol) { if (!symbol) return false; var upperSymbol=symbol.toUpperCase(); if (upperSymbol.indexOf('.SH')>0) { upperSymbol=upperSymbol.replace('.SH',''); //51XXXX.sh if (upperSymbol.charAt(0)=='5' && upperSymbol.charAt(1)=='1') return true; } else if (upperSymbol.indexOf('.SZ')>0) { upperSymbol=upperSymbol.replace('.SZ',''); //15XXXX.sz, 16XXXX.sz, 17XXXX.sz, 18XXXX.sz if (upperSymbol.charAt(0)=='1' && (upperSymbol.charAt(1)=='5' || upperSymbol.charAt(1)=='6' || upperSymbol.charAt(1)=='7' || upperSymbol.charAt(1)=='8') ) return true; } return false; } //设置窗口基类 function IDivDialog(divElement) { this.DivElement=divElement; //父节点 this.ID=null; //div id this.TimeOut=null; //定时器 //隐藏窗口 this.Hide=function() { $("#"+this.ID).hide(); } //显示窗口 this.Show=function(left,top,width,height) { //显示位置 $("#"+this.ID).css({'display':'block','top':top+'px', "left":left+'px', "width":width+'px', "height":height+'px' }); } } //修改指标 function ModifyIndexDialog(divElement) { this.newMethod=IDivDialog; //派生 this.newMethod(divElement); delete this.newMethod; this.Title={ ID:Guid() }; //标题 this.ParamList={ID:Guid() }; //参数列表 class='parameter-content' this.ParamData=[]; //{ ID:参数ID, Value:参数值} this.Identify; this.HQChart; //创建 this.Create=function() { this.ID=Guid(); var div=document.createElement('div'); div.className='jchart-modifyindex-box'; div.id=this.ID; div.innerHTML= "
\
\ \ \
\
MA
\ \
"; this.DivElement.appendChild(div); //确定按钮 $("#"+this.ID+" .submit").click( { divBox:this, }, function(event) { event.data.divBox.Hide(); }); //给一个id 后面查找方便 var titleElement=div.getElementsByTagName('span')[0]; titleElement.id=this.Title.ID; var paramListElement=div.getElementsByClassName('parameter-content')[0]; paramListElement.id=this.ParamList.ID; } //设置标题 this.SetTitle=function(title) { $("#"+this.Title.ID).html(title); } //清空参数 this.ClearParamList=function() { $("#"+this.ParamList.ID).empty(); this.ParamData=[]; } this.BindParam=function(chart,identify) { var windowIndex=chart.WindowIndex[identify]; for(var i in windowIndex.Arguments) { var item=windowIndex.Arguments[i]; if (item.Name==null || isNaN(item.Value)) break; var guid=Guid(); var param = ''+ item.Name +'
'; $("#"+this.ParamList.ID).append(param); this.ParamData.push({ID:guid,Value:item.Value}); } //绑定参数修改事件 var self=this; for(var i in this.ParamData) { var item=this.ParamData[i]; $("#"+item.ID).mouseup( { Chart:chart, Identify:identify, ParamIndex:i //参数序号 }, function(event) { var value = parseInt($(this).val()); //获取当前操作的input属性值,转化为整型 var chart=self.HQChart; var identify=self.Identify; var paramIndex=event.data.ParamIndex; chart.WindowIndex[identify].Arguments[paramIndex].Value = value; //为参数属性重新赋值 chart.UpdateWindowIndex(identify); //调用更新窗口指标函数,参数用来定位窗口 } ) $("#"+item.ID).keyup( { Chart:chart, Identify:identify, ParamIndex:i //参数序号 }, function(event) { var value = parseInt($(this).val()); //获取当前操作的input属性值,转化为整型 var chart=self.HQChart; var identify=self.Identify; var paramIndex=event.data.ParamIndex; chart.WindowIndex[identify].Arguments[paramIndex].Value = value; //为参数属性重新赋值 chart.UpdateWindowIndex(identify); //调用更新窗口指标函数,参数用来定位窗口 } ) } } //绑定取消事件 this.BindCancel=function() { //取消按钮事件 var self=this; $("#"+this.ID+" .cancel").click( function() { var chart=self.HQChart; var identify=self.Identify; self.RestoreParam(chart.WindowIndex[identify]); chart.UpdateWindowIndex(identify); self.Hide(); } ); //关闭和取消是一样的 $("#"+this.ID+" #close").click( function() { var chart=self.HQChart; var identify=self.Identify; self.RestoreParam(chart.WindowIndex[identify]); chart.UpdateWindowIndex(identify); self.Hide(); } ); } //还原参数 this.RestoreParam=function(windowIndex) { for(var i in this.ParamData) { var item=this.ParamData[i]; windowIndex.Arguments[i].Value=item.Value; } } //显示 this.DoModal=function(event) { var chart=event.data.Chart; var identify=event.data.Identify; var dialog=chart.ModifyIndexDialog; if(!dialog) return; if (dialog.ID==null) dialog.Create(); //第1次 需要创建div dialog.Identify=identify; dialog.HQChart=chart; dialog.SetTitle(chart.WindowIndex[identify].Name+" 指标参数设置"); //设置标题 dialog.ClearParamList(); //清空参数 dialog.BindParam(chart,identify); //绑定参数 dialog.BindCancel(); //绑定取消和关闭事件 //居中显示 var border=chart.Frame.ChartBorder; var scrollPos=GetScrollPosition(); var left=border.GetLeft()+border.GetWidth()/2; var top=border.GetTop()+border.GetHeight()/2; //left = left + border.UIElement.getBoundingClientRect().left+scrollPos.Left; //top = top+ border.UIElement.getBoundingClientRect().top+scrollPos.Top; dialog.Show(left,top,200,200); //显示 } } //换指标 function ChangeIndexDialog(divElement) { this.newMethod=IDivDialog; //派生 this.newMethod(divElement); delete this.newMethod; this.DivElement=divElement; //父节点 this.IndexTreeApiUrl="https://opensourcecache.zealink.com/cache/hqh5/index/commonindextree.json"; //数据下载地址 this.OverlayIndexTreeApiUrl="https://opensourcecache.zealink.com/cache/hqh5/index/commonindextree.json"; //叠加指标列表数据下载地址 this.IsOverlayIndex=false; this.Create=function() { var div=document.createElement('div'); div.className='jchart-changeindex-box'; div.id=this.ID=Guid(); div.innerHTML= '
\n' + '
\n' + ' 换指标\n' + ' \n' + '
\n' + '
\n' + '
\n' + ' \n' + '
    \n' + '
    \n' + '
    \n' + '
      \n' + '
      \n' + '
      \n' + '
      '; this.DivElement.appendChild(div); } //下载数据 如果上次下载过可以 可以不用下载 this.ReqeustData=function() { if($(".target-left ul li").length>0){ return false; } var url = this.IndexTreeApiUrl; if (this.IsOverlayIndex==true) url=this.OverlayIndexTreeApiUrl; JSNetwork.HttpRequest({ url: url, type: 'get', success: function (res) { var item = res.list; changeIndexLeftList(item); //处理左侧list列表 changeIndexRightList(item); //处理右侧内容列表 } }); //处理左侧list列表 function changeIndexLeftList(item) { $.each(item,function(i,result){ var htmlList; htmlList = '
    • ' + result.node + '
    • '; $(".target-left ul").append(htmlList); }); //默认选中第一项 $(".target-left ul li:first-child").addClass("active-list"); } //处理右侧内容列表 function changeIndexRightList(listNum) { var contentHtml; var conData = []; $.each(listNum,function(index,result){ conData.push(result.list); }) //页面初始化时显示第一个列表分类下的内容 $.each(conData[0],function (i, res) { contentHtml = '
    • '+ res.name +'
    • '; $(".target-right ul").append(contentHtml); }) //切换list $(".target-left ul").delegate("li","click",function () { $(this).addClass("active-list").siblings().removeClass("active-list"); var item = $(this).index(); $(".target-right ul").html(""); $.each(conData[item],function (i, res) { contentHtml = '
    • '+ res.name +'
    • '; $(".target-right ul").append(contentHtml); }) }) } } this.BindClose=function(chart) { //关闭按钮 $("#"+this.ID+" .close-tar").click( { Chart:chart, }, function(event) { var chart=event.data.Chart; chart.ChangeIndexDialog.Hide(); } ); } //搜索事件 this.BindSearch=function(chart) { $(".target-left input").on('input', { Chart:chart }, function(event) { let scriptData = new JSIndexScript(); let result=scriptData.Search(event.target.value); $(".target-right ul").html(""); for(var i in result) { var name=result[i]; var contentHtml = '
    • '+ name +'
    • '; $(".target-right ul").append(contentHtml); } } ); } this.DoModal=function(event) { var chart=event.data.Chart; var identify=event.data.Identify; var dialog=chart.ChangeIndexDialog; var isOverlay=event.data.IsOverlay; //是否叠加 if(!dialog) return; if (dialog.ID==null) dialog.Create(); //第1次 需要创建div dialog.IsOverlayIndex=isOverlay; dialog.ReqeustData(); //下载数据 //切换窗口指标类型 每次委托事件执行之前,先用undelegate()解除之前的所有绑定 changeIndeWindow(); function changeIndeWindow() { $(".target-right ul").undelegate().delegate("li","click",function () { var idv = $(this).attr("id"); if (isOverlay) chart.AddOverlayIndex({WindowIndex:identify,IndexName:idv}); else chart.ChangeIndex(identify,idv); $(this).addClass("active-list").siblings().removeClass("active-list"); }); } dialog.BindSearch(chart); //关闭弹窗 dialog.BindClose(chart); //居中显示 var border=chart.Frame.ChartBorder; var scrollPos=GetScrollPosition(); var left=border.GetLeft()+border.GetWidth()/2; var top=border.GetTop()+border.GetHeight()/2; //left = left + border.UIElement.getBoundingClientRect().left+scrollPos.Left; //top = top+ border.UIElement.getBoundingClientRect().top+scrollPos.Top; dialog.Show(left,top,200,200); } } //信息地理tooltip function KLineInfoTooltip(divElement) { this.newMethod=IDivDialog; //派生 this.newMethod(divElement); delete this.newMethod; this.UpColor=g_JSChartResource.UpTextColor; this.DownColor=g_JSChartResource.DownTextColor; this.UnchagneColor=g_JSChartResource.UnchagneTextColor; this.Create=function() { this.ID=Guid(); var div=document.createElement('div'); div.className='jchart-klineinfo-tooltip'; div.id=this.ID; div.innerHTML="
      "; this.DivElement.appendChild(div); } this.BindInfoList=function(infoType,infoList) { var strBox="
      共"+infoList.length+"条
      "; var strText=[]; for(var i in infoList) { var item=infoList[i]; var strOld=item.Date; if(infoType==KLINE_INFO_TYPE.PFORECAST) { var reportDate=item.ExtendData.ReportDate; var year=parseInt(reportDate/10000); //年份 var day=reportDate%10000; //比较 这个去掉年份的日期 var reportType; if(day == 1231){ reportType = "年报" }else if(day == 331){ reportType = "一季度报" }else if(day == 630){ reportType = "半年度报" }else if(day == 930){ reportType = "三季度报" } var weekData=""; if (item.ExtendData.FWeek) { if (item.ExtendData.FWeek.Week1!=null) weekData+="一周后涨幅:"+ item.ExtendData.FWeek.Week1.toFixed(2)+"%"; if (item.ExtendData.FWeek.Week4!=null) weekData+=" 四周后涨幅:"+ item.ExtendData.FWeek.Week4.toFixed(2)+"%"; if (weekData.length>0) weekData="
        "+weekData+""; } var strDate=item.Date.toString(); var strNew=strDate.substring(0,4)+"-"+strDate.substring(4,6)+"-"+strDate.substring(6,8); //转换时间格式 strText+=""+strNew+"  "+year+reportType+item.Title+" "+weekData+""; } else if (infoType==KLINE_INFO_TYPE.RESEARCH) //调研单独处理 { var levels=item.ExtendData.Level; var recPerson=[]; if(levels.length==0){ recPerson = "" }else{ for(var j in levels) { if(levels[j]==0){ recPerson+="证券代表   "; }else if(levels[j]==1){ recPerson+="董秘   "; }else if(levels[j]==2){ recPerson+="总经理   "; }else if(levels[j]==3){ recPerson+="董事长   "; } } } var strDate=item.Date.toString(); var strNew=strDate.substring(0,4)+"-"+strDate.substring(4,6)+"-"+strDate.substring(6,8); //转换时间格式 strText+=""+strNew+"   接待:   "+recPerson+""; }else if(infoType==KLINE_INFO_TYPE.BLOCKTRADING) { var showPriceInfo = item.ExtendData; var strDate=item.Date.toString(); var strNew=strDate.substring(0,4)+"-"+strDate.substring(4,6)+"-"+strDate.substring(6,8); //转换时间格式 strText+=""+strNew+"  成交价: "+showPriceInfo.Price.toFixed(2)+"收盘价: "+showPriceInfo.ClosePrice.toFixed(2)+ "
      溢折价率: "+ showPriceInfo.Premium.toFixed(2)+"%成交量(万股): "+showPriceInfo.Vol.toFixed(2)+"
      "; } else if (infoType==KLINE_INFO_TYPE.TRADEDETAIL) //龙虎榜 { /*var detail=[ "日价格涨幅偏离值达到9.89%", "日价格涨幅偏离值达格涨幅偏离值达格涨幅偏离值达到9.89%" ]*/ var detail=item.ExtendData.Detail; //格式:日期 上榜原因: detail[0].TypeExplain // detail[1].TypeExplain // 一周后涨幅: xx 四周后涨幅: xx var str=strOld.toString(); var strNew=str.substring(0,4)+"-"+str.substring(4,6)+"-"+str.substring(6,8); //转换时间格式 var reasons = []; for(var i in detail){ reasons += ""+detail[i].TypeExplain+"
      " // reasons += detail[i] + "
      " } strText = ""+strNew+"   上榜原因:  "+reasons+"
      一周后涨幅: "+ item.ExtendData.FWeek.Week1.toFixed(2)+ "%   四周后涨幅: "+ item.ExtendData.FWeek.Week4.toFixed(2)+"%
      "; } else { var str=strOld.toString(); var strNew=str.substring(0,4)+"-"+str.substring(4,6)+"-"+str.substring(6,8); //转换时间格式 strText+=""+strNew+"   "+item.Title+""; } } var titleInnerBox = $(".title-length").html(strText); $("#"+this.ID).html(titleInnerBox); //当信息超过8条时,添加“共XX条”统计总数 if(infoList.length > 8){ $("#"+this.ID).append(strBox); } } this.GetColor=function(price) { if(price>0) return this.UpColor; else if (price<0) return this.DownColor; else return this.UnchagneColor; } //显示窗口,改函数仅为KLineInfoTooltip使用 this.Show=function(left,top,width,height,tooltip,times) { //显示位置 $("#"+this.ID).css({'display':'block','top':top+'px', "left":left+'px', "width":width+'px', "height":height+'px' }); function toolHide() { tooltip.Hide(); } if (this.TimeOut!=null) clearTimeout(this.TimeOut); //清空上一次的定时器,防止定时器不停的被调用 //设置窗口定时隐藏 this.TimeOut=setTimeout(toolHide,times); } this.DoModal=function(event) { var chart=event.data.Chart; var infoType=event.data.InfoType; //信息地雷类型 var infoList=event.data.InfoList; //信息数据列表 var tooltip=chart.KLineInfoTooltip; if(!tooltip) return; if (tooltip.ID==null) tooltip.Create(); //第1次 需要创建div tooltip.BindInfoList(infoType,infoList); var left=event.pageX; var top=event.pageY+10; var widthTool=380; var heightTool=$("#"+tooltip.ID).height(); if((left + widthTool) > chart.UIElement.getBoundingClientRect().width){ left = left - widthTool; } /*if(top+heightTool>chart.UIElement.getBoundingClientRect().height){ top=top-heightTool-45; }*/ tooltip.Show(left,top,widthTool,"auto",tooltip,8000); } //鼠标离开 this.Leave=function(event) { var chart=event.data.Chart; var tooltip=chart.KLineInfoTooltip; if(!tooltip || tooltip.ID==null) return; tooltip.Hide(); } } //历史K线上双击 弹出分钟走势图框 function MinuteDialog(divElement) { this.newMethod=IDivDialog; //派生 this.newMethod(divElement); delete this.newMethod; this.JSChart=null; this.Height=500; this.Width=600; this.Symbol; this.TradeDate; this.HistoryData; this.Create=function() { this.ID=Guid(); var div=document.createElement('div'); div.className='jchart-kline-minute-box'; div.id=this.ID; var hqchartID=Guid(); div.innerHTML=`
      `; div.style.width=this.Height+'px'; div.style.height=this.Width+'px'; this.DivElement.appendChild(div); this.JSChart=JSChart.Init(document.getElementById(hqchartID)); var option= { Type:'历史分钟走势图', Symbol:this.Symbol, //股票代码 IsAutoUpdate:false, //是自动更新数据 IsShowRightMenu:false, //右键菜单 HistoryMinute: { TradeDate:this.TradeDate, IsShowName:false, IsShowDate:false } //显示的交易日期 }; this.JSChart.SetOption(option); } this.BindClose=function(chart) { //关闭按钮 $("#"+this.ID+" .close-munite").click( { Chart:chart }, function(event) { var chart=event.data.Chart; chart.MinuteDialog.Hide(); } ); } this.DoModal=function(event) { this.UpColor=g_JSChartResource.UpTextColor; this.DownColor=g_JSChartResource.DownTextColor; this.UnchagneColor=g_JSChartResource.UnchagneTextColor; var chart=event.data.Chart; var tooltip=event.data.Tooltip; var dialog=chart.MinuteDialog; dialog.Symbol=chart.Symbol; dialog.TradeDate=tooltip.Data.Date; if(!dialog) return; if (dialog.ID==null) { dialog.Create(); //第1次 需要创建div } else { dialog.JSChart.JSChartContainer.TradeDate=dialog.TradeDate; dialog.JSChart.ChangeSymbol(this.Symbol); } var left=event.clientX; var top=event.clientY+10; dialog.Show(500,100,600,500); dialog.JSChart.OnSize(); this.BindClose(chart); this.GetColor=function(price,yclse) { if(price>yclse) return this.UpColor; else if (price"+""+strNewDate+" "+ "开:"+strData.Open.toFixed(2)+""+ "高:"+strData.High.toFixed(2)+""+ "低:"+strData.Low.toFixed(2)+""+ "收:"+strData.Close.toFixed(2)+""+ "量:"+IFrameSplitOperator.FormatValueString(strData.Vol,2)+""+ "额:"+IFrameSplitOperator.FormatValueString(strData.Amount,2)+""; $(".minute-dialog-title span").html(str); } } //区间统计 function KLineSelectRectDialog(divElement) { this.newMethod=IDivDialog; //派生 this.newMethod(divElement); delete this.newMethod; this.SelectData; this.Dialog; this.HQChart; //隐藏窗口 this.Close=function() { if (this.Dialog) { this.DivElement.removeChild(this.Dialog); this.Dialog=null; } this.HQChart.HideSelectRect(); } //创建 this.Create=function() { this.ID=Guid(); var div=document.createElement('div'); div.className='jchart-select-statistics-box'; div.id=this.ID; div.innerHTML= "
      \
      \ 区间统计\ \
      \
      统计数据
      \ \
      "; this.DivElement.appendChild(div); this.Dialog=div; //关闭按钮 $("#"+this.ID+" #close").click( { divBox:this, }, function(event) { event.data.divBox.Close(); }); //形态匹配 $("#"+this.ID+" #match").click( { divBox:this, }, function(event) { event.data.divBox.KLineMatch(); }); } this.BindData=function() { var hqData=this.SelectData.Data; var start=this.SelectData.Start; var end=this.SelectData.End; var showData= { Open:0,Close:0,High:0,Low:0, YClose:0, Vol:0, Amount:0, Date:{Start:0,End:0}, Count:0, KLine:{ Up:0,Down:0,Unchanged:0 } //阳线|阴线|平线 } for(var i=start; i<=end && iitem.Low) showData.Low=item.Low; if (item.Close>item.Open) ++showData.KLine.Up; else if (item.Close0) showData.AvPrice=showData.Amount/showData.Vol; //均价 if (item.YClose>0) { showData.Increase = (showData.Close - showData.YClose) / showData.YClose *100; //涨幅 showData.Amplitude = (showData.High - showData.Low) / showData.YClose * 100; //振幅 } // console.log('[KLineSelectRectDialog::BindData]', showData); var defaultfloatPrecision=GetfloatPrecision(this.SelectData.Symbol); var startDate = showData.Date.Start.toString().substring(0,4) + "/" + showData.Date.Start.toString().substring(4,6) + "/" + showData.Date.Start.toString().substring(6,8); var endDate = showData.Date.End.toString().substring(0,4) + "/" + showData.Date.End.toString().substring(4,6) + "/" + showData.Date.End.toString().substring(6,8); var startLeftClass="",startRightClass="",endLeftClass="",endRightClass=""; if(start<=0) startLeftClass = "BtnBackground"; if(start >= end) { startRightClass = "BtnBackground"; endLeftClass = "BtnBackground"; } if(end >= hqData.Data.length - 1) endRightClass = "BtnBackground"; var div=document.createElement('div'); div.className='jchart-select-table-right'; div.innerHTML= '
      \n' + ' 开始: '+ startDate +'<>\n' + ' 结束: '+ endDate +'<>\n' + ' 总个数: '+ showData.Count +'\n' + '
      \n' + ' \n' + ' ' + ' ' + ' \n' + ' ' + ' ' + ' \n' + ' ' + ' ' + ' \n' + ' ' + ' ' + ' \n' + '
      起始价: '+ showData.YClose.toFixed(defaultfloatPrecision) +'最终价: '+ showData.Close.toFixed(defaultfloatPrecision) +'均价: '+ showData.AvPrice.toFixed(defaultfloatPrecision) +'
      最低价: '+ showData.Low.toFixed(defaultfloatPrecision) +'最高价: '+ showData.High.toFixed(defaultfloatPrecision) +'涨跌幅: '+ showData.Increase.toFixed(2) +'%
      振幅: '+ showData.Amplitude.toFixed(2) +'%成交量: '+ IFrameSplitOperator.FormatValueString(showData.Vol,2) +'股金额: '+ IFrameSplitOperator.FormatValueString(showData.Amount,2) +'元
      阴线: '+ showData.KLine.Up +'阳线: '+ showData.KLine.Down +'平线: '+ showData.KLine.Unchanged +'
      '; $(".parameter-content").html(div); this.BindEvent(); } this.BindEvent = function () { var _self = this; if(_self.SelectData.Start > 0){ $(".jchart-select-date .start-date-left").click(function () { _self.SelectData.Start--; _self.BindData(); _self.HQChart.UpdateSelectRect(_self.SelectData.Start,_self.SelectData.End); }) } if(_self.SelectData.Start < _self.SelectData.End){ $(".jchart-select-date .start-date-right").click(function () { _self.SelectData.Start++; _self.BindData(); _self.HQChart.UpdateSelectRect(_self.SelectData.Start,_self.SelectData.End); }) $(".jchart-select-date .end-date-left").click(function () { _self.SelectData.End--; _self.BindData(); _self.HQChart.UpdateSelectRect(_self.SelectData.Start,_self.SelectData.End); }) } if(_self.SelectData.End < _self.SelectData.Data.Data.length - 1){ $(".jchart-select-date .end-date-right").click(function () { _self.SelectData.End++; _self.BindData(); _self.HQChart.UpdateSelectRect(_self.SelectData.Start,_self.SelectData.End); }) } } //显示 this.DoModal=function(event) { var chart=event.data.Chart; if (this.ID==null) this.Create(); //第1次 需要创建div this.SelectData=event.data.SelectData; this.HQChart=chart; this.BindData(); //居中显示 var border=chart.Frame.ChartBorder; var scrollPos=GetScrollPosition(); var left=border.GetWidth()/2; var top=border.GetHeight()/2; //left = left + border.UIElement.getBoundingClientRect().left+scrollPos.Left; //top = top+ border.UIElement.getBoundingClientRect().top+scrollPos.Top; this.Show(left,top,200,200); //显示 } //形态匹配 this.KLineMatch=function(data) { var waitDialog=new WaitDialog(this.DivElement); waitDialog.DoModal( { data: { Title:'计算中......', Chart:this.HQChart } }); this.Close(); //关闭窗口 var hqChart=this.HQChart; var param= { Scope: { Plate:["CNA.ci"],Minsimilar:0.90 }, WaitDialog:waitDialog } //沪深A股, 相似度>=90% hqChart.RequestKLineMatch(this.SelectData, param); } } //形态选股 function KLineMatchDialog(divElement) { this.newMethod=IDivDialog; //派生 this.newMethod(divElement); delete this.newMethod; this.MatchData; //匹配的股票数据 this.Sample; //样本数据 this.Dialog; this.HQChart; this.PageData; //分页数据 //隐藏窗口 this.Close=function() { this.DivElement.removeChild(this.Dialog); } //创建 this.Create=function() { this.ID=Guid(); var div=document.createElement('div'); div.className='jchart-kline-match-box'; div.id=this.ID; div.innerHTML= `
      形态匹配

      股票名称 匹配度 时间段
      `.trim(); this.DivElement.appendChild(div); this.Dialog=div; //关闭按钮 $("#"+this.ID+" #close").click( { divBox:this, }, function(event) { event.data.divBox.Close(); }); } this.BindData=function() { console.log(`[KLineMatchDialog::BindData] 形态源: ${this.Sample.Stock.Name} 区间:${this.Sample.Date.Start} - ${this.Sample.Date.End}`); var count = this.MatchData.length + 1; var pageData = {NewData:{},MetaData:[],PageCount:0,Count:count}; var pageCount = 0; var paginationHtml = ''; $('#'+this.ID+' .dataCount').html('个数:'+count); for(let i = 0; i < count ; i++){ var dataObj = {}; if(i == 0){ dataObj = { Symbol:this.Sample.Stock.Symbol, Name:this.Sample.Stock.Name, Rate:'形态源', Color:'red', Date:`${this.Sample.Date.Start}-${this.Sample.Date.End}` }; }else{ let dataItem = this.MatchData[i - 1]; dataObj = { Symbol:dataItem.Symbol, Name:dataItem.Name, Rate:Number(dataItem.Similar * 100).toFixed(2), Color:'', Date:`${dataItem.Start}-${dataItem.End}` }; } pageData.MetaData.push(dataObj); } if(pageData.Count % 10 == 0){ pageCount = pageData.Count / 10; }else{ pageCount = Math.floor(pageData.Count / 10) + 1; } pageData.PageCount = pageCount; this.PaginationMetaData(pageData); this.PageData = pageData; console.log('[KLineMatchDialog::DoModal pageData]',pageData); this.RenderDom(1); this.PaginationInit('#'+this.ID,pageData.PageCount,this.paginationCallback); // $('#' + this.ID + ' .pagination').html(paginationHtml); } this.RenderDom = function(page){ let currentPageData = this.PageData.NewData[page]; console.log('[KLineMatchDialog::RenderDom currentPageData]',currentPageData); let bodyHtml = ''; for(let i = 0; i < currentPageData.length; i++){ bodyHtml += ` ${currentPageData[i].Name} ${currentPageData[i].Rate} ${currentPageData[i].Date} `.trim(); } $('#'+this.ID + ' .matchTable tbody').html(bodyHtml) } var _this = this; this.paginationCallback = function(page) { _this.RenderDom(page); _this.PaginationInit('#'+_this.ID,_this.PageData.PageCount,_this.paginationCallback); //更新UI } this.PaginationInit = function(id, maxPageNum, callback) { //初始化分页 var spanStr = ""; var currentPageNum = $(id + " .pagination").data("current"); var lastPageNum = 0; var showCountPage = 5; //只显示5个数字项 if (currentPageNum < showCountPage) { //当前页小于预显示页数 if (maxPageNum >= showCountPage) { for (var j = 0; j < showCountPage; j++) { //上 1 2 3 4 5 下 spanStr += (j + 1) != currentPageNum ? "" + (j + 1) + "" : "" + (j + 1) + ""; } } else { for (var j = 0; j < maxPageNum; j++) { //上 1 2 3 4 5 下 spanStr += (j + 1) != currentPageNum ? "" + (j + 1) + "" : "" + (j + 1) + ""; } } } else { //大于5时,最终页数是当前页数加1 lastPageNum = (currentPageNum + 1) > maxPageNum ? currentPageNum : (currentPageNum + 1); for (var i = currentPageNum - 3; i <= lastPageNum; i++) { //含最终项之前的五项 spanStr += i != currentPageNum ? "" + i + "" : "" + i + ""; } } spanStr = "上一页" + spanStr + "下一页"; $(id + " .pagination").html(spanStr); $(id + " .pagination span").bind('click', { "maxpage": maxPageNum, "Callback": callback }, this.PaginationCurrentIndex); // return spanStr; } this.PaginationCurrentIndex = function(event) { //分页切换 var text = $(this).text(); console.log('[::PaginationCurrentIndex text]',text); var currentPageNum = Number($(this).parent().data("current")); var maxPageNum = event.data.maxpage; var callback = event.data.Callback; var flag = 1; if (text === "上一页") { flag = currentPageNum === 1 ? currentPageNum : currentPageNum - 1; } else if (text === "下一页") { flag = currentPageNum === maxPageNum ? currentPageNum : currentPageNum + 1; } else { flag = Number(text); } $(this).parent().data("current", flag); //将当前页存到dom上 callback(flag); } this.PaginationMetaData = function(data){ //假分页数据,每页10条数据 // data = {NewData:{},MetaData:[],PageCount:0,Callback:null}; var newData = {}; var metaData = data.MetaData; var pageCount = data.PageCount; for(let i = 0; i < pageCount; i++){ var itemArr = []; for(let j = 0; j < 10; j++){ var itemIndex = 10*i + j; if(itemIndex <= metaData.length - 1){ var item = metaData[itemIndex]; itemArr.push(item); }else { break; } } newData[i+1] = itemArr; } data.NewData = newData; } //显示 this.DoModal=function(event) { var chart=event.data.Chart; if (this.ID==null) this.Create(); //第1次 需要创建div this.MatchData=event.data.MatchData; this.Sample=event.data.Sample; this.HQChart=chart; this.BindData(); //居中显示 var border=chart.Frame.ChartBorder; var scrollPos=GetScrollPosition(); var left=border.GetWidth()/2; var top=border.GetHeight()/2; this.Show(left,top,200,200); //显示 } } //等待动画窗口 function WaitDialog(divElement) { this.newMethod=IDivDialog; //派生 this.newMethod(divElement); delete this.newMethod; this.Title='加载中......'; this.Dialog; //隐藏窗口 this.Close=function() { if (this.Dialog) { this.DivElement.removeChild(this.Dialog); this.Dialog=null; } } this.SetTitle=function(title) { this.Title=title; if (!this.Dialog) return; //TODO: 更新标题数据 } this.Create=function() { this.ID=Guid(); var div=document.createElement('div'); div.className='jchart-wait-box'; div.id=this.ID; div.innerHTML= `
      ${this.Title}
      `.trim(); this.DivElement.appendChild(div); this.Dialog=div; } //显示 this.DoModal=function(event) { this.Title=event.data.Title; var chart=event.data.Chart; if (this.ID==null) this.Create(); //第1次 需要创建div //居中显示 var border=chart.Frame.ChartBorder; var scrollPos=GetScrollPosition(); var left=border.GetWidth()/2; var top=border.GetHeight()/2; this.Show(left,top,200,40); //显示 } } //K线右键菜单类 //id:"kline" function KLineRightMenu(divElement) { this.newMethod=IDivDialog; //派生 this.newMethod(divElement); delete this.newMethod; this.option={}; this.Create = function () { var _self = this; this.ID=Guid(); _self.BindData(); _self.BindEvent(); } this.BindData=function(){ var _self = this; var id=this.DivElement.id; var $body = $("#" + id); $body.find("div[id^='topMenu_']").remove(); $body.find("div[id^='childMenu_']").remove(); var $topMenu = $("
      "); $topMenu.attr("id", "topMenu_"+_self.ID).addClass("context-menu-wrapper topmenu").hide(); $body.append($topMenu); var $topTable = $(""); $topTable.attr({ id: "topTable_" + _self.ID, cellspacing: "0", cellpadding: "0" }).addClass("context-menu"); $topMenu.append($topTable); $topTable.append(_self.childrenList(_self.option.data)); for (var i = 0; i < _self.option.data.length; i++) { var isHasChildren = typeof _self.option.data[i].children != "undefined"; if (isHasChildren) { var $childMenu = $("
      "); $childMenu.attr({ id: "childMenu_"+_self.ID + i, "data-index": i }).addClass("context-menu-wrapper").hide(); $body.append($childMenu); var $childTable = $("
      "); $childTable.attr({ id: "childTable_" + _self.ID + i, cellspacing: "0", cellpadding: "0" }).addClass("context-menu"); $childMenu.append($childTable); $childTable.append(_self.childrenList(_self.option.data[i].children)); } } } this.Update=function() { var _self = this; //var id=this.DivElement.id; //var $body=$("#"+id); // //var $topTable = $("#topTable_" + _self.ID); //$topTable.empty(); //$topTable.append(_self.childrenList(_self.option.data)); // //for (var i = 0; i < _self.option.data.length; i++) { // var isHasChildren = typeof _self.option.data[i].children != "undefined"; // // if (isHasChildren) { // var $childTable = $("#childTable_" + _self.ID + i); // $childTable.empty(); // $childTable.append(_self.childrenList(_self.option.data[i].children)); // } //} _self.BindData(); _self.BindEvent(); } this.childrenList = function(list) { var result = []; for (var i = 0; i < list.length; i++) { var isBorder = typeof list[i].isBorder != "undefined" && list[i].isBorder; var $tr = $(""); $tr.addClass("font_Arial context-menu"); if (isBorder) $tr.addClass("border"); var $td1 = $("
      "); if(list[i].selected){ $td1.addClass("spacer context-menu").html("√"); }else{ $td1.addClass("spacer context-menu"); } var $td2 = $(""); $td2.addClass("text").html(list[i].text); var $td3 = $(""); $td3.addClass("right shortcut"); var $td4 = $(""); $td4.addClass(typeof list[i].children != "undefined" ? "submenu-arrow" : "context-menu spacer"); $tr.append($td1).append($td2).append($td3).append($td4); result.push($tr); } return result; } this.Show=function (obj) { var _self = this; $.extend(_self.option, obj); if (!_self.ID) _self.Create(); //判断是否重复创建 else _self.Update(); //更新菜单状态 var $topMenu = $("#topMenu_"+_self.ID), topWidth = $topMenu.outerWidth(), topHeight = $topMenu.outerHeight(); var x = _self.option.x, y = _self.option.y; if (topWidth > _self.option.position.X + _self.option.position.W- x) //超过了右边距 x = x - topWidth; if (topHeight > _self.option.position.Y +_self.option.position.H - y)//超过了下边距 y = y - topHeight; $topMenu.hide(); $topMenu.css({ position:"absolute",left: x + "px", top: y + "px" }).show(); this.isInit = true; } this.Hide=function () { var _self = this; $("#topMenu_" + _self.ID).hide(); $("[id^='childMenu_" + _self.ID + "']").hide(); } this.BindEvent=function () { var _self = this; var $childMenu = $("[id^='childMenu_" + _self.ID + "']"); $("#topTable_" + _self.ID).find("tr").mouseenter(function () { var $this = $(this), index = $this.index(), $topMenu = $("#topMenu_" + _self.ID), $child = $("#childMenu_" + _self.ID + index), trWidth = $this.outerWidth(), trHeight = $this.outerHeight(); var left = $topMenu.position().left + trWidth + 1; var top = $topMenu.position().top + (trHeight * index); if (trWidth > _self.option.position.X + _self.option.position.W - left) //超过了右边距 left = left - trWidth - $topMenu.outerWidth() - 2; if ($child.outerHeight() > _self.option.position.Y +_self.option.position.H - top)//超过了下边距 top = $topMenu.position().top + $topMenu.outerHeight() - $child.outerHeight(); $childMenu.hide(); $child.css({ left: left + "px", top: top + "px" }).show(); }).mouseleave(function () { var index = $(this).index(); setTimeout(function () { if ($("#childMenu_" + _self.ID + index).attr("data-isShow") != 1) { $("#childMenu_" + _self.ID + index).hide(); } }, 10) }).click(function () { var $this = $(this); var index = $this.index(); if ($.type(_self.option.data[index].click) == "function") { _self.option.data[index].click(_self.option.returnData); $this.hide(); } }); $childMenu.mouseenter(function () { $(this).attr("data-isShow", "1"); }).mouseleave(function () { $(this).attr("data-isShow", "0"); }); $childMenu.find("tr").click(function () { var $this = $(this); var divIndex = parseInt($this.closest("div").attr("data-index")); var trIndex = $this.index(); if ($.type(_self.option.data[divIndex].children[trIndex].click) == "function") { _self.option.data[divIndex].children[trIndex].click(_self.option.windowIndex || 1); $childMenu.hide(); } }); } this.GetPeriod=function (chart) { var data= [ { text: "日线", Value:0, click: function () { chart.ChangePeriod(0); } }, { text: "周线",Value:1, click: function () { chart.ChangePeriod(1); } }, { text: "月线",Value:2, click: function () { chart.ChangePeriod(2); } }, { text: "季线",Value:9, click: function () { chart.ChangePeriod(9); } }, { text: "年线",Value:3, click: function () { chart.ChangePeriod(3); } }, { text: "1分",Value:4, click: function () { chart.ChangePeriod(4); } }, { text: "5分",Value:5, click: function () { chart.ChangePeriod(5); } }, { text: "15分",Value:6, click: function () { chart.ChangePeriod(6); } }, { text: "30分",Value:7, click: function () { chart.ChangePeriod(7); } }, { text: "60分",Value:8, click: function () { chart.ChangePeriod(8); } }, { text: "2小时",Value:11, click: function () { chart.ChangePeriod(11); } }, { text: "4小时",Value:12, click: function () { chart.ChangePeriod(12); } }, { text: "分笔",Value:10, click: function () { chart.ChangePeriod(10); } }, { text: "自定义周期:3分钟",Value:20003, click: function () { chart.ChangePeriod(20003); } }, { text: "自定义周期:35分钟",Value:20035, click: function () { chart.ChangePeriod(20035); } }, { text: "自定义周期:8日",Value:40008, click: function () { chart.ChangePeriod(40008); } } ]; for(var i in data) { var item=data[i]; if (item.Value==chart.Period) { item.selected=true; break; } } return data; } this.GetRight=function(chart) { var data= [ { text: "不复权", click: function () { chart.ChangeRight(0); } }, { text: "前复权", click: function () { chart.ChangeRight(1); } }, { text: "后复权", click: function () { chart.ChangeRight(2); } } ]; if (chart.Right>=0 && chart.Right0) { data[data.length-1].isBorder=true; data.push( { text: "取消叠加", click: function () { chart.ClearOverlaySymbol();} } ); } return data; } //K线类型设置 this.GetKLineType=function(chart) { var data= [ { text: "K线(空心阳线)", click: function () { chart.ChangeKLineDrawType(3);} }, { text: "K线(实心阳线)", click: function () { chart.ChangeKLineDrawType(0); } }, { text: "美国线", click: function () { chart.ChangeKLineDrawType(2); } }, { text: "收盘线", click: function () { chart.ChangeKLineDrawType(1); } }, { text: "收盘面积", click: function () { chart.ChangeKLineDrawType(4); } } ]; switch(chart.KLineDrawType) { case 0: data[1].selected=true; break; case 1: data[3].selected=true; break; case 2: data[2].selected=true; break; case 3: data[0].selected=true; break; case 4: data[4].selected=true; break; } return data; } //指标窗口个数 this.GetIndexWindowCount=function(chart) { var data= [ { text: "1个窗口", click: function () { chart.ChangeIndexWindowCount(1); } }, { text: "2个窗口", click: function () { chart.ChangeIndexWindowCount(2); } }, { text: "3个窗口", click: function () { chart.ChangeIndexWindowCount(3); } }, { text: "4个窗口", click: function () { chart.ChangeIndexWindowCount(4); } }, { text: "5个窗口", click: function () { chart.ChangeIndexWindowCount(5); } } ]; var count=chart.Frame.SubFrame.length; if ((count-1)>=0 && (count-1)0) { if (chart.Frame.SubFrame[0].Frame.CoordinateType==1) data[2].selected=true; else data[0].selected=true; if (chart.Frame.SubFrame[0].Frame.YSplitOperator.CoordinateType==1) data[1].selected=true; } return data; } //拖拽模式 this.GetDragModeType=function(chart) { var data= [ { text: "禁止拖拽", click: function () { chart.DragMode=0; } }, { text: "启动拖拽", click: function () { chart.DragMode=1; } }, { text: "区间选择", click: function () { chart.DragMode=2; } } ]; if (chart.DragMode>=0 && chart.DragMode0) { data[data.length-1].isBorder=true; var item={ text:'删除所有', click:function() { chart.ClearKLineInfo()} }; data.push(item); } return data; } this.CreateKlineInfoItem=function(infoName,bExist,chart) { var item= { text:infoName, selected:bExist } if (bExist) item.click=function() { chart.DeleteKLineInfo(infoName) }; else item.click=function() { chart.AddKLineInfo(infoName,true) } return item; } this.DoModal=function(event) { var chart=event.data.Chart; var rightMenu=chart.RightMenu; var x = event.offsetX; var y = event.offsetY; var dataList=[{ text: "分析周期", children: this.GetPeriod(chart) }, { text: "复权处理", children: this.GetRight(chart) }, { text: "指标切换", children: this.GetIndex(chart) }, { text:"五彩K线", children: this.GetColorIndex(chart) }, { text:'专家系统', children: this.GetTradeIndex(chart) }, { text:'信息地雷', children: this.GetKLineInfo(chart) }, { text: "叠加品种", children: this.GetOverlay(chart) }, { text:'主图线型', children: this.GetKLineType(chart) }, { text:"坐标类型", children:this.GetCoordinateType(chart) }, { text:'指标窗口个数', children: this.GetIndexWindowCount(chart) }, { text:'鼠标拖拽', children: this.GetDragModeType(chart) }, { text:"工具", children:this.GetTools(chart) } ]; var upperSymbol=chart.Symbol.toUpperCase(); if(MARKET_SUFFIX_NAME.IsSHSZIndex(chart.Symbol) || MARKET_SUFFIX_NAME.IsBIT(upperSymbol)) { dataList.splice(1,1); } var identify=event.data.FrameID; var overlayIndex=this.GetOverlayIndex(chart,identify); if (overlayIndex && overlayIndex.length>0) { var delOverlayIndexMenu={ text:'删除叠加指标', children:this.GetDeleteOverlayIndex(chart,overlayIndex) } dataList.splice(3,0,delOverlayIndexMenu); } console.log('[KLineRightMenu::DoModal]',identify); rightMenu.Show({ windowIndex :identify, x:x+chart.UIElement.offsetLeft, y:y+chart.UIElement.offsetTop, position:chart.Frame.Position, data:dataList }) $(document).click(function () { rightMenu.Hide(); }); } this.GetOverlayIndex=function(chart, windowsIndex) { if (windowsIndex>=chart.Frame.SubFrame.length) return []; var result=[]; var item=chart.Frame.SubFrame[windowsIndex]; for(var i in item.OverlayIndex) { var overlayItem=item.OverlayIndex[i]; result.push({Name:overlayItem.Script.Name, Identify:overlayItem.Identify}); } return result; } this.GetDeleteOverlayIndex=function(chart,overlayIndex) { var data=[]; for(var i in overlayIndex) { let identify=overlayIndex[i].Identify; data.push({text:overlayIndex[i].Name, click:function() { chart.DeleteOverlayWindowsIndex(identify) }}); } return data; } } //K线区间选择右键菜单 function KLineSelectRightMenu(divElement) { this.newMethod=KLineRightMenu; //派生 this.newMethod(divElement); delete this.newMethod; this.DoModal=function(event) { var chart=event.data.Chart; var rightMenu=this; var x = event.data.X; var y = event.data.Y; var dataList= [ { text: "区间统计", click: function () { console.log('[KLineSelectRightMenu::click] 区间统计'); var dialog=new KLineSelectRectDialog(divElement); dialog.DoModal(event); } } ]; rightMenu.Show({ x:x, y:y, position:chart.Frame.Position, data:dataList }); } this.Show=function (obj) { var _self = this; $.extend(_self.option, obj); //判断是否重复创建 if (!_self.ID) _self.Create(); var $topMenu = $("#topMenu_"+_self.ID), topWidth = $topMenu.outerWidth(), topHeight = $topMenu.outerHeight(); var x = _self.option.x, y = _self.option.y; if (topWidth > _self.option.position.X + _self.option.position.W- x) //超过了右边距 x = x - topWidth; if (topHeight > _self.option.position.Y +_self.option.position.H - y)//超过了下边距 y = y - topHeight; $topMenu.hide(); $topMenu.css({ position:"absolute",left: x + "px", top: y + "px" }).show(); $("#topMenu_" + _self.ID).find("tr").show(); //把菜单列表显示 this.isInit = true; } } //分钟数据右键菜单 function MinuteRightMenu(divElement) { this.newMethod=KLineRightMenu; //派生 this.newMethod(divElement); delete this.newMethod; this.DoModal=function(event) { var chart=event.data.Chart; var rightMenu=chart.RightMenu; var x = event.offsetX; var y = event.offsetY; var dataList= [ { text: "叠加品种", children: this.GetOverlay(chart) }, { text: "多日分时图", children: this.GetDayCount(chart) }, { text:'指标窗口个数', children: this.GetIndexWindowCount(chart) }, { text: "副图指标切换", children: this.GetIndex(chart) } ]; var symbol=chart.Symbol; if (MARKET_SUFFIX_NAME.IsSHSZStockA(symbol)) { dataList.push({text:'集合竞价',children: this.GetShowBeforeData(chart)}); } var identify=event.data.FrameID; console.log('[MinuteRightMenu::DoModal]',identify); rightMenu.Show({ windowIndex :identify, x:x+chart.UIElement.offsetLeft, y:y+chart.UIElement.offsetTop, position:chart.Frame.Position, data:dataList }) $(document).click(function () { rightMenu.Hide(); }); } this.GetDayCount=function(chart) { var data= [ { text: "当日分时图", click: function () { chart.ChangeDayCount(1); }, isBorder:true }, { text: "最近2日", click: function () { chart.ChangeDayCount(2); } }, { text: "最近3日", click: function () { chart.ChangeDayCount(3); } }, { text: "最近4日", click: function () { chart.ChangeDayCount(4); } }, { text: "最近5日", click: function () { chart.ChangeDayCount(5); } }, { text: "最近6日", click: function () { chart.ChangeDayCount(6); } } ]; if ((chart.DayCount-1)>=0 && (chart.DayCount-1)=0 && (count-1)'+ ''+ '\n' + ''+ ''; }else{ toolsDiv = '

      ' + '

      \n' + '

      '; } this.SubToolsDiv.style.right = right + "px"; this.SubToolsDiv.style.top = top + "px"; this.SubToolsDiv.innerHTML = toolsDiv; this.SubToolsDiv.style.position = "absolute"; this.SubToolsDiv.style.display = "block"; var hqChart = this.HQChart; var picture = this.ChartPicture; var subToolDiv = this.SubToolsDiv; $(".subtool-del").click(function(){ hqChart.ClearChartDrawPicture(picture); // subToolDiv.innerHTML = ""; $(".subTolls").css("display","none"); }); var self = this; $(".subtool-set").click(function(){ $(self.SubToolsDiv).hide(); //创建div设置窗口 if (!this.SettingMenu) self.SettingMenu=new ChartPictureTextSettingMenu(frame.ChartBorder.UIElement.parentNode); self.SettingMenu.ChartPicture=picture; self.SettingMenu.HQChart=hqChart; self.SettingMenu.Position={Left:right + 80,Top:top + 20}; self.SettingMenu.DoModal(); }); $(".changes-color").click(function () { document.getElementById('color').click(); $(".change-color").change(function () { var color = $(".change-color").val(); picture.LineColor = color; picture.PointColor = color; if (hqChart.ChartDrawStorage) hqChart.ChartDrawStorage.SaveDrawData(picture); //保存下 }); }) console.log("[ChartPictureSettingMenu::DoModal]", {Top:top,Left:left, Right:right}); } } //画图工具 文本设置窗口 function ChartPictureTextSettingMenu(divElement) { this.newMethod=IDivDialog; //派生 this.newMethod(divElement); delete this.newMethod; this.ChartPicture; this.SettingDiv; this.Position; this.BackupData; //画图工具备份数据 this.Close=function() { if (this.SettingDiv) this.DivElement.removeChild(this.SettingDiv); //直接删除 } this.DoModal=function() { var text=this.ChartPicture.Text; //显示的文本 var fontOption=this.ChartPicture.FontOption; //字体设置 var lineColor=this.ChartPicture.LineColor; //数据备份, 点取消的时候把备份数据设置回去 this.BackupData= { Text:text, LineColor:lineColor, FontOption:{Family: fontOption.Family, Size: fontOption.Size, Weight: fontOption.Weight, Style: fontOption.Style } }; console.log('[ChartPictureTextSettingMenu::DoModal] picture info',this.BackupData); var self=this; var div=this.DivElement.getElementsByClassName('chartpicture-text-setting')[0]; if (!div) { div=document.createElement("div"); div.className='chartpicture-text-setting'; this.DivElement.appendChild(div); this.SettingDiv=div; } else { this.SettingDiv=div; } var titleContainerStr = '
      '+ '样式设置'+ ''+ '
      '; var fontSizeArray = [10,11,12,14,16,20,24,28,32,40]; var fontArray = ['微软雅黑','宋体','Arial','仿宋']; var sizeListStr = ""; var fontListStr = ""; fontArray.forEach(function(item,index){ fontListStr += index !== 0 ? '

      '+item+'

      ' : '

      '+item+'

      '; }); fontSizeArray.forEach(function(item,index){ sizeListStr += index !== 5 ? '

      '+item+'

      ' : '

      '+item+'

      '; }); var contentContainerStr = '
      '+ '
      '+ ''+ '
      微软雅黑
      '+fontListStr+'
      '+ '
      20
      '+sizeListStr+'
      '+ ''+ ''+ '
      '+ ''+ '
      '; var btnContainer = '
      '+ '确认'+ '取消'+ '
      '; var DoModalStr = titleContainerStr+contentContainerStr+btnContainer; this.SettingDiv.style.left = this.Position.Left + "px"; this.SettingDiv.style.top = this.Position.Top + "px"; this.SettingDiv.innerHTML=DoModalStr; this.SettingDiv.style.position = "absolute"; this.SettingDiv.style.display = "block"; $(".chartpicture-text-setting .colorPicker").css({ //初始设置 "borderColor":self.ChartPicture.LineColor, "background-color":self.ChartPicture.LineColor }); var family = this.ChartPicture.FontOption.Family; $('.chartpicture-text-setting .fontSelect .choicedText').html(family); fontArray.forEach(function(item,index){ if(item == family){ $('.chartpicture-text-setting .fontSelect p').removeClass('active'); $('.chartpicture-text-setting .fontSelect p').eq(index).addClass('active'); } }); var size = this.ChartPicture.FontOption.Size; $('.chartpicture-text-setting .fontSizeSelect .choicedText').html(size); fontSizeArray.forEach(function(item,index){ if(item == size){ $('.chartpicture-text-setting .fontSizeSelect p').removeClass('active'); $('.chartpicture-text-setting .fontSizeSelect p').eq(index).addClass('active'); } }); var weight = this.ChartPicture.FontOption.Weight; if( weight != null && weight == 'bold'){ $('.chartpicture-text-setting .strongFont').addClass('hot'); } var style = this.ChartPicture.FontOption.Style; if( style != null && style == 'italic'){ $('.chartpicture-text-setting .italicsFont').addClass('hot'); } var text = this.ChartPicture.Text; $('.chartpicture-text-setting .tArea').val(text); //结束初始设置 var defaultTextOption = { Family:'微软雅黑', Size:20, Weight:null, Style:null }; $(".chartpicture-text-setting #fontColor").change( { Picture:this.ChartPicture }, function(event) { //颜色选择 var value = $(this).val(); $(this).parent().css({ "borderColor":value, "background-color":value }); var chart=event.data.Picture; chart.LineColor = value; if (chart.Update) chart.Update(); //更新界面 } ); $(".chartpicture-text-setting .fontSelect,.chartpicture-text-setting .fontSizeSelect").click(function(){ $(this).find('.selectList').toggle(); $(this).toggleClass('hot'); }); $(".chartpicture-text-setting .fontSelect p").click( { Picture:this.ChartPicture }, function(event){ //字体选择 var choicedText = $(this).closest(".fontSelect").find('.choicedText').html(); var currentSelect = event.currentTarget.innerHTML; if(choicedText !== currentSelect){ $(this).closest(".fontSelect").find('.choicedText').html(currentSelect); $(this).siblings().removeClass('active'); $(this).addClass('active'); var chart = event.data.Picture; chart.FontOption.Family = currentSelect; if (chart.Update) chart.Update(); //更新界面 } }); $(".chartpicture-text-setting .fontSizeSelect p").click( { Picture:this.ChartPicture }, function(event){ //字号选择 var choicedText = $(this).closest(".fontSizeSelect").find('.choicedText').html(); var currentSelect = event.currentTarget.innerHTML; if(choicedText !== currentSelect){ $(this).closest(".fontSizeSelect").find('.choicedText').html(currentSelect); $(this).siblings().removeClass('active'); $(this).addClass('active'); var chart = event.data.Picture; chart.FontOption.Size = Number(currentSelect); if (chart.Update) chart.Update(); //更新界面 } }); $(".chartpicture-text-setting .strongFont").click( { Picture:this.ChartPicture }, function(event){ $(this).toggleClass('hot'); var classnames = $(this).attr('class'); if(classnames.indexOf('hot') > 0){ var chart = event.data.Picture; chart.FontOption.Weight = 'bold'; if (chart.Update) chart.Update(); //更新界面 } }); $(".chartpicture-text-setting .italicsFont").click( { Picture:this.ChartPicture }, function(event){ $(this).toggleClass('hot') var classnames = $(this).attr('class'); if(classnames.indexOf('hot') > 0){ var chart = event.data.Picture; chart.FontOption.Style = 'italic'; if (chart.Update) chart.Update(); //更新界面 } }); $(".chartpicture-text-setting .titleWrap .closeBtn,.chartpicture-text-setting .btnsContainer .cancelBtn").click( //取消 { Picture:this.ChartPicture }, function(event){ var picture = event.data.Picture; picture.Text = self.BackupData.Text; picture.LineColor = self.BackupData.LineColor; picture.FontOption = self.BackupData.FontOption; if (picture.Update) picture.Update(); self.Close(); }); $(".chartpicture-text-setting .tArea").keyup( //文本内容 { Picture:this.ChartPicture }, function(event){ console.log('[ChartPictureTextSettingMenu::DoModal] $(".chartpicture-text-setting .tArea").keyup()'); var content = $(this).val(); var chart = event.data.Picture; chart.Text = content; if (chart.Update) chart.Update(); //更新界面 }); //确定按钮 $(".chartpicture-text-setting .btnsContainer .okBtn").click( function() { self.Close(); if (self.HQChart && self.HQChart.ChartDrawStorage) self.HQChart.ChartDrawStorage.SaveDrawData(self.ChartPicture); //保存下 } ); } } /////////////////////////////////////////////////////////////////////////////////////// // // 各个品种分钟走势图坐标信息 // ////////////////////////////////////////////////////////////////////////////////////// var MARKET_SUFFIX_NAME= { SH:'.SH', SZ:'.SZ', HK:'.HK', //港股 FHK:'.FHK', //港股期货 SHFE: '.SHF', //上期所 (Shanghai Futures Exchange) SHFE2:'.SHFE', //上期所 (Shanghai Futures Exchange) CFFEX: '.CFE', //中期所 (China Financial Futures Exchange) DCE: '.DCE', //大连商品交易所(Dalian Commodity Exchange) CZCE: '.CZC', //郑州期货交易所 USA:'.USA', //美股 FTSE:'.FTSE', //富时中国 BIT:'.BIT', //数字货币 如比特币 BIZ:'.BIZ', //数字货币 ET:'.ET', //其他未知的品种 IsET:function(upperSymbol) { if (!upperSymbol) return false; return upperSymbol.indexOf(this.ET) > 0; }, IsFTSE:function(upperSymbol) { if (!upperSymbol) return false; return upperSymbol.indexOf(this.FTSE) > 0; }, IsFHK:function(upperSymbol) { if (!upperSymbol) return false; return upperSymbol.indexOf(this.FHK) > 0; }, IsBIT:function(upperSymbol) { if (!upperSymbol) return false; if (upperSymbol.indexOf(this.BIT) > 0) return true; if (upperSymbol.indexOf(this.BIZ) > 0) return true; return false; }, IsUSA:function(upperSymbol) //是否是美股 { if (!upperSymbol) return false; return upperSymbol.indexOf(this.USA) > 0; }, IsSH: function (upperSymbol) { //需要精确匹配最后3位 var pos = upperSymbol.length-this.SH.length; var find = upperSymbol.indexOf(this.SH); return find == pos; }, IsSZ: function (upperSymbol) { var pos = upperSymbol.length - this.SZ.length; var find = upperSymbol.indexOf(this.SZ); return find == pos; }, IsHK: function (upperSymbol) { var pos = upperSymbol.length - this.HK.length; var find = upperSymbol.indexOf(this.HK); return find == pos; }, IsSHFE: function (upperSymbol) { if (!upperSymbol) return false; if (upperSymbol.indexOf(this.SHFE) > 0) return true; if (upperSymbol.indexOf(this.SHFE2) > 0) return true; return false; }, IsCFFEX: function (upperSymbol) { return upperSymbol.indexOf(this.CFFEX) > 0; }, IsDCE: function (upperSymbol) { return upperSymbol.indexOf(this.DCE) > 0; }, IsCZCE: function (upperSymbol) { return upperSymbol.indexOf(this.CZCE) > 0; }, IsChinaFutures:function(upperSymbol) //是否是国内期货 { return this.IsCFFEX(upperSymbol) || this.IsCZCE(upperSymbol) || this.IsDCE(upperSymbol) || this.IsSHFE(upperSymbol); }, IsSHSZ:function(upperSymbol) //是否是沪深的股票 { return this.IsSZ(upperSymbol)|| this.IsSH(upperSymbol); }, IsSHSZFund:function(upperSymbol) //是否是交易所基金 { if (!upperSymbol) return false; if (this.IsSH(upperSymbol)) //51XXXX.SH { if (upperSymbol.charAt(0)=='5' && upperSymbol.charAt(1)=='1') return true; } else if (this.IsSZ(upperSymbol)) //15XXXX.sz, 16XXXX.sz, 17XXXX.sz, 18XXXX.sz { if (upperSymbol.charAt(0)=='1' && (upperSymbol.charAt(1)=='5' || upperSymbol.charAt(1)=='6' || upperSymbol.charAt(1)=='7' || upperSymbol.charAt(1)=='8') ) return true; } return false; }, IsSHSZIndex:function(symbol) //是否是沪深指数代码 { if (!symbol) return false; var upperSymbol=symbol.toUpperCase(); if (this.IsSH(upperSymbol)) { var temp=upperSymbol.replace('.SH',''); if (upperSymbol.charAt(0)=='0' && parseInt(temp)<=3000) return true; } else if (this.IsSZ(upperSymbol)) { if (upperSymbol.charAt(0)=='3' && upperSymbol.charAt(1)=='9') return true; } else if (upperSymbol.indexOf('.CI')>0) //自定义指数 { return true; } return false; }, IsSHSZStockA:function(symbol) //是否是沪深A股 { if (!symbol) return false; var upperSymbol=symbol.toUpperCase(); if (this.IsSH(upperSymbol)) { var temp=upperSymbol.replace('.SH',''); if (upperSymbol.charAt(0)=='6') return true; } else if (this.IsSZ(upperSymbol)) { if (upperSymbol.charAt(0)=='0') { if (upperSymbol.charAt(1)=='0' && upperSymbol.charAt(1)=='2') return true; //002 中小板 if (upperSymbol.charAt(1)!='7' && upperSymbol.charAt(1)!='8') return true; } } return false; }, IsSHStockSTAR:function(symbol) // 是否是科创板 Sci-Tech innovAtion boaRd (STAR Market) { if (!symbol) return false; var upperSymbol=symbol.toUpperCase(); if (!this.IsSH(upperSymbol)) return false; if (upperSymbol.charAt(0)=='6' && upperSymbol.charAt(1)=='8' && upperSymbol.charAt(2)=='8') return true; return false; }, GetMarketStatus:function(symbol) //获取市场状态 0=闭市 1=盘前 2=盘中 3=盘后 { if (!symbol) return 0; var upperSymbol=symbol.toUpperCase(); var nowDate= new Date(); var day = nowDate.getDay(); var time = nowDate.getHours() * 100 + nowDate.getMinutes(); if (this.IsUSA(upperSymbol)) { var usaDate=GetLocalTime(-4); var day = usaDate.getDay(); var time = usaDate.getHours() * 100 + usaDate.getMinutes(); if(day == 6 || day== 0) return 0; //周末 //9:30 - 16:00 考虑夏令时间时间增加1小时 9:30 - 17:00 if (time>1730) return 3; if (time<930) return 1; return 2; } else if (this.IsBIT(upperSymbol)) //数字货币24小时 { return 2; } else if (this.IsFTSE(upperSymbol)) //富时中国 9:00-16:30 17:00-04:45 { if(day == 6 || day== 0) return 0; //周末 if (time>=830 && time<=2359) return 2; if (time>=0 && time<=500) return 2; return 0; } else if (this.IsFHK(upperSymbol)) //港股指数期货 9:15-12:00 13:00-16:30 17:15-01:00 { if(day == 6 || day== 0) return 0; //周末 if (time>=900 && time<=2359) return 2; if (time>=0 && time<=320) return 2; return 0; } else if (this.IsET(upperSymbol)) { return this.GetETMarketStatus(symbol); } else //9:30 - 15:40 { if(day == 6 || day== 0) return 0; //周末 if(time>1540) return 3; if(time<925) return 1; return 2; } }, GetLimitPriceRange:function(symbol, name) //涨停范围 { if (!this.IsSHSZStockA(symbol)) return null; if (this.IsSHStockSTAR(symbol)) return {Max:0.2 , Min:-0.2}; //科创板 [20%- -20%] if (!name) return null; if (name.indexOf('ST')>=0) return { Max:0.05, Min:-0.05 }; //ST 股票 [5% - -5%] return {Max:0.1 , Min:-0.1}; //[10% - -10%] }, GetFHKDecimal:function(symbol) //港股指数期货 小数位数 { return 0; }, GetFTSEDecimal:function(symbol) //富时中国A50期货 小数位数 { return 0; }, GetBITDecimal:function(symbol) { return 2; }, GetETDecimal:function(symbol) { return 2; }, GetETMarketStatus:function(symbol) { // 0=闭市 1=盘前 2=盘中 3=盘后 return 2; } } //走势图分钟数据对应的时间 function MinuteTimeStringData() { this.SHSZ = null; //上海深证交易所时间 this.HK = null; //香港交易所时间 this.Futures=new Map(); //期货交易时间 key=时间名称 Value=数据 this.USA = null; //美股交易时间 this.FTSE=null; //富时中国 this.FHK=null; //港股指数期货 this.Initialize = function () //初始化 默认只初始化沪深的 其他市场动态生成 { //this.SHSZ = this.CreateSHSZData(); //this.HK = this.CreateHKData(); } this.GetSHSZ=function() //动态创建 { if (!this.SHSZ) this.SHSZ=this.CreateSHSZData(); return this.SHSZ; } this.GetHK=function() { if (!this.HK) this.HK = this.CreateHKData(); return this.HK; } this.GetFutures=function(splitData) { if (!this.Futures.has(splitData.Name)) { var data = this.CreateTimeData(splitData.Data); this.Futures.set(splitData.Name,data); } return this.Futures.get(splitData.Name); } this.GetUSA=function() { if (!this.USA) this.USA=this.CreateUSAData(0); return this.USA; } this.GetFTSE=function() { if (!this.FTSE) this.FTSE=this.CreateFTSEData(); return this.FTSE; } this.GetFHK=function() { if (!this.FHK) this.FHK=this.CreateFHKData(); return this.FHK; } this.CreateSHSZData = function () { const TIME_SPLIT = [ { Start: 925, End: 925 }, { Start: 930, End: 1130 }, { Start: 1300, End: 1500 } ]; return this.CreateTimeData(TIME_SPLIT); } this.CreateHKData = function () { const TIME_SPLIT = [ { Start: 930, End: 1200 }, { Start: 1300, End: 1600 } ]; return this.CreateTimeData(TIME_SPLIT); } this.CreateFTSEData=function() { const TIME_SPLIT= [ { Start:1700, End:2359 }, { Start:0, End:445 }, { Start:900, End:1630 } ]; return this.CreateTimeData(TIME_SPLIT); } this.CreateFHKData=function() { //港股指数期货 9:15-12:00 13:00-16:30 17:15-03:00 const TIME_SPLIT= [ { Start:1715, End:2359 }, { Start:0, End:300 }, { Start:915, End:1200 }, { Start:1300, End:1630 }, ]; return this.CreateTimeData(TIME_SPLIT); } this.CreateUSAData=function(type) { if (type==1) //美国夏令时 { const TIME_SPLIT = [ { Start: 2130, End: 2359 }, { Start: 0, End: 400 } ]; return this.CreateTimeData(TIME_SPLIT); } else if (type==2) //非夏令时 { const TIME_SPLIT = [ { Start: 2230, End: 2359 }, { Start: 0, End: 500 } ]; return this.CreateTimeData(TIME_SPLIT); } else //使用美国本地时间 { const TIME_SPLIT = [ { Start: 930, End: 1600 } //美国东部时间9:30到16:00 ]; return this.CreateTimeData(TIME_SPLIT); } } this.CreateTimeData = function (timeSplit) { var data = []; for (var i in timeSplit) { var item = timeSplit[i]; for (var j = item.Start; j <= item.End; ++j) { if (j % 100 >= 60) continue; //大于60分钟的数据去掉 data.push(j); } } return data; } this.GetTimeData = function (symbol) { if (!symbol) return this.SHSZ; var upperSymbol = symbol.toLocaleUpperCase(); //转成大写 if (MARKET_SUFFIX_NAME.IsSH(upperSymbol) || MARKET_SUFFIX_NAME.IsSZ(upperSymbol)) return this.GetSHSZ(); if (MARKET_SUFFIX_NAME.IsHK(upperSymbol)) return this.GetHK(); if (MARKET_SUFFIX_NAME.IsUSA(upperSymbol)) return this.GetUSA(true); if (MARKET_SUFFIX_NAME.IsCFFEX(upperSymbol) || MARKET_SUFFIX_NAME.IsCZCE(upperSymbol) || MARKET_SUFFIX_NAME.IsDCE(upperSymbol) || MARKET_SUFFIX_NAME.IsSHFE(upperSymbol)) { var splitData = g_FuturesTimeData.GetSplitData(upperSymbol); if (!splitData) return null; return this.GetFutures(splitData); } if (MARKET_SUFFIX_NAME.IsFTSE(upperSymbol)) return this.GetFTSE(); if (MARKET_SUFFIX_NAME.IsFHK(upperSymbol)) return this.GetFHK(); } } //走势图刻度分钟线 function MinuteCoordinateData() { //沪深走势图时间刻度 const SHZE_MINUTE_X_COORDINATE = { Full: //完整模式 [ [0, 0, "rgb(200,200,200)", "09:30"], [31, 0, "RGB(200,200,200)", "10:00"], [61, 0, "RGB(200,200,200)", "10:30"], [91, 0, "RGB(200,200,200)", "11:00"], [122, 1, "RGB(200,200,200)", "13:00"], [152, 0, "RGB(200,200,200)", "13:30"], [182, 0, "RGB(200,200,200)", "14:00"], [212, 0, "RGB(200,200,200)", "14:30"], [242, 1, "RGB(200,200,200)", "15:00"], // 15:00 ], Simple: //简洁模式 [ [0, 0, "rgb(200,200,200)", "09:30"], [61, 0, "RGB(200,200,200)", "10:30"], [122, 1, "RGB(200,200,200)", "13:00"], [182, 0, "RGB(200,200,200)", "14:00"], [242, 1, "RGB(200,200,200)", "15:00"] ], Min: //最小模式 [ [0, 0, "rgb(200,200,200)", "09:30"], [122, 1, "RGB(200,200,200)", "13:00"], [242, 1, "RGB(200,200,200)", "15:00"] ], Count: 243, MiddleCount: 122, GetData: function (width) { if (width < 200) return this.Min; else if (width < 400) return this.Simple; return this.Full; } }; //港股走势图时间刻度 const HK_MINUTE_X_COORDINATE = { Full: //完整模式 [ [0, 1, "RGB(200,200,200)", "09:30"], [30, 0, "RGB(200,200,200)", "10:00"], [60, 1, "RGB(200,200,200)", "10:30"], [90, 0, "RGB(200,200,200)", "11:00"], [120, 1, "RGB(200,200,200)", "11:30"], [151, 0, "RGB(200,200,200)", "13:00"], [181, 1, "RGB(200,200,200)", "13:30"], [211, 0, "RGB(200,200,200)", "14:00"], [241, 1, "RGB(200,200,200)", "14:30"], [271, 0, "RGB(200,200,200)", "15:00"], [301, 1, "RGB(200,200,200)", "15:30"], [331, 1, "RGB(200,200,200)", "16:00"] ], Simple: //简洁模式 [ [0, 1, "RGB(200,200,200)", "09:30"], [60, 1, "RGB(200,200,200)", "10:30"], [120, 1, "RGB(200,200,200)", "11:30"], [211, 0, "RGB(200,200,200)", "14:00"], [271, 0, "RGB(200,200,200)", "15:00"], [331, 1, "RGB(200,200,200)", "16:00"] ], Min: //最小模式 [ [0, 1, "RGB(200,200,200)", "09:30"], [151, 0, "RGB(200,200,200)", "13:00"], [331, 1, "RGB(200,200,200)", "16:00"] ], Count: 332, MiddleCount: 151, GetData: function (width) { if (width < 200) return this.Min; else if (width < 450) return this.Simple; return this.Full; } }; //美股走势图时间刻度 const USA_MINUTE_X_COORDINATE = { /* Full: //完整模式 [ [0, 0, "rgb(200,200,200)", "21:30"], [60, 0, "RGB(200,200,200)", "22:30"], [120, 1, "RGB(200,200,200)", "23:30"], [210, 0, "RGB(200,200,200)", "01:00"], [270, 0, "RGB(200,200,200)", "02:00"], [330, 0, "RGB(200,200,200)", "03:00"], [390, 0, "RGB(200,200,200)", "04:00"], ], Simple: //简洁模式 [ [0, 0, "rgb(200,200,200)", "21:30"], [160, 1, "RGB(200,200,200)", "00:00"], [270, 0, "RGB(200,200,200)", "02:00"], [390, 0, "RGB(200,200,200)", "04:00"], ], Min: //最小模式 [ [0, 0, "rgb(200,200,200)", "21:30"], [160, 1, "RGB(200,200,200)", "00:00"], [390, 0, "RGB(200,200,200)", "04:00"], ], */ //美国本地时间 Full: //完整模式 [ [0, 0, "rgb(200,200,200)", "9:30"], [30, 0, "RGB(200,200,200)", "10:00"], [90, 1, "RGB(200,200,200)", "11:00"], [150, 0, "RGB(200,200,200)", "12:00"], [210, 0, "RGB(200,200,200)", "13:00"], [270, 0, "RGB(200,200,200)", "14:00"], [330, 0, "RGB(200,200,200)", "15:00"], [390, 0, "RGB(200,200,200)", "16:00"], ], Simple: //简洁模式 [ [30, 0, "rgb(200,200,200)", "10:00"], [150, 1, "RGB(200,200,200)", "12:00"], [270, 0, "RGB(200,200,200)", "14:00"], [390, 0, "RGB(200,200,200)", "16:00"], ], Min: //最小模式 [ [30, 0, "rgb(200,200,200)", "10:00"], [210, 1, "RGB(200,200,200)", "13:00"], [390, 0, "RGB(200,200,200)", "16:00"], ], Count: 391, MiddleCount: 211, GetData: function (width) { if (width < 200) return this.Min; else if (width < 400) return this.Simple; return this.Full; } }; //富时中国 const FTSE_MINUTE_X_COORDINATE= { Full: //完整模式 [ [0, 1, "RGB(200,200,200)", "17:00"], //[60, 0, "RGB(200,200,200)", "18:00"], [120, 1, "RGB(200,200,200)", "19:00"], //[180, 0, "RGB(200,200,200)", "20:00"], [240, 1, "RGB(200,200,200)", "21:00"], //[300, 0, "RGB(200,200,200)", "22:00"], [360, 1, "RGB(200,200,200)", "23:00"], //[420, 0, "RGB(200,200,200)", "00:00"], [480, 1, "RGB(200,200,200)", "01:00"], //[540, 0, "RGB(200,200,200)", "02:00"], [600, 1, "RGB(200,200,200)", "03:00"], //[660, 1, "RGB(200,200,200)", "04:00"], [706, 1, "RGB(200,200,200)", "09:00"], //[766, 1, "RGB(200,200,200)", "10:00"], [826, 1, "RGB(200,200,200)", "11:00"], //[886, 1, "RGB(200,200,200)", "12:00"], [946, 1, "RGB(200,200,200)", "13:00"], //[1006, 1, "RGB(200,200,200)", "14:00"], [1066, 1, "RGB(200,200,200)", "15:00"], [1156, 1, "RGB(200,200,200)", "16:30"], ], Simple: //简洁模式 [ [0, 1, "RGB(200,200,200)", "17:00"], //[60, 0, "RGB(200,200,200)", "18:00"], //[120, 1, "RGB(200,200,200)", "19:00"], //[180, 0, "RGB(200,200,200)", "20:00"], [240, 1, "RGB(200,200,200)", "21:00"], //[300, 0, "RGB(200,200,200)", "22:00"], //[360, 1, "RGB(200,200,200)", "23:30"], //[420, 0, "RGB(200,200,200)", "00:00"], [480, 1, "RGB(200,200,200)", "01:00"], //[540, 0, "RGB(200,200,200)", "02:00"], //[600, 1, "RGB(200,200,200)", "03:00"], //[660, 1, "RGB(200,200,200)", "04:00"], [706, 1, "RGB(200,200,200)", "09:00"], //[766, 1, "RGB(200,200,200)", "10:00"], //[826, 1, "RGB(200,200,200)", "11:00"], //[886, 1, "RGB(200,200,200)", "12:00"], [946, 1, "RGB(200,200,200)", "13:00"], //[1006, 1, "RGB(200,200,200)", "14:00"], //[1066, 1, "RGB(200,200,200)", "15:00"], [1156, 1, "RGB(200,200,200)", "16:30"], ], Min: //最小模式 [ [0, 1, "RGB(200,200,200)", "17:00"], [706, 1, "RGB(200,200,200)", "09:00"], [1156, 1, "RGB(200,200,200)", "16:30"], ], Count: 1157, MiddleCount: 707, GetData: function (width) { if (width < 200) return this.Min; else if (width < 450) return this.Simple; return this.Full; } } //港股指数期货 const FHK_MINUTE_X_COORDINATE= { Full: //完整模式 [ [0, 1, "RGB(200,200,200)", "17:15"], [105, 1, "RGB(200,200,200)", "19:00"], [225, 1, "RGB(200,200,200)", "21:00"], [345, 1, "RGB(200,200,200)", "23:00"], [586, 0, "RGB(200,200,200)", "09:15"], [691, 1, "RGB(200,200,200)", "11:00"], [812, 1, "RGB(200,200,200)", "14:00"], [963, 1, "RGB(200,200,200)", "16:30"], ], Simple: //简洁模式 [ [0, 1, "RGB(200,200,200)", "17:15"], [225, 1, "RGB(200,200,200)", "21:00"], [586, 0, "RGB(200,200,200)", "09:15"], [752, 1, "RGB(200,200,200)", "13:00"], [963, 1, "RGB(200,200,200)", "16:30"], ], Min: //最小模式 [ [0, 1, "RGB(200,200,200)", "17:15"], [586, 0, "RGB(200,200,200)", "09:15"], [963, 1, "RGB(200,200,200)", "16:30"], ], Count: 963, MiddleCount: 526, GetData: function (width) { if (width < 200) return this.Min; else if (width < 450) return this.Simple; return this.Full; } } this.GetCoordinateData = function (symbol, width) { var data = null; if (!symbol) { data = SHZE_MINUTE_X_COORDINATE; //默认沪深股票 } else { var upperSymbol = symbol.toLocaleUpperCase(); //转成大写 if (MARKET_SUFFIX_NAME.IsSH(upperSymbol) || MARKET_SUFFIX_NAME.IsSZ(upperSymbol) || MARKET_SUFFIX_NAME.IsSHSZIndex(upperSymbol)) data = this.GetSHSZData(upperSymbol,width); else if (MARKET_SUFFIX_NAME.IsHK(upperSymbol)) data = HK_MINUTE_X_COORDINATE; else if (MARKET_SUFFIX_NAME.IsCFFEX(upperSymbol) || MARKET_SUFFIX_NAME.IsCZCE(upperSymbol) || MARKET_SUFFIX_NAME.IsDCE(upperSymbol) || MARKET_SUFFIX_NAME.IsSHFE(upperSymbol)) return this.GetFuturesData(upperSymbol,width); else if (MARKET_SUFFIX_NAME.IsUSA(upperSymbol)) data = this.GetUSAData(upperSymbol,width); else if (MARKET_SUFFIX_NAME.IsFTSE(upperSymbol,width)) data=this.GetFTSEData(upperSymbol,width); else if (MARKET_SUFFIX_NAME.IsFHK(upperSymbol,width)) data=this.GetFHKData(upperSymbol,width); } //console.log('[MiuteCoordinateData]', width); var result = { Count: data.Count, MiddleCount: data.MiddleCount, Data: data.GetData(width) }; return result; } this.GetSHSZData=function(upperSymbol,width) { var result=SHZE_MINUTE_X_COORDINATE; return result; } this.GetUSAData=function(upperSymbol,width) { var result=USA_MINUTE_X_COORDINATE; return result; } this.GetFuturesData = function (upperSymbol,width) { var splitData = g_FuturesTimeData.GetSplitData(upperSymbol); if (!splitData) return null; var stringData = g_MinuteTimeStringData.GetFutures(splitData); if (!stringData) return null; var result = { Count: stringData.length }; var coordinate=null; var minWidth=200, simpleWidth=480; /* if (splitData.Name =='21:00-1:00,9:00-10:15,10:30-11:30,13:30-15:00') { minWidth=250; simpleWidth=500; } */ if (width < minWidth) coordinate = splitData.Coordinate.Min; else if (width < simpleWidth) coordinate = splitData.Coordinate.Simple; else coordinate = splitData.Coordinate.Full; var data=[]; for(var i=0;i> 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 >= 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 >= 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; } //重新下载数据 this.ThrowDownloadJob=function(index, line, col, description,job) { let error=this.CreateError(index,line,col,description); error.Job=job; 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; 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=='OR' || str=='<>') { 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.IsNeedFinanceData=new Set(); //需要下载的财务数据 this.IsNeedMarginData=new Set(); this.IsNeedNewsAnalysisData=new Set(); //新闻统计数据 this.IsNeedBlockIncreaseData=new Set(); //是否需要市场涨跌股票数据统计 this.IsNeedSymbolExData=new Set(); //下载股票行情的其他数据 this.IsNeedHK2SHSZData=new Set(); //下载北上资金数据 this.IsNeedSectionFinance=new Map(); //下载截面财务数据 { key= 报告期 , Set() 字段} this.IsCustomFunction=[]; //自定义函数 {Name, ID, Args:} this.IsCustomVariant=[]; //自定义变量 {Name, ID} 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.IsNeedFinanceData) { if (jobID==JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_DIVIDEND_YIELD_DATA) //股息率 需要总市值 jobs.push({ID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARKETVALUE_DATA}); jobs.push({ID:jobID}); } //加载融资融券 for(var jobID of this.IsNeedMarginData) { jobs.push({ID:jobID}); } //加载北上资金 for(var jobID of this.IsNeedHK2SHSZData) { jobs.push({ID:jobID}); } //加载新闻统计 for(var jobID of this.IsNeedNewsAnalysisData) { jobs.push({ID:jobID}); } //行情其他数据 for(var jobID of this.IsNeedSymbolExData) { jobs.push({ID:jobID}); } //获取截面数据下载任务 for(var item of this.IsNeedSectionFinance) { jobs.push({ID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_SF, SF:item}); } for(var i in this.IsCustomVariant) { var item=this.IsCustomVariant[i]; jobs.push({ID:item.ID, Name:item.Name}); } for(var i in this.IsCustomFunction) { var item=this.IsCustomFunction[i]; jobs.push({ID:item.ID, Name:item.Name, Args:item.Args}); } return jobs; } this.VerifySymbolVariable=function(varName) { 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); } if (varName=='HYBLOCK' || varName=='DYBLOCK' || varName=='GNBLOCK') { if (!this.IsNeedSymbolExData.has(JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_GROUP_DATA)) this.IsNeedSymbolExData.add(JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_GROUP_DATA); } //流通股本(手) if (varName==='CAPITAL') { if (!this.IsNeedFinanceData.has(JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_CAPITAL_DATA)) this.IsNeedFinanceData.add(JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_CAPITAL_DATA); } if (varName==='EXCHANGE') { if (!this.IsNeedFinanceData.has(JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_EXCHANGE_DATA)) this.IsNeedFinanceData.add(JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_EXCHANGE_DATA); } if (g_JSComplierResource.IsCustomVariant(varName)) //自定义函数( 不过滤了, 调一次就写一次) { var item={Name:varName, ID:JS_EXECUTE_JOB_ID.JOB_CUSTOM_VARIANT_DATA} this.IsCustomVariant.push(item); } } this.VerifySymbolFunction=function(callee,args) { if (callee.Name=='DYNAINFO') { this.IsNeedLatestData=true; return; } //财务函数 if (callee.Name=='FINANCE') { let jobID=JS_EXECUTE_JOB_ID.GetFinnanceJobID(args[0].Value); if (jobID && !this.IsNeedFinanceData.has(jobID)) this.IsNeedFinanceData.add(jobID); 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==='HK2SHSZ') //北上资金 { let jobID=JS_EXECUTE_JOB_ID.GetHK2SHSZJobID(args[0].Value); if (jobID && !this.IsNeedHK2SHSZData.has(jobID)) this.IsNeedHK2SHSZData.add(jobID); return; } if (callee.Name=='COST' || callee.Name=='WINNER') //筹码都需要换手率 { if (!this.IsNeedFinanceData.has(JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_EXCHANGE_DATA)) this.IsNeedFinanceData.add(JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_EXCHANGE_DATA); 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=='SF') //Section finance { let period=JS_EXECUTE_JOB_ID.GetSectionReportPeriod(args[0].Value,args[1].Value); //报告期 if (!period) return; let jobID=JS_EXECUTE_JOB_ID.GetSectionFinanceID(args[2].Value); if (!jobID) return; var sfkey=period.Year+ '-' + period.Quarter; if (!this.IsNeedSectionFinance.has(sfkey)) { var finacne={ Period:period, Fields:new Set([jobID]) }; this.IsNeedSectionFinance.set(sfkey, finacne); } else { var finacne=this.IsNeedSectionFinance.get(sfkey); if (!finacne.Fields.has(jobID)) finacne.Fields.add(jobID); } return; } if (g_JSComplierResource.IsCustomFunction(callee.Name)) //自定义函数( 不过滤了, 调一次就写一次) { var item={Name:callee.Name, ID:JS_EXECUTE_JOB_ID.JOB_CUSTOM_FUNCTION_DATA, Args:args} this.IsCustomFunction.push(item); } } 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) { this.VerifySymbolVariable(name); 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) { this.VerifySymbolFunction(callee, args); return { Type:Syntax.CallExpression, Callee:callee, Arguments:args }; } } 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=false; var args=this.ParseArguments(); //解析 调用参数 expr=this.Finalize(this.StartNode(startToken), this.Node.CallExpression(expr,args)); } else { break; } } return expr; } // 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 */ expr=this.Finalize(node, this.Node.Identifier(this.NextToken().Value)); 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.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; } this.MAX=function(data,data2) { let isNumber=typeof(data)=='number'; let isNumber2=typeof(data2)=='number'; //单数值 if (isNumber && isNumber2) return Math.max(data,data2); //都是数组 let result=[]; if (!isNumber && !isNumber2) { let count=Math.max(data.length, data2.length); for(let i=0;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; } } else { for(var i=0;i=dayCount.length) continue; var sumCount=dayCount[i]; if (!this.IsNumber(sumCount)) continue; if (sumCount<=0) sumCount=i; //0计算当前所有的 var sum=0; for(var j=i, k=0;j>=0 && k=data.length) return result; //取首个有效数据 for(;offset= 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) { var total = 0; 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=0;++j) { if (data[i-j]) ++count; } result[i]=count; } return result; } /* HHV 最高值 求最高值。 用法: HHV(X,N) 求N周期内X最高值,N=0则从第一个有效值开始。 例如: HHV(HIGH,30) 表示求30日最高价。 */ this.HHV=function(data,n) { let result = []; if (Array.isArray(n)) { var max=null; for(var i=0,j=0;i=n.length) continue; max=null; var count=n[i]; if (count>0 && count<=i) { for(j=i-count;j<=i;++j) { if (max==null || maxdata.length) return result; if (n<=0) n=data.length-1; var nMax=0; for(nMax=0;nMax=data[nMax]) nMax=i; result[i]=data[nMax]; } for(;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 min=null; for(var i=n;idata[min]?min:i; } else { for(var j=(min=i-n+1)+1;j<=i;++j) { if(data[j]data2[index] && data[index-1]data2 && data[index-1]data) ? 1:0; } } return result; } //累乘 this.MULAR=function(data,n) { var result=[]; if(data.length0)) continue; for(var j=i, k=0 ;j>=0 && kdatanum) 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; 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; j < num && j <= i; ++j) { Ex += (i - j); Ey += data[i - j]; } Ex /= num; Ey /= num; for(j = 0; j < num && j <= i; ++j) { Sxy += (i-j-Ex)*(data[i-j]-Ey); Sxx += (i-j-Ex)*(i-j-Ex); } Slope = Sxy / Sxx; Const = (Ey - Ex*Slope) / num; 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; } return result; } //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 (latestID!=null && i-latestIDOPEN,5)查找阳线,5天内再次出现的阳线不被记录在内 */ this.FILTER=function(data,n) { var result=[]; for(let i=0,j=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=[]; var day=null; for(let i=0;i10)表示股价超过10元时到当前的周期数 */ this.BARSSINCE=function(data) { var result=[]; var day=null; for(let i=0;iOPEN,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;in) { secondData={ID:parseInt(i), Value:item, Up:true}; lastData={ID:parseInt(i), Value:item}; bSecondPont=true; } else if (temp<-n) { secondData={ID:parseInt(i), Value:item, Up:false}; lastData={ID:parseInt(i), Value:item}; bSecondPont=true; } } else if (bFirstPoint==true && bSecondPont==true) { var temp=(item-lastData.Value)/lastData.Value*100; if (secondData.Up==true) //找下跌的点 { if (temp<-n) { thridData={ID:parseInt(i), Value:item, Up:false}; this.CalculateZIGLine(firstData,secondData,thridData,data,result); lastData={ID:parseInt(i), Value:item}; } else { if (item>lastData.Value) lastData={ID:parseInt(i), Value:item}; } } else { if (temp>n) { thridData={ID:parseInt(i), Value:item, Up:true}; this.CalculateZIGLine(firstData,secondData,thridData,data,result); lastData={ID:parseInt(i), Value:item}; } else { if (itemsubItem) 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 i=0,result=[]; for(i=0;i=0 && zigData[i]=0 && zigData[i]n2) { trough.shift(); //大于计算的波谷数,去掉第1个波谷 start=trough[0]; --j; result[i]=i-start; } } else { if (j+1===n2) result[i]=i-start; } } return result; } /* 属于未来函数,前M个ZIG转向波峰到当前距离. 用法: PEAKBARS(K,N,M)表示之字转向ZIG(K,N)的前M个波峰到当前的周期数,M必须大于等于1 例如: PEAKBARS(0,5,1)表示%5开盘价ZIG转向的上一个波峰到当前的周期数 */ this.PEAKBARS=function(data,n,n2) { var zigData=this.ZIG(data,n); //计算ZIG var i=0,result=[]; for(i=0;i=0 && zigData[i]>zigData[i-1] && zigData[i]>zigData[i+1]) //波峰 { trough[0]=i; break; } } for(i+=1;i=0 && zigData[i]>zigData[i-1] && zigData[i]>zigData[i+1]) //波峰 { console.log('[TROUGHBARS] i',i,zigData[i]); ++j; trough[j]=i; if (j+1==n2) { result[i]=i-start; } else if (j+1>n2) { trough.shift(); //大于计算的波谷数,去掉第1个波谷 start=trough[0]; --j; result[i]=i-start; } } else { if (j+1===n2) result[i]=i-start; } } return result; } /* 一直存在. 例如: EVERY(CLOSE>OPEN,N) 表示N日内一直阳线(N应大于0,小于总周期数,N支持变量) */ this.EVERY=function(data,n) { var result=[]; if (n<1) return result; var i=0; for(;i=0; --i) { result[i]=null; var chipData=this.CalculateChip(i,exchangeData,this.SymbolData.Data.Data,1); if (chipData.Max==null || chipData.Min==null || chipData.Max<=0 || chipData.Min<=0) continue; var max=parseInt(chipData.Max*100); var min=parseInt(chipData.Min*100); if (singleData!=null) { compareData=singleData; } else { if (i>=data.length) continue; compareData=data[i]; } var totalVol=0,vol=0; var aryMap=new Map(); for(j=i; j>=0; --j) { var item=chipData.Data[j]; var start=parseInt(item.Low*100); var end=parseInt(item.High*100); if ((end-start+1)<=0) continue; var iAverageVolume=item.Vol; iAverageVolume=iAverageVolume/(end-start+1); if (iAverageVolume<=0) continue; for(k=start;k<=end && k<=max;++k) { if (aryMap.has(k)) { vol=aryMap.get(k); aryMap.set(k,vol+iAverageVolume); } else { aryMap.set(k,iAverageVolume); } } totalVol+=item.Vol; } //计算获利盘 vol=0; for(var priceData of aryMap) { vol+=priceData[1]; result[i]=priceData[0]/100; if (vol/totalVol*100>compareData) break; } } return result; } /* 获利盘比例. 用法: WINNER(CLOSE),表示以当前收市价卖出的获利盘比例,例如返回0.1表示10%获利盘;WINNER(10.5)表示10.5元价格的获利盘比例 该函数仅对日线分析周期有效 !!!!计算比较耗时间 */ this.WINNER=function(data) { var result=[]; var exchangeID=201; var exchangeData=this.SymbolData.GetFinanceCacheData(exchangeID); //换手率 if (!exchangeData) return result; var isNumber=Array.isArray(data)?false:true; var singleData=null; if (isNumber) singleData=parseInt(parseFloat(data)*100); var compareData=null; for(let i=this.SymbolData.Data.Data.length-1, j=0,k=0 ; i>=0; --i) { result[i]=null; var chipData=this.CalculateChip(i,exchangeData,this.SymbolData.Data.Data,1); if (chipData.Max==null || chipData.Min==null || chipData.Max<=0 || chipData.Min<=0) continue; var max=parseInt(chipData.Max*100); var min=parseInt(chipData.Min*100); if (singleData!=null) { compareData=singleData; } else { if (i>=data.length) continue; compareData=parseInt(data[i]*100); } var totalVol=0,vol=0; for(j=i; j>=0; --j) { var item=chipData.Data[j]; var start=parseInt(item.Low*100); var end=parseInt(item.High*100); if ((end-start+1)<=0) continue; var iAverageVolume=item.Vol; iAverageVolume=iAverageVolume/(end-start+1); if (iAverageVolume<=0) continue; var profitVol=0; //获利的成交量 if (compareData>end) profitVol=item.Vol; else if (compareData0) result[i]=vol/totalVol; } 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 (maxdata.length) return result; var days=0; for(let i=0;idata[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;iY 用法: 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=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=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]=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=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=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>=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 (n<1) n=data.length; var nMax=null; //最大值索引 for(var i=0;i=data[nMax]) nMax=i; if(n==data.length) result[i]=(i-nMax); } for(;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 (n<1) n=data.length; var nMin=null; //最小值索引 for(var i=0;i0 && 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=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;i0) 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=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;iitem.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;iysip) { 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.Lowsar[index]; for(var i=index+1;isar[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; for(var i=0;i=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; } //用法:BETWEEN(A,B,C)表示A处于B和C之间时返回1,否则返回0 //例如:BETWEEN(CLOSE,MA(CLOSE,20),MA(CLOSE,10))表示收盘价介于10日均线和20日均线之间 this.BETWEEN=function(condition, data, data2) { var result=[]; var isNumber=typeof(condition)=='number'; var isNumber2=typeof(data)=='number'; var isNumber3=typeof(data2)=='number'; if (isNumber && isNumber2 && isNumber3) //单数值 { return (condition>=data && condition<=data2) ? 1 : 0; } for(var i in condition) { result[i]=0; var item=condition[i]; var left=null, right=null; if (isNumber2) left=data; else if (iright) { if (item>=right && item<=left) result[i]=1; } else { if (item<=right && item>=left) result[i]=1; } } return result; } //STRCAT(A,B):将两个字符串A,B(非序列化)相加成一个字符串C. //用法: STRCAT('多头','开仓')将两个字符串'多头','开仓'相加成一个字符串'多头开仓' this.STRCAT=function(str1, str2) { var result=str1+str2; return result; } //CON2STR(A,N):取A最后的值(非序列值)转为字符串,小数位数N. //用法: CON2STR(FINANCE(20),3)表示取营业收入,以3位小数转为字符串 this.CON2STR=function(data,n) { var result=[]; if (Array.isArray(data)) { for(var i=data.length-1 ; i>=0; --i) { var item=data[i]; if (IFrameSplitOperator.IsNumber(item)) { result=item.toFixed(n); return result; } } } else { if (IFrameSplitOperator.IsNumber(data)) result=data.toFixed(n); } return result; } //函数调用 this.CallFunction=function(name,args,node,symbolData) { 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 '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 '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 'DEVSQ': return this.DEVSQ(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 'PEAKBARS': return this.PEAKBARS(args[0],args[1],args[2]); case 'COST': return this.COST(args[0]); case 'WINNER': return this.WINNER(args[0]); 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 '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 '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 'BETWEEN': return this.BETWEEN(args[0], args[1], args[2]); case 'STRCAT': return this.STRCAT(args[0], args[1]); case 'CON2STR': return this.CON2STR(args[0], args[1]); //三角函数 case 'ATAN': return this.Trigonometric(args[0],Math.atan); case 'ACOS': return this.Trigonometric(args[0],Math.acos); case 'ASIN': return this.Trigonometric(args[0],Math.asin); 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: if (g_JSComplierResource.IsCustomFunction(name)) return this.CallCustomFunction(name, args, symbolData); this.ThrowUnexpectedNode(node,'函数'+name+'不存在'); } } this.CallCustomFunction=function(name, args,symbolData) { var item=g_JSComplierResource.CustomFunction.Data.get(name); if (!item || !item.Invoke) return []; var obj={ Name:name, Args:args, Symbol:symbolData.Symbol, Period:symbolData.Period, Right:symbolData.Right, KData:symbolData.Data }; return item.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.IsDivideNumber=function(value) { if (value==null) return false; if (isNaN(value)) return false; if (value==0) return false; return true; } /* 绘图函数 */ 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 (condition.length<=0) return result; var IsNumber=typeof(price)=="number"; 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]; } } return result; } this.DRAWTEXT_FIX=function(condition,x,y,type,text) { let result={Position:null, DrawType:'DRAWTEXT_FIX',Text:text}; if (condition.length<=0) return result; for(var i in condition) { if (isNaN(condition[i]) || !condition[i]) continue; result.Position={X:x, Y:y, Type:type}; return result; } return result; } //direction 文字Y轴位置 0=middle 1=价格的顶部 2=价格的底部 //offset 文字Y轴偏移 this.SUPERDRAWTEXT=function(condition,price,text,direction,offset) { let drawData=[]; let result={DrawData:drawData, DrawType:'SUPERDRAWTEXT',Text:text,YOffset:offset,Direction:direction,TextAlign:'center'}; if (condition.length<=0) return result; var IsNumber=typeof(price)=="number"; 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]; } } return result; } /* STICKLINE 绘制柱线 在图形上绘制柱线。 用法: STICKLINE(COND,PRICE1,PRICE2,WIDTH,EMPTY),当COND条件满足时,在PRICE1和PRICE2位置之间画柱状线,宽度为WIDTH(10为标准间距),EMPTH不为0则画空心柱。 例如: STICKLINE(CLOSE>OPEN,CLOSE,OPEN,0.8,1)表示画K线中阳线的空心柱体部分。 */ this.STICKLINE=function(condition,data,data2,width,type) { let drawData=[]; let result={DrawData:drawData, DrawType:'STICKLINE',Width:width, Type:type}; if(condition.length<=0) return result; var IsNumber=typeof(data)=="number"; var IsNumber2=typeof(data2)=="number"; for(var i in condition) { drawData[i]=null; if (isNaN(condition[i]) || !condition[i]) continue; if (IsNumber && IsNumber2) { drawData[i]={Value:data,Value2:data2}; } else if (IsNumber && !IsNumber2) { if (isNaN(data2[i])) continue; drawData[i]={Value:data,Value2:data2[i]}; } else if (!IsNumber && IsNumber2) { if (isNaN(data[i])) continue; drawData[i]={Value:data[i],Value2:data2}; } else { if (isNaN(data[i]) || isNaN(data2[i])) continue; drawData[i]={Value:data[i],Value2:data2[i]}; } } return result; } /* DRAWLINE 绘制直线段 在图形上绘制直线段。 用法: DRAWLINE(COND1,PRICE1,COND2,PRICE2,EXPAND) 当COND1条件满足时,在PRICE1位置画直线起点,当COND2条件满足时,在PRICE2位置画直线终点,EXPAND为延长类型。 例如: DRAWLINE(HIGH>=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;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'}; let isNumber=typeof(data2)=='number'; let text; if (isNumber) text=data2.toFixed(2); for(let i in condition) { drawData.Value[i]=null; if (!condition[i]) continue; 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(); } } return result; } /* 在图形上绘制小图标. 用法: DRAWICON(COND,PRICE,TYPE),当COND条件满足时,在PRICE位置画TYPE号图标(TYPE为1--41). 例如: DRAWICON(CLOSE>OPEN,LOW,1)表示当收阳时在最低价位置画1号图标. */ this.DRAWICON=function(condition,data,type) { var icon=g_JSComplierResource.GetDrawIcon(type); if (!icon) { //图标对应的字符代码 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:'B',Color:'rgb(238,44,44)'} ],[8,{Symbol:'S',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)'} ], [40,{Symbol:'◉',Color:'rgb(238,44,44)'}], [41,{Symbol:'◈',Color:'rgb(238,44,44)'}], [42,{Symbol:'📌'}], [43,{Symbol:'💎'}], [44,{Symbol:'🥇'}],[45,{Symbol:'🥈'}],[46,{Symbol:'🥉'}],[47,{Symbol:'🏅'}] ]); icon=mapIcon.get(type); } if (!icon) icon={Symbol:'🚩'}; 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;i0) result.Border.Width=borderWidth; if (dotted) { let ary=dotted.split(','); result.Border.Dotted=[]; for(var i in ary) { var item=ary[i]; if (!item) continue; var value=parseInt(ary[i]); if (value<=0) continue; result.Border.Dotted.push(value); } if (result.Border.Dotted.length<=0) result.Border.Dotted=null; } var IsNumber=typeof(data)=="number"; var IsNumber2=typeof(data2)=="number"; if (typeof(condition)=='number') { if (!condition) return result; //条件是否 for(var i=0;iOPEN,RGB(255,0,0),CLOSEC,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.DRAWTEXT_LINE=function(condition, price, text, textcolor, fontSize, linetype, linecolor) { let drawData={ Text:{ Title:text, Color:textcolor }, Line:{ Type:linetype, Color:linecolor } }; if (fontSize<=0) fontSize=12; drawData.Text.Font=fontSize*GetDevicePixelRatio()+'px 微软雅黑'; let result={DrawData:null, DrawType:'DRAWTEXT_LINE'}; if (Array.isArray(condition)) { for(var i in condition) { var item=condition[i]; if (item) { if (Array.isArray(price)) drawData.Price=price[i]; else drawData.Price=price; result.DrawData=drawData; break; } } } else { if (condition) { if (Array.isArray(price)) drawData.Price=price[0]; else drawData.Price=price; result.DrawData=drawData; } } 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:left, Top:top, Right:right, Bottom:bottom }, Color:color }; if (color==0) drawData.Color=null; let result={DrawData:drawData, DrawType:'DRAWRECTREL'}; return result; } } 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.MaxRequestDataCount=option.MaxRequestDataCount; if (option.MaxRequestMinuteDayCount>0) this.MaxRequestMinuteDayCount=option.MaxRequestMinuteDayCount; if (option.KLineApiUrl) this.KLineApiUrl=option.KLineApiUrl; if (option.Right) this.Right=option.Right; if (option.Period) this.Period=option.Period; if (option.IsBeforeData===true) this.IsBeforeData=option.IsBeforeData; if (option.NetworkFilter) this.NetworkFilter=option.NetworkFilter; if (option.DayCount>0) this.DayCount=option.DayCount; } this.RecvError=function(request) { console.log('[JSSymbolData::RecvError] ajax error.',request.status); throw {FunctionName:'RecvError', Request:request}; } //最新行情 this.GetLatestData=function() { if (this.LatestData) return this.Execute.RunNextJob(); var self=this; if (this.NetworkFilter) { var obj= { Name:'JSSymbolData::GetLatestData', //类名:: Explain:'DYNAINFO()', Request:{ Url:self.RealtimeApiUrl, Type:'POST' , Data: { symbol:[this.Symbol], field: ["name","symbol","yclose","open","price","high","low","vol","amount","date","time","increase","exchangerate","amplitude"] } }, Self:this, PreventDefault:false }; this.NetworkFilter(obj, function(data) { self.RecvLatestData(data); self.Execute.RunNextJob(); }); if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求 } JSNetwork.HttpRequest({ url: self.RealtimeApiUrl, data: { "field": ["name","symbol","yclose","open","price","high","low","vol","amount","date","time","increase","exchangerate","amplitude"], "symbol": [this.Symbol] }, type:"post", dataType: "json", async:true, success: function (recvData) { self.RecvLatestData(recvData); self.Execute.RunNextJob(); }, error: function(request) { self.RecvError(request); } }); } this.RecvLatestData=function(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}; console.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; $.ajax({ url: self.RealtimeApiUrl, data: { "field": ["name","symbol","avgvol5", 'date'], "symbol": [this.Symbol] }, type:"post", dataType: "json", async:true, success: function (recvData) { self.RecvVolRateData(recvData,volrKey); self.Execute.RunNextJob(); }, error: function(request) { self.RecvError(request); } }); } this.RecvVolRateData=function(data,key) { 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); console.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;i0) result[i]=totalVol/(j+1)/avgVol5*100; ++j; } return result; } this.GetGroupData=function(job) { var key=job.ID.toString()+'-Group-'+this.Symbol; if (this.ExtendData.has(key)) return this.Execute.RunNextJob(); var self=this; if (this.NetworkFilter) { var obj= { Name:'JSSymbolData::GetGroupData', //类名:: Explain:'HYBLOCK|DYBLOCK', Request:{ Url:self.RealtimeApiUrl, Type:'POST' , Data: { symbol:[this.Symbol], field: ["name","symbol","industry", 'concept','region'] } }, Self:this, PreventDefault:false }; this.NetworkFilter(obj, function(data) { self.RecvGroupData(data,key); self.Execute.RunNextJob(); }); if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求 } JSNetwork.HttpRequest({ url: self.RealtimeApiUrl, data: { "field": ["name","symbol","industry", 'concept','region'], "symbol": [this.Symbol] }, type:"post", dataType: "json", async:true, success: function (recvData) { self.RecvGroupData(recvData,key); self.Execute.RunNextJob(); }, error: function(request) { self.RecvError(request); } }); } this.RecvGroupData=function(data,key) { if (!data.stock) return; if (data.stock.length!=1) return; var stock=data.stock[0]; var industry=stock.industry; var concept=stock.concept; var region=stock.region; var groupData={Industry:[],Concept:[], Region:[] }; if (industry) { for(var i in industry) { var item=industry[i]; groupData.Industry.push({Name:item.name, Symbol:item.symbol}); } } if (concept) { for(var i in concept) { var item=concept[i]; groupData.Concept.push({Name:item.name, Symbol:item.symbol}); } } if (region) { for(var i in region) { var item=region[i]; groupData.Region.push({Name:item.name, Symbol:item.symbol}); } } this.ExtendData.set(key,groupData); } //获取大盘指数数据 this.GetIndexData=function() { if (this.IndexData) return this.Execute.RunNextJob(); var self=this; if (ChartData.IsDayPeriod(this.Period,true)) //请求日线数据 9=季线 { if (this.NetworkFilter) { var obj= { Name:'JSSymbolData::GetIndexData', //类名:: Explain:'大盘数据', Period:self.Period, Request:{ Url:self.KLineApiUrl, Type:'POST' , Data: { field:[ "name", "symbol","yclose","open","price","high","low","vol",'up','down','stop','unchanged'], symbol: '000001.sh', start: -1 , count: self.MaxRequestDataCount+500 } }, Self:this, PreventDefault:false }; this.NetworkFilter(obj, function(data) { self.RecvIndexHistroyData(data); self.Execute.RunNextJob(); }); if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求 } JSNetwork.HttpRequest({ url: self.KLineApiUrl, data: { "field": [ "name", "symbol","yclose","open","price","high","low","vol",'up','down','stop','unchanged'], "symbol": '000001.sh', "start": -1, "count": self.MaxRequestDataCount+500 //多请求2年的数据 确保股票剔除停牌日期以后可以对上 }, type:"post", dataType: "json", async:true, success: function (recvData) { self.RecvIndexHistroyData(recvData); self.Execute.RunNextJob(); }, error: function(request) { self.RecvError(request); } }); } else if (ChartData.IsMinutePeriod(this.Period, true)) //请求分钟数据 { if (this.NetworkFilter) { var obj= { Name:'JSSymbolData::GetIndexData', //类名:: Explain:'大盘数据', Period:self.Period, Request:{ Url:self.MinuteKLineApiUrl, Type:'POST' , Data: { field:["name","symbol","yclose","open","price","high","low","vol"], symbol: '000001.sh', start: -1 , count: self.MaxRequestDataCount+5 } }, Self:this, PreventDefault:false }; this.NetworkFilter(obj, function(data) { self.RecvIndexMinuteHistroyData(data); self.Execute.RunNextJob(); }); if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求 } JSNetwork.HttpRequest({ url: self.MinuteKLineApiUrl, data: { "field": ["name","symbol","yclose","open","price","high","low","vol"], "symbol": '000001.sh', "start": -1, "count": self.MaxRequestMinuteDayCount+5 }, type:"post", dataType: "json", async:true, success: function (data) { self.RecvIndexMinuteHistroyData(data); self.Execute.RunNextJob(); }, error: function(request) { self.RecvError(request); } }); } } this.RecvIndexHistroyData=function(data) { console.log('[JSSymbolData::RecvIndexHistroyData] recv data' , data); let hisData=this.JsonDataToHistoryData(data); this.IndexData=new ChartData(); this.IndexData.DataType=0; /*日线数据 */ this.IndexData.Data=hisData; var aryOverlayData=this.SourceData.GetOverlayData(this.IndexData.Data); //和主图数据拟合以后的数据 this.IndexData.Data=aryOverlayData; if (ChartData.IsDayPeriod(this.Period,false)) //周期数据 { let periodData=this.IndexData.GetPeriodData(this.Period); this.IndexData.Data=periodData; } } this.RecvIndexMinuteHistroyData=function(data) { console.log('[JSSymbolData::RecvIndexMinuteHistroyData] recv data' , data); let hisData=this.JsonDataToMinuteHistoryData(data); this.IndexData=new ChartData(); this.IndexData.DataType=1; /*分钟线数据 */ this.IndexData.Data=hisData; if (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; if (this.DataType===HQ_DATA_TYPE.MINUTE_ID || this.DataType===HQ_DATA_TYPE.MULTIDAY_MINUTE_ID) //走势图数据 { var apiUrl=g_JSComplierResource.CacheDomain+'/cache/analyze/increaseanalyze/'+symbol+'.json'; console.log('[JSSymbolData::GetIndexIncreaseData] minute Get url=' , apiUrl); $.ajax({ url: apiUrl, type:"get", dataType: "json", async:true, success: function (data) { self.RecvMinuteIncreaseData(data, {UpKey:upKey,DownKey:downKey}); self.Execute.RunNextJob(); }, error: function(request) { self.RecvError(request); } }); } else if (this.DataType===HQ_DATA_TYPE.KLINE_ID && this.Period===0) //K线图 日线 { console.log('[JSSymbolData::GetIndexIncreaseData] K day Get url=' , self.KLineApiUrl); $.ajax({ url: self.KLineApiUrl, data: { "symbol": symbol, "start": -1, "count": self.MaxRequestDataCount }, type:"post", dataType: "json", async:true, success: function (data) { self.RecvHistoryIncreaseData(data, {UpKey:upKey,DownKey:downKey}); self.Execute.RunNextJob(); }, error: function(request) { self.RecvError(request); } }); } } this.RecvHistoryIncreaseData=function(data,key) { console.log('[JSSymbolData::RecvHistoryIncreaseData] recv data' , data); var upData=[],downData=[]; for(var i in data.data) { var item=data.data[i]; let upItem=new SingleData(); let downItem=new SingleData(); upItem.Date=item[0]; upItem.Value=item[8]; upData[i]=upItem; downItem.Date=item[0]; downItem.Value=item[9]; downData[i]=downItem; } var aryFixedData=this.Data.GetFittingData(upData); var bindData=new ChartData(); bindData.Data=aryFixedData; bindData.Period=this.Period; //只支持日线 var data=bindData.GetValue(); this.ExtendData.set(key.UpKey,data); aryFixedData=this.Data.GetFittingData(downData); bindData=new ChartData(); bindData.Data=aryFixedData; bindData.Period=this.Period; //只支持日线 data=bindData.GetValue(); this.ExtendData.set(key.DownKey,data); } this.RecvMinuteIncreaseData=function(data,key) { console.log('[JSSymbolData::RecvMinuteIncreaseData] recv data' , data); if (!data.minute) return; var minuteData=data.minute; if (!minuteData.time || !minuteData.up || !minuteData.down) return; var upData=[],downData=[]; if (this.IsBeforeData) { for(var i=0, j=0;i0) //复权 { let rightData=this.Data.GetRightDate(this.Right); this.Data.Data=rightData; } if (ChartData.IsDayPeriod(this.Period,false)) //周期数据 { let periodData=this.Data.GetPeriodData(this.Period); this.Data.Data=periodData; } this.Data.Right=this.Right; this.Data.Period=this.Period; this.Name=data.name; } this.RecvMinuteHistroyData=function(data) { console.log('[JSSymbolData::RecvMinuteHistroyData] recv data' , data); let hisData=this.JsonDataToMinuteHistoryData(data); this.Data=new ChartData(); this.Data.DataType=1; /*分钟线数据 */ this.Data.Data=hisData; this.SourceData=new ChartData; this.SourceData.Data=hisData; if (ChartData.IsMinutePeriod(this.Period,false)) //周期数据 { let periodData=this.Data.GetPeriodData(this.Period); this.Data.Data=periodData; } this.Data.Period=this.Period; this.Name=data.name; } //最新的分钟数据走势图 this.RecvMinuteData=function(data) { console.log('[JSSymbolData::RecvMinuteData] recv data' , data); var aryMinuteData=this.JsonDataToMinuteData(data); this.Data=new ChartData(); this.Data.DataType=2; /*分钟走势图数据 */ this.Data.Data=aryMinuteData; this.Name=data.stock[0].name; } this.RecvMultiDayMinuteData=function(data) { var aryMinuteData=this.JsonDataToMultiDayMinuteData(data); this.Data=new ChartData(); this.Data.DataType=2; /*分钟走势图数据 */ this.Data.Data=aryMinuteData; this.Name=data.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': return this.Data.GetAmount(); } } this.GetCurrBarsCount=function() { let result=[]; if (!this.Data || !this.Data.Data || !this.Data.Data.length) return result; let lCount=this.Data.Data.length; 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;i0) //周期数据 { var periodData=bindData.GetPeriodSingleData(bindData.Period); bindData.Data=periodData; } let data=bindData.GetValue(); this.HKToSHSZData.set(allData[i].JobID,data); } } this.RecvMulitMinuteHKToSHSZData=function(data,jobID) //多日分时图北上资金 { if (!data.data || data.data.length<=0) return; var arySHSZData=[], arySHData=[], arySZData=[]; for(var i=0 ,j=0;idate) { ++i; continue; } else if (day.dateup) 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]; if (isNaN(item.Open) || item.Open<=0) continue; //停牌的数据剔除 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 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 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.Increase=jsData.increase; item.Risefall=jsData.risefall; item.AvPrice=jsData.avprice; aryMinuteData[i]=item; } return aryMinuteData; } //多日日线数据API 转化成array[]; this.JsonDataToMultiDayMinuteData=function(data) { var symbol=data.symbol; var upperSymbol=symbol.toUpperCase(); var isSHSZ=MARKET_SUFFIX_NAME.IsSHSZ(upperSymbol); var isFutures=MARKET_SUFFIX_NAME.IsChinaFutures(upperSymbol); var result=[]; for(var i in data.data) { var minuteData=[]; var dayData=data.data[i]; var date=dayData.date; var yClose=dayData.yclose; //前收盘 计算涨幅 var preClose=yClose; //前一个数据价格 var preAvPrice=null; //上一个均价 //var preAvPrice=data.stock[0].yclose; //前一个均价 for(var j in dayData.minute) { var jsData=dayData.minute[j]; if (jsData[2]) preClose=jsData[2]; //保存上一个收盘数据 var item=new MinuteData(); item.Close=jsData[2]; item.Open=jsData[1]; item.High=jsData[3]; item.Low=jsData[4]; item.Vol=jsData[5]/100; //原始单位股 item.Amount=jsData[6]; if (70) { item.AvPrice=jsData[7]; //均价 preAvPrice=jsData[7]; } item.DateTime=date.toString()+" "+jsData[0].toString(); item.Date=date item.Time=jsData[0]; if (!item.Close) //当前没有价格 使用上一个价格填充 { item.Close=preClose; item.Open=item.High=item.Low=item.Close; } if (!item.AvPrice && preAvPrice) item.AvPrice=preAvPrice; if (item.Close && yClose) item.Increase = (item.Close - yClose)/yClose*100; else item.Increase=null; if (j==0) //第1个数据 写死9:25 { if (isSHSZ) item.DateTime=date.toString()+" 0925"; item.IsFristData=true; } //价格是0的 都用空 if (item.Open<=0) item.Open=null; if (item.Close<=0) item.Close=null; if (item.AvPrice<=0) item.AvPrice=null; if (item.High<=0) item.High=null; if (item.Low<=0) item.Low=null; if (item.AvPrice<=0) item.AvPrice=null; minuteData[j]=item; } var newData=new ChartData(); newData.Data=minuteData; newData.YClose=yClose; newData.Close=dayData.close; newData.Date=date; result.push(newData); } var minuteData=[]; for(var i=result.length-1; i>=0;--i) { var item=result[i]; for(var j in item.Data) { minuteData.push(item.Data[j]); } } return minuteData; } //CODELIKE 模糊股票代码 this.CODELIKE=function(value) { if (this.Symbol && 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.GetIndustry=function() { var key=JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_GROUP_DATA.toString()+'-Group-'+this.Symbol; if (!this.ExtendData.has(key)) return ''; var group=this.ExtendData.get(key); if (!group.Industry || group.Industry.length<=0) return ''; var result=''; for(var i in group.Industry) { var item=group.Industry[i]; if (result.length>0) result+=' '; result+=item.Name; } return result; } this.GetRegion=function() { var key=JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_GROUP_DATA.toString()+'-Group-'+this.Symbol; if (!this.ExtendData.has(key)) return ''; var group=this.ExtendData.get(key); if (!group.Region || group.Region.length<=0) return ''; var result=''; for(var i in group.Region) { var item=group.Region[i]; if (result.length>0) result+=' '; result+=item.Name; } return result; } this.GetConcept=function() { var key=JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_GROUP_DATA.toString()+'-Group-'+this.Symbol; if (!this.ExtendData.has(key)) return ''; var group=this.ExtendData.get(key); if (!group.Concept || group.Concept.length<=0) return ''; var result=''; for(var i in group.Concept) { var item=group.Concept[i]; if (result.length>0) result+=' '; result+=item.Name; } 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; } 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 index=null; for(let i in this.Data.Data) //查找日期对应的索引 { if (this.Data.Data[i].Date==date) { 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=2000 && quarter>=1 && quarter<=4) return { Year:year, Quarter:quarter }; return null; } }; function JSExecute(ast,option) { this.AST=ast; //语法树 this.ErrorHandler=new ErrorHandler(); this.VarTable=new Map(); //变量表 this.OutVarTable=[]; //输出变量 this.Arguments=[]; this.ErrorCallback; //执行错误回调 //脚本自动变量表, 只读 this.ConstVarTable=new Map([ //个股数据 ['CLOSE',null],['VOL',null],['OPEN',null],['HIGH',null],['LOW',null],['AMOUNT',null], ['C',null],['V',null],['O',null],['H',null],['L',null],['VOLR',null], //日期类 ['DATE',null],['YEAR',null],['MONTH',null],['PERIOD', null],['WEEK',null], //大盘数据 ['INDEXA',null],['INDEXC',null],['INDEXH',null],['INDEXL',null],['INDEXO',null],['INDEXV',null], ['INDEXADV',null],['INDEXDEC',null], ['CURRBARSCOUNT',null], //到最后交易日的周期数 ['ISLASTBAR',null], //判断是否为最后一个周期 ['CAPITAL',null], //流通股本(手) ['EXCHANGE',null], //换手率 ['SETCODE', null], //市场类型 ['CODE',null], //品种代码 ['STKNAME',null], //品种名称 ['HYBLOCK',null], //所属行业板块 ['DYBLOCK',null], //所属地域板块 ['GNBLOCK',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; this.IsSectionMode=false; if (option) { if (option.Callback) this.UpdateUICallback=option.Callback; if (option.CallbackParam) this.CallbackParam=option.CallbackParam; if (option.Arguments) this.Arguments=option.Arguments; if (option.IsSectionMode) this.IsSectionMode=option.IsSectionMode; } this.Execute=function() { console.log('[JSExecute::Execute] JobList', this.JobList); this.OutVarTable=[]; this.VarTable=new Map(); 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_GROUP_DATA: return this.SymbolData.GetGroupData(jobItem); //行业|概念|地区 case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_TOTAL_EQUITY_DATA: case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_CAPITAL_DATA: case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_FLOW_EQUITY_DATA: case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_PER_NETASSET_DATA: case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_PER_U_PROFIT_DATA: case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_PER_C_RESERVE_DATA: case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_PER_S_EARNING_DATA: case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_PER_S_EARNING2_DATA: case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_N_PROFIT_DATA: case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_FLOW_MARKETVALUE_DATA: case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARKETVALUE_DATA: case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_EXCHANGE_DATA: case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_AL_RATIO_DATA: case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_PROFIT_YOY_DATA: case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_DIVIDEND_YIELD_DATA: case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SHAREHOLDER_DATA: return this.SymbolData.GetFinanceData(jobItem.ID); case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_RELEASE_DATE_DATA: return this.SymbolData.GetCompanyReleaseDate(jobItem.ID); 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_HK_TO_SH_SZ: //北上总的 case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_HK_TO_SH: //北上上证 case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_HK_TO_SZ: //北上深证 return this.SymbolData.GetHKToSHSZData(jobItem.ID); case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_SF: return this.SymbolData.GetSectionFinanceData(jobItem); //财务截面报告数据 case JS_EXECUTE_JOB_ID.JOB_CUSTOM_VARIANT_DATA: return this.SymbolData.DownloadCustomVariantData(jobItem); case JS_EXECUTE_JOB_ID.JOB_CUSTOM_FUNCTION_DATA: return this.SymbolData.DownloadCustomFunctionData(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': return this.SymbolData.GetSymbolCacheData(name); case 'VOLR': return this.SymbolData.GetVolRateCacheData(node); //大盘数据 case 'INDEXA': case 'INDEXC': case 'INDEXH': 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 'CAPITAL': return this.SymbolData.GetFinanceCacheData(JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_CAPITAL_DATA); case 'EXCHANGE': return this.SymbolData.GetFinanceCacheData(JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_EXCHANGE_DATA); case 'SETCODE': return this.SymbolData.SETCODE(); case 'CODE': return this.SymbolData.GetSymbol(); case 'STKNAME': return this.SymbolData.GetName(); case 'HYBLOCK': return this.SymbolData.GetIndustry(); case 'DYBLOCK': return this.SymbolData.GetRegion(); case 'GNBLOCK': return this.SymbolData.GetConcept(); 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) { var item=g_JSComplierResource.CustomVariant.Data.get(name); if (!item || !item.Read) return []; var obj={ Name:name, Symbol:this.SymbolData.Symbol, KData: this.SymbolData.Data, Period:this.SymbolData.Period, Right:this.SymbolData.Right }; return item.Read(obj); } //读取变量 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.SingleDataToArrayData=function(value) { let count=this.SymbolData.Data.Data.length; let result=[]; for(let i=0;i': 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) console.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) console.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) console.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.ThrowDownloadSF=function(node,job,message) { let marker=node.Marker; let msg=message; return this.ErrorHandler.ThrowDownloadJob(marker.Index,marker.Line,marker.Column,msg,job); } this.ThrowError=function() { } } //对外导出类 function JSComplier() { } //词法分析 JSComplier.Tokenize=function(code) { console.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) { console.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= async function() es5不能执行 去掉异步 var asyncExecute= function() { try { console.log('[JSComplier.Execute]',code,option); console.log('[JSComplier.Execute] parser .....'); let parser=new JSParser(code); parser.Initialize(); let program=parser.ParseScript(); let ast=program; console.log('[JSComplier.Execute] parser finish.', ast); console.log('[JSComplier.Execute] execute .....'); let execute=new JSExecute(ast,option); execute.ErrorCallback=errorCallback; //执行错误回调 execute.JobList=parser.Node.GetDataJobList(); execute.JobList.push({ID:JS_EXECUTE_JOB_ID.JOB_RUN_SCRIPT}); let result=execute.Execute(); }catch(error) { console.log(error); if (errorCallback) errorCallback(error); } } asyncExecute(); console.log('[JSComplier.Execute] async execute.'); } JSComplier.SetDomain = function (domain, cacheDomain) //修改API地址 { if (domain) g_JSComplierResource.Domain = domain; if (cacheDomain) g_JSComplierResource.CacheDomain = cacheDomain; } JSComplier.AddIcon=function(obj) //添加一个obj={ID:, Text:, Color, Family: } { g_JSComplierResource.CustomDrawIcon.Data.set(obj.ID, obj); } JSComplier.AddFunction=function(obj) //添加函数 { if (!obj || !obj) return; var ID=obj.Name.toUpperCase(); g_JSComplierResource.CustomFunction.Data.set(ID, obj); } JSComplier.AddVariant=function(obj) { if (!obj || !obj) return; var ID=obj.Name.toUpperCase(); g_JSComplierResource.CustomVariant.Data.set(ID, obj); } var HQ_DATA_TYPE= { KLINE_ID:0, //K线 MINUTE_ID:2, //当日走势图 HISTORY_MINUTE_ID:3,//历史分钟走势图 MULTIDAY_MINUTE_ID:4,//多日走势图 }; //脚本指标 //name=指标名字 args=参数名字 参数值 function ScriptIndex(name,script,args,option) { this.newMethod=BaseIndex; //派生 this.newMethod(name); delete this.newMethod; this.Script=script; this.Arguments=[]; this.OutVar=[]; this.ID; //指标ID this.FloatPrecision=2; //小数位数 this.StringFormat; this.KLineType=null; //K线显示类型 this.InstructionType; //五彩K线, 交易指标 this.YSpecificMaxMin=null; //最大最小值 this.YSplitScale=null; //固定刻度 this.Condition=null; //限制条件 //指标上锁配置信息 this.IsLocked=false; //是否锁住指标 this.LockCallback=null; this.LockID=null; this.LockBG=null; //锁背景色 this.LockTextColor=null; this.LockText=null; this.LockFont=null; this.LockCount=20; this.LockMinWidth=null; if (option) { if (option.FloatPrecision>=0) this.FloatPrecision=option.FloatPrecision; if (option.StringFormat>0) this.StringFormat=option.StringFormat; if (option.ID) this.ID=option.ID; if (option.KLineType>=0 || option.KLineType===-1) this.KLineType=option.KLineType; if (option.InstructionType) this.InstructionType=option.InstructionType; if (option.YSpecificMaxMin) this.YSpecificMaxMin=option.YSpecificMaxMin; if (option.YSplitScale) this.YSplitScale=option.YSplitScale; if (option.Condition) this.Condition=option.Condition; } if (option && option.Lock) { if (option.Lock.IsLocked==true) this.IsLocked=true; //指标上锁 if (option.Lock.Callback) this.LockCallback=option.Lock.Callback; //锁回调 if (option.Lock.ID) this.LockID=option.Lock.ID; //锁ID if (option.Lock.BG) this.LockBG=option.Lock.BG; if (option.Lock.TextColor) this.LockTextColor=option.Lock.TextColor; if (option.Lock.Text) this.LockText=option.Lock.Text; if (option.Lock.Font) this.LockFont=option.Lock.Font; if (option.Lock.Count) this.LockCount=option.Lock.Count; if (option.Lock.MinWidth) this.LockMinWidth=option.Lock.MinWidth*GetDevicePixelRatio(); } if (args) this.Arguments=args; this.SetLock=function(lockData) { if (lockData.IsLocked==true) { this.IsLocked=true; //指标上锁 if (lockData.Callback) this.LockCallback=lockData.Callback; //锁回调 if (lockData.ID) this.LockID=lockData.ID; //锁ID if (lockData.BG) this.LockBG=lockData.BG; if (lockData.TextColor) this.LockTextColor=lockData.TextColor; if (lockData.Text) this.LockText=lockData.Text; if (lockData.Font) this.LockFont=lockData.Font; if (lockData.Count) this.LockCount=lockData.Count; if (lockData.MinWidth) this.LockMinWidth=lockData.MinWidth*GetDevicePixelRatio(); } else { //清空锁配置信息 this.IsLocked=false; //是否锁住指标 this.LockCallback=null; this.LockID=null; this.LockBG=null; //锁背景色 this.LockTextColor=null; this.LockText=null; this.LockFont=null; this.LockCount=20; } } this.ExecuteScript=function(hqChart,windowIndex,hisData) { this.OutVar=[]; let self = this; let param= { HQChart:hqChart, WindowIndex:windowIndex, HistoryData:hisData, Self:this }; //数据类型 let hqDataType=HQ_DATA_TYPE.KLINE_ID; //默认K线 if (hqChart.ClassName==='MinuteChartContainer' || hqChart.ClassName==='MinuteChartHScreenContainer') { if (hqChart.DayCount>1) hqDataType=HQ_DATA_TYPE.MULTIDAY_MINUTE_ID; //多日分钟 else hqDataType=HQ_DATA_TYPE.MINUTE_ID; //分钟数据 } else if (hqChart.ClassName==='HistoryMinuteChartContainer') { hqDataType=HQ_DATA_TYPE.HISTORY_MINUTE_ID; //历史分钟 } let option= { HQDataType:hqDataType, Symbol:hqChart.Symbol, Name:hqChart.Name, Data:hisData, SourceData:hqChart.SourceData, Callback:this.RecvResultData, CallbackParam:param, Async:true, MaxRequestDataCount:hqChart.MaxReqeustDataCount, MaxRequestMinuteDayCount:hqChart.MaxRequestMinuteDayCount, Arguments:this.Arguments, Condition:this.Condition, IsBeforeData:hqChart.IsBeforeData }; if (hqDataType===HQ_DATA_TYPE.HISTORY_MINUTE_ID) option.TrateDate=hqChart.TradeDate; if (hqDataType===HQ_DATA_TYPE.MULTIDAY_MINUTE_ID) option.DayCount=hqChart.DayCount; if (hqChart.NetworkFilter) option.NetworkFilter=hqChart.NetworkFilter; if (this.Condition && !this.IsMeetCondition(param,option)) { this.ShowConditionError(param); return; } let code=this.Script; let run=JSComplier.Execute(code,option,hqChart.ScriptErrorCallback); } //是否符合限制条件 this.IsMeetCondition=function(param,option) { console.log('[ScriptIndex::IsMeetCondition] ', this.Condition); if (this.Condition.Period) //周期是否满足 { if (!this.IsMeetPeriodCondition(param,option)) return false; } return true; } //周期是否满足条件 this.IsMeetPeriodCondition=function(param,option) { if (!this.Condition.Period) return true; for(var i in this.Condition.Period) { var item=this.Condition.Period[i]; switch(item) { case CONDITION_PERIOD.MINUTE_ID: if (option.HQDataType==HQ_DATA_TYPE.MINUTE_ID) return true; break; case CONDITION_PERIOD.MULTIDAY_MINUTE_ID: if (option.HQDataType==HQ_DATA_TYPE.MULTIDAY_MINUTE_ID) return true; break; case CONDITION_PERIOD.KLINE_DAY_ID: case CONDITION_PERIOD.KLINE_WEEK_ID: case CONDITION_PERIOD.KLINE_MONTH_ID: case CONDITION_PERIOD.KLINE_YEAR_ID: case CONDITION_PERIOD.KLINE_MINUTE_ID: case CONDITION_PERIOD.KLINE_5_MINUTE_ID: case CONDITION_PERIOD.KLINE_15_MINUTE_ID: case CONDITION_PERIOD.KLINE_30_MINUTE_ID: case CONDITION_PERIOD.KLINE_60_MINUTE_ID: if (param.HQChart.Period==item) return true; break; } } return false; } //显示指标不符合条件 this.ShowConditionError=function(param) { var hqChart=param.HQChart; var windowIndex=param.WindowIndex; hqChart.DeleteIndexPaint(windowIndex); if (windowIndex==0) hqChart.ShowKLine(true); var message='指标不支持当前品种或周期'; let line=new ChartLine(); line.Canvas=hqChart.Canvas; line.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder; line.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame; line.NotSupportMessage=message; hqChart.ChartPaint.push(line); hqChart.Draw(); } this.RecvResultData=function(outVar,param) { let hqChart=param.HQChart; let windowIndex=param.WindowIndex; let hisData=param.HistoryData; param.Self.OutVar=outVar; param.Self.BindData(hqChart,windowIndex,hisData); if (param.Self.IsLocked==false) //不上锁 { param.HQChart.Frame.SubFrame[windowIndex].Frame.SetLock(null); } else //上锁 { let lockData={ IsLocked:true,Callback:param.Self.LockCallback,IndexName:param.Self.Name ,ID:param.Self.LockID, BG:param.Self.LockBG,Text:param.Self.LockText,TextColor:param.Self.LockTextColor, Font:param.Self.LockFont, Count:param.Self.LockCount, MinWidth:param.Self.LockMinWidth }; param.HQChart.Frame.SubFrame[windowIndex].Frame.SetLock(lockData); } param.HQChart.UpdataDataoffset(); //更新数据偏移 param.HQChart.UpdateFrameMaxMin(); //调整坐标最大 最小值 param.HQChart.Draw(); if (hqChart.GetIndexEvent) { var event=hqChart.GetIndexEvent(); //指标计算完成回调 if (event) { var self=param.Self; var data={ OutVar:self.OutVar, WindowIndex: windowIndex, Name: self.Name, Arguments: self.Arguments, HistoryData: hisData, Stock: {Symbol:hqChart.Symbol,Name:hqChart.Name} }; event.Callback(event,data,self); } } } this.CreateLine=function(hqChart,windowIndex,varItem,id) { let line=new ChartLine(); line.Canvas=hqChart.Canvas; line.DrawType=1; line.Name=varItem.Name; line.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder; line.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame; if (varItem.Color) line.Color=this.GetColor(varItem.Color); else line.Color=this.GetDefaultColor(id); if (varItem.LineWidth) { let width=parseInt(varItem.LineWidth.replace("LINETHICK","")); if (!isNaN(width) && width>0) line.LineWidth=width; } if (varItem.IsDotLine) line.IsDotLine=true; //虚线 if (varItem.IsShow==false) line.IsShow=false; let titleIndex=windowIndex+1; line.Data.Data=varItem.Data; hqChart.TitlePaint[titleIndex].Data[id]=new DynamicTitleData(line.Data,varItem.Name,line.Color); hqChart.ChartPaint.push(line); } //创建柱子 this.CreateBar=function(hqChart,windowIndex,varItem,id) { let bar=new ChartStickLine(); bar.Canvas=hqChart.Canvas; if (varItem.Draw.Width>0) bar.LineWidth=varItem.Draw.Width; else bar.LineWidth=1; bar.Name=varItem.Name; bar.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder; bar.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame; if (varItem.Color) bar.Color=this.GetColor(varItem.Color); else bar.Color=this.GetDefaultColor(id); let titleIndex=windowIndex+1; bar.Data.Data=varItem.Draw.DrawData; bar.BarType=varItem.Draw.Type; //hqChart.TitlePaint[titleIndex].Data[id]=new DynamicTitleData(bar.Data,varItem.Name,bar.Color); hqChart.ChartPaint.push(bar); } //创建文本 this.CreateText=function(hqChart,windowIndex,varItem,id) { let chartText=new ChartSingleText(); chartText.Canvas=hqChart.Canvas; chartText.Name=varItem.Name; chartText.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder; chartText.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame; if (varItem.Color) chartText.Color=this.GetColor(varItem.Color); else chartText.Color=this.GetDefaultColor(id); let titleIndex=windowIndex+1; if (varItem.Draw.Position) chartText.Position=varItem.Draw.Position; //赋值坐标 if (varItem.Draw.DrawData) chartText.Data.Data=varItem.Draw.DrawData; chartText.Text=varItem.Draw.Text; if (varItem.Draw.Direction>0) chartText.Direction=varItem.Draw.Direction; if (varItem.Draw.YOffset>0) chartText.YOffset=varItem.Draw.YOffset; if (varItem.Draw.TextAlign) chartText.TextAlign=varItem.Draw.TextAlign; //hqChart.TitlePaint[titleIndex].Data[id]=new DynamicTitleData(bar.Data,varItem.Name,bar.Color); hqChart.ChartPaint.push(chartText); } //COLORSTICK this.CreateMACD=function(hqChart,windowIndex,varItem,id) { let chartMACD=new ChartMACD(); chartMACD.Canvas=hqChart.Canvas; chartMACD.Name=varItem.Name; chartMACD.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder; chartMACD.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame; let titleIndex=windowIndex+1; chartMACD.Data.Data=varItem.Data; hqChart.TitlePaint[titleIndex].Data[id]=new DynamicTitleData(chartMACD.Data,varItem.Name,this.GetDefaultColor(id)); hqChart.ChartPaint.push(chartMACD); } this.CreatePointDot=function(hqChart,windowIndex,varItem,id) { let pointDot=new ChartPointDot(); pointDot.Canvas=hqChart.Canvas; pointDot.Name=varItem.Name; pointDot.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder; pointDot.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame; if (varItem.Color) pointDot.Color=this.GetColor(varItem.Color); else pointDot.Color=this.GetDefaultColor(id); if (varItem.Radius) pointDot.Radius=varItem.Radius; if (varItem.LineWidth) { let width=parseInt(varItem.LineWidth.replace("LINETHICK","")); if (!isNaN(width) && width>0) pointDot.Radius=width; } let titleIndex=windowIndex+1; pointDot.Data.Data=varItem.Data; hqChart.TitlePaint[titleIndex].Data[id]=new DynamicTitleData(pointDot.Data,varItem.Name,pointDot.Color); hqChart.ChartPaint.push(pointDot); } this.CreateStick=function(hqChart,windowIndex,varItem,id) { let chart=new ChartStick(); chart.Canvas=hqChart.Canvas; chart.Name=varItem.Name; chart.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder; chart.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame; if (varItem.Color) chart.Color=this.GetColor(varItem.Color); else chart.Color=this.GetDefaultColor(id); if (varItem.LineWidth) { let width=parseInt(varItem.LineWidth.replace("LINETHICK","")); if (!isNaN(width) && width>0) chart.LineWidth=width; } let titleIndex=windowIndex+1; chart.Data.Data=varItem.Data; hqChart.TitlePaint[titleIndex].Data[id]=new DynamicTitleData(chart.Data,varItem.Name,chart.Color); hqChart.ChartPaint.push(chart); } this.CreateLineStick=function(hqChart,windowIndex,varItem,id) { let chart=new ChartLineStick(); chart.Canvas=hqChart.Canvas; chart.Name=varItem.Name; chart.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder; chart.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame; if (varItem.Color) chart.Color=this.GetColor(varItem.Color); else chart.Color=this.GetDefaultColor(id); if (varItem.LineWidth) { let width=parseInt(varItem.LineWidth.replace("LINETHICK","")); if (!isNaN(width) && width>0) chart.LineWidth=width; } let titleIndex=windowIndex+1; chart.Data.Data=varItem.Data; hqChart.TitlePaint[titleIndex].Data[id]=new DynamicTitleData(chart.Data,varItem.Name,chart.Color); hqChart.ChartPaint.push(chart); } this.CreateStraightLine=function(hqChart,windowIndex,varItem,id) { let line=new ChartLine(); line.DrawType=1; line.Canvas=hqChart.Canvas; line.Name=varItem.Name; line.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder; line.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame; if (varItem.Color) line.Color=this.GetColor(varItem.Color); else line.Color=this.GetDefaultColor(id); if (varItem.LineWidth) { let width=parseInt(varItem.LineWidth.replace("LINETHICK","")); if (!isNaN(width) && width>0) line.LineWidth=width; } let titleIndex=windowIndex+1; line.Data.Data=varItem.Draw.DrawData; //hqChart.TitlePaint[titleIndex].Data[id]=new DynamicTitleData(line.Data,varItem.Name,line.Color); hqChart.ChartPaint.push(line); } this.CreateVolStick=function(hqChart,windowIndex,varItem,id,hisData) { let chart=new ChartVolStick(); chart.Canvas=hqChart.Canvas; chart.Name=varItem.Name; chart.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder; chart.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame; chart.KLineDrawType=hqChart.KLineDrawType; //设置K线显示类型 if (varItem.Color) chart.Color=this.GetColor(varItem.Color); else chart.Color=this.GetDefaultColor(id); let titleIndex=windowIndex+1; chart.Data.Data=varItem.Data; chart.HistoryData=hisData; hqChart.TitlePaint[titleIndex].Data[id]=new DynamicTitleData(chart.Data,varItem.Name,chart.Color); hqChart.ChartPaint.push(chart); } this.CreateBand=function(hqChart,windowIndex,varItem,id) { let chart=new ChartBand(); chart.Canvas=hqChart.Canvas; chart.Name=varItem.Name; chart.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder; chart.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame; chart.FirstColor = varItem.Draw.Color[0]; chart.SecondColor = varItem.Draw.Color[1]; chart.Data.Data=varItem.Draw.DrawData; hqChart.ChartPaint.push(chart); } //创建K线图 this.CreateKLine=function(hqChart,windowIndex,varItem,id) { let chart=new ChartKLine(); chart.Canvas=hqChart.Canvas; chart.Name=varItem.Name; chart.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder; chart.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame; chart.Data.Data=varItem.Draw.DrawData; chart.IsShowMaxMinPrice=false; chart.IsShowKTooltip=false; if (varItem.Color) //如果设置了颜色,使用外面设置的颜色 chart.UnchagneColor=chart.DownColor=chart.UpColor=this.GetColor(varItem.Color); hqChart.ChartPaint.push(chart); } this.CreatePolyLine=function(hqChart,windowIndex,varItem,id) { let line=new ChartLine(); line.Canvas=hqChart.Canvas; line.Name=varItem.Name; line.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder; line.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame; if (varItem.Color) line.Color=this.GetColor(varItem.Color); else line.Color=this.GetDefaultColor(id); if (varItem.LineWidth) { let width=parseInt(varItem.LineWidth.replace("LINETHICK","")); if (!isNaN(width) && width>0) line.LineWidth=width; } let titleIndex=windowIndex+1; line.Data.Data=varItem.Draw.DrawData; hqChart.TitlePaint[titleIndex].Data[id]=new DynamicTitleData(line.Data,' ',line.Color); //给一个空的标题 hqChart.ChartPaint.push(line); } this.CreateBackgroud=function(hqChart,windowIndex,varItem,id) { let chart=new ChartBackground(); chart.Canvas=hqChart.Canvas; chart.Name=varItem.Name; chart.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder; chart.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame; if (varItem.Draw && varItem.Draw.DrawData) { var drawData=varItem.Draw.DrawData; chart.Color=drawData.Color; chart.ColorAngle=drawData.Angle; } hqChart.ChartPaint.push(chart); } this.CreateTextLine=function(hqChart,windowIndex,varItem,id) { let chart=new ChartTextLine(); chart.Canvas=hqChart.Canvas; chart.Name=varItem.Name; chart.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder; chart.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame; if (varItem.Draw && varItem.Draw.DrawData) { var drawData=varItem.Draw.DrawData; chart.Text=drawData.Text; chart.Line=drawData.Line; chart.Price=drawData.Price; } hqChart.ChartPaint.push(chart); } this.CreateNumberText=function(hqChart,windowIndex,varItem,id) { let chartText=new ChartSingleText(); chartText.Canvas=hqChart.Canvas; chartText.Name=varItem.Name; chartText.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder; chartText.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame; if (varItem.Color) chartText.Color=this.GetColor(varItem.Color); else chartText.Color=this.GetDefaultColor(id); let titleIndex=windowIndex+1; chartText.Data.Data=varItem.Draw.DrawData.Value; chartText.Text=varItem.Draw.DrawData.Text; //hqChart.TitlePaint[titleIndex].Data[id]=new DynamicTitleData(bar.Data,varItem.Name,bar.Color); hqChart.ChartPaint.push(chartText); } //创建图标 this.CreateIcon=function(hqChart,windowIndex,varItem,id) { let chartText=new ChartSingleText(); chartText.Canvas=hqChart.Canvas; chartText.TextAlign='center'; chartText.Name=varItem.Name; chartText.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder; chartText.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame; let titleIndex=windowIndex+1; chartText.Data.Data=varItem.Draw.DrawData; var icon=varItem.Draw.Icon; if (icon.IconFont==true) { chartText.IconFont={ Family:icon.Family, Text:icon.Symbol, Color:icon.Color }; } else { chartText.Text=icon.Symbol; if (varItem.Color) chartText.Color=this.GetColor(varItem.Color); else if (icon.Color) chartText.Color=icon.Color; else chartText.Color='rgb(0,0,0)'; } //hqChart.TitlePaint[titleIndex].Data[id]=new DynamicTitleData(bar.Data,varItem.Name,bar.Color); hqChart.ChartPaint.push(chartText); } //创建通道 this.CreateChannel=function(hqChart,windowIndex,varItem,id) { let chart=new ChartChannel(); chart.Canvas=hqChart.Canvas; chart.Name=varItem.Name; chart.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder; chart.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame; if(varItem.Draw.AreaColor) chart.AreaColor=varItem.Draw.AreaColor; else if (varItem.Color) chart.AreaColor=this.GetColor(varItem.Color); else chart.AreaColor=this.GetDefaultColor(id); if (varItem.Draw.Border.Color) chart.LineColor=varItem.Draw.Border.Color; else chart.LineColor=null; if (varItem.Draw.Border.Dotted) chart.LineDotted=varItem.Draw.Border.Dotted; if (varItem.Draw.Border.Width>0) chart.LineWidth=varItem.Draw.Border.Width; //let titleIndex=windowIndex+1; chart.Data.Data=varItem.Draw.DrawData; hqChart.ChartPaint.push(chart); } this.CreatePartLine=function(hqChart,windowIndex,varItem,i) { let chart=new ChartPartLine(); chart.Canvas=hqChart.Canvas; chart.Name=varItem.Name; chart.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder; chart.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame; chart.Data.Data=varItem.Draw.DrawData; hqChart.ChartPaint.push(chart); } this.CreateMultiLine=function(hqChart,windowIndex,varItem,i) { let chart=new ChartMultiLine(); chart.Canvas=hqChart.Canvas; chart.Name=varItem.Name; chart.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder; chart.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame; chart.Data=hqChart.ChartPaint[0].Data;//绑定K线 chart.Lines=varItem.Draw.DrawData; hqChart.ChartPaint.push(chart); } this.CreateMultiText=function(hqChart,windowIndex,varItem,i) { let chart=new ChartMultiText(); chart.Canvas=hqChart.Canvas; chart.Name=varItem.Name; chart.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder; chart.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame; chart.Data=hqChart.ChartPaint[0].Data;//绑定K线 chart.Texts=varItem.Draw.DrawData; hqChart.ChartPaint.push(chart); } this.CreateMultiSVGIcon=function(hqChart,windowIndex,varItem,i) { let chart=new ChartMultiSVGIcon(); chart.Canvas=hqChart.Canvas; chart.Name=varItem.Name; chart.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder; chart.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame; chart.Data=hqChart.ChartPaint[0].Data;//绑定K线 chart.Family=varItem.Draw.DrawData.Family; chart.Icon= varItem.Draw.DrawData.Icon; hqChart.ChartPaint.push(chart); } this.CreateRectangle=function(hqChart,windowIndex,varItem,i) { let chart=new ChartRectangle(); chart.Canvas=hqChart.Canvas; chart.Name=varItem.Name; chart.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder; chart.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame; chart.Color=[varItem.Draw.DrawData.Color]; chart.Rect=varItem.Draw.DrawData.Rect; if (varItem.Color) chart.BorderColor=this.GetColor(varItem.Color); hqChart.ChartPaint.push(chart); } //创建K线 this.CreateSelfKLine=function(hqChart,windowIndex,hisData) { let chart=new ChartKLine(); chart.Canvas=hqChart.Canvas; chart.Name="Self Kline" chart.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder; chart.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame; chart.Data=hisData chart.IsShowMaxMinPrice=false; chart.IsShowKTooltip=false; chart.DrawType=this.KLineType; hqChart.ChartPaint.push(chart); } this.BindInstructionData=function(hqChart,windowIndex,hisData) //绑定指示指标 { if (this.OutVar==null || this.OutVar.length<0) return; if (this.InstructionType==2) //五彩K线 { let varItem=this.OutVar[this.OutVar.length-1]; //取最后一组数据作为指示数据 hqChart.SetInstructionData(this.InstructionType, {Data:varItem.Data, Name:this.Name, ID:this.ID }); //设置指示数据 return true; } else if (this.InstructionType==1) //交易系统 { var buyData, sellData; for(var i in this.OutVar) { let item=this.OutVar[i]; if (item.Name=='ENTERLONG') buyData=item.Data; else if (item.Name=='EXITLONG') sellData=item.Data; } hqChart.SetInstructionData(this.InstructionType, {Buy:buyData, Sell:sellData, Name:this.Name, ID:this.ID}); //设置指示数据 return true; } } this.BindData=function(hqChart,windowIndex,hisData) { if (windowIndex==0 && this.InstructionType) { this.BindInstructionData(hqChart,windowIndex,hisData); return; } //清空主指标图形 hqChart.DeleteIndexPaint(windowIndex); if (windowIndex==0) hqChart.ShowKLine(true); if (this.OutVar==null || this.OutVar.length<0) return; //叠加一个K线背景 if (this.KLineType!=null) { if (this.KLineType===0 || this.KLineType===1 || this.KLineType===2) this.CreateSelfKLine(hqChart,windowIndex,hisData); else if (this.KLineType===-1 && windowIndex==0) hqChart.ShowKLine(false); } if (windowIndex>=1 && hqChart.Frame) { hqChart.Frame.SubFrame[windowIndex].Frame.YSplitOperator.FloatPrecision=this.FloatPrecision; if (this.YSpecificMaxMin) hqChart.Frame.SubFrame[windowIndex].Frame.YSpecificMaxMin=this.YSpecificMaxMin; //最大最小值 if (this.YSplitScale) hqChart.Frame.SubFrame[windowIndex].Frame.YSplitScale=this.YSplitScale; //固定刻度 } /* if (this.Name=='MA') //测试多线段 { var point1={Point:[{Index:300, Value:15.5}, {Index:301, Value:14.2} , {Index:304, Value:14.05}], Color:'rgb(244,55,50)'}; var point2={Point:[{Index:307, Value:14.5}, {Index:308, Value:14.2} , {Index:309, Value:14.15}], Color:'rgb(0,55,50)'}; var testData={ Name:'MULTI_LINE', Type:1,Draw:{ DrawType:'MULTI_LINE', DrawData:[point1,point2] } }; this.OutVar.push(testData); } */ for(let i in this.OutVar) { let item=this.OutVar[i]; if (item.IsExData===true) continue; //扩展数据不显示图形 if (item.Type==0) { this.CreateLine(hqChart,windowIndex,item,i); } else if (item.Type==1) { switch(item.Draw.DrawType) { case 'STICKLINE': this.CreateBar(hqChart,windowIndex,item,i); break; case 'DRAWTEXT': case 'SUPERDRAWTEXT': case 'DRAWTEXT_FIX': this.CreateText(hqChart,windowIndex,item,i); break; case 'DRAWLINE': this.CreateStraightLine(hqChart,windowIndex,item,i); break; case 'DRAWBAND': this.CreateBand(hqChart,windowIndex,item,i); break; case 'DRAWKLINE': this.CreateKLine(hqChart,windowIndex,item,i); break; case 'DRAWKLINE_IF': this.CreateKLine(hqChart,windowIndex,item,i); break; case 'POLYLINE': this.CreatePolyLine(hqChart,windowIndex,item,i); break; case 'DRAWGBK': this.CreateBackgroud(hqChart,windowIndex,item,i); break; case 'DRAWTEXT_LINE': this.CreateTextLine(hqChart,windowIndex,item,i); break; case 'DRAWNUMBER': this.CreateNumberText(hqChart,windowIndex,item,i); break; case 'DRAWICON': this.CreateIcon(hqChart,windowIndex,item,i); break; case 'DRAWCHANNEL': this.CreateChannel(hqChart,windowIndex,item,i); break; case 'PARTLINE': this.CreatePartLine(hqChart,windowIndex,item,i); break; case 'DRAWRECTREL': this.CreateRectangle(hqChart,windowIndex,item,i); break; case 'MULTI_LINE': this.CreateMultiLine(hqChart,windowIndex,item,i); break; case 'MULTI_TEXT': this.CreateMultiText(hqChart,windowIndex,item,i); break; case 'MULTI_SVGICON': this.CreateMultiSVGIcon(hqChart,windowIndex,item,i); break; } } else if (item.Type==2) { this.CreateMACD(hqChart,windowIndex,item,i); } else if (item.Type==3) { this.CreatePointDot(hqChart,windowIndex,item,i); } else if (item.Type==4) { this.CreateLineStick(hqChart,windowIndex,item,i); } else if (item.Type==5) { this.CreateStick(hqChart,windowIndex,item,i); } else if (item.Type==6) { this.CreateVolStick(hqChart,windowIndex,item,i,hisData); } var titlePaint=hqChart.TitlePaint[windowIndex+1]; if (titlePaint && titlePaint.Data && i0) titlePaint.Data[i].StringFormat=this.StringFormat; if (this.FloatPrecision>=0) titlePaint.Data[i].FloatPrecision=this.FloatPrecision; } } let titleIndex=windowIndex+1; hqChart.TitlePaint[titleIndex].Title=this.Name; let indexParam=''; for(let i in this.Arguments) { let item=this.Arguments[i]; if (indexParam.length>0) indexParam+=','; indexParam+=item.Value.toString(); } if (indexParam.length>0) hqChart.TitlePaint[titleIndex].Title=this.Name+'('+indexParam+')'; return true; } //给一个默认的颜色 this.GetDefaultColor=function(id) { let COLOR_ARRAY= [ "rgb(255,174,0)", "rgb(25,199,255)", "rgb(175,95,162)", "rgb(236,105,65)", "rgb(68,114,196)", "rgb(229,0,79)", "rgb(0,128,255)", "rgb(252,96,154)", "rgb(42,230,215)", "rgb(24,71,178)", ]; let number=parseInt(id); return COLOR_ARRAY[number%(COLOR_ARRAY.length-1)]; } //获取颜色 this.GetColor=function(colorName) { let COLOR_MAP=new Map([ ['COLORBLACK','rgb(0,0,0)'], ['COLORBLUE','rgb(18,95,216)'], ['COLORGREEN','rgb(25,158,0)'], ['COLORCYAN','rgb(0,255,198)'], ['COLORRED','rgb(238,21,21)'], ['COLORMAGENTA','rgb(255,0,222)'], ['COLORBROWN','rgb(149,94,15)'], ['COLORLIGRAY','rgb(218,218,218)'], //画淡灰色 ['COLORGRAY','rgb(133,133,133)'], //画深灰色 ['COLORLIBLUE','rgb(94,204,255)'], //淡蓝色 ['COLORLIGREEN','rgb(183,255,190)'], //淡绿色 ['COLORLICYAN','rgb(154,255,242)'], //淡青色 ['COLORLIRED','rgb(255,172,172)'], //淡红色 ['COLORLIMAGENTA','rgb(255,145,241)'], //淡洋红色 ['COLORWHITE','rgb(255,255,255)'], //白色 ['COLORYELLOW','rgb(255,198,0)'] ]); if (COLOR_MAP.has(colorName)) return COLOR_MAP.get(colorName); //COLOR 自定义色 //格式为COLOR+“RRGGBB”:RR、GG、BB表示红色、绿色和蓝色的分量,每种颜色的取值范围是00-FF,采用了16进制。 //例如:MA5:MA(CLOSE,5),COLOR00FFFF 表示纯红色与纯绿色的混合色:COLOR808000表示淡蓝色和淡绿色的混合色。 if (colorName.indexOf('COLOR')==0) return '#'+colorName.substr(5); return 'rgb(30,144,255)'; } } function OverlayScriptIndex(name,script,args,option) { this.newMethod=ScriptIndex; //派生 this.newMethod(name,script,args,option); delete this.newMethod; //叠加指标 this.OverlayIndex=null; // { IsOverlay:true, Identify:overlayFrame.Identify, WindowIndex:windowIndex, Frame:overlayFrame } this.BindData=function(hqChart,windowIndex,hisData) { if (!this.OverlayIndex || this.OverlayIndex.IsOverlay!=true) return; this.OverlayIndex.Frame.ChartPaint=[]; if (this.OutVar==null || this.OutVar.length<0) return; /*叠加一个K线背景 if (this.KLineType!=null) { if (this.KLineType===0 || this.KLineType===1 || this.KLineType===2) this.CreateSelfKLine(hqChart,windowIndex,hisData); else if (this.KLineType===-1 && windowIndex==0) hqChart.ShowKLine(false); } if (windowIndex>=1 && hqChart.Frame) { hqChart.Frame.SubFrame[windowIndex].Frame.YSplitOperator.FloatPrecision=this.FloatPrecision; if (this.YSpecificMaxMin) hqChart.Frame.SubFrame[windowIndex].Frame.YSpecificMaxMin=this.YSpecificMaxMin; //最大最小值 if (this.YSplitScale) hqChart.Frame.SubFrame[windowIndex].Frame.YSplitScale=this.YSplitScale; //固定刻度 } */ //指标名字 var titleInfo={ Data:[], Title:this.Name }; let indexParam=''; for(var i in this.Arguments) { let item=this.Arguments[i]; if (indexParam.length>0) indexParam+=','; indexParam+=item.Value.toString(); } if (indexParam.length>0) titleInfo.Title=this.Name+'('+indexParam+')'; var titleIndex=windowIndex+1; var titlePaint=hqChart.TitlePaint[titleIndex]; titlePaint.OverlayIndex.set(this.OverlayIndex.Identify,titleInfo); this.OverlayIndex.Frame.Frame.Title=titleInfo.Title; //给子框架设置标题 for(var i in this.OutVar) { let item=this.OutVar[i]; if (item.IsExData===true) continue; //扩展数据不显示图形 if (item.Type==0) { this.CreateLine(hqChart,windowIndex,item,i); } else if (item.Type==1) { switch(item.Draw.DrawType) { case 'STICKLINE': this.CreateBar(hqChart,windowIndex,item,i); break; case 'DRAWTEXT': case 'SUPERDRAWTEXT': case 'DRAWTEXT_FIX': this.CreateText(hqChart,windowIndex,item,i); break; case 'DRAWLINE': this.CreateStraightLine(hqChart,windowIndex,item,i); break; case 'DRAWBAND': this.CreateBand(hqChart,windowIndex,item,i); break; case 'DRAWKLINE': this.CreateKLine(hqChart,windowIndex,item,i); break; case 'DRAWKLINE_IF': this.CreateKLine(hqChart,windowIndex,item,i); break; case 'POLYLINE': this.CreatePolyLine(hqChart,windowIndex,item,i); break; case 'DRAWNUMBER': this.CreateNumberText(hqChart,windowIndex,item,i); break; case 'DRAWICON': this.CreateIcon(hqChart,windowIndex,item,i); break; case 'DRAWCHANNEL': this.CreateChannel(hqChart,windowIndex,item,i); break; } } else if (item.Type==2) { this.CreateMACD(hqChart,windowIndex,item,i); } else if (item.Type==3) { this.CreatePointDot(hqChart,windowIndex,item,i); } else if (item.Type==4) { this.CreateLineStick(hqChart,windowIndex,item,i); } else if (item.Type==5) { this.CreateStick(hqChart,windowIndex,item,i); } else if (item.Type==6) { this.CreateVolStick(hqChart,windowIndex,item,i,hisData); } } /* hqChart.TitlePaint[titleIndex].Title=this.Name; let indexParam=''; for(let i in this.Arguments) { let item=this.Arguments[i]; if (indexParam.length>0) indexParam+=','; indexParam+=item.Value.toString(); } if (indexParam.length>0) hqChart.TitlePaint[titleIndex].Title=this.Name+'('+indexParam+')'; */ return true; } //指标执行完成 this.RecvResultData=function(outVar,param) { let hqChart=param.HQChart; let windowIndex=param.WindowIndex; let hisData=param.HistoryData; param.Self.OutVar=outVar; param.Self.BindData(hqChart,windowIndex,hisData); param.HQChart.UpdataDataoffset(); //更新数据偏移 param.HQChart.UpdateFrameMaxMin(); //调整坐标最大 最小值 param.HQChart.Draw(); var event=hqChart.GetOverlayIndexEvent(); //指标计算完成回调 if (event) { var self=param.Self; var data={ OutVar:self.OutVar, WindowIndex: windowIndex, Name: self.Name, Arguments: self.Arguments, HistoryData: hisData, Identify:self.OverlayIndex.Identify, Stock: {Symbol:hqChart.Symbol,Name:hqChart.Name} }; event.Callback(event,data,self); } } ////////////////////////////////////////////////////////////////////////////////////// // 图形创建 ///////////////////////////////////////////////////////////////////////////////////// this.CreateLine=function(hqChart,windowIndex,varItem,id) { var overlayIndex=this.OverlayIndex; var frame=overlayIndex.Frame; let chart=new ChartLine(); chart.Canvas=hqChart.Canvas; chart.DrawType=1; chart.Name=varItem.Name; chart.ChartBorder=frame.Frame.ChartBorder; chart.ChartFrame=frame.Frame; chart.Identify=overlayIndex.Identify; if (varItem.Color) chart.Color=this.GetColor(varItem.Color); else chart.Color=this.GetDefaultColor(id); if (varItem.LineWidth) { let width=parseInt(varItem.LineWidth.replace("LINETHICK","")); if (!isNaN(width) && width>0) line.LineWidth=width; } if (varItem.IsShow==false) line.IsShow=false; let titleIndex=windowIndex+1; chart.Data.Data=varItem.Data; var titlePaint=hqChart.TitlePaint[titleIndex]; titlePaint.OverlayIndex.get(overlayIndex.Identify).Data[id]=new DynamicTitleData(chart.Data,varItem.Name,chart.Color); frame.ChartPaint.push(chart); } //创建柱子 this.CreateBar=function(hqChart,windowIndex,varItem,id) { var overlayIndex=this.OverlayIndex; var frame=overlayIndex.Frame; let chart=new ChartStickLine(); chart.Canvas=hqChart.Canvas; if (varItem.Draw.Width>0) chart.LineWidth=varItem.Draw.Width; else chart.LineWidth=1; chart.Name=varItem.Name; chart.ChartBorder=frame.Frame.ChartBorder; chart.ChartFrame=frame.Frame; chart.Identify=overlayIndex.Identify; if (varItem.Color) chart.Color=this.GetColor(varItem.Color); else chart.Color=this.GetDefaultColor(id); let titleIndex=windowIndex+1; chart.Data.Data=varItem.Draw.DrawData; //hqChart.TitlePaint[titleIndex].Data[id]=new DynamicTitleData(bar.Data,varItem.Name,bar.Color); frame.ChartPaint.push(chart); } //创建文本 this.CreateText=function(hqChart,windowIndex,varItem,id) { var overlayIndex=this.OverlayIndex; var frame=overlayIndex.Frame; let chart=new ChartSingleText(); chart.Canvas=hqChart.Canvas; chart.Name=varItem.Name; chart.ChartBorder=frame.Frame.ChartBorder; chart.ChartFrame=frame.Frame; chart.Identify=overlayIndex.Identify; if (varItem.Color) chart.Color=this.GetColor(varItem.Color); else chart.Color=this.GetDefaultColor(id); let titleIndex=windowIndex+1; if (varItem.Draw.Position) chart.Position=varItem.Draw.Position; //赋值坐标 if (varItem.Draw.DrawData) chart.Data.Data=varItem.Draw.DrawData; chart.Text=varItem.Draw.Text; if (varItem.Draw.Direction>0) chart.Direction=varItem.Draw.Direction; if (varItem.Draw.YOffset>0) chart.YOffset=varItem.Draw.YOffset; if (varItem.Draw.TextAlign) chart.TextAlign=varItem.Draw.TextAlign; //hqChart.TitlePaint[titleIndex].Data[id]=new DynamicTitleData(bar.Data,varItem.Name,bar.Color); frame.ChartPaint.push(chart); } //COLORSTICK this.CreateMACD=function(hqChart,windowIndex,varItem,id) { var overlayIndex=this.OverlayIndex; var frame=overlayIndex.Frame; let chart=new ChartMACD(); chart.Canvas=hqChart.Canvas; chart.Name=varItem.Name; chart.ChartBorder=frame.Frame.ChartBorder; chart.ChartFrame=frame.Frame; chart.Identify=overlayIndex.Identify; let titleIndex=windowIndex+1; chart.Data.Data=varItem.Data; var titlePaint=hqChart.TitlePaint[titleIndex]; titlePaint.OverlayIndex.get(overlayIndex.Identify).Data[id]=new DynamicTitleData(chart.Data,varItem.Name,this.GetDefaultColor(id)); frame.ChartPaint.push(chart); } this.CreatePointDot=function(hqChart,windowIndex,varItem,id) { var overlayIndex=this.OverlayIndex; var frame=overlayIndex.Frame; let chart=new ChartPointDot(); chart.Canvas=hqChart.Canvas; chart.Name=varItem.Name; chart.ChartBorder=frame.Frame.ChartBorder; chart.ChartFrame=frame.Frame; chart.Identify=overlayIndex.Identify; if (varItem.Color) chart.Color=this.GetColor(varItem.Color); else chart.Color=this.GetDefaultColor(id); if (varItem.Radius) chart.Radius=varItem.Radius; if (varItem.LineWidth) { let width=parseInt(varItem.LineWidth.replace("LINETHICK","")); if (!isNaN(width) && width>0) chart.Radius=width; } let titleIndex=windowIndex+1; chart.Data.Data=varItem.Data; var titlePaint=hqChart.TitlePaint[titleIndex]; titlePaint.OverlayIndex.get(overlayIndex.Identify).Data[id]=new DynamicTitleData(chart.Data,varItem.Name,chart.Color); frame.ChartPaint.push(chart); } this.CreateStick=function(hqChart,windowIndex,varItem,id) { var overlayIndex=this.OverlayIndex; var frame=overlayIndex.Frame; let chart=new ChartStick(); chart.Canvas=hqChart.Canvas; chart.Name=varItem.Name; chart.ChartBorder=frame.Frame.ChartBorder; chart.ChartFrame=frame.Frame; chart.Identify=overlayIndex.Identify; if (varItem.Color) chart.Color=this.GetColor(varItem.Color); else chart.Color=this.GetDefaultColor(id); if (varItem.LineWidth) { let width=parseInt(varItem.LineWidth.replace("LINETHICK","")); if (!isNaN(width) && width>0) chart.LineWidth=width; } let titleIndex=windowIndex+1; chart.Data.Data=varItem.Data; var titlePaint=hqChart.TitlePaint[titleIndex]; titlePaint.OverlayIndex.get(overlayIndex.Identify).Data[id]=new DynamicTitleData(chart.Data,varItem.Name,chart.Color); frame.ChartPaint.push(chart); } this.CreateLineStick=function(hqChart,windowIndex,varItem,id) { var overlayIndex=this.OverlayIndex; var frame=overlayIndex.Frame; let chart=new ChartLineStick(); chart.Canvas=hqChart.Canvas; chart.Name=varItem.Name; chart.ChartBorder=frame.Frame.ChartBorder; chart.ChartFrame=frame.Frame; chart.Identify=overlayIndex.Identify; if (varItem.Color) chart.Color=this.GetColor(varItem.Color); else chart.Color=this.GetDefaultColor(id); if (varItem.LineWidth) { let width=parseInt(varItem.LineWidth.replace("LINETHICK","")); if (!isNaN(width) && width>0) chart.LineWidth=width; } let titleIndex=windowIndex+1; chart.Data.Data=varItem.Data; var titlePaint=hqChart.TitlePaint[titleIndex]; titlePaint.OverlayIndex.get(overlayIndex.Identify).Data[id]=new DynamicTitleData(chart.Data,varItem.Name,chart.Color); frame.ChartPaint.push(chart); } this.CreateStraightLine=function(hqChart,windowIndex,varItem,id) { var overlayIndex=this.OverlayIndex; var frame=overlayIndex.Frame; let chart=new ChartLine(); chart.DrawType=1; chart.Canvas=hqChart.Canvas; chart.Name=varItem.Name; chart.ChartBorder=frame.Frame.ChartBorder; chart.ChartFrame=frame.Frame; chart.Identify=overlayIndex.Identify; if (varItem.Color) chart.Color=this.GetColor(varItem.Color); else chart.Color=this.GetDefaultColor(id); if (varItem.LineWidth) { let width=parseInt(varItem.LineWidth.replace("LINETHICK","")); if (!isNaN(width) && width>0) chart.LineWidth=width; } let titleIndex=windowIndex+1; chart.Data.Data=varItem.Draw.DrawData; //hqChart.TitlePaint[titleIndex].Data[id]=new DynamicTitleData(line.Data,varItem.Name,line.Color); frame.ChartPaint.push(chart); } this.CreateVolStick=function(hqChart,windowIndex,varItem,id,hisData) { var overlayIndex=this.OverlayIndex; var frame=overlayIndex.Frame; let chart=new ChartVolStick(); chart.Canvas=hqChart.Canvas; chart.Name=varItem.Name; chart.ChartBorder=frame.Frame.ChartBorder; chart.ChartFrame=frame.Frame; chart.Identify=overlayIndex.Identify; chart.KLineDrawType=hqChart.KLineDrawType; //设置K线显示类型 if (varItem.Color) chart.Color=this.GetColor(varItem.Color); else chart.Color=this.GetDefaultColor(id); let titleIndex=windowIndex+1; chart.Data.Data=varItem.Data; chart.HistoryData=hisData; var titlePaint=hqChart.TitlePaint[titleIndex]; titlePaint.OverlayIndex.get(overlayIndex.Identify).Data[id]=new DynamicTitleData(chart.Data,varItem.Name,chart.Color); frame.ChartPaint.push(chart); } this.CreateBand=function(hqChart,windowIndex,varItem,id) { var overlayIndex=this.OverlayIndex; var frame=overlayIndex.Frame; let chart=new ChartBand(); chart.Canvas=hqChart.Canvas; chart.Name=varItem.Name; chart.ChartBorder=frame.Frame.ChartBorder; chart.ChartFrame=frame.Frame; chart.Identify=overlayIndex.Identify; chart.FirstColor = varItem.Draw.Color[0]; chart.SecondColor = varItem.Draw.Color[1]; chart.Data.Data=varItem.Draw.DrawData; frame.ChartPaint.push(chart); } //创建K线图 this.CreateKLine=function(hqChart,windowIndex,varItem,id) { var overlayIndex=this.OverlayIndex; var frame=overlayIndex.Frame; let chart=new ChartKLine(); chart.Canvas=hqChart.Canvas; chart.Name=varItem.Name; chart.ChartBorder=frame.Frame.ChartBorder; chart.ChartFrame=frame.Frame; chart.Identify=overlayIndex.Identify; chart.Data.Data=varItem.Draw.DrawData; chart.IsShowMaxMinPrice=false; chart.IsShowKTooltip=false; if (varItem.Color) //如果设置了颜色,使用外面设置的颜色 chart.UnchagneColor=chart.DownColor=chart.UpColor=this.GetColor(varItem.Color); frame.ChartPaint.push(chart); } this.CreatePolyLine=function(hqChart,windowIndex,varItem,id) { var overlayIndex=this.OverlayIndex; var frame=overlayIndex.Frame; let chart=new ChartLine(); chart.Canvas=hqChart.Canvas; chart.Name=varItem.Name; chart.ChartBorder=frame.Frame.ChartBorder; chart.ChartFrame=frame.Frame; chart.Identify=overlayIndex.Identify; if (varItem.Color) chart.Color=this.GetColor(varItem.Color); else chart.Color=this.GetDefaultColor(id); if (varItem.LineWidth) { let width=parseInt(varItem.LineWidth.replace("LINETHICK","")); if (!isNaN(width) && width>0) chart.LineWidth=width; } let titleIndex=windowIndex+1; chart.Data.Data=varItem.Draw.DrawData; var titlePaint=hqChart.TitlePaint[titleIndex]; titlePaint.OverlayIndex.get(overlayIndex.Identify).Data[id]=new DynamicTitleData(line.Data,' ',line.Color); //给一个空的标题 frame.ChartPaint.push(chart); } this.CreateNumberText=function(hqChart,windowIndex,varItem,id) { var overlayIndex=this.OverlayIndex; var frame=overlayIndex.Frame; let chart=new ChartSingleText(); chart.Canvas=hqChart.Canvas; chart.Name=varItem.Name; chart.ChartBorder=frame.Frame.ChartBorder; chart.ChartFrame=frame.Frame; chart.Identify=overlayIndex.Identify; if (varItem.Color) chart.Color=this.GetColor(varItem.Color); else chart.Color=this.GetDefaultColor(id); let titleIndex=windowIndex+1; chart.Data.Data=varItem.Draw.DrawData.Value; chart.Text=varItem.Draw.DrawData.Text; //hqChart.TitlePaint[titleIndex].Data[id]=new DynamicTitleData(bar.Data,varItem.Name,bar.Color); frame.ChartPaint.push(chart); } //创建图标 this.CreateIcon=function(hqChart,windowIndex,varItem,id) { var overlayIndex=this.OverlayIndex; var frame=overlayIndex.Frame; let chart=new ChartSingleText(); chart.Canvas=hqChart.Canvas; chart.TextAlign='center'; chart.Name=varItem.Name; chart.ChartBorder=frame.Frame.ChartBorder; chart.ChartFrame=frame.Frame; chart.Identify=overlayIndex.Identify; let titleIndex=windowIndex+1; chart.Data.Data=varItem.Draw.DrawData; var icon=varItem.Draw.Icon; if (icon.IconFont==true) { chart.IconFont={ Family:icon.Family, Text:icon.Symbol, Color:icon.Color }; } else { chart.Text=icon.Symbol; if (varItem.Color) chart.Color=this.GetColor(varItem.Color); else if (icon.Color) chart.Color=icon.Color; else chart.Color='rgb(0,0,0)'; } //hqChart.TitlePaint[titleIndex].Data[id]=new DynamicTitleData(bar.Data,varItem.Name,bar.Color); frame.ChartPaint.push(chart); } //创建通道 this.CreateChannel=function(hqChart,windowIndex,varItem,id) { var overlayIndex=this.OverlayIndex; var frame=overlayIndex.Frame; let chart=new ChartChannel(); chart.Canvas=hqChart.Canvas; chart.Name=varItem.Name; chart.ChartBorder=frame.Frame.ChartBorder; chart.ChartFrame=frame.Frame; chart.Identify=overlayIndex.Identify; if(varItem.Draw.AreaColor) chart.AreaColor=varItem.Draw.AreaColor; else if (varItem.Color) chart.AreaColor=this.GetColor(varItem.Color); else chart.AreaColor=this.GetDefaultColor(id); if (varItem.Draw.Border.Color) chart.LineColor=varItem.Draw.Border.Color; else chart.LineColor=null; if (varItem.Draw.Border.Dotted) chart.LineDotted=varItem.Draw.Border.Dotted; if (varItem.Draw.Border.Width>0) chart.LineWidth=varItem.Draw.Border.Width; //let titleIndex=windowIndex+1; chart.Data.Data=varItem.Draw.DrawData; frame.ChartPaint.push(chart); } // this.CreatePartLine=function(hqChart,windowIndex,varItem,i) { var overlayIndex=this.OverlayIndex; var frame=overlayIndex.Frame; let chart=new ChartPartLine(); chart.Canvas=hqChart.Canvas; chart.Name=varItem.Name; chart.ChartBorder=frame.Frame.ChartBorder; chart.ChartFrame=frame.Frame; chart.Identify=overlayIndex.Identify; chart.Data.Data=varItem.Draw.DrawData; frame.ChartPaint.push(chart); } //创建K线 this.CreateSelfKLine=function(hqChart,windowIndex,hisData) { var overlayIndex=this.OverlayIndex; var frame=overlayIndex.Frame; let chart=new ChartKLine(); chart.Canvas=hqChart.Canvas; chart.Name="Self Kline" chart.ChartBorder=frame.Frame.ChartBorder; chart.ChartFrame=frame.Frame; chart.Identify=overlayIndex.Identify; chart.Data=hisData chart.IsShowMaxMinPrice=false; chart.IsShowKTooltip=false; chart.DrawType=this.KLineType; frame.ChartPaint.push(chart); } //给一个默认的颜色 this.GetDefaultColor=function(id) { let COLOR_ARRAY= [ "rgb(24,71,178)", "rgb(42,230,215)", "rgb(252,96,154)", "rgb(0,128,255)", "rgb(229,0,79)", "rgb(68,114,196)", "rgb(255,174,0)", "rgb(25,199,255)", "rgb(175,95,162)", "rgb(236,105,65)", ]; let number=parseInt(id); return COLOR_ARRAY[number%(COLOR_ARRAY.length-1)]; } } //后台执行指标 function APIScriptIndex(name,script,args,option) { this.newMethod=ScriptIndex; //派生 this.newMethod(name,script,args,option); delete this.newMethod; this.ApiUrl; //指标执行api地址 this.HQDataType; if (option.API) { if (option.API.Url) this.ApiUrl=option.API.Url; if (option.API.Name) this.Name=this.ID=option.API.Name; if (option.API.ID) this.ID=option.API.ID; } this.ExecuteScript=function(hqChart,windowIndex,hisData) { console.log('[APIScriptIndex::ExecuteScript] name, Arguments ', this.Name,this.Arguments ); //数据类型 let hqDataType=HQ_DATA_TYPE.KLINE_ID; //默认K线 if (hqChart.ClassName==='MinuteChartContainer' || hqChart.ClassName==='MinuteChartHScreenContainer') { if (hqChart.DayCount>1) hqDataType=HQ_DATA_TYPE.MULTIDAY_MINUTE_ID; //多日分钟 else hqDataType=HQ_DATA_TYPE.MINUTE_ID; //分钟数据 } else if (hqChart.ClassName==='HistoryMinuteChartContainer') { hqDataType=HQ_DATA_TYPE.HISTORY_MINUTE_ID; //历史分钟 } var args=[]; if (this.Arguments) { for(var i in this.Arguments) { var item=this.Arguments[i]; args.push({name:item.Name, value:item.Value}); } } var requestCount=hqChart.GetRequestDataCount(); var self=this; var postData = { indexname:this.ID, symbol: hqChart.Symbol, script:this.Script, args:args, period:hqChart.Period, right:hqChart.Right, maxdatacount:requestCount.MaxRequestDataCount, maxminutedaycount:requestCount.MaxRequestMinuteDayCount, hqdatatype: hqDataType }; if (hqDataType==HQ_DATA_TYPE.MULTIDAY_MINUTE_ID || hqDataType==HQ_DATA_TYPE.MINUTE_ID) postData.daycount=hqChart.DayCount; this.HQDataType=hqDataType; if (hqChart.NetworkFilter) { var obj= { Name:'APIScriptIndex::ExecuteScript', //类名:: Explain:'指标计算', Request:{ Url:self.ApiUrl, Type:'POST', Data: postData }, Self:this, HQChart:hqChart, PreventDefault:false }; hqChart.NetworkFilter(obj, function(data) { self.RecvAPIData(data,hqChart,windowIndex,hisData); }); if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求 } JSNetwork.HttpRequest({ url: self.ApiUrl, data: postData, type:"post", dataType: "json", async:true, success: function (recvData) { self.RecvAPIData(recvData,hqChart,windowIndex,hisData); }, error: function(request) { self.RecvError(request); } }); } this.RecvAPIData=function(data,hqChart,windowIndex,hisData) { console.log('[APIScriptIndex::RecvAPIData] recv data ', this.Name,data ); if (data.code!=0) return; if (data.outdata && data.outdata.name) this.Name=data.outdata.name; this.Arguments=[]; if (data.outdata.args) { for(var i in data.outdata.args) { var item= data.outdata.args[i]; this.Arguments.push({Name:item.name, Value:item.value}); } } if (this.HQDataType==HQ_DATA_TYPE.KLINE_ID) { this.OutVar=this.FittingData(data.outdata,hqChart); console.log('[APIScriptIndex::RecvAPIData] conver to OutVar ', this.OutVar); } else { this.OutVar=this.FittingMinuteData(data.outdata,hqChart); //走势图数据 } this.BindData(hqChart,windowIndex,hisData); if (this.IsLocked==false) //不上锁 { hqChart.Frame.SubFrame[windowIndex].Frame.SetLock(null); } else //上锁 { let lockData={ IsLocked:true,Callback:this.LockCallback,IndexName:this.Name ,ID:this.LockID, BG:this.LockBG,Text:this.LockText,TextColor:this.LockTextColor, Font:this.LockFont, Count:this.LockCount, MinWidth:this.LockMinWidth }; hqChart.Frame.SubFrame[windowIndex].Frame.SetLock(lockData); } hqChart.UpdataDataoffset(); //更新数据偏移 hqChart.UpdateFrameMaxMin(); //调整坐标最大 最小值 hqChart.Draw(); if (hqChart.GetIndexEvent) { var event=hqChart.GetIndexEvent(); //指标计算完成回调 if (event) { var self=param.Self; var data={ OutVar:self.OutVar, WindowIndex: windowIndex, Name: this.Name, Arguments: this.Arguments, HistoryData: hisData, Stock: {Symbol:hqChart.Symbol,Name:hqChart.Name} }; event.Callback(event,data,this); } } } this.FittingArray=function(sourceData,date,time,hqChart,arrayType) //arrayType 0=单值数组 1=结构体 { var kdata=hqChart.ChartPaint[0].Data; //K线 var arySingleData=[]; for(var i in sourceData) { var value=sourceData[i]; var indexItem=new SingleData(); //单列指标数据 indexItem.Date=date[i]; if (time && i=1) outVarItem.LineWidth=item.linewidth; if (item.isshow==false) outVarItem.IsShow = false; if (item.isexdata==true) outVarItem.IsExData = true; result.push(outVarItem); } else if (item.Draw) { var draw=item.Draw; var drawItem={}; if (draw.DrawType=='DRAWICON') //图标 { drawItem.Icon=draw.Icon; drawItem.Name=draw.Name; drawItem.DrawType=draw.DrawType; drawItem.DrawData=this.FittingArray(draw.DrawData,date,time,hqChart); outVarItem.Draw=drawItem; result.push(outVarItem); } else if (draw.DrawType=='DRAWTEXT') //文本 { drawItem.Text=draw.Text; drawItem.Name=draw.Name; drawItem.DrawType=draw.DrawType; drawItem.DrawData=this.FittingArray(draw.DrawData,date,time,hqChart); outVarItem.Draw=drawItem; result.push(outVarItem); } else if (draw.DrawType=='STICKLINE') //柱子 { drawItem.Name=draw.Name; drawItem.Type=draw.Type; drawItem.Width=draw.Width; drawItem.DrawType=draw.DrawType; drawItem.DrawData=this.FittingArray(draw.DrawData,date,time,hqChart,1); outVarItem.Draw=drawItem; result.push(outVarItem); } else if (draw.DrawType=='MULTI_LINE') { drawItem.Text=draw.Text; drawItem.Name=draw.Name; drawItem.DrawType=draw.DrawType; drawItem.DrawData=this.FittingMultiLine(draw.DrawData,date,time,hqChart); outVarItem.Draw=drawItem; result.push(outVarItem); } else if (draw.DrawType=='MULTI_TEXT') { drawItem.Text=draw.Text; drawItem.Name=draw.Name; drawItem.DrawType=draw.DrawType; drawItem.DrawData=this.FittingMultiText(draw.DrawData,date,time,hqChart); outVarItem.Draw=drawItem; result.push(outVarItem); } else if (draw.DrawType=='MULTI_SVGICON') { drawItem.Text=draw.Text; drawItem.Name=draw.Name; drawItem.DrawType=draw.DrawType; drawItem.DrawData={ Icon:this.FittingMultiText(draw.DrawData.Icon,date,time,hqChart), Family:draw.DrawData.Family }; outVarItem.Draw=drawItem; result.push(outVarItem); } } } return result; } this.FittingMinuteData=function(jsonData, hqChart) { var outVar=jsonData.outvar; var date=jsonData.date; var time=jsonData.time; var result=[]; for(var i in outVar) { item=outVar[i]; var outVarItem={Name:item.name,Type:item.type} if (item.data) { outVarItem.Data=this.FittingMinuteArray(item.data,date,time,hqChart); if (item.color) outVarItem.Color=item.color; if (item.linewidth>=1) outVarItem.LineWidth=item.linewidth; if (item.isshow==false) outVarItem.IsShow = false; if (item.isexdata==true) outVarItem.IsExData = true; result.push(outVarItem); } } return result; } this.FittingMinuteArray=function(sourceData,date,time,hqChart) { var minutedata=hqChart.SourceData;; //分钟线 var arySingleData=[]; for(var i in sourceData) { var value=sourceData[i]; var indexItem=new SingleData(); //单列指标数据 indexItem.Date=date[i]; if (time && i