hqchart
Version:
stock chart
52,905 lines • 1.85 MB
JavaScript
//日志输出类
var JSConsole=
{
Chart:{ Log:console.log }, //图形日志
Complier:{ Log:console.log } //编译器日志
};
/*
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(CLOSE<REF(CLOSE,1),VOL,0),N);\n\
TQ:=SUM(IF(CLOSE==REF(CLOSE,1),VOL,0),N);\n\
VR:100*(TH*2+TQ)/(TL*2+TQ);\n\
MAVR:MA(VR,M);'
};
return data;
}
JSIndexScript.prototype.EMV=function()
{
let data=
{
Name:'EMV', Description:'简易波动指标', IsMainIndex:false,
Args:[ { Name:'N', Value:14},{ Name:'M', Value:9} ],
Script: //脚本
'VOLUME:=MA(VOL,N)/VOL;\n\
MID:=100*(HIGH+LOW-REF(HIGH+LOW,1))/(HIGH+LOW);\n\
EMV:MA(MID*VOLUME*(HIGH-LOW)/MA(HIGH-LOW,N),N);\n\
MAEMV:MA(EMV,M);'
};
return data;
}
JSIndexScript.prototype.ROC=function()
{
let data=
{
Name:'ROC', Description:'变动率指标', IsMainIndex:false,
Args:[ { Name:'N', Value:12},{ Name:'M', Value:6} ],
Script: //脚本
'ROC:100*(CLOSE-REF(CLOSE,N))/REF(CLOSE,N);\n\
MAROC:MA(ROC,M);'
};
return data;
}
JSIndexScript.prototype.MTM=function()
{
let data=
{
Name:'MTM', Description:'动量线', IsMainIndex:false,
Args:[ { Name:'N', Value:12},{ Name:'M', Value:6} ],
Script: //脚本
'MTM:CLOSE-REF(CLOSE,N);\n\
MAMTM:MA(MTM,M);'
};
return data;
}
JSIndexScript.prototype.FSL=function()
{
let data=
{
Name:'FSL', Description:'分水岭', IsMainIndex:false,
Args:[ ],
Script: //脚本
'SWL:(EMA(CLOSE,5)*7+EMA(CLOSE,10)*3)/10;\n\
SWS:DMA(EMA(CLOSE,12),MAX(1,100*(SUM(VOL,5)/(3*CAPITAL))));'
};
return data;
}
JSIndexScript.prototype.CYR=function()
{
let data=
{
Name:'CYR', Description:'市场强弱', IsMainIndex:false,
Args:[ { Name:'N', Value:13},{ Name:'M', Value:5}],
Script: //脚本
'DIVE:=0.01*EMA(AMOUNT,N)/EMA(VOL,N);\n\
CYR:(DIVE/REF(DIVE,1)-1)*100;\n\
MACYR:MA(CYR,M);'
};
return data;
}
JSIndexScript.prototype.MASS=function()
{
let data=
{
Name:'MASS', Description:'市场强弱', IsMainIndex:false,
Args:[ { Name:'N1', Value:9},{ Name:'N2', Value:25}, { Name:'M', Value:6}],
Script: //脚本
'MASS:SUM(MA(HIGH-LOW,N1)/MA(MA(HIGH-LOW,N1),N1),N2);\n\
MAMASS:MA(MASS,M);'
};
return data;
}
JSIndexScript.prototype.WAD=function()
{
let data=
{
Name:'WAD', Description:'威廉多空力度线', IsMainIndex:false,
Args:[ { Name:'M', Value:30}],
Script: //脚本
'MIDA:=CLOSE-MIN(REF(CLOSE,1),LOW);\n\
MIDB:=IF(CLOSE<REF(CLOSE,1),CLOSE-MAX(REF(CLOSE,1),HIGH),0);\n\
WAD:SUM(IF(CLOSE>REF(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(V<REF(V,1),C/REF(C,1),1),0);\n\
MANVI:MA(NVI,N);'
};
return data;
}
JSIndexScript.prototype.PVI=function()
{
let data=
{
Name:'PVI', Description:'正成交量', IsMainIndex:false,
Args:[ { Name:'N', Value:72} ],
Script: //脚本
'NVI:100*MULAR(IF(V>REF(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<REF(TYP,1),TYP*VOL,0),N);\n\
MFI:100-(100/(1+V1));'
};
return data;
}
JSIndexScript.prototype.LWR = function ()
{
let data =
{
Name: 'LWR', Description: 'LWR威廉指标', IsMainIndex: false,
Args: [{ Name: 'N', Value: 9 },{ Name: 'M1', Value: 3 },{ Name: 'M2', Value: 3 }],
Script: //脚本
'RSV:= (HHV(HIGH,N)-CLOSE)/(HHV(HIGH,N)-LLV(LOW,N))*100;\n\
LWR1:SMA(RSV,M1,1);\n\
LWR2:SMA(LWR1,M2,1);'
};
return data;
}
JSIndexScript.prototype.MARSI = function ()
{
let data =
{
Name: 'MARSI', Description: '相对强弱平均线', IsMainIndex: false,
Args: [{ Name: 'M1', Value: 10 },{ Name: 'M2', Value: 6 }],
Script: //脚本
'DIF:=CLOSE-REF(CLOSE,1);\n\
VU:=IF(DIF>=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 C<O*1.02,1,3);\n\
V5:=MA(V,5);\n\
V12:=MA(V,12);\n\
V34:=MA(V,34);\n\
C6:=MA(C,6);\n\
STICKLINE(VOL,0,VOL,10,0),COLORLIGRAY;\n\
STICKLINE(CROSS(C,C6) AND V>V5*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 C<REF(C,1)*1.05,0,VOL,10,0),COLORYELLOW;\n\
STICKLINE(VOL<MA(VOL,5)/2 AND V<V12/2,0,VOL,10,0),COLORBLUE;\n\
STICKLINE(VOL>MA(VOL,5)*2 AND V>V34*3 AND C<REF(C,1)*1.05 AND CROSS(C,C6) AND V>V5*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 C<REF(C,1)*1.05 AND CROSS(C6,C) AND V>V5*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\
低:VOL<REF(LLV(VOL,13),1),COLORGREEN;\n\
地:VOL<REF(LLV(VOL,100),1),COLORMAGENTA; \n\
平:=ABS(VOL-HHV(REF(VOL,1),5))/HHV(REF(VOL,1),5)<=0.03 OR ABS(VOL-REF(VOL,1))/REF(VOL,1)<=0.03,NODRAW,COLORWHITE;\n\
倍缩:VOL<=REF(V,1)*0.5,COLORFF8000;\n\
梯量:COUNT(V>REF(V,1),3)==3 AND COUNT(C>O,3)==3,COLORBROWN;\n\
缩量涨:COUNT(C>REF(C,1),2)==2 AND COUNT(V<REF(V,1),2)==2,COLORBLUE;\n\
STICKLINE(C>=REF(C,1),V,0,2,0),COLORRED;\n\
STICKLINE(C<REF(C,1),V,0,2,0),COLORGREEN;\n\
STICKLINE(倍,0,V,2,0),COLORYELLOW;\n\
STICKLINE(低,0,V,2,0),COLORGREEN;\n\
STICKLINE(地,0,V,2,0),COLORLIMAGENTA;\n\
STICKLINE(平,0,V,2,0),COLORGRAY;\n\
STICKLINE(倍缩,0,V,2,0),COLORFF8000;\n\
STICKLINE(梯量,0,V,2,0),COLORBROWN;\n\
STICKLINE(缩量涨,0,V,2,0),COLORBLUE;'
};
return data;
}
/*
能图-资金分析
M:=55;
N:=34;
LC:=REF(CLOSE,1);
RSI:=((SMA(MAX((CLOSE - LC),0),3,1) / SMA(ABS((CLOSE - LC)),3,1)) * 100);
FF:=EMA(CLOSE,3);
MA15:=EMA(CLOSE,21); DRAWTEXT(CROSS(85,RSI),75,'▼'),COLORGREEN;
VAR1:=IF(YEAR>=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 && CLOSE<REF(CLOSE,2);'
};
return data;
}
JSIndexScript.prototype.COLOR_SHI1=function()
{
let data=
{
Name: '长十字', Description: '长十字', IsMainIndex: true, InstructionType:2,
Script: //脚本
'KSTAR:CLOSE==OPEN&&HIGH/LOW>1.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)<MAX(REF(CLOSE,1),REF(OPEN,1))&&\n\
MIN(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&&CLOSE<HIGH;'
};
return data;
}
JSIndexScript.prototype.COLOR_K140=function()
{
let data=
{
Name: '早晨十字星', Description: '早晨十字星', IsMainIndex: true, InstructionType:2,
Script: //脚本
'KSTAR:REF(CLOSE,2)/REF(OPEN,2)<0.95&&\n\
REF(OPEN,1)<REF(CLOSE,2)&&\n\
REF(OPEN,1)==REF(CLOSE,1)&&\n\
CLOSE/OPEN>1.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&&CLOSE<REF(CLOSE,2);'
};
return data;
}
JSIndexScript.prototype.COLOR_K160=function()
{
let data=
{
Name: '射击之星', Description: '射击之星', IsMainIndex: true, InstructionType:2,
Script: //脚本
'KSTAR:MIN(OPEN,CLOSE)==LOW&&\n\
HIGH-LOW>3*(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\
CLOSE<MA(CLOSE,5);'
};
return data;
}
JSIndexScript.prototype.COLOR_K170=function()
{
let data=
{
Name: '锤头', Description: '锤头', IsMainIndex: true, InstructionType:2,
Script: //脚本
'OUT:HIGH==MAX(OPEN,CLOSE)&&\n\
HIGH-LOW>3*(HIGH-MIN(OPEN,CLOSE))&&\n\
CLOSE<MA(CLOSE,5);'
};
return data;
}
JSIndexScript.prototype.COLOR_K180=function()
{
let data=
{
Name: '吊颈', Description: '吊颈', IsMainIndex: true, InstructionType:2,
Script: //脚本
'OUT:HIGH==MAX(OPEN,CLOSE)&&\n\
HIGH-LOW>3*(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\
CLOSE<REF(OPEN,1)&&OPEN>REF(CLOSE,1))||\n\
(REF(CLOSE,1)/REF(OPEN,1)<0.97&&\n\
CLOSE/OPEN>1.04&&\n\
CLOSE>REF(OPEN,1)&&OPEN<REF(CLOSE,1));'
};
return data;
}
JSIndexScript.prototype.COLOR_SWORD=function()
{
let data=
{
Name: '剑', Description: '剑', IsMainIndex: true, InstructionType:2,
Script: //脚本
'AA:=VOL>REF(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<OPEN && LOW<CLOSE&&HIGH>(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&&OPEN<MA(CLOSE,M)&&OPEN<MA(CLOSE,LL);\n\
CSFRO:CC&&(CLOSE-OPEN)>0.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 CLOSE<REF(CLOSE,1), 3);'
};
return data;
}
JSIndexScript.prototype.COLOR_SGCJ=function()
{
let data=
{
Name: '曙光初现', Description: '曙光初现', IsMainIndex: true, InstructionType:2,
Script: //脚本
'VAR1:BACKSET( \n\
REF(CLOSE,1)/REF(OPEN,1)<0.97 AND \n\
CLOSE/OPEN>1.03 AND \n\
OPEN<REF(CLOSE,1) AND CLOSE>REF(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)<REF(OPEN,1) AND \n\
CLOSE>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( HIGH<REF(LOW,1) OR LOW>REF(HIGH,1),2);'
};
return data;
}
JSIndexScript.prototype.COLOR_SFWY=function()
{
let data=
{
Name: '双飞乌鸦', Description: '双飞乌鸦', IsMainIndex: true, InstructionType:2,
Script: //脚本
'VAR1:BACKSET( REF(CLOSE,1)<REF(OPEN,1) AND CLOSE<OPEN AND CLOSE/OPEN<0.98,1);'
};
return data;
}
JSIndexScript.prototype.COLOR_SSSBQ=function()
{
let data=
{
Name: '上升三部曲', Description: '上升三部曲', IsMainIndex: true, InstructionType:2,
Script: //脚本
'VAR1:BACKSET( \n\
REF(CLOSE,4)/REF(OPEN,4)>1.03 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(LOW,3) AND \n\
REF(LOW,4)<REF(LOW,2) AND \n\
REF(LOW,4)<REF(LOW,1) AND \n\
REF(HIGH,4)>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(LOW,3) AND \n\
REF(LOW,4)<REF(LOW,2) AND \n\
REF(LOW,4)<REF(LOW,1) AND \n\
REF(HIGH,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\
CLOSE<REF(CLOSE,4), 5);'
};
return data;
}
JSIndexScript.prototype.COLOR_CHXY=function()
{
let data=
{
Name: '长下影', Description: '长下影', IsMainIndex: true, InstructionType:2,
Script: //脚本
'VAR2:(MIN(CLOSE,OPEN)-LOW)/(HIGH-LOW)>0.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<OPEN,VOL,0)+IF(CLOSE=OPEN,VOL/2,0)),N)*100;\n\
ENTERLONG:CROSS(LL,WVR);\n\
EXITLONG:CROSS(WVR,LH);'
};
return data;
}
JSIndexScript.prototype.TRADE_DPSJ = function ()
{
let data =
{
Name: 'DPSJ', Description: '大盘随机专家系统', IsMainIndex: true, InstructionType:1,
Args: [{ Name: 'N1', Value: 18 },{ Name: 'N2', Value: 12 }],
Script: //脚本
'RSV:=(INDEXC-LLV(INDEXL,N1))/(HHV(INDEXH,N1)-LLV(INDEXL,N1))*100;\n\
K:=SMA(RSV,N2,1);\n\
HSL:VOL/100/(FINANCE(7));\n\
ENTERLONG: CROSS(K,20);\n\
EXITLONG: (CROSS(HSL,5) OR CROSS(K,80));'
};
return data;
}
JSIndexScript.prototype.Zealink_Index1 = function ()
{
let data =
{
Name: '资金吸筹', Description: '资金吸筹', IsMainIndex: false,
Args: [],
Script: //脚本
'VAR1:=REF((LOW+OPEN+CLOSE+HIGH)/4,1); \n\
VAR2:= SMA(ABS(LOW - VAR1), 13, 1) / SMA(MAX(LOW - VAR1, 0), 10, 1);\n\
VAR3:= EMA(VAR2, 10);\n\
VAR4:= LLV(LOW, 33);\n\
VAR5:= EMA(IF(LOW <= VAR4, VAR3, 0), 3) * 0.2;\n\
主力进场: IF(VAR5 > 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<OPEN,LOW,HIGH,0,1),COLORRED;\n\
STICKLINE(买线>=卖线 AND CLOSE>OPEN,CLOSE,OPEN,50,1),COLORRED;\n\
STICKLINE(买线>=卖线 AND CLOSE<OPEN,CLOSE,OPEN,50,0),COLORRED;\n\
STICKLINE(买线<卖线 AND CLOSE<OPEN,LOW,HIGH,0,1),COLORGREEN;\n\
STICKLINE(买线<卖线 AND CLOSE>OPEN,LOW,HIGH,0,1),COLORGREEN;\n\
STICKLINE(买线<卖线 AND CLOSE<OPEN,CLOSE,OPEN,50,0),COLORGREEN;\n\
STICKLINE(买线<卖线 AND CLOSE>OPEN,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:=SVARF<REF(SVAR10X,1) AND VOL>REF(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\
SELL1:=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\
S1:=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(A<B,A,B,2,0),COLORBLUE;\n\
\n\
VR1:=(C+O+REF(C,1))/3;\n\
VR3:=HHV(VR1,21);\n\
VR4:=LLV(VR1,21);\n\
VR5:=(2*VR1-VR4-REF(VR4,1))/(VR3-VR4);\n\
VR6:=(VR1-VR4)/(VR3-VR4);\n\
VR7:=IF(VR1<=VR4,VR5*60,VR6*60);\n\
VR8:=600*(EMA(C,3)-EMA(L,30))/EMA(L,30);\n\
VR9:=EMA(VR8,7);\n\
VRA:=(WINNER(120*C/100)-WINNER(100*C/100))*100;\n\
VRB:=(-100)*(WINNER(120*C/100)-WINNER(100*C/100))+5;\n\
VRC:=HHV(H,9)-LLV(L,9);\n\
VRD:=HHV(H,9)-C;\n\
VRE:=C-LLV(L,9);\n\
VRF:=VRD/VRC*100-70;\n\
VR10:=(C-LLV(L,60))/(HHV(H,60)-LLV(L,60))*100;\n\
VR11:=(2*C+H+L)/4;\n\
VR12:=SMA(VRE/VRC*100,3,1);\n\
VR13:=LLV(L,34);\n\
VR14:=SMA(VR12,3,1)-SMA(VRF,9,1);\n\
VR15:=IF(VR14>100,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\
S1:=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(VR17<VR18,1) OR MAX(VR17,VR18)<REF(MIN(VR17,VR18),1)));\n\
\n\
DRAWICON(REF(B1,1) AND (REF(VR17>VR18,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<VR18,1) OR MAX(VR17,VR18)<REF(MIN(VR17,VR18),1)) AND REF(S9,1)>=B9,H*1.03,14);\n\
\n\
DRAWKLINE_IF(VR17>VR18,HIGH,CLOSE,LOW,OPEN),COLORRED;\n\
DRAWKLINE_IF(VR17<VR18,HIGH,CLOSE,LOW,OPEN),COLORBLUE;\n\
\n\
INDEXCLOSE:INDEXC,EXDATA; //取指数的收盘价 回测的时候计算BATE系数用 "
};
return data;
}
JSIndexScript.prototype.HeikinAshi=function()
{
let data =
{
Name: '平均K线', Description: 'Heikin-Ashi 平均K线', IsMainIndex: true, KLineType:-1,
Args: [],
Script: //脚本
"HCLOSE:(OPEN+HIGH+LOW+CLOSE)/4, NODRAW;\n\
HOPEN:(REF(OPEN,1)+REF(CLOSE,1))/2,NODRAW;\n\
HHIGH:MAX(HIGH,MAX(HOPEN,HCLOSE)),NODRAW;\n\
HLOW:MIN(LOW,MIN(HOPEN,HCLOSE)),NODRAW;\n\
DRAWKLINE(HHIGH,HOPEN,HLOW,HCLOSE);"
}
return data;
}
JSIndexScript.prototype.EMPTY = function ()
{
let data =
{
Name: '', Description: '空指标', IsMainIndex: true,
Args: [],
Script: //脚本
'VAR2:=C;'
};
return data;
}
JSIndexScript.prototype.TEST = function ()
{
let data =
{
Name: 'TEST', Description: '测试脚本', IsMainIndex: false,
Args: [{ Name: 'N', Value: 10 }],
Script: //脚本
"DRAWCHANNEL(OPEN>C,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版本)
*/
//日志输出类
if (!JSConsole)
{
var JSConsole=
{
Chart:{ Log:console.log }, //图形日志
Complier:{ Log:console.log } //编译器日志
};
}
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;
JSConsole.Chart.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.TouchMoveMinAngle) chart.TouchMoveMinAngle=option.TouchMoveMinAngle;
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.KLine.RightSpaceCount>0) chart.RightSpaceCount=option.KLine.RightSpaceCount;
}
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.SourceDatatLimit) chart.SetSourceDatatLimit(option.SourceDatatLimit);
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.CorssCursorInfo.HPenType>0) chart.ChartCorssCursor.HPenType=option.CorssCursorInfo.HPenType;
if (option.CorssCursorInfo.VPenType>0) chart.ChartCorssCursor.VPenType=option.CorssCursorInfo.VPenType;
}
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 (IFrameSplitOperator.IsNumber(item.SplitType)) chart.Frame.SubFrame[i].Frame.YSplitOperator.SplitType=item.SplitType;
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.KLine.IsShowMaxMinPrice == false) chart.ChartPaint[0].IsShowMaxMinPrice=option.KLine.IsShowMaxMinPrice;
}
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;
if (item.IsShortTitle) indexInfo.IsShortTitle=item.IsShortTitle;
if (item.TitleFont) indexInfo.TitleFont=item.TitleFont;
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 (item.IsDrawTitleBG==true) chart.Frame.SubFrame[i].Frame.IsDrawTitleBG=item.IsDrawTitleBG;
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.DisableMouse==true) chart.DisableMouse=option.DisableMouse;
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 (item.Custom) chart.Frame.SubFrame[i].Frame.YSplitOperator.Custom=item.Custom;
}
}
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,item);
}
}
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;
if (option.IsApiPeriod==true) chart.IsApiPeriod=option.IsApiPeriod;
//创建改参数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线 4=面积图
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)
{
JSConsole.Chart.Log("[JSChart::ForceLandscape] bForceLandscape="+bForceLandscape);
this.JSChartContainer.IsForceLandscape=bForceLandscape;
}
}
//锁指标
this.LockIndex=function(lockData)
{
if(this.JSChartContainer && typeof(this.JSChartContainer.LockIndex)=='function')
{
JSConsole.Chart.Log('[JSChart:LockIndex] lockData', lockData);
this.JSChartContainer.LockIndex(lockData);
}
}
//历史分钟数据 更改日期
this.ChangeTradeDate=function(tradeDate)
{
if(this.JSChartContainer && typeof(this.JSChartContainer.ChangeTradeDate)=='function')
{
JSConsole.Chart.Log('[JSChart:ChangeTradeDate] date', tradeDate);
this.JSChartContainer.ChangeTradeDate(tradeDate);
}
}
//多日走势图
this.ChangeDayCount=function(count)
{
if(this.JSChartContainer && typeof(this.JSChartContainer.ChangeDayCount)=='function')
{
JSConsole.Chart.Log('[JSChart:ChangeDayCount] count', count);
this.JSChartContainer.ChangeDayCount(count);
}
}
//返回弹幕数据类
this.StartAnimation=function(option)
{
if(this.JSChartContainer && typeof(this.JSChartContainer.StartAnimation)=='function')
{
JSConsole.Chart.Log('[JSChart:StartAnimation] start.');
return this.JSChartContainer.StartAnimation(option);
}
}
this.StopAnimation=function()
{
if(this.JSChartContainer && typeof(this.JSChartContainer.StopAnimation)=='function')
{
JSConsole.Chart.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')
{
JSConsole.Chart.Log('[JSChart:AddEventCallback] ', obj);
this.JSChartContainer.AddEventCallback(obj);
}
}
//设置语言 'EN', 'CN'
this.SetLanguage=function(language)
{
if(this.JSChartContainer && typeof(this.JSChartContainer.SetLanguage)=='function')
{
JSConsole.Chart.Log('[JSChart:SetLanguage] ', language);
this.JSChartContainer.SetLanguage(language);
}
}
//切换指标模板
this.ChangeIndexTemplate=function(option)
{
if(this.JSChartContainer && typeof(this.JSChartContainer.ChangeIndexTemplate)=='function')
{
JSConsole.Chart.Log('[JSChart:ChangeIndexTemplate] ', option);
this.JSChartContainer.ChangeIndexTemplate(option);
}
}
//画图工具
this.SetChartDrawOption=function(option)
{
if(this.JSChartContainer && typeof(this.JSChartContainer.SetChartDrawOption)=='function')
{
JSConsole.Chart.Log('[JSChart:SetChartDrawOption] ', option);
this.JSChartContainer.SetChartDrawOption(option);
}
}
this.CreateChartDrawPicture=function(name)
{
if(this.JSChartContainer && typeof(this.JSChartContainer.CreateChartDrawPicture)=='function')
{
JSConsole.Chart.Log('[JSChart:CreateChartDrawPicture] ', name);
this.JSChartContainer.CreateChartDrawPicture(name);
}
}
}
//初始化
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;
}
JSChart.GetKLineZoom=function() //K线缩放配置
{
return ZOOM_SEED;
}
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, //标题信息绘制事件
ON_SELECT_RECT:13, //区间选择事件通知
RECV_MINUTE_DATA:14, //分时图数据到达
ON_CLICK_INDEXTITLE:15, //点击指标标题事件
RECV_KLINE_UPDATE_DATA:16, //K线日,分钟更新数据到达
ON_CLICK_DRAWPICTURE:17, //点击画图工具
ON_FINISH_DRAWPICTURE:18, //完成画图工具
ON_INDEXTITLE_DRAW:19, //指标标题重绘事件
ON_CUSTOM_VERTICAL_DRAW:20, //自定义X轴绘制事件
}
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页数据
}
var JSCHART_DRAG_ID=
{
DISABLE_DRAG_ID:0,
CLICK_TOUCH_MODE_ID:3 //长按十字光标显示保留/点击十字光标消失 (使用TouchStatus)
}
/*
图形控件
*/
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.ChartDrawOption={ IsLockScreen:false, Zoom:5 }; //画图工具设置 { IsLockScreen://是否锁住屏幕, Zoom: //线段|点放大倍数 }
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 区间选择 3(CLICK_TOUCH_MODE_ID)=长按十字光标显示保留/点击十字光标消失 (使用TouchStatus)
this.TouchStatus={ CorssCursorShow:false }, //十字光标是否显示
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.TouchMoveMinAngle=70; //左右移动最小角度
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=(e)=>{ this.UIOnMouseMove(e);}
uielement.oncontextmenu=(e)=> { return this.UIOnContextMenu(e); }
uielement.ondblclick=(e)=>{ this.UIOnDblClick(e); }
uielement.onmousedown=(e)=> { this.UIOnMouseDown(e); }
this.UIOnMouseMove=function(e)
{
//JSConsole.Chart.Log('[JSChartContainer.UIOnMouseMove] e.clientX, e.clientY, left, top ',e.clientX, e.clientY, this.getBoundingClientRect().left,this.getBoundingClientRect().top);
var pixelTatio = GetDevicePixelRatio(); //鼠标移动坐标是原始坐标 需要乘以放大倍速
var x = (e.clientX-this.UIElement.getBoundingClientRect().left)*pixelTatio;
var y = (e.clientY-this.UIElement.getBoundingClientRect().top)*pixelTatio;
//加载数据中,禁用鼠标事件
if (this.ChartSplashPaint && this.ChartSplashPaint.IsEnableSplash == true) return;
if (this.DisableMouse==true) return;
this.OnMouseMove(x,y,e);
}
this.UIOnContextMenu=function(e)
{
var x = e.clientX-this.UIElement.getBoundingClientRect().left;
var y = e.clientY-this.UIElement.getBoundingClientRect().top;
if(typeof(this.OnRightMenu)=='function') this.OnRightMenu(x,y,e); //右键菜单事件
return false;
}
this.UIOnDblClick=function(e)
{
var x = e.clientX-this.UIElement.getBoundingClientRect().left;
var y = e.clientY-this.UIElement.getBoundingClientRect().top;
this.OnDoubleClick(x,y,e);
}
this.UIOnMouseDown=function(e)
{
if(this.DragMode==0) return;
var pixelTatio = GetDevicePixelRatio();
this.IsOnTouch=true;
if (this.TryClickLock)
{
//JSConsole.Chart.Log('[uielement.onmousedown] left, top ',e.clientX, e.clientY, this.getBoundingClientRect().left,this.getBoundingClientRect().top);
var x = (e.clientX-this.UIElement.getBoundingClientRect().left)*pixelTatio;
var y = (e.clientY-this.UIElement.getBoundingClientRect().top)*pixelTatio;
if (this.TryClickLock(x,y)) return;
}
this.HideSelectRect();
if (this.SelectRectRightMenu) this.SelectRectRightMenu.Hide();
if (this.ChartPictureMenu) this.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.MouseDrag=drag;
this.SelectChartDrawPicture=null;
if (this.CurrentChartDrawPicture) //画图工具模式
{
var drawPicture=this.CurrentChartDrawPicture;
if (drawPicture.Status==2)
this.SetChartDrawPictureThirdPoint(drag.Click.X,drag.Click.Y);
else
{
this.SetChartDrawPictureFirstPoint(drag.Click.X,drag.Click.Y);
//只有1个点 直接完成
if (this.FinishChartDrawPicturePoint()) this.DrawDynamicInfo();
}
}
else //是否在画图工具上
{
var drawPictrueData={};
var pixelTatio = GetDevicePixelRatio(); //鼠标移动坐标是原始坐标 需要乘以放大倍速
drawPictrueData.X=(e.clientX-this.UIElement.getBoundingClientRect().left)*pixelTatio;
drawPictrueData.Y=(e.clientY-this.UIElement.getBoundingClientRect().top)*pixelTatio;
if (this.GetChartDrawPictureByPoint(drawPictrueData))
{
drawPictrueData.ChartDrawPicture.Status=20;
drawPictrueData.ChartDrawPicture.ValueToPoint();
drawPictrueData.ChartDrawPicture.MovePointIndex=drawPictrueData.PointIndex;
this.CurrentChartDrawPicture=drawPictrueData.ChartDrawPicture;
this.SelectChartDrawPicture=drawPictrueData.ChartDrawPicture;
this.OnSelectChartPicture(drawPictrueData.ChartDrawPicture); //选中画图工具事件
}
}
document.onmousemove=(e)=>{ this.DocOnMouseMove(e); }
document.onmouseup=(e)=> { this.DocOnMouseUp(e); }
}
this.DocOnMouseMove=function(e)
{
//加载数据中,禁用鼠标事件
if (this.ChartSplashPaint && this.IsEnableSplash == true) return;
var drag=this.MouseDrag;
if (!drag) return;
var moveSetp=Math.abs(drag.LastMove.X-e.clientX);
if (this.CurrentChartDrawPicture)
{
var drawPicture=this.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.SetChartDrawPictureSecondPoint(e.clientX,e.clientY))
{
this.DrawDynamicInfo();
}
}
else if (drawPicture.Status==3)
{
if(this.SetChartDrawPictureThirdPoint(e.clientX,e.clientY))
{
this.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.MoveChartDrawPicture(e.clientX-drag.LastMove.X,e.clientY-drag.LastMove.Y))
{
this.DrawDynamicInfo();
}
}
drag.LastMove.X=e.clientX;
drag.LastMove.Y=e.clientY;
}
else if (this.DragMode==1) //数据左右拖拽
{
if (moveSetp<5) return;
var isLeft=true;
if (drag.LastMove.X<e.clientX) isLeft=false;//右移数据
this.UIElement.style.cursor="pointer";
if(this.DataMove(moveSetp,isLeft))
{
this.UpdataDataoffset();
this.UpdatePointByCursorIndex();
this.UpdateFrameMaxMin();
this.ResetFrameXYSplit();
this.Draw();
}
else
{
if (this.DragDownloadData) this.DragDownloadData();
}
drag.LastMove.X=e.clientX;
drag.LastMove.Y=e.clientY;
}
else if (this.DragMode==2) //区间选择
{
var yMoveSetp=Math.abs(drag.LastMove.Y-e.clientY);
if (moveSetp<5 && yMoveSetp<5) return;
var x=drag.Click.X-uielement.getBoundingClientRect().left;
var y=drag.Click.Y-uielement.getBoundingClientRect().top;
var x2=e.clientX-uielement.getBoundingClientRect().left;
var y2=e.clientY-uielement.getBoundingClientRect().top;
this.ShowSelectRect(x,y,x2,y2);
drag.LastMove.X=e.clientX;
drag.LastMove.Y=e.clientY;
}
}
this.DocOnMouseUp=function(e)
{
//清空事件
document.onmousemove=null;
document.onmouseup=null;
var bClearDrawPicture=true;
if (this.CurrentChartDrawPicture)
{
var drawPicture=this.CurrentChartDrawPicture;
if (drawPicture.Status==2 || drawPicture.Status==1 || drawPicture.Status==3)
{
drawPicture.PointStatus=drawPicture.Status;
if (this.FinishChartDrawPicturePoint())
this.DrawDynamicInfo();
else
bClearDrawPicture=false;
}
else if (drawPicture.Status==20)
{
if (this.FinishMoveChartDrawPicture())
this.DrawDynamicInfo();
}
}
else if (this.DragMode==2) //区间选择
{
var drag=this.MouseDrag;
var selectData=new SelectRectData();
//区间起始位置 结束位子
selectData.XStart=drag.Click.X-uielement.getBoundingClientRect().left;
selectData.XEnd=drag.LastMove.X-uielement.getBoundingClientRect().left;
selectData.JSChartContainer=this.JSChartContainer;
selectData.Stock={Symbol:this.Symbol, Name:this.Name};
if (this.GetSelectRectData(selectData))
{
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_SELECT_RECT);
if (event && event.Callback)
{
var data=
{
X:drag.LastMove.X-uielement.getBoundingClientRect().left,
Y:drag.LastMove.Y-uielement.getBoundingClientRect().top,
SelectData:selectData, //区间选择的数据
};
event.Callback(event,data,this);
}
if (this.SelectRectRightMenu)
{
e.data=
{
Chart:this,
X:drag.LastMove.X-uielement.getBoundingClientRect().left,
Y:drag.LastMove.Y-uielement.getBoundingClientRect().top,
SelectData:selectData, //区间选择的数据
};
this.SelectRectRightMenu.DoModal(e);
}
}
}
//清空数据
JSConsole.Chart.Log('[KLineChartContainer::document.onmouseup]',e);
this.UIElement.style.cursor="default";
this.MouseDrag=null;
this.IsOnTouch=false;
if (bClearDrawPicture===true) this.CurrentChartDrawPicture=null;
}
//判断是单个手指
this.IsPhoneDragging=function(e)
{
// JSConsole.Chart.Log(e);
var changed=e.changedTouches.length;
var touching=e.touches.length;
return changed==1 && touching==1;
}
//是否是2个手指操所
this.IsPhonePinching=function(e)
{
var changed=e.changedTouches.length;
var touching=e.touches.length;
return (changed==1 || changed==2) && touching==2;
}
this.PreventTouchEvent=function(e)
{
if (e.cancelable) e.preventDefault();
e.stopPropagation();
}
this.GetToucheData=function(e, isForceLandscape)
{
var touches=new Array();
var pixelTatio = GetDevicePixelRatio(); //获取设备的分辨率
for(var i=0; i<e.touches.length; ++i)
{
var item=e.touches[i];
if (isForceLandscape)
{
touches.push(
{
clientX:item.clientY*pixelTatio, clientY:item.clientX*pixelTatio,
pageX:item.pageY*pixelTatio, pageY:item.pageX*pixelTatio
});
}
else
{
touches.push(
{
clientX:item.clientX*pixelTatio, clientY:item.clientY*pixelTatio,
pageX:item.pageX*pixelTatio, pageY:item.pageY*pixelTatio
});
}
}
return touches;
}
this.IsSingleTouch=function(e) //是否是单点触屏
{
var touchCount=e.touches.length;
return touchCount==1;
}
this.StopDragTimer=function()
{
if (IFrameSplitOperator.IsNumber(this.DragTimer))
{
clearTimeout(this.DragTimer);
this.DragTimer=null;
}
}
this.GetMoveAngle=function(pt,pt2) //计算角度
{
var xMove=Math.abs(pt.X-pt2.X);
var yMove=Math.abs(pt.Y-pt2.Y);
var angle=Math.atan(xMove/yMove)*180/Math.PI;
return angle;
}
//手机拖拽
uielement.ontouchstart=(e)=> { this.OnTouchStart(e); }
uielement.ontouchmove=(e)=> {this.OnTouchMove(e); }
uielement.ontouchend=(e)=> {this.OnTouchEnd(e); }
this.OnTouchStart=function(e)
{
this.IsOnTouch=true;
this.TouchDrawCount=0;
this.PhonePinch=null;
this.StopDragTimer();
var isSingleTouch=this.IsSingleTouch(e);
if (this.EnableScrollUpDown==false || !isSingleTouch || //多点触屏
(this.DragMode==JSCHART_DRAG_ID.CLICK_TOUCH_MODE_ID && this.TouchStatus.CorssCursorShow==true)) //十字光标显示,不能滚动页面
{
if (e.cancelable) e.preventDefault();
}
if (this.IsPhoneDragging(e))
{
if (this.TryClickLock || this.TryClickIndexTitle) //指标枷锁区域 , 指标标题点击
{
var touches = this.GetToucheData(e, this.IsForceLandscape);
var x = touches[0].clientX;
var y = touches[0].clientY;
var pixelTatio = GetDevicePixelRatio();
x -= uielement.getBoundingClientRect().left*pixelTatio; //减去控件的偏移偏移量
y -= uielement.getBoundingClientRect().top*pixelTatio;
if (this.TryClickLock && this.TryClickLock(x, y)) return;
if (this.TryClickIndexTitle && this.TryClickIndexTitle(x,y)) return;
}
var bStartTimer=true;
if (this.ChartDrawOption.IsLockScreen)
{
bStartTimer=false;
}
else if (this.DragMode==JSCHART_DRAG_ID.CLICK_TOUCH_MODE_ID)
{
if (this.TouchStatus.CorssCursorShow==true) bStartTimer=false;
}
else if (this.DragMode==JSCHART_DRAG_ID.DISABLE_DRAG_ID)
{
bStartTimer=false;
}
else
{
if (!isSingleTouch) bStartTimer=false;
}
var drag=
{
"Click":{},
"LastMove":{} //最后移动的位置
};
var touches=this.GetToucheData(e,this.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;
this.MouseDrag=drag;
if (this.SelectChartDrawPicture) this.SelectChartDrawPicture.IsSelected=false;
this.SelectChartDrawPicture=null;
var isDrawPictrue=false;
if (this.CurrentChartDrawPicture) //画图工具模式
{
var drawPicture=this.CurrentChartDrawPicture;
if (drawPicture.Status==2)
this.SetChartDrawPictureThirdPoint(drag.Click.X,drag.Click.Y);
else
{
this.SetChartDrawPictureFirstPoint(drag.Click.X,drag.Click.Y);
//只有1个点 直接完成
if (this.FinishChartDrawPicturePoint()) this.DrawDynamicInfo({Corss:false, Tooltip:false});
}
if (e.cancelable) e.preventDefault();
return;
}
else
{
var drawPictrueData={};
var pixelTatio = GetDevicePixelRatio(); //鼠标移动坐标是原始坐标 需要乘以放大倍速
drawPictrueData.X=(touches[0].clientX-uielement.getBoundingClientRect().left);
drawPictrueData.Y=(touches[0].clientY-uielement.getBoundingClientRect().top);
if (this.GetChartDrawPictureByPoint(drawPictrueData))
{
drawPictrueData.ChartDrawPicture.Status=20;
drawPictrueData.ChartDrawPicture.ValueToPoint();
drawPictrueData.ChartDrawPicture.MovePointIndex=drawPictrueData.PointIndex;
drawPictrueData.ChartDrawPicture.IsSelected=true;
this.CurrentChartDrawPicture=drawPictrueData.ChartDrawPicture;
this.SelectChartDrawPicture=drawPictrueData.ChartDrawPicture;
let event=this.GetEventCallback(JSCHART_EVENT_ID.ON_CLICK_DRAWPICTURE); //选中画图工具事件
if (event && event.Callback)
{
let sendData={ DrawPicture: drawPictrueData.ChartDrawPicture };
event.Callback(event,sendData,this);
}
if (e.cancelable) e.preventDefault();
return;
}
}
if (bStartTimer)
{
//长按2秒,十字光标
var self=this;
this.DragTimer=setTimeout(function()
{
if (drag.Click.X==drag.LastMove.X && drag.Click.Y==drag.LastMove.Y) //手指没有移动,出现十字光标
{
var mouseDrag=self.MouseDrag;
self.MouseDrag=null;
if (self.DragMode==JSCHART_DRAG_ID.CLICK_TOUCH_MODE_ID) self.TouchStatus.CorssCursorShow=true; //十字显示
self.MoveCorssCursor(drag.Click,e);//移动十字光标
}
}, self.PressTime);
}
if (this.ChartDrawOption.IsLockScreen)
{
this.MouseDrag=null;
}
else if (this.DragMode==JSCHART_DRAG_ID.CLICK_TOUCH_MODE_ID)
{
}
else if (this.DragMode==JSCHART_DRAG_ID.DISABLE_DRAG_ID)
{
this.MouseDrag=null;
this.MoveCorssCursor(drag.Click,e);
}
else if (this.IsClickShowCorssCursor)
{
this.MoveCorssCursor(drag.Click,e);
}
}
else if (this.IsPhonePinching(e))
{
var phonePinch=
{
"Start":{},
"Last":{}
};
var touches=this.GetToucheData(e,this.IsForceLandscape);
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.PhonePinch=phonePinch;
this.SelectChartDrawPicture=null;
}
}
this.OnTouchMove=function(e)
{
var touches=this.GetToucheData(e,this.IsForceLandscape);
if (this.IsPhoneDragging(e))
{
var drag=this.MouseDrag;
if (drag==null)
{
if (this.IsForceLandscape) y=uielement.getBoundingClientRect().width-touches[0].clientY; //强制横屏Y计算
if (!this.ChartDrawOption.IsLockScreen) this.MoveCorssCursor({X:touches[0].clientX, Y:touches[0].clientY},e);
}
else
{
var moveAngle=this.GetMoveAngle(drag.LastMove,{X:touches[0].clientX, Y:touches[0].clientY});
var moveSetp=Math.abs(drag.LastMove.X-touches[0].clientX);
var moveUpDown=Math.abs(drag.LastMove.Y-touches[0].clientY);
moveSetp=parseInt(moveSetp);
var isMoveCorssCursor=(this.DragMode==JSCHART_DRAG_ID.CLICK_TOUCH_MODE_ID && this.TouchStatus.CorssCursorShow==true); //是否移动十字光标
//JSConsole.Chart.Log("[JSChartContainer::uielement.ontouchmove] moveAngle , moveUpDown", moveAngle,moveUpDown);
if (this.CurrentChartDrawPicture)
{
var drawPicture=this.CurrentChartDrawPicture;
if (drawPicture.Status==1 || drawPicture.Status==2)
{
if(moveSetp<5 && moveUpDown<5) return;
if(this.SetChartDrawPictureSecondPoint(touches[0].clientX,touches[0].clientY))
{
this.DrawDynamicInfo();
}
}
else if (drawPicture.Status==3)
{
if(this.SetChartDrawPictureThirdPoint(touches[0].clientX,touches[0].clientY))
{
this.DrawDynamicInfo();
}
}
else if (drawPicture.Status==20) //画图工具移动
{
if(moveSetp<5 && moveUpDown<5) return;
if(this.MoveChartDrawPicture(touches[0].clientX-drag.LastMove.X,touches[0].clientY-drag.LastMove.Y))
{
this.DrawDynamicInfo();
}
}
drag.LastMove.X=touches[0].clientX;
drag.LastMove.Y=touches[0].clientY;
}
else if (isMoveCorssCursor) //点击模式下 十字光标显示 左右移动十字光标
{
var mouseDrag=this.MouseDrag;
this.MouseDrag=null;
this.MoveCorssCursor(drag.Click,e); //移动十字光标
}
else if (this.DragMode==1 || isMoveCorssCursor==false) //数据左右拖拽
{
if ( ((moveUpDown>0 && moveSetp<=3) || moveAngle<=this.TouchMoveMinAngle) && this.EnableScrollUpDown==true )
{
this.StopDragTimer();
return;
}
if (moveSetp<5 || moveAngle<=this.TouchMoveMinAngle)
{
this.PreventTouchEvent(e);
return;
}
var isLeft=true;
if (drag.LastMove.X<touches[0].clientX) isLeft=false;//右移数据
if(this.DataMove(moveSetp,isLeft))
{
this.UpdataDataoffset();
this.UpdatePointByCursorIndex();
this.UpdateFrameMaxMin();
this.ResetFrameXYSplit();
this.Draw();
}
else
{
if (this.DragDownloadData) this.DragDownloadData();
}
drag.LastMove.X=touches[0].clientX;
drag.LastMove.Y=touches[0].clientY;
}
}
}
else if (this.IsPhonePinching(e))
{
if (this.DragMode==JSCHART_DRAG_ID.DISABLE_DRAG_ID) return;
this.PreventTouchEvent(e);
var phonePinch=this.PhonePinch;
if (!phonePinch) return;
var yHeight=Math.abs(touches[0].pageY-touches[1].pageY);
var yLastHeight=Math.abs(phonePinch.Last.Y-phonePinch.Last.Y2);
var yStep=yHeight-yLastHeight;
var xHeight=Math.abs(touches[0].pageX-touches[1].pageX);
var xLastHeight=Math.abs(phonePinch.Last.X-phonePinch.Last.X2);
var xStep=xHeight-xLastHeight;
var minStep=this.ZoomStepPixel;
if (Math.abs(yStep)<minStep && Math.abs(xStep)<minStep) return;
var step=yStep;
if (Math.abs(yStep)<minStep) step=xStep;
if (step>0) //放大
{
var cursorIndex={};
cursorIndex.Index=parseInt(Math.abs(this.CursorIndex-0.5).toFixed(0));
if (!this.Frame.ZoomUp(cursorIndex)) return;
this.CursorIndex=cursorIndex.Index;
this.UpdatePointByCursorIndex();
this.UpdataDataoffset();
this.UpdateFrameMaxMin();
this.Draw();
this.ShowTooltipByKeyDown();
this.StopDragTimer();
}
else //缩小
{
var cursorIndex={};
cursorIndex.Index=parseInt(Math.abs(this.CursorIndex-0.5).toFixed(0));
if (!this.Frame.ZoomDown(cursorIndex)) return;
this.CursorIndex=cursorIndex.Index;
this.UpdataDataoffset();
this.UpdatePointByCursorIndex();
this.UpdateFrameMaxMin();
this.Draw();
this.ShowTooltipByKeyDown();
this.StopDragTimer();
}
phonePinch.Last={"X":touches[0].pageX,"Y":touches[0].pageY,"X2":touches[1].pageX,"Y2":touches[1].pageY};
}
this.PreventTouchEvent(e);
}
this.OnTouchEnd=function(e)
{
JSConsole.Chart.Log('[KLineChartContainer:OnTouchEnd]',e);
var bClearDrawPicture=true;
if (this.CurrentChartDrawPicture)
{
var drawPicture=this.CurrentChartDrawPicture;
if (drawPicture.Status==2 || drawPicture.Status==1 || drawPicture.Status==3)
{
drawPicture.PointStatus=drawPicture.Status;
if (this.FinishChartDrawPicturePoint())
this.DrawDynamicInfo();
else
bClearDrawPicture=false;
}
else if (drawPicture.Status==20)
{
if (this.FinishMoveChartDrawPicture())
this.DrawDynamicInfo();
}
}
this.IsOnTouch = false;
if (bClearDrawPicture===true) this.CurrentChartDrawPicture=null;
this.StopDragTimer();
this.OnTouchFinished();
this.TouchDrawCount=0;
}
this.MoveCorssCursor=function(point,e)
{
var pixelTatio = GetDevicePixelRatio();
var x = point.X-this.UIElement.getBoundingClientRect().left*pixelTatio;
var y = point.Y-this.UIElement.getBoundingClientRect().top*pixelTatio;
if (this.DragMode==JSCHART_DRAG_ID.CLICK_TOUCH_MODE_ID) this.TouchStatus.CorssCursorShow=true; //十字显示
this.OnMouseMove(x,y,e);
}
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();
if (this.Frame.DrawCustomVertical)
{
var eventCVericalDraw=this.GetEventCallback(JSCHART_EVENT_ID.ON_CUSTOM_VERTICAL_DRAW);
this.Frame.DrawCustomVertical(eventCVericalDraw);
}
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.DragMode==JSCHART_DRAG_ID.CLICK_TOUCH_MODE_ID)
{ //点击手势模式下
if (this.TouchStatus.CorssCursorShow==true) this.ChartCorssCursor.Draw();
}
else 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);
var eventIndexTitleDraw=this.GetEventCallback(JSCHART_EVENT_ID.ON_INDEXTITLE_DRAW);
for(var i in this.TitlePaint)
{
var item=this.TitlePaint[i];
if (!item.IsDynamic) continue;
item.CursorIndex=this.CursorIndex;
if (item.ClassName=='DynamicChartTitlePainting') item.OnDrawEvent=eventIndexTitleDraw
else 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(option)
{
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 (option && option.Corss==false)
{
}
else if (this.DragMode==JSCHART_DRAG_ID.CLICK_TOUCH_MODE_ID)
{
if (this.TouchStatus.CorssCursorShow==true) this.ChartCorssCursor.Draw();
}
else if ( !(this.IsOnTouch===false && this.CorssCursorTouchEnd===true) && !this.CurrentChartDrawPicture)
{
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.ClassName=='KLineTooltipPaint' && option && option.Tooltip==false) continue;
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;
JSConsole.Chart.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)
{
//JSConsole.Chart.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";
//JSConsole.Chart.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";
//JSConsole.Chart.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 (x<borderLeft) x=borderLeft;
if (x2<borderLeft) x2=borderLeft;
if (x>x2) 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);
JSConsole.Chart.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.Max<range.Max) frameItem.Range.Max=range.Max;
if (frameItem.Range.Min>range.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 (this.RightSpaceCount>0)
{
if (xPointcount+data.DataOffset>=data.Data.length+this.RightSpaceCount-1) return false;
data.DataOffset+=step;
if (data.DataOffset+xPointcount>=data.Data.length+this.RightSpaceCount)
data.DataOffset=data.Data.length-(xPointcount-this.RightSpaceCount);
}
else
{
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));
//JSConsole.Chart.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; // 数据加载中不能保存
JSConsole.Chart.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);
JSConsole.Chart.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)
{
JSConsole.Chart.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)
{
JSConsole.Chart.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;v<Agents.length;v++)
{
if(userAgentInfo.indexOf(Agents[v])>0) 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;
//JSConsole.Chart.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.XBottomOffset=g_JSChartResource.Frame.XBottomOffset; //X轴文字显示向下偏移
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)<this.MinYDistance) continue; //两个坐标在近了 就不画了
this.Canvas.strokeStyle=item.LineColor;
if (item.LineType==2)
{
this.Canvas.save();
this.Canvas.setLineDash([5,5]); //虚线
this.Canvas.beginPath();
this.Canvas.moveTo(left,ToFixedPoint(y));
this.Canvas.lineTo(right,ToFixedPoint(y));
this.Canvas.stroke();
this.Canvas.restore();
}
else
{
this.Canvas.beginPath();
this.Canvas.moveTo(left,ToFixedPoint(y));
this.Canvas.lineTo(right,ToFixedPoint(y));
this.Canvas.stroke();
}
if (y >= 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(); //获取设备的分辨率
//JSConsole.Chart.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)<this.MinXDistance) continue;
if (this.VerticalInfo[i].LineType>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<testWidth/2)
{
this.Canvas.textAlign="left";
this.Canvas.textBaseline="top";
textLeft=x;
}
else if ((x + testWidth / 2) >= 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+this.XBottomOffset);
textRightPrev=textLeft+testWidth;
}
}
xPrev=x;
}
}
//Y坐标转y轴数值
this.GetYData=function(y)
{
if (this.CoordinateType==1) //反转坐标
{
if (y<this.ChartBorder.GetTopEx()) return this.HorizontalMin;
if (y>this.ChartBorder.GetBottomEx()) return this.HorizontalMax;
return (y-this.ChartBorder.GetTopEx())/this.ChartBorder.GetHeightEx()*(this.HorizontalMax-this.HorizontalMin)+this.HorizontalMin;
}
else
{
if (y<this.ChartBorder.GetTopEx()) return this.HorizontalMax;
if (y>this.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());
}
this.DrawCustomItem=function(item) //显示自定义刻度
{
//if (this.IsHScreen===true) return; //横屏不画
if (!item.Message[1] && !item.Message[0]) return;
if (item.Value>this.HorizontalMax || item.Value<this.HorizontalMin) 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 (this.IsHScreen)
{
borderLeft=this.ChartBorder.Top;
borderRight=this.ChartBorder.Bottom;
top=this.ChartBorder.GetTop();
bottom=this.ChartBorder.GetBottom();
}
var pixelTatio = GetDevicePixelRatio();
var textHeight=18*pixelTatio;
var y = this.GetYFromData(item.Value);
if (item.Message[0]) // 左
{
if (borderLeft<10)
{
if (item.Font != null) this.Canvas.font = item.Font;
this.Canvas.textAlign = "left";
this.Canvas.textBaseline = "middle";
var textWidth = this.Canvas.measureText(item.Message[0]).width+2*pixelTatio;
var bgColor=item.LineColor;
var rgb=this.RGBToStruct(item.LineColor);
if (rgb) bgColor=`rgba(${rgb.R}, ${rgb.G}, ${rgb.B}, ${g_JSChartResource.FrameLatestPrice.BGAlpha})`; //内部刻度 背景增加透明度
this.Canvas.fillStyle=bgColor;
if (this.IsHScreen)
{
var bgTop=top;
var textLeft=y-textHeight/2-1*pixelTatio;
this.Canvas.fillRect(textLeft,bgTop,textHeight,textWidth);
this.DrawHScreenText({X:y, Y:bgTop}, {Text:item.Message[0], Color:item.TextColor, XOffset:1*pixelTatio, YOffset:2*pixelTatio});
if (item.LineType!=-1) this.DrawDotLine(bgTop+textWidth,bottom,y,item.LineColor);
}
else
{
var bgTop=y-textHeight/2-1*pixelTatio;
var textLeft=left + 1*pixelTatio
this.Canvas.fillRect(textLeft,bgTop,textWidth,textHeight);
this.Canvas.fillStyle = item.TextColor;
this.Canvas.fillText(item.Message[0], textLeft + 1*pixelTatio, y);
if (item.LineType!=-1) this.DrawDotLine(textLeft+textWidth,right,y,item.LineColor);
}
}
else
{
if (item.Font != null) this.Canvas.font = item.Font;
this.Canvas.textAlign = "right";
this.Canvas.textBaseline = "middle";
var textWidth = this.Canvas.measureText(item.Message[0]).width+2*pixelTatio;
this.Canvas.fillStyle=item.LineColor;
if (this.IsHScreen)
{
var bgTop=top-textWidth;
var textLeft=y-textHeight/2-1*pixelTatio;
this.Canvas.fillRect(textLeft,bgTop,textHeight,textWidth);
this.DrawHScreenText({X:y, Y:bgTop}, {Text:item.Message[0], Color:item.TextColor, XOffset:1*pixelTatio, YOffset:2*pixelTatio});
if (item.LineType!=-1) this.DrawDotLine(bgTop+textWidth,bottom,y,item.LineColor);
}
else
{
var bgTop=y-textHeight/2-1*pixelTatio;
this.Canvas.fillRect(left-textWidth,bgTop,textWidth,textHeight);
this.Canvas.fillStyle = item.TextColor;
this.Canvas.fillText(item.Message[0], left - 1*pixelTatio, y);
if (item.LineType!=-1) this.DrawDotLine(left,right,y,item.LineColor);
}
}
}
else if (item.Message[1]) //右
{
if (borderRight<10)
{
if (item.Font != null) this.Canvas.font = item.Font;
this.Canvas.textAlign = "left";
this.Canvas.textBaseline = "middle";
var textWidth = this.Canvas.measureText(item.Message[1]).width+2*pixelTatio;
var bgColor=item.LineColor;
var rgb=this.RGBToStruct(item.LineColor);
if (rgb) bgColor=`rgba(${rgb.R}, ${rgb.G}, ${rgb.B}, ${g_JSChartResource.FrameLatestPrice.BGAlpha})`; //内部刻度 背景增加透明度
this.Canvas.fillStyle=bgColor;
if (this.IsHScreen)
{
var bgTop=bottom-textWidth;
var textLeft=y-textHeight/2-1*pixelTatio;
this.Canvas.fillRect(textLeft,bgTop,textHeight,textWidth);
this.DrawHScreenText({X:y, Y:bgTop}, {Text:item.Message[1], Color:item.TextColor, XOffset:1*pixelTatio, YOffset:2*pixelTatio});
if (item.LineType!=-1) this.DrawDotLine(top,bgTop,y,item.LineColor);
}
else
{
var bgTop=y-textHeight/2-1*pixelTatio;
var textLeft=right-textWidth;
this.Canvas.fillRect(textLeft,bgTop,textWidth,textHeight); //文本背景区域
this.Canvas.fillStyle = item.TextColor;
this.Canvas.fillText(item.Message[1], textLeft + 1*pixelTatio, y);
if (item.LineType!=-1) this.DrawDotLine(left,textLeft,y,item.LineColor); //虚线
}
}
else
{
if (item.Font != null) this.Canvas.font = item.Font;
this.Canvas.textAlign = "left";
this.Canvas.textBaseline = "middle";
var textWidth = this.Canvas.measureText(item.Message[1]).width+2*pixelTatio;
this.Canvas.fillStyle=item.LineColor;
if (this.IsHScreen)
{
var bgTop=bottom;
var textLeft=y-textHeight/2-1*pixelTatio;
this.Canvas.fillRect(textLeft,bgTop,textHeight,textWidth);
this.DrawHScreenText({X:y, Y:bgTop}, {Text:item.Message[1], Color:item.TextColor, XOffset:1*pixelTatio, YOffset:2*pixelTatio});
if (item.LineType!=-1) this.DrawDotLine(top,bgTop,y,item.LineColor);
}
else
{
var bgTop=y-textHeight/2-1*pixelTatio;
this.Canvas.fillRect(right,bgTop,textWidth,textHeight);
this.Canvas.fillStyle = item.TextColor;
this.Canvas.fillText(item.Message[1], right + 1*pixelTatio, y);
if (item.LineType!=-1) this.DrawDotLine(left,right,y,item.LineColor);
}
}
}
}
this.DrawDotLine=function(left,right,y, color)
{
var pixelTatio = GetDevicePixelRatio();
this.Canvas.save();
this.Canvas.strokeStyle=color;
this.Canvas.setLineDash([5*pixelTatio,5*pixelTatio]); //虚线
this.Canvas.beginPath();
if (this.IsHScreen)
{
this.Canvas.moveTo(ToFixedPoint(y),left);
this.Canvas.lineTo(ToFixedPoint(y),right);
}
else
{
this.Canvas.moveTo(left,ToFixedPoint(y));
this.Canvas.lineTo(right,ToFixedPoint(y));
}
this.Canvas.stroke();
this.Canvas.restore();
}
this.DrawHScreenText=function(center,data)
{
this.Canvas.textAlign = "left";
this.Canvas.textBaseline = "middle";
this.Canvas.fillStyle = data.Color;
this.Canvas.save();
this.Canvas.translate(center.X, center.Y);
this.Canvas.rotate(90 * Math.PI / 180);
this.Canvas.fillText(data.Text, data.XOffset, data.YOffset);
this.Canvas.restore();
}
this.RGBToStruct=function(rgb)
{
if(/^(rgb|RGB)/.test(rgb))
{
var aColor = rgb.replace(/(?:\(|\)|rgb|RGB)*/g,"").split(",");
var result={};
if (aColor.length!=3) return null;
result.R = Number(aColor[0]);
result.G = Number(aColor[1]);
result.B = Number(aColor[2]);
return result;
}
return null;
}
}
function MinuteFrame()
{
this.newMethod=AverageWidthFrame; //派生
this.newMethod();
delete this.newMethod;
this.MinuteCount=243; //每天的分钟个数
this.IsBeforeData=false; //是否显示集合竞价
this.BeforeBGColor=g_JSChartResource.Minute.BeforeBGColor; //集合竞价背景
this.CustomHorizontalInfo=[];
this.RightFrame=null; //右侧多重坐标
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());
}
this.DrawCustomHorizontal=function() //Y轴刻度定制显示
{
for(var i in this.CustomHorizontalInfo)
{
var item=this.CustomHorizontalInfo[i];
switch(item.Type)
{
case 1:
this.DrawCustomItem(item); //自定义刻度
break;
}
}
}
}
function OverlayMinuteFrame()
{
this.newMethod=MinuteFrame; //派生
this.newMethod();
delete this.newMethod;
this.IsShow=true; //坐标是否显示
this.Draw=function()
{
this.SplitXYCoordinate();
if (this.IsShow)
{
}
this.SizeChange=false;
this.XYSplit=false;
}
}
//走势图 横屏框架
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 (x<this.ChartBorder.GetLeft()) return this.HorizontalMin;
if (x>this.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)<this.MinYDistance) continue; //两个坐标在近了 就不画了
this.Canvas.strokeStyle=item.LineColor;
this.Canvas.beginPath();
this.Canvas.moveTo(ToFixedPoint(y),top);
this.Canvas.lineTo(ToFixedPoint(y),bottom);
this.Canvas.stroke();
if (y >= 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.MinXDistance) 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 (x<testWidth/2)
{
this.Canvas.textAlign="left";
this.Canvas.textBaseline="top";
}
else if ((x + testWidth / 2) >= 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;
}
}
//Y刻度画在左边内部
this.DrawInsideHorizontal = function ()
{
if (this.IsShowYText[0]===false && this.IsShowYText[1]===false) return;
var left = this.ChartBorder.GetLeft();
var right = this.ChartBorder.GetRightEx();
var top=this.ChartBorder.GetTop();
var bottom=this.ChartBorder.GetBottom();
var borderTop=this.ChartBorder.Top;
var borderBottom=this.ChartBorder.Bottom;
var titleHeight = this.ChartBorder.TitleHeight;
var pixelTatio = GetDevicePixelRatio();
if ( (borderTop<10*pixelTatio && this.IsShowYText[0]===true) || (borderBottom<10*pixelTatio && 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 && borderTop < 10*pixelTatio && this.IsShowYText[0]===true)
{
if (item.Font != null) this.Canvas.font = item.Font;
this.Canvas.fillStyle = item.TextColor;
this.Canvas.textAlign = "left";
if (y >= right - 2) this.Canvas.textBaseline = 'top';
else if (y <= left + 2) this.Canvas.textBaseline = 'bottom';
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]}} ;
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();
}
if (item.Message[1] != null && borderBottom < 10*pixelTatio && this.IsShowYText[1]===true)
{
if (item.Font != null) this.Canvas.font = item.Font;
this.Canvas.fillStyle = item.TextColor;
this.Canvas.textAlign = "right";
if (y >= right - 2) this.Canvas.textBaseline = 'top';
else if (y <= left + 2) this.Canvas.textBaseline = 'bottom';
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]}} ;
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;
}
}
}
}
//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=[]; //定制Y轴刻度
this.IsDrawTitleBG=false;
this.CustomVerticalInfo=[]; //定制X轴刻度 Type:0, Date:, Time: , Line:{ Color:线段颜色, Type:线段类型 0 直线 1 虚线 }
// Type:1, Space: 第几个空白间距, Line:{ Color:线段颜色, Type:线段类型 0 直线 1 虚线 }
this.DrawCustomVerticalEvent;
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",""));
//JSConsole.Chart.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;
const modifyButton=`<span class='index_param icon iconfont icon-index_param' id='modifyindex' style='cursor:pointer;margin-left:2px;margin-right:2px;' title='调整指标参数'></span>`;
const changeButton=`<span class='index_change icon iconfont icon-change_index' id='changeindex' style='cursor:pointer;margin-left:2px;margin-right:2px;' title='切换指标'></span>`;
const overlayButton=`<span class='index_overlay icon iconfont icon-overlay_index' id='overlayindex' style='cursor:pointer;margin-left:2px;margin-right:2px;' title='叠加指标'></span>`;
const closeButton=`<span class='index_close icon iconfont icon-close' id='closeindex' style='cursor:pointer;margin-left:2px;margin-right:2px;' title='关闭指标窗口'></span>`;
var spanIcon=modifyButton+changeButton+overlayButton;
if (this.Identify!==0 && this.CloseIndex) //第1个窗口不能关闭
{
spanIcon+=closeButton;
}
//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<absIndex;++i)
{
offset-=(this.DistanceWidth+this.DataWidth);
}
}
}
else
{
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坐标转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(xPoint<right && index<10000) //自己算x的数值
{
if (xPoint>x) 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;
//JSConsole.Chart.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<ZOOM_SEED.length;++i)
{
if((ZOOM_SEED[i][0] + ZOOM_SEED[i][1]) * this.XPointCount < width)
{
this.ZoomIndex=i;
this.DataWidth = ZOOM_SEED[i][0];
this.DistanceWidth = ZOOM_SEED[i][1];
this.TrimKLineDataWidth(width);
JSConsole.Chart.Log('[KLineFrame::CalculateDataWidth] ZOOM_SEED, DataWidth, DistanceWidth, XPointCount', ZOOM_SEED[this.ZoomIndex], this.DataWidth,this.DistanceWidth,this.XPointCount);
return;
}
}
//太多了 就平均分了
this.ZoomIndex=ZOOM_SEED.length-1;
this.DataWidth=width/this.XPointCount;
this.DistanceWidth=0;
}
this.TrimKLineDataWidth=function(width)
{
var dataWidth=ZOOM_SEED[this.ZoomIndex][0];
var distanceWidth=ZOOM_SEED[this.ZoomIndex][1];
if (dataWidth==1 && distanceWidth==0)
{
this.DataWidth=width/this.XPointCount;
return;
}
while(true)
{
if((this.DistanceWidth + this.DataWidth) * this.XPointCount + this.DistanceWidth > 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;
//JSConsole.Chart.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;
//JSConsole.Chart.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<this.XPointCount)
{
this.Data.DataOffset=0;
cursorIndex.Index=lastCursorIndex;
}
else
{
this.Data.DataOffset = lastDataIndex - this.XPointCount+1;
cursorIndex.Index=lastCursorIndex-this.Data.DataOffset;
}
}
return true;
}
this.ZoomDown=function(cursorIndex)
{
if (this.ZoomIndex+1>=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;
//JSConsole.Chart.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;
//JSConsole.Chart.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: //最新价格刻度
case 1: //固定价格刻度
this.DrawCustomItem(item);
break;
}
}
}
this.DrawCustomVerticalItem=function(item)
{
this.Canvas.save();
if (item.Data.Line.Type==1) this.Canvas.setLineDash([5,5]); //虚线
this.Canvas.strokeStyle=item.Data.Line.Color;
this.Canvas.beginPath();
if (item.IsHScreen)
{
this.Canvas.moveTo(item.Top,ToFixedPoint(item.X));
this.Canvas.lineTo(item.Bottom,ToFixedPoint(item.X));
}
else
{
this.Canvas.moveTo(ToFixedPoint(item.X),item.Top);
this.Canvas.lineTo(ToFixedPoint(item.X),item.Bottom);
}
this.Canvas.stroke();
this.Canvas.restore();
}
this.DrawCustomVertical=function() //X轴定制刻度显示
{
if (!this.CustomVerticalInfo) return;
if (this.CustomVerticalInfo.length<=0) return;
if (!this.Data) return;
var isHScreen=this.IsHScreen;
var top=this.ChartBorder.GetTopEx();
var bottom=this.ChartBorder.GetBottomEx();
var dataWidth=this.DataWidth;
var distanceWidth=this.DistanceWidth;
var xOffset=this.ChartBorder.GetLeft()+distanceWidth/2.0+2.0;
if (isHScreen)
{
xOffset=this.ChartBorder.GetTop()+distanceWidth/2.0+2.0;
top=this.ChartBorder.GetLeftEx();
bottom=this.ChartBorder.GetRightEx();
}
var j=0;
for(var i=this.Data.DataOffset;i<this.Data.Data.length && j<this.XPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
{
var kItem=this.Data.Data[i];
for(var k in this.CustomVerticalInfo)
{
var item=this.CustomVerticalInfo[k];
if (item.Type!=0) continue;
if (IFrameSplitOperator.IsNumber(item.Time))
{
if (kItem.Date!=item.Date || kItem.Time!=item.Time) continue;
}
else
{
if (kItem.Date!=item.Date) continue;
}
var left=xOffset;
var right=xOffset+dataWidth;
var x=left+(right-left)/2;
var DrawData={X:x, Top:top, Bottom:bottom, Data:item , IsHScreen:isHScreen};
this.DrawCustomVerticalItem(DrawData);
if (this.DrawCustomVerticalEvent)
this.DrawCustomVerticalEvent.Callback(this.DrawCustomVerticalEvent, DrawData, this);
break;
}
}
for(var i=1;j<this.XPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
{
for(var k in this.CustomVerticalInfo)
{
var item=this.CustomVerticalInfo[k];
if (item.Type!=1) continue;
if (item.Space!=i) continue;
var left=xOffset;
var right=xOffset+dataWidth;
var x=left+(right-left)/2;
var DrawData={X:x, Top:top, Bottom:bottom, Data:item,IsHScreen:isHScreen };
this.DrawCustomVerticalItem(DrawData);
if (this.DrawCustomVerticalEvent)
this.DrawCustomVerticalEvent.Callback(this.DrawCustomVerticalEvent, DrawData, this);
break;
}
}
}
}
function OverlayKLineFrame()
{
this.newMethod=KLineFrame; //派生
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)<this.MinYDistance) continue; //两个坐标在近了 就不画了
if (y >= 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)<this.MinYDistance) 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;
}
}
//Y刻度画在左边内部
this.DrawInsideHorizontal = function ()
{
if (this.IsShowYText[0]===false && this.IsShowYText[1]===false) return;
var left = this.ChartBorder.GetLeft();
var right = this.ChartBorder.GetRightEx();
var top=this.ChartBorder.GetTop();
var bottom=this.ChartBorder.GetBottom();
var borderTop=this.ChartBorder.Top;
var borderBottom=this.ChartBorder.Bottom;
var titleHeight = this.ChartBorder.TitleHeight;
var pixelTatio = GetDevicePixelRatio();
if ( (borderTop<10*pixelTatio && this.IsShowYText[0]===true) || (borderBottom<10*pixelTatio && 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 && borderTop < 10*pixelTatio && this.IsShowYText[0]===true)
{
if (item.Font != null) this.Canvas.font = item.Font;
this.Canvas.fillStyle = item.TextColor;
this.Canvas.textAlign = "left";
if (y >= right - 2) this.Canvas.textBaseline = 'top';
else if (y <= left + 2) this.Canvas.textBaseline = 'bottom';
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]}} ;
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();
}
if (item.Message[1] != null && borderBottom < 10*pixelTatio && this.IsShowYText[1]===true)
{
if (item.Font != null) this.Canvas.font = item.Font;
this.Canvas.fillStyle = item.TextColor;
this.Canvas.textAlign = "right";
if (y >= right - 2) this.Canvas.textBaseline = 'top';
else if (y <= left + 2) this.Canvas.textBaseline = 'bottom';
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]}} ;
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 (x<testWidth/2)
{
this.Canvas.textAlign="left";
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;
}
}
//Y坐标转y轴数值
this.GetYData=function(x)
{
if (x<this.ChartBorder.GetLeftEx()) return this.HorizontalMin;
if (x>this.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;i<ZOOM_SEED.length;++i)
{
if((ZOOM_SEED[i][0] + ZOOM_SEED[i][1]) * this.XPointCount < width)
{
this.ZoomIndex=i;
this.DataWidth = ZOOM_SEED[i][0];
this.DistanceWidth = ZOOM_SEED[i][1];
if (i == 0) break; // 如果是最大的缩放因子,不再调整数据宽度
this.TrimKLineDataWidth(width);
return;
}
}
}
this.CalculateCount=function(zoomIndex) //计算当天的缩放比例下 一屏显示的数据个数
{
var width=this.ChartBorder.GetHeight();
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;
--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<this.XPointCount)
{
this.Data.DataOffset=0;
cursorIndex.Index=lastCursorIndex;
}
else
{
this.Data.DataOffset = lastDataIndex - this.XPointCount+1;
cursorIndex.Index=lastCursorIndex-this.Data.DataOffset;
}
}
return true;
}
this.ZoomDown=function(cursorIndex)
{
if (this.ZoomIndex+1>=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)<this.MinYDistance) continue; //两个坐标在近了 就不画了
if (y >= 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.Max<range.Max) value.Max=range.Max;
if (value.Min==null || value.Min>range.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.DrawCustomVertical=function(event)
{
for (var i in this.SubFrame)
{
var item = this.SubFrame[i];
item.Frame.DrawCustomVerticalEvent=event;
if (item.Frame.DrawCustomVertical) item.Frame.DrawCustomVertical();
}
}
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)
{
if (frame.RightFrame) outObject.RightYValue=frame.RightFrame.GetYData(y); //右侧子坐标
var yValue=frame.GetYData(y);
if (frame.YSplitOperator.CoordinateType==1) //百分比坐标 右边显示百分比信息
{
var firstOpenPrice=frame.YSplitOperator.GetFirstOpenPrice();
outObject.RightYValue=((yValue-firstOpenPrice)/firstOpenPrice*100).toFixed(2)+'%';
}
return yValue;
}
}
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;i<this.SubFrame.length;++i)
{
var item=this.SubFrame[i];
if (i>0) //第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;i<this.SubFrame.length;++i)
{
var item=this.SubFrame[i];
if (i>0) //第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; //mmhh 或者 mmhhss
this.FlowCapital=0; //流通股本
this.Position=null; //持仓量
//指数才有的数据
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; //日期
this.Position=null; //持仓量
}
//单指标数据
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.GetPosition=function()
{
var result=new Array();
for(var i in this.Data)
{
result[i]=this.Data[i].Position;
}
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.High<minData.High)
newData.High=minData.High;
if (newData.Low>minData.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.High<minData.High) newData.High=minData.High;
if (newData.Low>minData.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 weekCount=2;
var newData=null;
for(var i in this.Data)
{
var isNewData=false;
var dayData=this.Data[i];
switch(period)
{
case 1: //周线
if (isBit) var fridayDate=ChartData.GetSunday(dayData.Date); //数字货币全年的
else var fridayDate=ChartData.GetFirday(dayData.Date);
if (fridayDate!=startDate)
{
isNewData=true;
startDate=fridayDate;
}
break;
case 21: //双周
if (isBit) var fridayDate=ChartData.GetSunday(dayData.Date); //数字货币全年的
else var fridayDate=ChartData.GetFirday(dayData.Date);
if (fridayDate!=startDate)
{
++weekCount;
if (weekCount>=2)
{
isNewData=true;
weekCount=0;
}
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.High<dayData.High) newData.High=dayData.High;
if (newData.Low>dayData.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.High<dayData.High) newData.High=dayData.High;
if (newData.Low>dayData.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==21 || (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<this.Data.length;++index)
{
if (close!=this.Data[index].YClose) break;
result[index]=HistoryData.Copy(this.Data[index]);
close=this.Data[index].Close;
}
for(;index<this.Data.length;++index)
{
if(close!=this.Data[index].YClose)
seed *= close/this.Data[index].YClose;
result[index]=HistoryData.CopyRight(this.Data[index],seed);
close=this.Data[index].Close;
}
}
return result;
}
this.GetRightData=this.GetRightDate;
//叠加数据和主数据拟合,去掉主数据没有日期的数据
this.GetOverlayData=function(overlayData)
{
var result=[];
for(var i=0,j=0;i<this.Data.length;)
{
var date=this.Data[i].Date;
if (j>=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<date)
{
++j;
}
else
{
result[i]=new HistoryData();
result[i].Date=date;
++i;
}
}
return result;
}
this.GetOverlayMinuteData=function(overlayData)
{
var result=[];
for(var i=0,j=0;i<this.Data.length;)
{
var date=this.Data[i].Date;
var time=this.Data[i].Time;
if (j>=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<date || (overlayDate==date && overlayTime<time))
{
++j;
}
else
{
result[i]=new HistoryData();
result[i].Date=date;
result[i].Time=time;
++i;
}
}
return result;
}
/*
技术指标数据方法
*/
//以主图数据 拟合,返回 SingleData 数组
this.GetFittingData=function(overlayData)
{
var result=new Array();
for(var i=0,j=0;i<this.Data.length;)
{
var date=this.Data[i].Date;
if (j>=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<date)
{
++j;
}
else
{
result[i]=new SingleData();
result[i].Date=date;
++i;
}
}
return result;
}
// 缺省数据使用 emptyValue填充
this.GetFittingData2=function(overlayData,emptyValue)
{
var result=new Array();
for(var i=0,j=0;i<this.Data.length;)
{
var date=this.Data[i].Date;
if (j>=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<date)
{
++j;
}
else
{
result[i]=new SingleData();
result[i].Date=date;
result[i].Value=emptyValue;
++i;
}
}
return result;
}
//日期转化 对应数据索引
this.GetDateIndex=function(data)
{
for(var i=0,j=0;i<this.Data.length;)
{
var date=this.Data[i].Date;
if (j>=data.length) break;
var dateItem=data[j];
if (dateItem.Date==date)
{
dateItem.Index=i;
++j;
}
else if (dateItem.Date<date)
{
++j;
}
else
{
++i;
}
}
}
//日期 时间转化 对应数据索引
this.GetDateTimeIndex=function(data)
{
for(var i=0,j=0;i<this.Data.length;)
{
var date=this.Data[i].Date;
var time=this.Data[i].Time;
if (j>=data.length) break;
var dateTimeItem=data[j];
if (dateTimeItem.Date==date && dateTimeItem.Time==time)
{
dateTimeItem.Index=i;
++j;
}
else if (dateTimeItem.Date<date || (dateTimeItem.Date==date && dateTimeItem.Time<time))
{
++j;
}
else
{
++i;
}
}
}
// 分钟数据拟合
this.GetMinuteFittingData=function(overlayData)
{
var result=[];
for(var i=0,j=0;i<this.Data.length;)
{
var date=this.Data[i].Date;
var time=this.Data[i].Time;
if (j>=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<date || (overlayDate==date && overlayTime<time))
{
++j;
}
else
{
var item=new SingleData();
item.Date=date;
item.Time=time;
result[i]=item;
++i;
}
}
return result;
}
//把财报数据拟合到主图数据,返回 SingleData 数组
this.GetFittingFinanceData=function(financeData)
{
var result=[];
for(var i=0,j=0;i<this.Data.length;)
{
var date=this.Data[i].Date;
if (j+1<financeData.length)
{
if (financeData[j].Date<date && financeData[j+1].Date<=date)
{
++j;
continue;
}
}
var item=new SingleData();
item.Date=date;
if (j<financeData.length)
{
item.Value=financeData[j].Value;
item.FinanceDate=financeData[j].Date; //财务日期 调试用
}
else
{
item.Value=null;
item.FinanceDate=null;
}
result[i]=item;
++i;
}
return result;
}
//财务数据拟合到分钟数据上 返回 SingleData 数组
this.GetMinuteFittingFinanceData=function(financeData)
{
var result=[];
for(var i=0,j=0;i<this.Data.length;)
{
var date=this.Data[i].Date;
var time=this.Data[i].Time;
if (j+1<financeData.length)
{
if (financeData[j].Date<date && financeData[j+1].Date<=date)
{
++j;
continue;
}
}
var item=new SingleData();
item.Date=date;
item.Time=time;
if (j<financeData.length)
{
item.Value=financeData[j].Value;
item.FinanceDate=financeData[j].Date; //财务日期 调试用
}
else
{
item.Value=null;
item.FinanceDate=null;
}
result[i]=item;
++i;
}
return result;
}
//市值计算 financeData.Value 是股数
this.GetFittingMarketValueData=function(financeData)
{
var result=[];
for(var i=0,j=0;i<this.Data.length;)
{
var date=this.Data[i].Date;
var price=this.Data[i].Close;
if (j+1<financeData.length)
{
if (financeData[j].Date<date && financeData[j+1].Date<=date)
{
++j;
continue;
}
}
var item=new SingleData();
item.Date=date;
item.Value=financeData[j].Value*price; //市值计算 收盘价*股数
item.FinanceDate=financeData[j].Date; //财务日期 调试用
result[i]=item;
++i;
}
return result;
}
//月线数据拟合
this.GetFittingMonthData=function(overlayData)
{
var result=new Array();
var preDate=null;
for(var i=0,j=0;i<this.Data.length;)
{
var date=this.Data[i].Date;
if (j>=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 && preDate<overlayDate && date>overlayDate)
{
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<date)
{
++j;
}
else
{
result[i]=new SingleData();
result[i].Date=date;
++i;
}
preDate=date;
}
return result;
}
this.GetValue=function()
{
var result=[];
for(var i in this.Data)
{
if (this.Data[i] && this.Data[i].Value!=null)
{
var item=this.Data[i].Value;
if (!isNaN(item))
result[i]=item;
else if (item instanceof Array) //支持数组
result[i]=item;
else
result[i]=null;
}
else
result[i]=null;
}
return result;
}
this.GetObject=function()
{
var result=[];
for(var i in this.Data)
{
if (this.Data[i] && this.Data[i].Value)
{
var item=this.Data[i].Value;
result[i]=item;
}
else
result[i]=null;
}
return result;
}
this.GetPeriodSingleData=function(period)
{
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];
if (dayData==null || dayData.Date==null) continue;
switch(period)
{
case 1: //周线
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 SingleData();
newData.Date=dayData.Date;
newData.Value=dayData.Value;
result.push(newData);
}
else
{
if (newData==null) continue;
if (dayData.Value==null || isNaN(dayData.Value)) continue;
if (newData.Value==null || isNaN(newData.Value)) newData.Value=dayData.Value;
}
}
return result;
}
/*
分钟数据方法
this.GetClose() 每分钟价格
this.GetVol() 每分钟成交量
*/
//分钟均线
this.GetMinuteAvPrice=function()
{
var result=new Array();
for(var i in this.Data)
{
result[i]=this.Data[i].AvPrice;
}
return result;
}
this.MergeMinuteData=function(data) //合并数据
{
var sourceFirstItem=this.Data[0];
var firstItemID=0;
var firstItem=null;
for(var i=0;i<data.length;++i) //查找比原始数据起始位置大的数据位置
{
var item=data[i];
if (item.Date>=sourceFirstItem.Date && item.Time>=sourceFirstItem.Time)
{
firstItemID=i;
firstItem=item;
break;
}
}
if (firstItem==null) return false;
var index=null;
var bFind=false; //第1个数据是否完全匹配
for(var i=this.Data.length-1; i>=0;--i)
{
var date=this.Data[i].Date;
var time=this.Data[i].Time;
if (firstItem.Date>=date && firstItem.Time>=time)
{
index=i;
if (firstItem.Date==date && firstItem.Time==time) bFind=true;
break;
}
}
if (index==null) return false;
var j=index; //原始数据插入位置
var i=firstItemID; //合并数据起始位置
if (bFind==true) //第1个数据匹配,覆盖
{
var item=data[i];
if (j-1>0 && !item.YClose) item.YClose=this.Data[j-1].Close; //前收盘如果没有就是上一记录的收盘
var newItem=HistoryData.Copy(item);
this.Data[j]=newItem;
++j;
++i;
}
else //从下一个数据开始插入
{
++j;
}
for(;i<data.length; )
{
var item=data[i];
if (j>=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;
}
}
}
//JSConsole.Chart.Log('[ChartData::MergeMinuteData] ', this.Data, data);
return true;
}
this.CoverTo=function(data, curPeriod, changePeriod) //把数据用data, 日期时间不变, curPeriod=当前周期 changePeriod=需要转换周期
{
var result=[];
var tempItem=null;
var isMinute=ChartData.IsMinutePeriod(curPeriod,true);
var isMinute2=ChartData.IsMinutePeriod(changePeriod,true);
var isMimToMin=isMinute && isMinute2;
var isMinToDay=isMinute && !isMinute2;
var isDayToDay=!isMinute && !isMinute2;
for(var i=0,j=0; i<this.Data.length; ++i)
{
var item=this.Data[i]; //原始数据
for(;j<data.length;++j)
{
var periodItem=data[j];
if (isMimToMin) //都是分钟数据
{
if (periodItem.Date==item.Date && periodItem.Time>=item.Time)
{
tempItem=periodItem;
break;
}
}
else if (isMinToDay || isDayToDay) //分钟 => 日线, 日线 => 日线
{
if (periodItem.Date>=item.Date)
{
tempItem=periodItem;
break;
}
}
}
var newItem=null;
if (tempItem)
{
newItem=HistoryData.Copy(tempItem);
newItem.PDate=tempItem.Date;
newItem.PTime=tempItem.Time;
}
else newItem=new HistoryData();
newItem.Date=item.Date;
if (isMimToMin && isMinToDay) newItem.Time=item.Time;
result.push(newItem);
}
JSConsole.Chart.Log('[ChartData::CoverTo] result', result);
return result;
}
this.GetRef=function(n)
{
let result=[];
for(var i=0 ;i<this.Data.length; ++i )
{
result[i]=null;
var itemDate=this.Data[i]; //原始数据
if (i-n<0)
{
var newData=new HistoryData();
newData.Date=itemDate.Date;
newData.Time=itemDate.Time;
result[i]=newData;
continue;
}
var itemData=this.Data[i-n];
var newData=HistoryData.Copy(itemData);
newData.Date=itemDate.Date;
newData.Time=itemDate.Time;
result[i]=newData;
}
return result;
}
}
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=季线 21=双周 [40001-50000) 自定义日线 (isIncludeBase 是否包含基础日线周期)
var CUSTOM_DAY_PERIOD_START=40000, CUSTOM_DAY_PERIOD_END=49999;
ChartData.IsDayPeriod=function(period, isIncludeBase)
{
if (period==1 || period==2 || period==3 || period==9 || period==21) 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=29999;
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;
}
//是否是秒周期 [30001-32000)
var CUSTOM_SECOND_PERIOD_START=30000, CUSTOM_SECOND_PERIOD_END=32000;
ChartData.IsSecondPeriod=function(period)
{
if (period>CUSTOM_SECOND_PERIOD_START && period<=CUSTOM_SECOND_PERIOD_END) return true;
return false;
}
//是否是分笔图 10=分笔
ChartData.IsTickPeriod=function(period)
{
return period==10;
}
//获取周期名字
ChartData.GetPeriodName=function(period)
{
var mapName=new Map(
[
[0, '日线'],[1, '周线'],[2, '月线'],[3, '年线'],[9, '季线'], [21,'双周'],
[4, '1分'], [5, '5分'], [6, '15分'],[7, '30分'],[8, '60分'],[11, '2小时'],[12, '4小时'],
[10, '分笔']
]);
if (mapName.has(period)) return mapName.get(period);
return '';
}
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;i<this.Data.Data.length && j<xPointCount;++i,++j)
{
var value=this.Data.Data[i];
if (value==null || isNaN(value)) continue;
if (range.Max==null) range.Max=value;
if (range.Min==null) range.Min=value;
if (range.Max<value) range.Max=value;
if (range.Min>value) 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;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
{
var data=this.Data.Data[i];
if (data.Open==null || data.High==null || data.Low==null || data.Close==null) 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);
if (ptMax.Value==null || ptMax.Value<data.High) //求最大值
{
ptMax.X=x;
ptMax.Y=yHigh;
ptMax.Value=data.High;
ptMax.Align=j<xPointCount/2?'left':'right';
}
if (ptMin.Value==null || ptMin.Value>data.Low) //求最小值
{
ptMin.X=x;
ptMin.Y=yLow;
ptMin.Value=data.Low;
ptMin.Align=j<xPointCount/2?'left':'right';
}
if (data.Open<data.Close) this.Canvas.strokeStyle=this.UpColor; //阳线
else if (data.Open>data.Close) this.Canvas.strokeStyle=this.DownColor; //阳线
else this.Canvas.strokeStyle=this.UnchagneColor; //平线
if (this.ColorData) ///五彩K线颜色设置
{
if (i<this.ColorData.length)
upColor=downColor=unchagneColor=(this.ColorData[i]>0?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;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
{
var data=this.Data.Data[i];
if (data.Open==null || data.High==null || data.Low==null || data.Close==null) continue;
var left=xOffset;
var right=xOffset+dataWidth;
if (right>chartright) 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;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
{
var data=this.Data.Data[i];
if (data.Open==null || data.High==null || data.Low==null || data.Close==null) continue;
var left=xOffset;
var right=xOffset+dataWidth;
if (right>chartright) 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;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
{
var data=this.Data.Data[i];
if (data.Open==null || data.High==null || data.Low==null || data.Close==null) 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 (ptMax.Value==null || ptMax.Value<data.High) //求最大值
{
ptMax.X=x;
ptMax.Y=yHigh;
ptMax.Value=data.High;
ptMax.Align=j<xPointCount/2?'left':'right';
}
if (ptMin.Value==null || ptMin.Value>data.Low) //求最小值
{
ptMin.X=x;
ptMin.Y=yLow;
ptMin.Value=data.Low;
ptMin.Align=j<xPointCount/2?'left':'right';
}
if (this.ColorData) ///五彩K线颜色设置
{
if (i<this.ColorData.length)
upColor=downColor=unchagneColor=(this.ColorData[i]>0?this.UpColor:this.DownColor);
else
upColor=downColor=unchagneColor=this.DownColor;
}
if (data.Open<data.Close) //阳线
{
if (dataWidth>=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;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
{
var data=this.Data.Data[i];
if (data.Open==null || data.High==null || data.Low==null || data.Close==null) continue;
var buy=false,sell=false;
if (sellData && i<sellData.length) sell=sellData[i]>0;
if (buyData && i<buyData.length) buy=buyData[i]>0;
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;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
{
var data=this.Data.Data[i];
if (data.Open==null || data.High==null || data.Low==null || data.Close==null) continue;
var left=xOffset;
var right=xOffset+dataWidth;
if (right>chartright) 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<ptMax.Y) ptBottom=ptMax;
this.Canvas.textAlign=ptBottom.Align;
this.Canvas.textBaseline='top';
var left=ptBottom.Align=='left'?ptBottom.X:ptBottom.X;
var text=ptMin.Value.toFixed(defaultfloatPrecision);
if (ptBottom.Align=='left') text='←'+text;
else text=text+'→';
this.Canvas.fillText(text,left,ptBottom.Y);
this.ChartFrame.ChartKLine.Min={X:left, Y:ptBottom.Y, Text:{ BaseLine:'top'}};
}
this.HScreenDrawMaxMinPrice=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);
var xText=ptMax.Y;
var yText=ptMax.X;
this.Canvas.save();
this.Canvas.translate(xText, yText);
this.Canvas.rotate(90 * Math.PI / 180);
this.Canvas.font=this.TextFont;
this.Canvas.fillStyle=this.TextColor;
this.Canvas.textAlign=ptMax.Align;
this.Canvas.textBaseline='bottom';
var text=ptMax.Value.toFixed(defaultfloatPrecision);
if (ptMax.Align=='left') text='←'+text;
else text=text+'→';
this.Canvas.fillText(text,0,0);
this.Canvas.restore();
var xText=ptMin.Y;
var yText=ptMin.X;
this.Canvas.save();
this.Canvas.translate(xText, yText);
this.Canvas.rotate(90 * Math.PI / 180);
this.Canvas.font=this.TextFont;
this.Canvas.fillStyle=this.TextColor;
this.Canvas.textAlign=ptMin.Align;
this.Canvas.textBaseline='top';
var text=ptMin.Value.toFixed(defaultfloatPrecision);
if (ptMin.Align=='left') text='←'+text;
else text=text+'→';
this.Canvas.fillText(text,0,0);
this.Canvas.restore();
}
//画某一天的信息地雷
this.DrawInfo=function(item)
{
if (!this.InfoData || this.InfoData.length<=0) return;
var isHScreen=(this.ChartFrame.IsHScreen===true);
var dataWidth=this.ChartFrame.DataWidth;
var distanceWidth=this.ChartFrame.DistanceWidth;
var bottom=this.ChartBorder.GetBottom();
var infoData=this.InfoData.get(item.DayData.Date.toString());
if (!infoData || infoData.Data.length<=0) return;
var pixelTatio = GetDevicePixelRatio(); //获取设备的分辨率
var iconSize=dataWidth+distanceWidth;
var minIconSize=18*pixelTatio;
var bShowNum=true;
if (iconSize<=15) bShowNum=false;
if (iconSize<minIconSize) iconSize=minIconSize;
var text='', title='';
var mapImage=new Map();
var iconTop=item.YMax+1*pixelTatio;
var yOffset=0;
for(var i in infoData.Data)
{
var infoItem=infoData.Data[i];
var imageInfo=mapImage.get(infoItem.InfoType);
if (!imageInfo)
{
var icon=JSKLineInfoMap.GetIconFont(infoItem.InfoType);
this.Canvas.fillStyle=icon.Color;
this.Canvas.font=iconSize+'px '+icon.Family;
if (isHScreen)
{
this.Canvas.textBaseline="middle";
this.Canvas.textAlign="left";
this.Canvas.fillText(icon.HScreenText,iconTop,item.XCenter,iconSize);
var iconRect=new Rect(item.XCenter-iconSize/2,iconTop-iconSize,iconSize,iconSize);
infoCache={ Data:new Array(infoItem), Rect:iconRect, Type:infoItem.InfoType, TextRect:{X:iconTop, Y:item.XCenter} };
mapImage.set(infoItem.InfoType,infoCache);
iconTop+=iconSize;
}
else
{
this.Canvas.textBaseline="bottom";
this.Canvas.textAlign="center";
if (this.InfoPosition===1)
{
var yBottom=bottom+yOffset;
this.Canvas.fillText(icon.Text,item.XCenter,yBottom,iconSize);
var iconRect=new Rect(item.XCenter-iconSize/2,yBottom-iconSize,iconSize,iconSize);
var infoCache={ Data:new Array(infoItem), Rect:iconRect, Type:infoItem.InfoType, TextRect:{X:item.XCenter, Y:yBottom} };
mapImage.set(infoItem.InfoType,infoCache);
yOffset-=iconSize;
}
else
{
this.Canvas.fillText(icon.Text,item.XCenter,iconTop,iconSize);
var iconRect=new Rect(item.XCenter-iconSize/2,iconTop-iconSize,iconSize,iconSize);
var infoCache={ Data:new Array(infoItem), Rect:iconRect, Type:infoItem.InfoType, TextRect:{X:item.XCenter, Y:iconTop} };
mapImage.set(infoItem.InfoType,infoCache);
iconTop-=iconSize;
}
}
}
else
{
imageInfo.Data.push(infoItem);
}
}
var numText;
if (g_JSChartResource.KLine.NumIcon)
{
if (isHScreen) numText=g_JSChartResource.KLine.NumIcon.HScreenText;
else numText=g_JSChartResource.KLine.NumIcon.Text;
}
for(var item of mapImage)
{
var value=item[1];
if (value.Data.length>=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 (iconSize<iconSizeMin) iconSize=iconSizeMin;
else if (iconSize>iconSizeMax) iconSize=iconSizeMax;
this.Canvas.font=iconSize+'px '+this.TradeIcon.Family;
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
{
var data=this.Data.Data[i];
if (data.Open==null || data.High==null || data.Low==null || data.Close==null) continue;
var buy=false,sell=false;
if (sellData && i<sellData.length) sell=sellData[i]>0;
if (buyData && i<buyData.length) buy=buyData[i]>0;
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))
{
//JSConsole.Chart.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;
if (this.DrawType==1 || this.DrawType==4 ) // 1=收盘价线 4=收盘价面积图
{
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j)
{
var data=this.Data.Data[i];
if (!IFrameSplitOperator.IsNumber(data.Close)) continue;
if (range.Max==null) range.Max=data.Close;
if (range.Min==null) range.Min=data.Close;
if (range.Max<data.Close) range.Max=data.Close;
if (range.Min>data.Close) range.Min=data.Close;
}
}
else
{
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j)
{
var data=this.Data.Data[i];
if (data.Open==null || data.High==null || data.Low==null || data.Close==null) continue;
if (range.Max==null) range.Max=data.High;
if (range.Min==null) range.Min=data.Low;
if (range.Max<data.High) range.Max=data.High;
if (range.Min>data.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;i<this.Data.Data.length && j<xPointCount;++i,++j)
{
var data=this.Data.Data[i];
if (data.Open==null || data.High==null || data.Low==null || data.Close==null) continue;
var value=data.Close;
setPrice.add(value);
}
var aryPrice=[];
for(var item of setPrice)
{
aryPrice.push(item);
}
aryPrice.sort(function(a,b) { return a-b; }); //排序 升序
return aryPrice;
}
}
//K线叠加 支持横屏
var OVERLAY_STATUS_ID=
{
STATUS_NONE_ID:0, //空闲状态
STATUS_REQUESTDATA_ID:1, //请求数据
STATUS_RECVDATA_ID:2, //接收到数据
STATUS_FINISHED_ID:3, //数据下载完成
};
function ChartOverlayKLine()
{
this.newMethod=IChartPainting; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartOverlayKLine'; //类名
this.Color="rgb(65,105,225)";
this.MainData; //主图K线数据
this.SourceData; //叠加的原始数据
this.Title;
this.DrawType=0;
this.CustomDrawType=null; //图形类型
this.Status=OVERLAY_STATUS_ID.STATUS_NONE_ID;
this.IsDelete=false; //是否已经删除
this.SetOption=function(option)
{
if (!option) return;
if (IFrameSplitOperator.IsNumber(option.DrawType)) this.CustomDrawType=option.DrawType;
}
this.DrawKBar=function(firstOpen) //firstOpen 当前屏第1个显示数据
{
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 drawType=this.DrawType;
if (this.CustomDrawType!=null) drawType=this.CustomDrawType;
var isFristDraw=true;
var firstOverlayOpen=null;
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
{
var data=this.Data.Data[i];
if (!data || data.Open==null || data.High==null || data.Low==null || data.Close==null) continue;
if (firstOverlayOpen==null) firstOverlayOpen=data.Open;
if (isFristDraw)
{
this.Canvas.strokeStyle=this.Color;
this.Canvas.fillStyle=this.Color;
this.Canvas.beginPath();
isFristDraw=false;
}
var left=xOffset;
var right=xOffset+dataWidth;
if (right>chartright) 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<data.Close) //阳线
{
if (dataWidth>=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;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
{
var data=this.Data.Data[i];
if (data.Open==null || data.High==null || data.Low==null || data.Close==null) continue;
if (firstOverlayOpen==null) firstOverlayOpen=data.Open;
var left=xOffset;
var right=xOffset+dataWidth;
if (right>chartright) 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;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
{
var data=this.Data.Data[i];
if (data.Open==null || data.High==null || data.Low==null || data.Close==null) continue;
if (firstOverlayOpen==null) firstOverlayOpen=data.Open;
var left=xOffset;
var right=xOffset+dataWidth;
if (right>chartright) 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;i<this.MainData.Data.length && j<xPointCount;++i,++j)
{
var data=this.MainData.Data[i];
if (data.Open==null || data.High==null || data.Low==null || data.Close==null) continue;
firstOpen=data.Open;
break;
}
if (firstOpen==null) return;
var drawType=this.DrawType;
if (this.CustomDrawType!=null) drawType=this.CustomDrawType;
if (drawType==1) this.DrawCloseLine(firstOpen);
else if (drawType==2) this.DrawAKLine(firstOpen);
else this.DrawKBar(firstOpen);
}
this.GetMaxMin=function()
{
var xPointCount=this.ChartFrame.XPointCount;
var range={};
range.Max=null;
range.Min=null;
if (!this.MainData || !this.Data) return range;
var firstOpen=null; //主线数据第1个收盘价
for(var i=this.Data.DataOffset,j=0;i<this.MainData.Data.length && j<xPointCount;++i,++j)
{
var data=this.MainData.Data[i];
if (data.Open==null || data.High==null || data.Low==null || data.Close==null) continue;
firstOpen=data.Close;
break;
}
if (firstOpen==null) return range;
var firstOverlayOpen=null;
var high,low;
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j)
{
var data=this.Data.Data[i];
if (!data || data.Open==null || data.High==null || data.Low==null || data.Close==null) continue;
if (firstOverlayOpen==null) firstOverlayOpen=data.Open;
high=data.High/firstOverlayOpen*firstOpen;
low=data.Low/firstOverlayOpen*firstOpen;
if (range.Max==null) range.Max=high;
if (range.Min==null) range.Min=low;
if (range.Max<high) range.Max=high;
if (range.Min>low) 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;i<data.Data.length && j<xPointCount;++i,++j)
{
var item = data.Data[i];
var vol=null;
if (!item) continue;
var price=null;
if (item.Before)
{
vol=item.Before.Vol;
price=item.Before.Close;
}
else
{
vol=item.Vol;
price=item.Close;
}
if (!vol) continue;
var y=this.ChartFrame.GetYFromData(vol);
var x=this.ChartFrame.GetXFromIndex(i);
if (x>chartright) 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;i<this.Data.Data.length && j<xPointCount;++i,++j)
{
var item = this.Data.Data[i];
if (!item || !item.Vol) continue;
if (range.Max == null) range.Max = item.Vol;
if (range.Max < item.Vol) range.Max = item.Vol;
}
return range;
}
}
function ChartErrorMessage()
{
this.newMethod=IChartPainting; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartErrorMessage'; //类名
this.Draw=function()
{
if (!this.IsShow) return;
if (this.NotSupportMessage) this.DrawNotSupportmessage();
}
}
//线段 支持横屏
function ChartLine()
{
this.newMethod=IChartPainting; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartLine'; //类名
this.Color="rgb(255,193,37)"; //线段颜色
this.LineWidth; //线段宽度
this.DrawType=0; //画图方式 0=无效数平滑 1=无效数不画断开
this.IsDotLine=false; //虚线
this.Draw=function()
{
if (!this.IsShow)
return;
if (this.NotSupportMessage)
{
this.DrawNotSupportmessage();
return;
}
if (!this.Data || !this.Data.Data) return;
switch(this.DrawType)
{
case 0:
return this.DrawLine();
case 1:
return this.DrawStraightLine();
}
}
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;
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j)
{
var value=this.Data.Data[i];
if (value==null) continue;
var x=this.ChartFrame.GetXFromIndex(j);
var y=this.ChartFrame.GetYFromData(value);
if (x>chartright) 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;i<this.Data.Data.length && j<xPointCount;++i,++j)
{
var value=this.Data.Data[i];
if (value==null)
{
if (drawCount>0) 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;i<this.Data.Data.length && j<xPointCount;++i,++j)
{
var item=this.Data.Data[i];
if (item==null) continue;
var value=item.Value;
if (value==null) continue;
var color=item.RGB;
var x=this.ChartFrame.GetXFromIndex(j);
var y=this.ChartFrame.GetYFromData(value);
if (x>chartright) 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;i<this.Data.Data.length && j<xPointCount;++i,++j)
{
var item = this.Data.Data[i];
if (!item || !item.Value) continue;
if (range.Max == null || range.Max<item.Value) range.Max = item.Value;
if (range.Min == null || range.Min>item.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;i<this.Data.Data.length && j<xPointCount;++i,++j)
{
var value=this.Data.Data[i];
if (value==null) continue;
var x=this.ChartFrame.GetXFromIndex(j);
var y=this.ChartFrame.GetYFromData(value);
if (x>chartright) 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;i<this.Data.Data.length && j<xPointCount;++i,++j)
{
var value=this.Data.Data[i];
if (value==null) continue;
var x=this.ChartFrame.GetXFromIndex(j);
var y=this.ChartFrame.GetYFromData(value);
if (x>chartright) 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;i<this.Data.Data.length && j<xPointCount;++i,++j)
{
var value=this.Data.Data[i];
if (value==null) continue;
var x=this.ChartFrame.GetXFromIndex(j);
var y=this.ChartFrame.GetYFromData(value);
if (x>chartright) 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;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
{
var value=this.Data.Data[i];
var kItem=this.HistoryData.Data[i];
if (value==null || kItem==null) continue;
var left=xOffset;
var right=xOffset+dataWidth;
if (right>chartright) 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;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
{
var value=this.Data.Data[i];
var kItem=this.HistoryData.Data[i];
if (value==null || kItem==null) continue;
var y=this.ChartFrame.GetYFromData(value);
var x=this.ChartFrame.GetXFromIndex(j);
if (x>chartright) 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;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
{
var value=this.Data.Data[i];
var kItem=this.HistoryData.Data[i];
if (value==null || kItem==null) continue;
var left=xOffset;
var right=xOffset+dataWidth;
if (right>chartBottom) 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;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
{
var value=this.Data.Data[i];
var kItem=this.HistoryData.Data[i];
if (value==null || kItem==null) continue;
var y=this.ChartFrame.GetYFromData(value);
var x=this.ChartFrame.GetXFromIndex(j);
if (x>chartBottom) 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;i<this.Data.Data.length && j<xPointCount;++i,++j)
{
var value=this.Data.Data[i];
if (range.Max==null) range.Max=value;
if (range.Max<value) range.Max=value;
}
return range;
}
}
//线段 多数据(一个X点有多条Y数据) 支持横屏
function ChartLineMultiData()
{
this.newMethod=IChartPainting; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartLineMultiData'; //类名
this.Color="rgb(255,193,37)"; //线段颜色
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 bFirstPoint=true;
var drawCount=0;
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j)
{
var aryValue=this.Data.Data[i];
if (aryValue==null) continue;
var x=this.ChartFrame.GetXFromIndex(j);
if (x>chartright) 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;i<this.Data.Data.length && j<xPointCount;++i,++j)
{
var aryValue=this.Data.Data[i];
if (aryValue==null) continue;
for(var index in aryValue)
{
var value=aryValue[index].Value;
if (range.Max==null) range.Max=value;
if (range.Min==null) range.Min=value;
if (range.Max<value) range.Max=value;
if (range.Min>value) 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 (dataWidth<LineWidth) LineWidth=parseInt(dataWidth);
this.Canvas.lineWidth=LineWidth;
this.Canvas.strokeStyle=this.Color;
}
else
{
bFillBar=true;
this.Canvas.fillStyle=this.Color;
var fixedWidth=2*GetDevicePixelRatio();
}
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
{
var value=this.Data.Data[i];
if (value==null) continue;
var price=value.Value;
var price2=value.Value2;
if (price2==null) price2=0;
var x=this.ChartFrame.GetXFromIndex(j);
var y=this.ChartFrame.GetYFromData(price);
var y2=this.ChartFrame.GetYFromData(price2);
if (x>chartright) 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;i<this.Data.Data.length && j<xPointCount;++i,++j)
{
var data=this.Data.Data[i];
if (data == null) continue;
var value2=data.Value2;
if (value2==null) value2=0;
if (data==null || isNaN(data.Value) ||isNaN(value2)) continue;
var valueMax=Math.max(data.Value,value2);
var valueMin=Math.min(data.Value,value2);
if (range.Max==null) range.Max=valueMax;
if (range.Min==null) range.Min=valueMin;
if (range.Max<valueMax) range.Max=valueMax;
if (range.Min>valueMin) 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.Max<value) range.Max=value;
if (range.Min>value) 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 (iconSize<minIconSize) iconSize=minIconSize;
else if (iconSize>maxIconSize) 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;i<this.Data.Data.length && j<xPointCount;++i,++j)
{
var value=this.Data.Data[i];
if (value==null) continue;
var x=this.ChartFrame.GetXFromIndex(j);
var y=this.ChartFrame.GetYFromData(value);
if (x>chartright) 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
{
//JSConsole.Chart.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.Max<valueMax) range.Max=valueMax;
if (range.Min>valueMin) 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();
if (!data) return;
var bFirstPoint=true;
var ptFirst={}; //第1个点
var drawCount=0;
for(var i=data.DataOffset,j=0;i<data.Data.length && j<xPointCount;++i,++j)
{
var value=null;
if (isBeforeData)
{
var item=data.Data[i];
if (item.Before) value=item.Before.Close;
else value=item.Close;
}
else
{
value=data.Data[i];
}
if (value==null) continue;
var x=this.ChartFrame.GetXFromIndex(j);
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;
ptFirst={X:x,Y:y};
}
else
{
if (isHScreen) this.Canvas.lineTo(y,x);
else this.Canvas.lineTo(x,y);
}
++drawCount;
if (drawCount>=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;i<data.Data.length && j<xPointCount;++i,++j)
{
var value=data.Data[i];
if (!IFrameSplitOperator.IsNumber(value)) continue;
if (value==0) continue;
var x=this.ChartFrame.GetXFromIndex(j);
if (max==null || max<value) max=value;
if (min==null || min>value) 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;i<data.Data.length && j<xPointCount;++i,++j)
{
var value=null;
if (isBeforeData)
{
var item=data.Data[i];
if (item.Before) value=item.Before.Close;
else value=item.Close;
}
else
{
value=data.Data[i];
}
if (value==null) continue;
if (range.Max==null) range.Max=value;
if (range.Min==null) range.Min=value;
if (range.Max<value) range.Max=value;
if (range.Min>value) 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<this.Data.Data.length && j<xPointCount;++i,++j)
{
var value=this.Data.Data[i].Close;
if (value==null) continue;
var showValue=value/this.YClose*this.MainYClose;
var x=this.ChartFrame.GetXFromIndex(j+this.BeforeDataCount);
var y=this.ChartFrame.GetYFromData(showValue);
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>=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;i<this.Data.Data.length && j<xPointCount;++i,++j)
{
var value=this.Data.Data[i].Close;
if (value==null) continue;
var value=value/this.YClose*this.MainYClose;
if (range.Max==null) range.Max=value;
if (range.Min==null) range.Min=value;
if (range.Max<value) range.Max=value;
if (range.Min>value) 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;
//JSConsole.Chart.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;i<data.Data.length && j<xPointCount;++i,++j)
{
var item=this.SourceData.Data[i];
if (isBeforeData && item.Before) continue;
if (!item) continue;
var dateTime=item.DateTime;
if (!this.Data.has(dateTime)) continue;
if (this.IsHScreen)
this.CalcuateInfoHScreenPosition(this.Data.get(dateTime), j, item);
else
this.CalcuateInfoPosition(this.Data.get(dateTime), j, item);
}
for(var i in this.InfoDrawCache)
{
var item=this.InfoDrawCache[i];
this.DrawInfoLines(item);
}
for(var i in this.InfoDrawCache)
{
var item=this.InfoDrawCache[i];
this.DrawInfoText(item);
}
this.TextRectCache=[];
this.InfoDrawCache=[];
}
this.CalcuateInfoPosition=function(infoItem, index, minuteItem)
{
if (!infoItem || !infoItem.Data || infoItem.Data.length<=0) return;
var showItem=infoItem.Data[0];
this.Canvas.font = this.Font;
var textWidth=this.Canvas.measureText(showItem.Title).width+4*this.PixelTatio;
var textHeight=this.TextHeight*this.PixelTatio;
var x=this.ChartFrame.GetXFromIndex(index);
var y;
if (IFrameSplitOperator.IsNumber(showItem.Price)) y=this.ChartFrame.GetYFromData(showItem.Price);
else y=this.ChartFrame.GetYFromData(minuteItem.Close);
x=ToFixedPoint(x);
var isDrawLeft=x<(this.FrameLeft+Math.abs(this.FrameLeft-this.FrameRight)/2);
var ARRAY_OFFSET=[2,4,6,8,3,5,7];
var offset=textHeight+ARRAY_OFFSET[index%ARRAY_OFFSET.length]*this.PixelTatio;
var yData=
{
Y:
[
{Value:y+(textHeight+this.YOffset), Offset: offset},
{Value:y-(2*textHeight+this.YOffset), Offset:-offset}
]
};
if (minuteItem.Close<this.YClose)
yData.Y=yData.Y.reverse();
var rtBorder={X:x, Y:null, Width:textWidth,Height:textHeight};
if (!isDrawLeft) rtBorder.X-=rtBorder.Width;
this.FixTextRect(rtBorder,yData);
var InfoDrawItem={ Border:rtBorder, Start:{X:x,Y:y}, IsLeft:isDrawLeft, Title:showItem.Title };
if (showItem.Color) InfoDrawItem.Color=showItem.Color;
if (showItem.BGColor) InfoDrawItem.BGColor=showItem.BGColor;
this.InfoDrawCache.push(InfoDrawItem);
this.TextRectCache.push(rtBorder);
}
this.CalcuateInfoHScreenPosition=function(infoItem, index, minuteItem)
{
if (!infoItem || !infoItem.Data || infoItem.Data.length<=0) return;
var showItem=infoItem.Data[0];
this.Canvas.font = this.Font;
var textHeight=this.Canvas.measureText(showItem.Title).width+4*this.PixelTatio;
var textWidth=this.TextHeight*this.PixelTatio;
var y=this.ChartFrame.GetXFromIndex(index);
var x;
if (IFrameSplitOperator.IsNumber(showItem.Price)) x=this.ChartFrame.GetYFromData(showItem.Price);
else x=this.ChartFrame.GetYFromData(minuteItem.Close);
y=ToFixedPoint(y);
var isDrawLeft=y<(this.FrameLeft+Math.abs(this.FrameLeft-this.FrameRight)/2);
var ARRAY_OFFSET=[2,4,6,8,3,5,7];
var offset=textWidth+ARRAY_OFFSET[index%ARRAY_OFFSET.length]*this.PixelTatio;
var xData=
{
X:
[
{Value:x+(textWidth+this.YOffset), Offset: offset},
{Value:x-(2*textWidth+this.YOffset), Offset:-offset}
]
};
if (minuteItem.Close>this.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;
if (item.BGColor) this.Canvas.fillStyle=item.BGColor
else 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';
if (item.Color) this.Canvas.fillStyle=item.Color;
else 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 || y<this.FrameTop) break;
rect.Y=y;
}
}
}
this.FixHScreenTextRect=function(rect,xData)
{
for(var k in xData.X)
{
var xItem=xData.X[k];
rect.X=xItem.Value;
var x;
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;
x=rect.X;
x+=xItem.Offset;
if (x+rect.Width<this.FrameBottom || x>this.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;i<this.Data.Data.length && j<xPointCount;++i,++j)
{
var value=this.Data.Data[i];
if (value==null) continue;
var x=this.ChartFrame.GetXFromIndex(j);
var y=this.ChartFrame.GetYFromData(value);
if (x>chartright) 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;i<this.Data.Data.length && j<xPointCount;++i,++j)
{
var value=this.Data.Data[i];
if (value==null) continue;
var x=this.ChartFrame.GetXFromIndex(j);
var y=this.ChartFrame.GetYFromData(value);
if (x>chartright) 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;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
{
var value=this.Data.Data[i];
if (value==null || value==0) continue;
var left=xOffset;
var right=xOffset+dataWidth;
if (right>chartright) 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;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
{
var value=this.Data.Data[i];
if (value==null || value==0) continue;
var left=xOffset;
var right=xOffset+dataWidth;
if (right>chartright) 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<this.Data.Data.length && j<xPointCount;++i,++j)
{
var value=this.Data.Data[i];
if (range.Max==null) range.Max=value;
if (range.Max<value) range.Max=value;
}
return range;
}
}
// 面积图
function ChartBand()
{
this.newMethod=IChartPainting; //派生
this.newMethod();
delete this.newMethod;
this.IsDrawFirst = true;
this.ClassName="ChartBand";
this.FirstColor = g_JSChartResource.Index.LineColor[0];
this.SecondColor = g_JSChartResource.Index.LineColor[1];
this.Draw=function()
{
if (this.NotSupportMessage)
{
this.DrawNotSupportmessage();
return;
}
var dataWidth=this.ChartFrame.DataWidth;
var distanceWidth=this.ChartFrame.DistanceWidth;
var xPointCount=this.ChartFrame.XPointCount;
var xOffset=this.ChartBorder.GetLeft()+distanceWidth/2.0+2.0;
var x = 0;
var y = 0;
var y2 = 0;
var firstlinePoints = [];
var secondlinePoints = [];
var lIndex = 0;
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
{
var value=this.Data.Data[i];
if (value==null || value.Value==null || value.Value2 == null) continue;
x=this.ChartFrame.GetXFromIndex(j);
y=this.ChartFrame.GetYFromData(value.Value);
y2 = this.ChartFrame.GetYFromData(value.Value2);
firstlinePoints[lIndex] = {x:x,y:y};
secondlinePoints[lIndex] = {x:x,y:y2};
lIndex++;
}
if (firstlinePoints.length > 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;i<this.Data.Data.length && j<xPointCount;++i,++j)
{
var value=this.Data.Data[i];
if (value==null || value.Value==null || value.Value2 == null) continue;
var maxData = value.Value>value.Value2?value.Value:value.Value2;
var minData = value.Value<value.Value2?value.Value:value.Value2;
if (range.Max==null)
range.Max = maxData;
else if (range.Max < maxData)
range.Max = maxData;
if (range.Min==null)
range.Min = minData;
else if (range.Min > 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;i<this.Data.Data.length && j<this.PointCount;++i,++j)
{
var item=this.Data.Data[i];
if (!item || !IFrameSplitOperator.IsNumber(item.Value) || !IFrameSplitOperator.IsNumber(item.Value2))
{
if (lineData.length>0)
{
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<lineData.length;++i)
{
var item=lineData[i];
if (this.IsHScreen) this.Canvas.lineTo(item.Y,item.X);
else this.Canvas.lineTo(item.X,item.Y);
++drawCount;
}
for(var i=lineData.length-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;i<lineData.length;++i)
{
var item=lineData[i];
if (bFirstPoint)
{
this.Canvas.beginPath();
if (this.IsHScreen) this.Canvas.moveTo(k===0?item.Y:item.Y2,item.X);
else this.Canvas.moveTo(item.X, k===0?item.Y:item.Y2 );
bFirstPoint=false;
}
else
{
if (this.IsHScreen) this.Canvas.lineTo(k===0?item.Y:item.Y2,item.X);
else this.Canvas.lineTo(item.X,k===0?item.Y:item.Y2);
}
++drawCount;
}
if (drawCount>0) 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;i<drawData.length;++i)
{
var lineData=drawData[i];
this.DrawArea(lineData);
this.DrawLine(lineData);
}
this.Canvas.restore();
}
this.GetMaxMin=function()
{
var xPointCount=this.ChartFrame.XPointCount;
var range={Min:null, Max:null};
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j)
{
var value=this.Data.Data[i];
if (value==null || value.Value==null || value.Value2 == null) continue;
var maxData = value.Value>value.Value2?value.Value:value.Value2;
var minData = value.Value<value.Value2?value.Value:value.Value2;
if (range.Max==null)
range.Max = maxData;
else if (range.Max < maxData)
range.Max = maxData;
if (range.Min==null)
range.Min = minData;
else if (range.Min > 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-offsetY<top)
{
this.Canvas.textBaseline='top';
yText=top;
}
else if (y+offsetY>bottom)
{
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 };
if (line.BGColor) drawPoints.BGColor=line.BGColor;
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<xPointCount)
{
var x=this.ChartFrame.GetXFromIndex(index);
var y=this.ChartFrame.GetYFromData(point.Value);
drawPoints.Point.push({X:x, Y:y, End:false});
}
else
{
if (drawPoints.Point.length>0) drawPoints.Point[drawPoints.Point.length-1].End=true; //点断开
}
}
if (drawPoints.Point.length>=2) drawLines.push(drawPoints)
}
for(var i in drawLines)
{
var item=drawLines[i];
this.DrawLine(item);
}
}
this.DrawLine=function(line)
{
if (line.BGColor) //背景色
{
this.Canvas.fillStyle=line.BGColor;
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.closePath();
this.Canvas.fill();
}
this.Canvas.strokeStyle=line.Color;
var drawCount=0;
for(var i in line.Point)
{
var item=line.Point[i];
if (drawCount==0)
{
this.Canvas.beginPath();
if (this.IsHScreen) this.Canvas.moveTo(item.Y,item.X);
else this.Canvas.moveTo(item.X,item.Y);
++drawCount;
}
else
{
if (this.IsHScreen) this.Canvas.lineTo(item.Y,item.X);
else this.Canvas.lineTo(item.X,item.Y);
++drawCount;
}
if (item.End==true) //点断了 要重新画
{
if (drawCount>0) this.Canvas.stroke();
drawCount=0;
}
}
if (drawCount>0) 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.Index<end)
{
if (range.Max==null) range.Max=point.Value;
else if (range.Max<point.Value) range.Max=point.Value;
if (range.Min==null) range.Min=point.Value;
else if (range.Min>point.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.IsHScreen=false; //是否横屏
this.Draw=function()
{
if (!this.IsShow) return;
if (!this.Data || this.Data.length<=0) return;
if (!this.Texts) 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();
if (this.IsHScreen)
{
left=this.ChartBorder.GetTop();
right=this.ChartBorder.GetBottom();
}
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<xPointCount)
{
var x=this.ChartFrame.GetXFromIndex(index);
var y=this.ChartFrame.GetYFromData(item.Value);
if (item.Color) this.Canvas.fillStyle = item.Color;
else this.Canvas.fillStyle = this.Color;
if (item.Font) this.Canvas.font = item.Font;
else this.Canvas.font=this.Font;
var textWidth=this.Canvas.measureText(item.Text).width;
this.Canvas.textAlign='center';
if (x+textWidth/2>=right)
{
this.Canvas.textAlign='right';
x=right;
}
else if (x-textWidth/2<left)
{
this.Canvas.textAlign = 'left';
x=left;
}
if (item.Baseline==1) this.Canvas.textBaseline='top';
else if (item.Baseline==2) this.Canvas.textBaseline='bottom';
else this.Canvas.textBaseline = 'middle';
if (this.IsHScreen)
{
this.Canvas.save();
this.Canvas.translate(y, x);
this.Canvas.rotate(90 * Math.PI / 180);
this.Canvas.fillText(item.Text,0,0);
this.Canvas.restore();
}
else
{
this.Canvas.fillText(item.Text, x, y);
}
}
}
}
this.GetMaxMin=function()
{
var range={ Min:null, Max:null };
if (!this.Texts) return range;
var xPointCount=this.ChartFrame.XPointCount;
var start=this.Data.DataOffset;
var end=start+xPointCount;
for(var i in this.Texts)
{
var item=this.Texts[i];
if (item.Index>=start && item.Index<end)
{
if (range.Max==null) range.Max=item.Value;
else if (range.Max<item.Value) range.Max=item.Value;
if (range.Min==null) range.Min=item.Value;
else if (range.Min>item.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<xPointCount)
{
var x=this.ChartFrame.GetXFromIndex(index);
var y=this.ChartFrame.GetYFromData(item.Value);
if (item.Color) this.Canvas.fillStyle = item.Color;
else this.Canvas.fillStyle = this.Color;
var textWidth=this.Canvas.measureText(item.Text).width;
this.Canvas.textAlign='center';
if (x+textWidth/2>=right)
{
this.Canvas.textAlign='right';
x+=this.DataWidth/2;
}
else if (x-textWidth/2<left)
{
this.Canvas.textAlign = 'left';
x-=this.DataWidth/2;
}
if (item.Baseline==1) this.Canvas.textBaseline='top';
else if (item.Baseline==2) this.Canvas.textBaseline='bottom';
else this.Canvas.textBaseline = 'middle';
if (this.IsHScreen)
{
this.Canvas.save();
this.Canvas.translate(y, x);
this.Canvas.rotate(90 * Math.PI / 180);
this.Canvas.fillText(item.Symbol,0,0);
this.Canvas.restore();
}
else
{
this.Canvas.fillText(item.Symbol, x, y);
}
}
}
}
this.GetMaxMin=function()
{
var range={ Min:null, Max:null };
if (!this.Texts) return range;
var xPointCount=this.ChartFrame.XPointCount;
var start=this.Data.DataOffset;
var end=start+xPointCount;
for(var i in this.Icon)
{
var item=this.Icon[i];
if (item.Index>=start && item.Index<end)
{
if (range.Max==null) range.Max=item.Value;
else if (range.Max<item.Value) range.Max=item.Value;
if (range.Min==null) range.Min=item.Value;
else if (range.Min>item.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;i<this.ChartFrame.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
{
var data=this.ChartFrame.Data.Data[i];
if (data.Open==null || data.High==null || data.Low==null || data.Close==null) continue;
var left=xOffset;
var right=xOffset+dataWidth;
if (right>chartright) 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 && lWidth<this.MinWidth)
{
lWidth=this.MinWidth;
lLeft=this.ChartBorder.GetRight()-lWidth;
if (lLeft < this.ChartBorder.GetLeft()) lLeft = this.ChartBorder.GetLeft();
}
if (isDraw)
{
this.Canvas.fillStyle = this.BGColor;
this.Canvas.fillRect(lLeft, this.ChartBorder.GetTop(), lWidth, lHeight);
var xCenter = lLeft + lWidth / 2;
var yCenter = this.ChartBorder.GetTop() + lHeight / 2;
this.Canvas.textAlign = 'center';
this.Canvas.textBaseline = 'middle';
this.Canvas.fillStyle = this.TextColor;
this.Canvas.font = this.Font;
this.Canvas.fillText(this.Title, xCenter, yCenter);
}
this.LockRect={Left:lLeft,Top:this.ChartBorder.GetTop(),Width:lWidth,Heigh:lHeight}; //保存上锁区域
}
this.HScreenDraw=function(isDraw)
{
var xOffset = this.ChartBorder.GetBottom();
var lOffsetWidth = 0;
if (this.ChartFrame.Data != null)
{
var dataWidth=this.ChartFrame.DataWidth;
var distanceWidth=this.ChartFrame.DistanceWidth;
xOffset=this.ChartBorder.GetTop()+distanceWidth/2.0+2.0;
var chartright=this.ChartBorder.GetBottom();
var xPointCount=this.ChartFrame.XPointCount;
//求最后1个数据的位置
for(var i=this.ChartFrame.Data.DataOffset,j=0;i<this.ChartFrame.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
{
var data=this.ChartFrame.Data.Data[i];
if (data.Open==null || data.High==null || data.Low==null || data.Close==null) continue;
var left=xOffset;
var right=xOffset+dataWidth;
if (right>chartright) 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:日期*10000+时间, 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 (iconSize<minIconSize) iconSize=minIconSize;
this.Canvas.font=iconSize+'px '+this.IconFont.Family;
}
else
{
this.Canvas.font=this.TextFont;
}
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j)
{
var value=this.Data.Data[i];
if (value==null) continue;
if (x>chartright) break;
this.LastData={ID:j,Data:value};
var key=value.Date*10000;
if (IFrameSplitOperator.IsNumber(value.Time)) key+=value.Time;
if (!this.BuySellData.has(key)) continue;
var bsItem=this.BuySellData.get(key);
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); //占比
//JSConsole.Chart.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);
// JSConsole.Chart.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()
{
JSConsole.Chart.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;
//JSConsole.Chart.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<count;++i)
{
let ptBorder = { Index: i, Radius: radius, Angle: i * averageAngle + this.StartAngle };
let angle = ptBorder.Angle;
if (data && i<data.length)
{
var item=data[i];
let ptData={Index:i,Text:item.Text};
ptBorder.Text=item.Name;
if (!item.Value)
{
ptData.X=ptCenter.X;
ptData.Y=ptCenter.Y;
}
else
{
var value=item.Value;
if (value>=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()
{
JSConsole.Chart.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 (height<drawImageHeight || width<drawImageWidth)
{
this.ImageData=null;
return;
}
if (this.Left!=left || this.Top!=top || this.Width!=width || this.Height!=height || this.ImageWidth!=imageWidth || this.ImageHeight!=imageHeight)
{
this.ImageData=null;
this.ImageWidth=imageWidth;
this.ImageHeight=imageHeight;
this.Left=left;
this.Top=top;
this.Width=width;
this.Height=height;
JSConsole.Chart.Log(imageWidth,imageHeight);
}
if (this.ImageData==null)
{
this.Canvas.drawImage(CHINA_MAP_IMAGE,0,0,imageWidth,imageHeight,left,top,drawImageWidth,drawImageHeight);
this.ImageData=this.Canvas.getImageData(left,top,drawImageWidth,drawImageHeight);
let defaultColorSet=new Set(); //默认颜色填充的色块
let colorMap=new Map(); //定义颜色填充的色块
let nameMap=new Map();
if (this.Data.length>0)
{
for(let i in this.Data)
{
let item=this.Data[i];
nameMap.set(item.Name,item.Color)
}
}
JSConsole.Chart.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;i<this.ImageData.data.length;i+=4)
{
color='rgb('+ this.ImageData.data[i] + ',' + this.ImageData.data[i+1] + ',' + this.ImageData.data[i+2] + ')';
if (defaultColorSet.has(color))
{
this.ImageData.data[i]=this.DefaultColor[0];
this.ImageData.data[i+1]=this.DefaultColor[1];
this.ImageData.data[i+2]=this.DefaultColor[2];
}
else if (colorMap.has(color))
{
let colorValue=colorMap.get(color);
this.ImageData.data[i]=colorValue[0];
this.ImageData.data[i+1]=colorValue[1];
this.ImageData.data[i+2]=colorValue[2];
}
}
this.Canvas.clearRect(left,top,drawImageWidth,drawImageHeight);
this.Canvas.putImageData(this.ImageData,left,top,0,0,drawImageWidth,drawImageHeight);
}
else
{
this.Canvas.putImageData(this.ImageData,left,top,0,0,drawImageWidth,drawImageHeight);
}
}
}
/*
扩展图形
*/
function IExtendChartPainting()
{
this.Canvas; //画布
this.ChartBorder; //边框信息
this.ChartFrame; //框架画法
this.Name; //名称
this.Data; //数据区
this.IsDynamic=false;
this.IsAnimation=false; //是否是动画
this.ClassName='IExtendChartPainting';
this.SizeChange=true; //大小是否改变
this.IsEraseBG=false; //是否每次画的时候需要擦除K线图背景
this.DrawAfterTitle=false; //是否在动态标题画完以后再画,防止动态标题覆盖
//上下左右间距
this.Left=5;
this.Right=5;
this.Top=5;
this.Bottom=5;
this.Draw=function()
{
}
//设置参数接口
this.SetOption=function(option)
{
}
}
//K线Tooltip, 显示在左边或右边
function KLineTooltipPaint()
{
this.newMethod=IExtendChartPainting; //派生
this.newMethod();
delete this.newMethod;
this.IsDynamic=true;
this.IsEraseBG=true;
this.DrawAfterTitle=true;
this.ClassName='KLineTooltipPaint';
this.BorderColor=g_JSChartResource.TooltipPaint.BorderColor; //边框颜色
this.BGColor=g_JSChartResource.TooltipPaint.BGColor; //背景色
this.TitleColor=g_JSChartResource.TooltipPaint.TitleColor; //标题颜色
this.Left=1*GetDevicePixelRatio();
this.Top=5*GetDevicePixelRatio();;
this.Width=50;
this.Height=100;
this.LineHeight=15*GetDevicePixelRatio(); //行高
this.Font=[g_JSChartResource.TooltipPaint.TitleFont];
this.HQChart;
this.KLineTitlePaint;
this.IsHScreen=false; //是否横屏
this.LanguageID=JSCHART_LANGUAGE_ID.LANGUAGE_CHINESE_ID;
this.GetLeft=function()
{
if (this.IsHScreen) return this.ChartBorder.GetRightEx()-this.Height-this.Top;
return this.ChartBorder.GetLeft()+this.Left;
}
this.GetTop=function()
{
if (this.IsHScreen) return this.ChartBorder.GetTop();
return this.ChartBorder.GetTopEx()+this.Top;
}
this.IsEnableDraw=function()
{
if (!this.HQChart || !this.HQChart.TitlePaint || !this.HQChart.TitlePaint[0]) return false;
if (this.HQChart.DragMode==JSCHART_DRAG_ID.CLICK_TOUCH_MODE_ID)
{
if (this.HQChart.TouchStatus.CorssCursorShow==false) return false;
}
else if (!this.HQChart.IsOnTouch)
{
return false;
}
if (this.HQChart.CurrentChartDrawPicture) return false; //画图工具操作的时候 不显示
return true;
}
this.Draw=function()
{
if (!this.IsEnableDraw()) return;
this.KLineTitlePaint=this.HQChart.TitlePaint[0];
var klineData=this.KLineTitlePaint.GetCurrentKLineData();
if (!klineData) return;
var lineCount=8; //显示函数
if (this.ClassName==='MinuteTooltipPaint')
{
if (MARKET_SUFFIX_NAME.IsChinaFutures(this.HQChart.Symbol)) lineCount=8; //期货多一个持仓量
else lineCount=7;
}
else
{
if (klineData.Time!=null && !isNaN(klineData.Time) && klineData.Time>0) 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];
var defaultfloatPrecision=GetfloatPrecision(this.HQChart.Symbol);//价格小数位数
var maxText=' 擎: 9999.99亿 ';
if (defaultfloatPrecision>=5) maxText=` 擎: ${99.99.toFixed(defaultfloatPrecision)} `; //小数位数太多了
this.Width=this.Canvas.measureText(maxText).width;
this.Height=this.LineHeight*lineCount+2*GetDevicePixelRatio()*2;
this.DrawBG();
this.DrawTooltipData(klineData);
this.DrawBorder();
}
this.DrawTooltipData=function(item)
{
//JSConsole.Chart.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);
var period=this.HQChart.Period;
if (ChartData.IsMinutePeriod(period,true) && item.Time)
{
top+=this.LineHeight;
text=IFrameSplitOperator.FormatTimeString(item.Time);
this.Canvas.fillText(text, left,top);
}
else if (ChartData.IsSecondPeriod(period) && item.Time)
{
top+=this.LineHeight;
text=IFrameSplitOperator.FormatTimeString(item.Time,'HH:MM:SS');
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)
{
//JSConsole.Chart.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;
var upperSymbol=this.HQChart.Symbol.toUpperCase();
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);
var isShowAvPrice=true;
if (item.Before) isShowAvPrice=false; //集合竞价均价
else if (MARKET_SUFFIX_NAME.IsForeignExchange(upperSymbol)) isShowAvPrice=false; //外汇没有均价
else if (MARKET_SUFFIX_NAME.IsET(upperSymbol) && !MARKET_SUFFIX_NAME.IsETShowAvPrice(upperSymbol)) isShowAvPrice=false;
//均价
if (isShowAvPrice && IFrameSplitOperator.IsNumber(item.AvPrice))
{
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);
//成交量
if (IFrameSplitOperator.IsNumber(vol))
{
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 (IFrameSplitOperator.IsNumber(item.Position))
{
top+=this.LineHeight;
text=g_JSChartLocalization.GetText('Tooltip-Position',this.LanguageID);
this.Canvas.fillText(text, left,top);
var text=IFrameSplitOperator.FormatValueString(item.Position,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
{
JSConsole.Chart.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;j<chipData.length;++j)
{
var vol=chipData[j];
if(!vol) continue;
totalVol+=vol;
var price=(j+this.Data.MinPrice)/100;
var y=KLineFrame.GetYFromData(price);
var x=(vol/this.Data.MaxVol)*this.ClientRect.Width+this.ClientRect.Left;
aryPoint.push({X:x,Y:y});
}
this.Data.DayChip[i].Vol=totalVol;
this.DrawArea(aryPoint,this.Data.DayChip[i].Color);
}
}
this.Clear=function()
{
var divButton=document.getElementById(this.ButtonID);
if (divButton) this.ChartBorder.UIElement.parentNode.removeChild(divButton);
}
this.DrawButton=function() //顶部按钮
{
var divButton=document.getElementById(this.ButtonID);
if (!divButton)
{
divButton=document.createElement("div");
divButton.className='klineframe-button';
divButton.id=this.ButtonID;
//为divToolbar添加属性identify
// divButton.setAttribute("identify",this.Identify.toString());
this.ChartBorder.UIElement.parentNode.appendChild(divButton);
}
var pixelTatio = this.PixelRatio;
var left=this.ClientRect.Left;
var right=this.ClientRect.Left+this.ClientRect.Width;
var chartRight=this.ChartBorder.GetChartWidth();
var toolbarWidth=right-left;
var toolbarHeight=this.ChartBorder.GetTitleHeight();
// var left=this.ChartBorder.GetRight();
var top=this.ChartBorder.GetTop()/pixelTatio;
const spanStyle="<span class='{iconclass}' id='{iconid}' title='{icontitle}' style='cursor:pointer;display:inline-block;color:{iconcolor};font-size:{iconsize}px'></span>";
const ICON_LIST=
[
{Class:'chip_default icon iconfont icon-chip_default', ID:'chip_default',Color:['#808080','#FF0000'],Title:'默认筹码分布图'},
{Class:'chip_long icon iconfont icon-chip_date',ID:'chip_long',Color:['#808080','#FF8000'],Title:'远期筹码分布图'},
{Class:'chip_recent icon iconfont icon-chip_date',ID:'chip_recent', Color:['#808080','#0000CC'],Title:'近期筹码分布图'}
];
var spanHtml='';
for(var i in ICON_LIST)
{
var item=ICON_LIST[i];
var spanItem=spanStyle;
spanItem=spanItem.replace('{iconclass}',item.Class);
spanItem=spanItem.replace('{iconid}',item.ID);
spanItem=spanItem.replace('{iconcolor}',item.Color[i==this.ShowType?1:0]);
spanItem=spanItem.replace('{iconsize}',toolbarHeight);
spanItem=spanItem.replace('{icontitle}',item.Title);
if (spanHtml.length>0) 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<this.Data.AllChip.length;++i)
{
var vol=this.Data.AllChip[i];
if(!vol) continue;
var price=(i+this.Data.MinPrice)/100;
totalVol+=vol;
totalAmount+=price*vol;
if (price<yPrice) totalYProfitVol+=vol; //获利的成交量
if (price<selectPrice) totalProfitVol+=vol; //鼠标当前位置 获利的成交量
if (price<=maxPrice && price>=minPrice)
{
if (MaxVol<vol) MaxVol=vol;
}
}
this.Data.MaxVol=MaxVol; //把成交量最大值替换成 当前屏成交量最大值
for(var i=0;i<this.Data.AllChip.length;++i)
{
var vol=this.Data.AllChip[i];
if(!vol) continue;
var price=(i+this.Data.MinPrice)/100;
if (price>maxPrice || price<minPrice) continue;
var y=KLineFrame.GetYFromData(price);
var x=(vol/this.Data.MaxVol)*this.ClientRect.Width+this.ClientRect.Left;
if (price<selectPrice) aryProfitPoint.push({X:x,Y:y});
else aryNoProfitPoint.push({X:x,Y:y});
}
this.Data.ChipInfo=
{
Vol:totalVol, AveragePrice:totalAmount/totalVol, ProfitVol:totalProfitVol,
ProfitRate:totalVol>0?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;i<this.Data.AllChip.length;++i)
{
if (castCount==4) break;
var vol=this.Data.AllChip[i];
if (vol<=0) continue;
var price=(i+this.Data.MinPrice)/100;
tempVol+=vol;
var rate=tempVol/totalProfitVol;
for(var j in aryCast)
{
var itemCast=aryCast[j];
if (itemCast.MinPrice<=0 && rate>itemCast.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);
//JSConsole.Chart.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 || maxPrice<item.High) maxPrice=item.High;
if (!minPrice || minPrice>item.Low) minPrice=item.Low;
}
//JSConsole.Chart.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<dayChip.length;++k)
{
if (i==dayChip[k].Day)
{
dayChip[k].Chip=aryChip.slice(0);
break;
}
}
for(var j=low;j<=high && j<=maxPrice;++j)
{
var index=j-minPrice;
aryChip[index]+=averageVol;
if (maxVol<aryChip[index]) maxVol=aryChip[index];
}
}
}
else if (this.ShowType==1)
{
var dayChip=
[
{Day:5, Color:this.DAY_COLOR[0][0]},{Day:10, Color:this.DAY_COLOR[0][1]},{Day:20, Color:this.DAY_COLOR[0][2]},
{Day:30, Color:this.DAY_COLOR[0][3]},{Day:60, Color:this.DAY_COLOR[0][4]},{Day:100, Color:this.DAY_COLOR[0][5]}
];
for(let i=aryVol.length-1;i>=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;k<dayChip.length;++k)
{
if (i==dayChip[k].Day)
{
dayChip[k].Chip=aryChip.slice(0);
break;
}
}
for(var j=low;j<=high && j<=maxPrice;++j)
{
var index=j-minPrice;
aryChip[index]+=averageVol;
if (maxVol<aryChip[index]) maxVol=aryChip[index];
}
}
}
else
{
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 j=low;j<=high && j<=maxPrice;++j)
{
var index=j-minPrice;
aryChip[index]+=averageVol;
if (maxVol<aryChip[index]) maxVol=aryChip[index];
}
}
}
this.Data={AllChip:aryChip, MaxVol:maxVol, MaxPrice:maxPrice, MinPrice:minPrice,SelectData:selData, DayChip:dayChip, YPrice:yPrice};
return true;
}
this.DrawFrame=function() //X轴成交量坐标
{
if (this.IsShowX==false) return;
if (this.Data.MaxVol<=0) return;
var isDrawXFrame=this.HQChart.Frame.SubFrame.length===1 ? false:true; //是否画X轴,如果只有1个窗口就不画
var KLineFrame=this.HQChart.Frame.SubFrame[0].Frame;
var chartBorder=KLineFrame.ChartBorder;
var bottom=ToFixedPoint(chartBorder.GetBottomEx()+1);
if (!isDrawXFrame) bottom=this.ClientRect.Top+this.ClientRect.Height;
var left=this.ClientRect.Left;
var right=left+this.ClientRect.Width;
this.Canvas.strokeStyle=this.PenBorder;
this.Canvas.beginPath();
if (isDrawXFrame)
{
this.Canvas.moveTo(left,bottom);
this.Canvas.lineTo(right,bottom);
}
var showCount=this.ShowXCount;
var maxValue=this.Data.MaxVol;
var perValue=Math.floor(maxValue/showCount);
this.Canvas.font=this.Font;
this.Canvas.textBaseline='top';
this.Canvas.fillStyle=this.InfoColor;
var xOffset=10*GetDevicePixelRatio();
for(i=1;i<=showCount;++i)
{
var vol=perValue*i;
var x=(vol/this.Data.MaxVol)*this.ClientRect.Width+this.ClientRect.Left;
x=ToFixedPoint(x);
if (i==showCount) //最后一个刻度不要画线了
{
this.Canvas.textAlign='right';
var text=IFrameSplitOperator.FormatValueString(maxValue, 1);
this.Canvas.fillText(text,x,bottom+2);
}
else
{
this.Canvas.moveTo(x,this.ClientRect.Top);
this.Canvas.lineTo(x,bottom);
this.Canvas.textAlign='center';
var text=IFrameSplitOperator.FormatValueString(vol, 1);
var textWidth=this.Canvas.measureText(text).width;
this.Canvas.fillText(text,Math.floor(x-textWidth*0.25),bottom+2);
}
}
this.Canvas.stroke();
}
}
//画图工具条
function DrawToolsButton()
{
this.newMethod=IExtendChartPainting; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='DrawToolsButton';
this.HQChart;
this.ID=Guid();
this.ToolsDiv;
// this.Color='rgb(105,105,105)'; //颜色
this.Color = "#696969"; //input type="color"不支持rgb的颜色格式
//this.Left=5;
this.Top=5*GetDevicePixelRatio();
this.Width=45*GetDevicePixelRatio(); //宽度
this.SetOption=function(option)
{
var pixelRatio=GetDevicePixelRatio();
if (!option) return;
if (option.Width>10) 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 += '<p class="menuTwoItem ' + currentItem.HTML.ID + '">' + menuTwoName + '<i class="' + currentItem.HTML.IClass + '" title="' + currentItem.HTML.Title + '"></i></p>';
}
if (i !== TOOL_LIST.length - 1) { //不是“全部删除”项
menuTwoList = '<div class="menuTwo">' + menuTwoStr + '</div>';
contentArrow = '<i class="contentArrow iconfont icon-menu_arraw_left"></i>';
} else {
menuTwoList = "";
contentArrow = "";
}
var spanNode = '<div class="icon-image ' + 'first-' + itemOut.HTML.ID + '"><i class="' + itemOut.HTML.IClass + '" title="' + itemOut.HTML.Title + '"></i>' + menuTwoList + contentArrow +'</div>';
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;i<this.PlayList.length;++i)
{
var ary=this.PlayList[i];
var lineHeight=this.MinLineHeight;
if (ary.Height>this.MinLineHeight) lineHeight=ary.Height;
var bAddNewItem=true; //是否需要加入新弹幕
var bRemoveFirst=false; //是否删除第1个数据
for(var j=0;j<ary.Data.length;++j)
{
var item=ary.Data[j];
var playItem={ X:item.X, Y:yOffset, Text:item.Text, Color:item.Color, Height:lineHeight, Font:item.Font, Info:item.Info };
list.push(playItem);
if (!isMoveStep) continue;
if(j==ary.Data.length-1 && this.Cache.length>0) //最后一个数据了 判断是否需要增加弹幕
{
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.length<lineCount)
{
var addCount=lineCount-this.PlayList.length;
for(var i=0;i<addCount;++i)
{
this.PlayList.push({Data:[]});
}
}
else if (this.PlayList.length>lineCount)
{
var removeCount=this.PlayList.length-lineCount;
for(var i=0;i<removeCount;++i)
{
var ary=this.PlayList.pop();
for(var j=0;j<ary.Data.length;++j)
{
var item=ary.Data[j];
var cacheItem={ Text:item.Text, Color:item.Color, Font:item.Font, Info:item.Info };
this.Cache.unshift(cacheItem);
}
}
}
JSConsole.Chart.Log(`[BarrageList::CacluatePlayLine] LineCount=${this.PlayList.length} Height=${this.Height}` )
}
//添加弹幕
this.AddBarrage=function(barrageData)
{
for(var i in barrageData)
{
var item=barrageData[i];
this.Cache.push(item);
}
}
this.OnItemPlayEnd=function(hqChart, item) //单挑弹幕播放完毕
{
//监听事件
if (!hqChart.mapEvent.has(JSCHART_EVENT_ID.BARRAGE_PLAY_END)) return;
var event=hqChart.mapEvent.get(JSCHART_EVENT_ID.BARRAGE_PLAY_END);
if (!event.Callback) return;
event.Callback(event,item,this);
}
this.Count=function() { return this.Cache.length; } //未播放的弹幕个数
}
//弹幕
function BarragePaint()
{
this.newMethod=IExtendChartPainting; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='BarragePaint';
this.IsAnimation=true;
this.IsEraseBG=true;
this.HQChart;
this.Font=g_JSChartResource.Barrage.Font;
this.TextColor=g_JSChartResource.Barrage.Color;
this.FontHeight=g_JSChartResource.Barrage.Height;
this.BarrageList=new BarrageList(); //字幕列表
this.IsMoveStep=false;
//设置参数接口
this.SetOption=function(option)
{
if (option)
{
if (option.Step>0) 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;i<play.length;++i)
{
var item=play[i];
if (item.Color) this.Canvas.fillStyle=item.Color;
else this.Canvas.fillStyle=this.TextColor;
if (item.Font) this.Canvas.font=item.Font.Name;
else this.Canvas.font=this.Font;
var fontHeight=this.FontHeight;
if (item.Font && item.Font.Height>0) 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;i<play.length;++i)
{
var item=play[i];
if (item.Color) this.Canvas.fillStyle=item.Color;
else this.Canvas.fillStyle=this.TextColor;
if (item.Font) this.Canvas.font=item.Font.Name;
else this.Canvas.font=this.Font;
var fontHeight=this.FontHeight;
if (item.Font && item.Font.Height>0) 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<data.length-1;++i)
{
var item=data[i];
item.Message[0]=null;
item.Message[1]=null;
}
}
if (keepZero) //如果不存在0轴,增加一个0轴,刻度信息部显示
{
var bExsitZero=false;
for(var i=0;i<data;++i)
{
var item=data[i];
if (Math.abs(item.Value) < 0.00000001)
{
bExsitZero=true;
break;
}
}
if (bExsitZero==false)
{
var zeroCoordinate = new CoordinateInfo();
zeroCoordinate.Value = 0;
zeroCoordinate.Message[0] = null
zeroCoordinate.Message[1] = null;
data.push(zeroCoordinate);
}
}
return data;
}
this.RemoveZero = function (aryInfo) //移除小数后面多余的0
{
//所有的数字小数点后面都0,才会去掉
var isAllZero = [true, true];
for (var i in aryInfo)
{
var item = aryInfo[i];
var message = item.Message[0];
if (!this.IsDecimalZeroEnd(message)) isAllZero[0] = false;
var message = item.Message[1];
if (!this.IsDecimalZeroEnd(message)) isAllZero[1] = false;
}
if (isAllZero[0] == false && isAllZero[1] == false) return;
for (var i in aryInfo)
{
var item = aryInfo[i];
if (isAllZero[0])
{
var message = item.Message[0];
if (message!=null)
{
if (typeof (message) == 'number') message = message.toString();
item.Message[0] = message.replace(/[.][0]+/g, '');
}
}
if (isAllZero[1])
{
var message = item.Message[1];
if (message!=null)
{
if (typeof (message) == 'number') message = message.toString();
item.Message[1] = message.replace(/[.][0]+/g, '');
}
}
}
}
this.IsDecimalZeroEnd = function (text) //是否是0结尾的小数
{
if (text==null) return true;
if (typeof(text)=='number') text=text.toString();
if (text=='0') return true;
var pos = text.search(/[.]/);
if (pos < 0) return false;
for (var i = pos + 1; i < text.length; ++i)
{
var char = text.charAt(i);
if (char >= '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;i<floatPrecision;++i)
nullText+='-';
return nullText;
}
return '--';
}
var result='';
var num=value.toFixed(floatPrecision);
if(floatPrecision>0){
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<floatPrecision;++i)
nullText+='-';
return nullText;
}
return '--';
}
if (value<0.00000000001 && value>-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, format) //format hh:mm:ss
{
if (format=='HH:MM:SS')
{
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);
}
else if (format=='HH:MM')
{
var hour=parseInt(value/100);
var minute=value%100;
return IFrameSplitOperator.NumberToString(hour)+':'+ IFrameSplitOperator.NumberToString(minute);
}
else
{
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;
}
//是否时bool
IFrameSplitOperator.IsBool=function(value)
{
if (value===true || value===false) return true;
return false;
}
IFrameSplitOperator.IsString=function(value)
{
if (value && typeof(value)=='string') return true;
return false;
}
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.SplitType=0; //0=自动分割 1=固定分割
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;
JSConsole.Chart.Log(`[FrameSplitKLinePriceY::Operator] Max=${splitData.Max} Min=${splitData.Min} Count=${splitData.Count} isPhoneModel=${isPhoneModel} defaultfloatPrecision=${defaultfloatPrecision} `);
var bFilter=true; //是否需要通过高度过滤刻度
if (ChartData.IsTickPeriod(this.Period))
{
this.SplitTickData(splitData,defaultfloatPrecision);
}
else
{
switch(this.CoordinateType)
{
case 1:
this.SplitPercentage(splitData,defaultfloatPrecision);
break;
default:
if (this.SplitType==1)
{
this.SplitFixed(splitData,defaultfloatPrecision);
bFilter=false;
}
else
{
this.SplitDefault(splitData,defaultfloatPrecision);
}
break;
}
}
this.CustomCoordinate(defaultfloatPrecision);
if (bFilter) this.Frame.HorizontalInfo = this.Filter(this.Frame.HorizontalInfo,false);
this.Frame.HorizontalMax=splitData.Max;
this.Frame.HorizontalMin=splitData.Min;
JSConsole.Chart.Log(`[FrameSplitKLinePriceY::Operator] 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;i<splitData.Count;++i,value+=splitData.Interval)
{
var price=(value+1)*firstOpenPrice;
this.Frame.HorizontalInfo[i]= new CoordinateInfo();
this.Frame.HorizontalInfo[i].Value=price;
if (this.IsShowLeftText) this.Frame.HorizontalInfo[i].Message[0]=price.toFixed(floatPrecision); //左边价格坐标
if (this.IsShowRightText) this.Frame.HorizontalInfo[i].Message[1]=(value*100).toFixed(2)+'%'; //右边百分比
}
splitData.Min=(1+splitData.Min)*firstOpenPrice; //最大最小值调整
splitData.Max=(1+splitData.Max)*firstOpenPrice;
}
this.SplitDefault=function(splitData,floatPrecision) //默认坐标
{
this.IntegerCoordinateSplit(splitData);
this.Frame.HorizontalInfo=[];
for(var i=0,value=splitData.Min;i<splitData.Count;++i,value+=splitData.Interval)
{
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.SplitFixed=function(splitData,floatPrecision) //固定分割坐标
{
this.Frame.HorizontalInfo=[];
for(var i=0,value=splitData.Min;i<splitData.Count;++i,value+=splitData.Interval)
{
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.CustomCoordinate=function(floatPrecision)
{
this.Frame.CustomHorizontalInfo=[];
for(var i in this.Custom)
{
var item=this.Custom[i];
if (item.Type==0)
{
var latestItem=this.GetLatestPrice(floatPrecision,item);
if (latestItem) this.Frame.CustomHorizontalInfo.push(latestItem);
}
else if (item.Type==1)
{
this.CustomFixedCoordinate(item);
}
}
}
this.GetLatestPrice=function(floatPrecision,option)
{
if (!this.Data || !this.Data.Data) return null;
if (this.Data.Data.length<=0) return null;
var latestItem=this.Data.Data[this.Data.Data.length-1];
var info=new CoordinateInfo();
info.Type=0;
info.Value=latestItem.Close;
info.TextColor=g_JSChartResource.FrameLatestPrice.TextColor;
if (option.Position=='left') info.Message[0]=latestItem.Close.toFixed(floatPrecision);
else info.Message[1]=latestItem.Close.toFixed(floatPrecision);
if (latestItem.Close>latestItem.Open) info.LineColor=g_JSChartResource.FrameLatestPrice.UpBarColor;
else if (latestItem.Close<latestItem.Open) info.LineColor=g_JSChartResource.FrameLatestPrice.DownBarColor;
else info.LineColor=g_JSChartResource.FrameLatestPrice.UnchagneBarColor;
if (option.IsShowLine==false) info.LineType=-1;
return info;
}
this.GetFirstOpenPrice=function() //获取显示第1个数据的开盘价
{
if (!this.Data) return null;
var xPointCount=this.Frame.XPointCount;
for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j)
{
var data=this.Data.Data[i];
if (data.Open==null || data.High==null || data.Low==null || data.Close==null) continue;
return data.Open;
}
return null;
}
this.CustomFixedCoordinate=function(option) //固定坐标刻度
{
var defaultfloatPrecision=GetfloatPrecision(this.Symbol);
for(var i in option.Data)
{
var item=option.Data[i];
var info=new CoordinateInfo();
info.Type=1;
info.TextColor=item.TextColor;
info.LineColor=item.Color;
info.LineType=2; //虚线
if (option.IsShowLine==false) info.LineType=-1;
info.Value=item.Value;
var text;
if (item.Text) text=item.Text;
else text=info.Value.toFixed(defaultfloatPrecision);
if (option.Position=='left') info.Message[0]=text;
else info.Message[1]=text;
this.Frame.CustomHorizontalInfo.push(info);
}
}
//////////////////////
// data.Min data.Max data.Interval data.Count
//
this.IntegerCoordinateSplit2=function(data)
{
var splitItem=this.FrameSplitData2.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;
}
}
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(;floatPrecision<this.FLOATPRECISION_RANGE.length;++floatPrecision)
{
if (value>this.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<this.FLOATPRECISION_RANGE[this.FLOATPRECISION_RANGE.length-1])
{
coordinate.Message[1] = value.toExponential(2).toString();
}
else
{
var floatPrecision=this.GetFloatPrecision(absValue,this.FloatPrecision); //数据比小数位数还小, 调整小数位数
coordinate.Message[1] = IFrameSplitOperator.FormatValueString(value, floatPrecision,this.LanguageID);
}
coordinate.Message[0]=coordinate.Message[1];
if (this.IsShowLeftText==false) this.Frame.HorizontalInfo[i].Message[0]=null;
if (this.IsShowRightText==false) this.Frame.HorizontalInfo[i].Message[1]=null;
this.Frame.HorizontalInfo.push(coordinate);
}
}
else
{
for(var i=0,value=splitData.Min;i<splitData.Count;++i,value+=splitData.Interval)
{
this.Frame.HorizontalInfo[i]= new CoordinateInfo();
this.Frame.HorizontalInfo[i].Value=value;
if (this.StringFormat==1) //手机端格式 如果有万,亿单位了 去掉小数
{
var floatPrecision=this.FloatPrecision;
if (!isNaN(value) && Math.abs(value) > 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 (absValue<this.FLOATPRECISION_RANGE[this.FLOATPRECISION_RANGE.length-1])
{
this.Frame.HorizontalInfo[i].Message[1] = value.toExponential(2).toString();
}
else
{
var floatPrecision=this.GetFloatPrecision(absValue,this.FloatPrecision); //数据比小数位数还小, 调整小数位数
this.Frame.HorizontalInfo[i].Message[1] = IFrameSplitOperator.FormatValueString(value, floatPrecision,this.LanguageID);
}
}
this.Frame.HorizontalInfo[i].Message[0]=this.Frame.HorizontalInfo[i].Message[1];
if (this.IsShowLeftText==false) this.Frame.HorizontalInfo[i].Message[0]=null;
if (this.IsShowRightText==false) this.Frame.HorizontalInfo[i].Message[1]=null;
//this.Frame.HorizontalInfo[i].Font="14px 微软雅黑";
//this.Frame.HorizontalInfo[i].TextColor="rgb(100,0,200)";
//this.Frame.HorizontalInfo[i].LineColor="rgb(220,220,220)";
}
}
this.Frame.HorizontalInfo = this.Filter(this.Frame.HorizontalInfo,(splitData.Max>0 && splitData.Min<0));
this.RemoveZero(this.Frame.HorizontalInfo);
this.Frame.HorizontalMax=splitData.Max;
this.Frame.HorizontalMin=splitData.Min;
this.RightFrameSplitY();
}
this.RightFrameSplitY=function()
{
if (!this.Frame.RightFrame) return;
var rightFrame=this.Frame.RightFrame;
for(var i in this.Frame.HorizontalInfo)
{
var item=this.Frame.HorizontalInfo[i];
var y=this.Frame.GetYFromData(item.Value);
var yValue=rightFrame.GetYData(y);
item.Message[1] = IFrameSplitOperator.FormatValueString(yValue, this.FloatPrecision,this.LanguageID);
}
}
}
function FrameSplitKLineX()
{
this.newMethod=IFrameSplitOperator; //派生
this.newMethod();
delete this.newMethod;
this.ShowText=true; //是否显示坐标信息
this.Period; //周期
this.Symbol; //股票代码
this.MinTextDistance=50*GetDevicePixelRatio();
this.MinBarDistance=5; //刻度间最小的K线间距
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;
var barDistance=0;
for(var i=0, index=xOffset; i<xPointCount && index<this.Frame.Data.Data.length; ++i,++index)
{
textDistance+=itemWidth;
++barDistance;
var infoData=null;
if (i==0)
{
var date=IFrameSplitOperator.FormatDateString(this.Frame.Data.Data[index].Date,'MM-DD');
infoData={Value:index-xOffset, Text:date};
}
else if (textDistance>this.MinTextDistance && barDistance>=this.MinBarDistance)
{
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;
barDistance=0;
if (i==0) textDistance=-(this.MinTextDistance/2);
}
}
}
this.SplitSecond=function() //根据时间分割
{
this.Frame.VerticalInfo=[];
var itemWidth=this.Frame.DistanceWidth+this.Frame.DataWidth;
var xOffset=this.Frame.Data.DataOffset;
var xPointCount=this.Frame.XPointCount;
var textDistance=0;
var barDistance=0;
for(var i=0, index=xOffset; i<xPointCount && index<this.Frame.Data.Data.length; ++i,++index)
{
textDistance+=itemWidth;
++barDistance;
var infoData=null;
if (i==0)
{
var date=IFrameSplitOperator.FormatDateString(this.Frame.Data.Data[index].Date,'MM-DD');
infoData={Value:index-xOffset, Text:date};
}
else if (textDistance>this.MinTextDistance && barDistance>=this.MinBarDistance)
{
var time=IFrameSplitOperator.FormatTimeString(this.Frame.Data.Data[index].Time,"HH:MM:SS");
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;
barDistance=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;i<xPointCount && index<this.Frame.Data.Data.length ;++i,++index)
{
var year=parseInt(this.Frame.Data.Data[index].Date/10000);
var month=parseInt(this.Frame.Data.Data[index].Date/100)%100;
if (distance<minDistance ||
(lastYear!=null && lastYear==year && lastMonth!=null && lastMonth==month))
{
lastMonth=month;
++distance;
continue;
}
var info= new CoordinateInfo();
info.Value=index-xOffset;
var text;
if (lastYear==null || lastYear!=year)
{
text=year.toString();
}
else if (lastMonth==null || lastMonth!=month)
{
text=month.toString()+'月';
text=g_JSChartLocalization.GetText(text, this.LanguageID);
}
lastYear=year;
lastMonth=month;
if (this.ShowText)
{
info.Message[0]=text;
}
this.Frame.VerticalInfo.push(info);
distance=0;
}
}
this.Operator=function()
{
if (this.Frame.Data==null) return;
if (FrameSplitKLineX.SplitCustom) FrameSplitKLineX.SplitCustom(this); //自定义分割
else if (ChartData.IsMinutePeriod(this.Period, true)) this.SplitDateTime();
else if (ChartData.IsSecondPeriod(this.Period)) this.SplitSecond();
else this.SplitDate();
}
this.CreateCoordinateInfo=function()
{
return new CoordinateInfo();
}
}
//FrameSplitKLineX.SplitCustom=function(split) { }
function FrameSplitMinutePriceY()
{
this.newMethod=IFrameSplitOperator; //派生
this.newMethod();
delete this.newMethod;
this.High=null; //最高最低价
this.Low=null;
this.YClose; //昨收
this.Data; //分钟数据
this.AverageData; //分钟均线数据
this.SourceData; //原始数据
this.OverlayChartPaint;
this.SplitCount=7;
this.Symbol;
this.SplitType=0; //0=默认根据最大最小值分割 1=涨跌停分割
this.LimitPrice;
this.Custom;
this.Operator=function()
{
this.Frame.HorizontalInfo=[];
this.Frame.CustomHorizontalInfo=[];
if (!this.Data) return;
var range=this.GetMaxMin();
if (this.Symbol && MARKET_SUFFIX_NAME.IsUSA(this.Symbol.toUpperCase()))
{
this.USASplit(range);
}
else
{
this.DefaultSplit(range);
}
this.CustomCoordinate();
}
this.CustomCoordinate=function() //自定义刻度
{
if (!this.Custom) return;
for(var i in this.Custom)
{
var item=this.Custom[i];
if (item.Type==1) this.CustomFixedCoordinate(item);
}
}
this.CustomFixedCoordinate=function(option) //固定坐标刻度
{
var defaultfloatPrecision=GetfloatPrecision(this.Symbol);
for(var i in option.Data)
{
var item=option.Data[i];
var info=new CoordinateInfo();
info.Type=1;
info.TextColor=item.TextColor;
info.LineColor=item.Color;
info.LineType=2; //虚线
if (option.IsShowLine==false) info.LineType=-1;
if (IFrameSplitOperator.IsNumber(item.Increase)) //涨幅计算价格
{
if (!IFrameSplitOperator.IsNumber(this.YClose)) conintue;
info.Value=this.YClose*(1+item.Increase);
}
else
{
info.Value=item.Value;
}
var text;
if (item.Text) text=item.Text;
else text=info.Value.toFixed(defaultfloatPrecision);
if (option.Position=='left') info.Message[0]=text;
else info.Message[1]=text;
this.Frame.CustomHorizontalInfo.push(info);
}
}
this.GetMaxMin=function() //计算图中所有的数据的最大最小值
{
var max=this.YClose;
var min=this.YClose;
var data=this.Data;
var isBerforeData=false;
if (this.SourceData)
{
data=this.SourceData;
isBerforeData=true;
}
for(var i in data.Data)
{
var value=null;
if (isBerforeData)
{
var item=data.Data[i];
if (item.Before) value=item.Before.Close;
else value=item.Close;
}
else
{
value=data.Data[i];
}
if (value==null) continue;
if (max<value) max=value;
if (min>value) min=value;
}
if (this.AverageData)
{
for(var i in this.AverageData.Data)
{
if (this.AverageData.Data[i]==null) continue;
if (max<this.AverageData.Data[i]) max=this.AverageData.Data[i];
if (min>this.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.Min<min) min=range.Min;
}
if (this.SplitType==1 && this.LimitPrice)
{
if (max<this.LimitPrice.Max) max=this.LimitPrice.Max;
if (min>this.LimitPrice.Min) min=this.LimitPrice.Min;
}
if (IFrameSplitOperator.IsNumber(this.High) && IFrameSplitOperator.IsNumber(this.Low))
{
if (max<this.High) max=this.High;
if (min>this.Low) min=this.Low;
}
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 (distance<minDistance[defaultfloatPrecision])
{
distance=minDistance[defaultfloatPrecision];
max=min+distance*showCount;
//min=this.YClose-(distance*(showCount-1)/2);
}
for(var i=0;i<showCount;++i)
{
var price=min+(distance*i);
var coordinate=new CoordinateInfo();
coordinate.Value=price;
if (this.IsShowLeftText) coordinate.Message[0]=price.toFixed(defaultfloatPrecision);
if (this.YClose)
{
var per=(price/this.YClose-1)*100;
if (per>0) 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.YClose<max)
{
var coordinate=new CoordinateInfo();
coordinate.Value=this.YClose;
this.Frame.HorizontalInfo.push(coordinate);
}
this.Frame.HorizontalInfo.sort(function(a,b) { return a.Value-b.Value; });
this.Frame.HorizontalMax=max;
this.Frame.HorizontalMin=min;
}
this.DefaultSplit=function(range)
{
var max=range.Max;
var min=range.Min;
if (this.YClose==max && this.YClose==min)
{
max=this.YClose+this.YClose*0.1;
min=this.YClose-this.YClose*0.1
}
else
{
var distanceValue=Math.max(Math.abs(this.YClose-max),Math.abs(this.YClose-min));
max=this.YClose+distanceValue;
min=this.YClose-distanceValue;
}
var pixelTatio = GetDevicePixelRatio(); //获取设备的分辨率
var width=this.Frame.ChartBorder.GetChartWidth(); //画布的宽度
var isPhoneModel=width<450*pixelTatio;
JSConsole.Chart.Log('[FrameSplitMinutePriceY]'+ 'max='+ max + ' min='+ min +' isPhoneModel='+isPhoneModel);
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 (isPhoneModel && MARKET_SUFFIX_NAME.IsSHSZIndex(this.Symbol)) defaultfloatPrecision = 0; //手机端指数不显示小数位数,太长了
if (distance<minDistance[defaultfloatPrecision])
{
distance=minDistance[defaultfloatPrecision];
max=this.YClose+(distance*(showCount-1)/2);
min=this.YClose-(distance*(showCount-1)/2);
}
for(var i=0;i<showCount;++i)
{
var price=min+(distance*i);
this.Frame.HorizontalInfo[i]= new CoordinateInfo();
this.Frame.HorizontalInfo[i].Value=price;
if (this.IsShowLeftText) this.Frame.HorizontalInfo[i].Message[0]=price.toFixed(defaultfloatPrecision);
if (price==this.YClose)
{
this.Frame.HorizontalInfo[i].LineType=2;//中间的线画虚线
if (g_JSChartResource.FrameDotSplitPen) this.Frame.HorizontalInfo[i].LineColor=g_JSChartResource.FrameDotSplitPen;
}
if (this.YClose)
{
var per=(price/this.YClose-1)*100;
if (per>0) this.Frame.HorizontalInfo[i].TextColor=g_JSChartResource.UpTextColor;
else if (per<0) this.Frame.HorizontalInfo[i].TextColor=g_JSChartResource.DownTextColor;
if (this.IsShowRightText) this.Frame.HorizontalInfo[i].Message[1]=IFrameSplitOperator.FormatValueString(per,2)+'%'; //百分比
}
}
this.Frame.HorizontalMax=max;
this.Frame.HorizontalMin=min;
}
}
function FrameSplitMinuteX()
{
this.newMethod=IFrameSplitOperator; //派生
this.newMethod();
delete this.newMethod;
this.ShowText=true; //是否显示坐标信息
this.Symbol=null; //股票代码 x轴刻度根据股票类型来调整
this.DayCount=1;
this.ShowDateFormate=1; //0=YYYY-MM-DD 1=MM-DD
this.IsBeforeData=false; //是否显示盘前数据
this.Operator=function()
{
this.Frame.VerticalInfo=[];
var xPointCount=this.Frame.XPointCount;
var width = this.Frame.ChartBorder.GetWidth();
var isHScreen=(this.Frame.IsHScreen===true);
if (isHScreen) width = this.Frame.ChartBorder.GetHeight();
width=width/GetDevicePixelRatio();
const minuteCoordinate = g_MinuteCoordinateData;
var xcoordinateData = minuteCoordinate.GetCoordinateData(this.Symbol,width);
var minuteCount=xcoordinateData.Count;
var minuteMiddleCount=xcoordinateData.MiddleCount>0? 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<xPointCount && index<this.Frame.Data.Data.length ;++i,++index)
{
var info= new CoordinateInfo();
info.Value=index-xOffset;
if (this.ShowText)
info.Message[0]=this.Frame.XData[i];
this.Frame.VerticalInfo.push(info);
distance=0;
}
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
//十字光标
function ChartCorssCursor()
{
this.Frame;
this.Canvas; //画布
this.HPenColor=g_JSChartResource.CorssCursorHPenColor; //水平线颜色
this.HPenType=0; //水平线样式 0=虚线 1=实线
this.VPenColor=g_JSChartResource.CorssCursorVPenColor; //垂直线颜色
this.VPenType=0; //垂直线颜色 0=虚线 1=实线 2=K线宽度
this.Font=g_JSChartResource.CorssCursorTextFont; //字体
this.TextColor=g_JSChartResource.CorssCursorTextColor; //文本颜色
this.TextBGColor=g_JSChartResource.CorssCursorBGColor; //文本背景色
this.TextHeight=20; //文本字体高度
this.LastPoint;
this.CursorIndex;
this.IsOnlyDrawKLine=false; //是否只能画在K线上 (手机端)
this.PointX;
this.PointY;
this.StringFormatX;
this.StringFormatY;
this.ShowTextMode={ Left:1, Right:1, Bottom:1 }; //0=不显示 1=显示在框架外 2=显示在框架内
this.IsShowCorss=true; //是否显示十字光标
this.IsShow=true;
this.IsShowClose=false; //Y轴始终显示收盘价
//内部使用
this.Close=null; //收盘价格
this.GetCloseYPoint=function(index)
{
if (!this.StringFormatX.Data) return null;
var data = this.StringFormatX.Data;
if (!data.Data || data.Data.length <= 0) return null;
var dataIndex = data.DataOffset + index;
if (dataIndex >= 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)
{
var pixel=GetDevicePixelRatio();
this.Canvas.save();
this.Canvas.strokeStyle=this.HPenColor;
if (this.HPenType==0) this.Canvas.setLineDash([3*pixel,2*pixel]); //虚线
//this.Canvas.lineWidth=0.5
this.Canvas.beginPath();
this.Canvas.moveTo(left,ToFixedPoint(y));
this.Canvas.lineTo(right,ToFixedPoint(y));
this.Canvas.stroke();
this.Canvas.restore();
this.Canvas.save();
this.Canvas.strokeStyle=this.VPenColor;
if (this.VPenType==0)
{
this.Canvas.setLineDash([3*pixel,2*pixel]); //虚线
}
else if (this.VPenType==2)
{
let barWidth=this.Frame.SubFrame[0].Frame.DataWidth; //和K线一样宽度
if (barWidth>2*pixel) this.Canvas.lineWidth=barWidth;
}
this.Canvas.beginPath();
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.RValue=yValueExtend.RightYValue; //右侧子坐标
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<textWidth ) //左边空白的地方太少了画布下
{
this.Canvas.fillRect(2,y-this.TextHeight/2,textWidth,this.TextHeight);
this.Canvas.textAlign="left";
this.Canvas.textBaseline="middle";
this.Canvas.fillStyle=this.TextColor;
this.Canvas.fillText(text,2+2,y,textWidth);
}
else
{
this.Canvas.fillRect(left-2,y-this.TextHeight/2,-textWidth,this.TextHeight);
this.Canvas.textAlign="right";
this.Canvas.textBaseline="middle";
this.Canvas.fillStyle=this.TextColor;
this.Canvas.fillText(text,left-4,y,textWidth);
}
}
else if (this.ShowTextMode.Left==2) //在框架内显示
{
this.Canvas.fillStyle=this.TextBGColor;
this.Canvas.fillRect(left,y-this.TextHeight/2,textWidth,this.TextHeight);
this.Canvas.textAlign="left";
this.Canvas.textBaseline="middle";
this.Canvas.fillStyle=this.TextColor;
this.Canvas.fillText(text,left+2,y,textWidth);
}
if (this.StringFormatY.PercentageText)
{
text=this.StringFormatY.PercentageText+'%';
textWidth=this.Canvas.measureText(text).width+4; //前后各空2个像素
}
if (this.StringFormatY.RText)
{
text=this.StringFormatY.RText;
var textWidth=this.Canvas.measureText(text).width+4; //前后各空2个像素
}
if (this.Frame.ChartBorder.Right>=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<textWidth) //右边空白显示不下,
{
this.Canvas.fillRect(chartRight-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,chartRight-4,y,textWidth);
}
else
{
this.Canvas.fillRect(right+2,y-this.TextHeight/2,textWidth,this.TextHeight);
this.Canvas.textAlign="left";
this.Canvas.textBaseline="middle";
this.Canvas.fillStyle=this.TextColor;
this.Canvas.fillText(text,right+4,y,textWidth);
}
}
else if (this.ShowTextMode.Right==2)
{
this.Canvas.fillStyle=this.TextBGColor;
var showLeft=right-textWidth;
this.Canvas.fillRect(showLeft,y-this.TextHeight/2,textWidth,this.TextHeight);
this.Canvas.textAlign="left";
this.Canvas.textBaseline="middle";
this.Canvas.fillStyle=this.TextColor;
this.Canvas.fillText(text,showLeft+2,y,textWidth);
}
}
//X轴
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个像素
var yCenter=bottom+2+this.TextHeight/2;
//JSConsole.Chart.Log('[ChartCorssCursor::Draw] ',yCenter);
if (x-textWidth/2<3) //左边位置不够了, 顶着左边画
{
this.Canvas.fillRect(x-1,bottom+2,textWidth,this.TextHeight);
this.Canvas.textAlign="left";
this.Canvas.textBaseline="middle";
this.Canvas.fillStyle=this.TextColor;
this.Canvas.fillText(text,x+1,yCenter,textWidth);
}
else if (x+textWidth/2>=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 (textWidth<frame.Interval) break;
}
this.Canvas.fillStyle=this.TextBGColor;
this.Canvas.fillRect(overlayLeft+2,y-this.TextHeight/2,textWidth,this.TextHeight);
this.Canvas.textAlign="left";
this.Canvas.textBaseline="middle";
this.Canvas.fillStyle=this.TextColor;
this.Canvas.fillText(text,overlayLeft+4,y,textWidth);
}
}
}
this.HScreenDraw=function()
{
var x=this.LastPoint.X;
var y=this.LastPoint.Y;
if (this.IsOnlyDrawKLine) //手机端 十字只能画在K线上
y=this.Frame.GetXFromIndex(this.CursorIndex);
var left=this.Frame.ChartBorder.GetLeft();
var right=this.Frame.ChartBorder.GetRightEx();
var top=this.Frame.ChartBorder.GetTop();
var bottom=this.Frame.ChartBorder.GetBottom();
var bottomWidth=this.Frame.ChartBorder.Bottom;
this.PointY=[[left,y],[right,y]];
this.PointX=[[x,top],[x,bottom]];
//十字线
if (this.IsShowCorss)
{
var pixel=GetDevicePixelRatio();
this.Canvas.save();
this.Canvas.strokeStyle=this.HPenColor;
if (this.HPenType==0) this.Canvas.setLineDash([3*pixel,2*pixel]); //虚线
//画竖线
this.Canvas.beginPath();
this.Canvas.moveTo(ToFixedPoint(x),top);
this.Canvas.lineTo(ToFixedPoint(x),bottom);
this.Canvas.stroke();
this.Canvas.restore();
//画横线
this.Canvas.save();
this.Canvas.strokeStyle=this.VPenColor;
if (this.VPenType==0)
{
this.Canvas.setLineDash([3*pixel,2*pixel]); //虚线
}
else if (this.VPenType==2)
{
let barWidth=this.Frame.SubFrame[0].Frame.DataWidth; //和K线一样宽度
if (barWidth>2*pixel) this.Canvas.lineWidth=barWidth;
}
this.Canvas.beginPath();
if (this.Frame.SubFrame.length>0)
{
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.RValue; //右边值
this.RText;
this.Operator=function()
{
this.RText=null;
if (IFrameSplitOperator.IsString(this.RValue)) this.RText=this.RValue;
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 if (this.FrameID==1)
{
this.Text=IFrameSplitOperator.FormatValueString(this.Value,defaultfloatPrecision,this.LanguageID);
if (IFrameSplitOperator.IsNumber(this.RValue)) this.RText=IFrameSplitOperator.FormatValueString(this.RValue,defaultfloatPrecision,this.LanguageID);
}
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.IsSecondPeriod(this.Data.Period))
{
var time = IFrameSplitOperator.FormatTimeString(currentData.Time,'HH:MM:SS');
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)) // 分钟周期
{
title2=IFrameSplitOperator.FormatTimeString(data.Time);
}
else if (ChartData.IsSecondPeriod(this.Value.ChartPaint.Data.Period))
{
title2=IFrameSplitOperator.FormatTimeString(data.Time,'HH:MM:SS');
}
var defaultfloatPrecision=GetfloatPrecision(this.Symbol);//价格小数位数
var increase=null;
if (data.YClose>0) increase=(data.Close-data.YClose)/data.YClose*100;
var strText=
"<span class='tooltip-title'>"+strDate+"  "+title2+"</span>"+
"<span class='tooltip-con'>"+g_JSChartLocalization.GetText('DivTooltip-Open',this.LanguageID)+"</span>"+
"<span class='tooltip-num' style='color:"+this.GetColor(data.Open,data.YClose)+";'>"+data.Open.toFixed(defaultfloatPrecision)+"</span><br/>"+
"<span class='tooltip-con'>"+g_JSChartLocalization.GetText('DivTooltip-High',this.LanguageID)+"</span>"+
"<span class='tooltip-num' style='color:"+this.GetColor(data.High,data.YClose)+";'>"+data.High.toFixed(defaultfloatPrecision)+"</span><br/>"+
"<span class='tooltip-con'>"+g_JSChartLocalization.GetText('DivTooltip-Low',this.LanguageID)+"</span>"+
"<span class='tooltip-num' style='color:"+this.GetColor(data.Low,data.YClose)+";'>"+data.Low.toFixed(defaultfloatPrecision)+"</span><br/>"+
"<span class='tooltip-con'>"+g_JSChartLocalization.GetText('DivTooltip-Close',this.LanguageID)+"</span>"+
"<span class='tooltip-num' style='color:"+this.GetColor(data.Close,data.YClose)+";'>"+data.Close.toFixed(defaultfloatPrecision)+"</span><br/>"+
//"<span style='color:"+this.YClose+";font:微软雅黑;font-size:12px'> 前收: "+IFrameSplitOperator.FormatValueString(data.YClose,2)+"</span><br/>"+
"<span class='tooltip-con'>"+g_JSChartLocalization.GetText('DivTooltip-Vol',this.LanguageID)+"</span>"+
"<span class='tooltip-num' style='color:"+this.VolColor+";'>"+IFrameSplitOperator.FormatValueString(data.Vol,2,this.LanguageID)+"</span><br/>"+
"<span class='tooltip-con'>"+g_JSChartLocalization.GetText('DivTooltip-Amount',this.LanguageID)+"</span>"+
"<span class='tooltip-num' style='color:"+this.AmountColor+";'>"+IFrameSplitOperator.FormatValueString(data.Amount,2,this.LanguageID)+"</span><br/>"+
"<span class='tooltip-con'>"+g_JSChartLocalization.GetText('DivTooltip-Increase',this.LanguageID)+"</span>"+
(increase==null? "<span class='tooltip-num' style='color:"+this.GetColor(0,0)+";'>"+'--'+"</span><br/>" :
"<span class='tooltip-num' style='color:"+this.GetColor(increase,0)+";'>"+increase.toFixed(2)+'%'+"</span><br/>");
this.LineCount=8;
if(MARKET_SUFFIX_NAME.IsSHSZStockA(this.Symbol) && data.FlowCapital>0) //换手率
{
var value=data.Vol/data.FlowCapital*100;
strText+= "<span class='tooltip-con'>"+g_JSChartLocalization.GetText('DivTooltip-Exchange',this.LanguageID)+"</span>"+
"<span class='tooltip-num' style='color:"+this.AmountColor+";'>"+value.toFixed(2)+'%'+"</span><br/>";
++this.LineCount;
}
//叠加股票
if (this.Value.ChartPaint.Name=="Overlay-KLine")
{
var title="<span style='color:rgb(0,0,0);font:微软雅黑;font-size:12px;text-align:center;display: block;'>"+this.Value.ChartPaint.Title+"</span>";
strText=title+strText;
++this.LineCount;
}
this.Text=strText;
return true;
}
this.GetColor=function(price,yclse)
{
if(price>yclse) return this.UpColor;
else if (price<yclse) return this.DownColor;
else return this.UnchagneColor;
}
}
//K线信息地雷提示信息格式
function KLineInfoDataStringFormat()
{
this.newMethod=IChangeStringFormat; //派生
this.newMethod();
delete this.newMethod;
this.UpColor=g_JSChartResource.UpTextColor;
this.DownColor=g_JSChartResource.DownTextColor;
this.UnchagneColor=g_JSChartResource.UnchagneTextColor;
this.Operator=function()
{
if (!this.Value) return false;
var infoList=this.Value.Data.Data; //数据
var infoType=this.Value.Data.Type; //类型
var strText='';
for(var i in infoList)
{
var item=infoList[i];
var tempText='';
switch(infoType)
{
case KLINE_INFO_TYPE.BLOCKTRADING:
tempText=this.BlockTradingFormat(item);
break;
case KLINE_INFO_TYPE.TRADEDETAIL:
tempText=this.TradeDetailFormat(item);
break;
case KLINE_INFO_TYPE.RESEARCH:
tempText=this.ResearchFormat(item);
break;
case KLINE_INFO_TYPE.PFORECAST:
tempText=this.PerformanceForecastFormat(item);
break;
default:
tempText=this.DefaultFormat(item);
break;
}
strText+=tempText;
}
var html="<div class='title-length'>"+strText+"</div>";
if(infoList.length > 8)
{
var strBox="<div class='total-list'>共"+infoList.length+"条</div>";
html+=strBox;
}
this.Text=html;
return true;
}
this.DefaultFormat=function(item)
{
var strDate=IFrameSplitOperator.FormatDateString(item.Date);
var strText="<span>"+strDate+" "+item.Title+"</span>";
return strText;
}
//大宗交易
this.BlockTradingFormat=function(item)
{
var showPriceInfo = item.ExtendData;
var strDate=IFrameSplitOperator.FormatDateString(item.Date);
var strText="<span><i class='date-tipbox'>"+strDate+"</i> <i class='tipBoxTitle'>成交价: "+showPriceInfo.Price.toFixed(2)+"</i><i class='tipBoxTitle'>收盘价: "+showPriceInfo.ClosePrice.toFixed(2)+
"</i><br/><i class='rate-discount tipBoxTitle'>溢折价率: <strong style='color:"+ this.GetColor(showPriceInfo.Premium.toFixed(2))+"'>"+
showPriceInfo.Premium.toFixed(2)+"%</strong></i><i class='tipBoxTitle'>成交量(万股): "+showPriceInfo.Vol.toFixed(2)+"</i></span>";
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 += "<i>"+detail[i].TypeExplain+"</i><br/>"
// reasons += detail[i] + "<br/>"
}
var strText= "<span><i class='trade-time'>"+strDate+" 上榜原因: </i><i class='reason-list'>"+reasons+"</i><br/><i class='trade-detall'>一周后涨幅: <strong style='color:"+
this.GetColor(item.ExtendData.FWeek.Week1.toFixed(2))+"'>"+ item.ExtendData.FWeek.Week1.toFixed(2)+
"%</strong> 四周后涨幅: <strong style='color:"+this.GetColor(item.ExtendData.FWeek.Week4.toFixed(2))+";'>"+
item.ExtendData.FWeek.Week4.toFixed(2)+"%</strong></i></span>";
return strText;
}
//调研
this.ResearchFormat=function(item)
{
var levels=item.ExtendData.Level;
var recPerson='';
if(levels.length==0)
{
recPerson = "<i>一般调研</i>"
}
else
{
for(var j in levels)
{
if(levels[j]==0) recPerson+="<i style='color:#00a0e9'>证券代表 </i>";
else if(levels[j]==1) recPerson+="<i>董秘 </i>";
else if(levels[j]==2) recPerson+="<i style='color:#00a0e9'>总经理 </i>";
else if(levels[j]==3) recPerson+="<i style='color:#00a0e9'>董事长 </i>";
}
recPerson='接待: '+recPerson;
}
var researchType='';
if (item.ExtendData.Type && item.ExtendData.Type!='其他')
{
researchType=' '+'<i>'+item.ExtendData.Type+'</i>';
if (levels.length==0) recPerson='';
}
var strDate=IFrameSplitOperator.FormatDateString(item.Date);
var strText="<span>"+strDate+" "+researchType+recPerson+"</span>";
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+="一周后涨幅:<i class='increase' style='color:"+this.GetColor(item.ExtendData.FWeek.Week1.toFixed(2))+"'>"+ item.ExtendData.FWeek.Week1.toFixed(2)+"%</i>";
if (item.ExtendData.FWeek.Week4!=null) weekData+=" 四周后涨幅:<i class='increase' style='color:"+this.GetColor(item.ExtendData.FWeek.Week4.toFixed(2))+"'>"+ item.ExtendData.FWeek.Week4.toFixed(2)+"%</i>";
if (weekData.length>0) weekData="<br/> <i class='prorecast-week'>"+weekData+"</i>";
}
var strDate=IFrameSplitOperator.FormatDateString(item.Date);
var strText="<span>"+strDate+" "+year+reportType+item.Title+" "+weekData+"</span>";
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;
this.ClassName='IChartTitlePainting';
}
//var PERIOD_NAME=["日线","周线","月线","年线","1分","5分","15分","30分","60分","季线","分笔", "2小时","4小时","双周","",""];
var RIGHT_NAME=['不复权','前复权','后复权'];
function DynamicKLineTitlePainting()
{
this.newMethod=IChartTitlePainting; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='DynamicKLineTitlePainting';
this.IsDynamic=true;
this.IsShow=true; //是否显示
this.Period; //周期
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 if (this.Data.Period>CUSTOM_SECOND_PERIOD_START && this.Data.Period<=CUSTOM_SECOND_PERIOD_END)
periodName=(this.Data.Period-CUSTOM_SECOND_PERIOD_START)+g_JSChartLocalization.GetText('自定义秒',this.LanguageID);
else
periodName=g_JSChartLocalization.GetText(ChartData.GetPeriodName(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 (ChartData.IsMinutePeriod(this.Period,true) && item.Time)
{
var text=IFrameSplitOperator.FormatTimeString(item.Time);
if (!this.DrawText(text,this.DateTimeColor,position)) return;
}
else if (ChartData.IsSecondPeriod(this.Period) && item.Time)
{
var text=IFrameSplitOperator.FormatTimeString(item.Time, "HH:MM:SS");
if (!this.DrawText(text,this.DateTimeColor,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;
if (item.YClose>0)
{
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:this.ClassName};
this.OnDrawEvent.Callback(this.OnDrawEvent,data,this);
}
this.GetColor=function(price,yclse)
{
if(price>yclse) return this.UpColor;
else if (price<yclse) return this.DownColor;
else return this.UnchagneColor;
}
this.DrawText=function(title,color,position)
{
if (!title) return true;
var isHScreen=this.Frame.IsHScreen===true;
var right = this.Frame.ChartBorder.GetRight();
if (isHScreen) right=this.Frame.ChartBorder.GetHeight();
this.Canvas.fillStyle = color;
var textWidth = this.Canvas.measureText(title).width;
if (position.Left + textWidth > 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.ClassName='DynamicMinuteTitlePainting';
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.NameColor,position)) return;
}
var text=IFrameSplitOperator.FormatDateTimeString(item.DateTime,this.IsShowDate);
if (!this.DrawText(text,this.DateTimeColor,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;
}
var isShowAvPrice=true;
var upperSymbol=this.Symbol.toUpperCase();
if (MARKET_SUFFIX_NAME.IsET(upperSymbol) && !MARKET_SUFFIX_NAME.IsETShowAvPrice(upperSymbol)) isShowAvPrice=false;
if (item.AvPrice && isShowAvPrice)
{
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.ClassName='DynamicChartTitlePainting';
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.TitleRect; //指标名字显示区域
this.IsDrawTitleBG=false; //是否绘制指标名字背景色
this.BGColor=g_JSChartResource.IndexTitleBGColor;
this.OnDrawEvent;
this.IsClickTitle=function(x,y) //是否点击了指标标题
{
if (!this.TitleRect) return false;
if (x>this.TitleRect.Left && x<this.TitleRect.Left+this.TitleRect.Width && y>this.TitleRect.Top && y<this.TitleRect.Top+this.TitleRect.Height)
{
return true;
}
return false;
}
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()
{
this.IsDrawTitleBG=this.Frame.IsDrawTitleBG;
this.TitleRect=null;
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)
{
var textWidth=this.Canvas.measureText(this.Title).width+2;
if (this.IsDrawTitleBG)
{
var spaceSize=GetDevicePixelRatio()*2;
this.Canvas.fillStyle=this.BGColor;
this.TitleRect={Left:left, Top:this.Frame.ChartBorder.GetTop()+spaceSize, Width:textWidth, Height:this.Frame.ChartBorder.TitleHeight-(spaceSize*2)}; //保存下标题的坐标
this.Canvas.fillRect(this.TitleRect.Left,this.TitleRect.Top,this.TitleRect.Width,this.TitleRect.Height);
}
this.Canvas.fillStyle=this.TitleColor;
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+textWidth<right)
{
this.Canvas.fillText(text,left,bottom,textWidth);
left+=textWidth;
}
}
if (this.ColorIndex)
{
this.Canvas.fillStyle='rgb(105,105,105)'
var textWidth=this.Canvas.measureText(this.ColorIndex.Name).width+2; //后空2个像素
this.Canvas.fillText(this.ColorIndex.Name,left,bottom,textWidth);
left+=textWidth;
}
if (this.TradeIndex)
{
this.Canvas.fillStyle='rgb(105,105,105)';
var textWidth=this.Canvas.measureText(this.TradeIndex.Name).width+2; //后空2个像素
this.Canvas.fillText(this.TradeIndex.Name,left,bottom,textWidth);
left+=textWidth;
}
this.DrawOverlayIndex(left+10*GetDevicePixelRatio()); //间距都空点 和主指标区分开
}
this.DrawOverlayIndex=function(left) //叠加指标标题
{
var bottom=this.Frame.ChartBorder.GetTop()+this.Frame.ChartBorder.TitleHeight/2; //上下居中显示
var right=this.Frame.ChartBorder.GetRight();
if (this.Frame.IsHScreen===true)
{
bottom=-this.Frame.ChartBorder.TitleHeight/2;
right=this.Frame.ChartBorder.GetHeight();
}
if (left>right) 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)
{
var textWidth=this.Canvas.measureText(this.Title).width+2;
if (this.IsDrawTitleBG)
{
var spaceSize=GetDevicePixelRatio()*2;
this.Canvas.fillStyle=this.BGColor;
this.TitleRect= {Left:this.Frame.ChartBorder.GetRightTitle(),Top:this.Frame.ChartBorder.GetTop(),Width:this.Frame.ChartBorder.TitleHeight ,Height:textWidth}; //保存下标题的坐标
let drawRect={Left:left, Top:-this.Frame.ChartBorder.TitleHeight+spaceSize, Width:textWidth, Height:this.Frame.ChartBorder.TitleHeight-(spaceSize*2)};
this.Canvas.fillRect(drawRect.Left,drawRect.Top,drawRect.Width,drawRect.Height);
}
this.Canvas.fillStyle=this.TitleColor;
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<right)
{
this.Canvas.fillText(text,left,bottom,textWidth);
left+=textWidth;
}
}
this.DrawOverlayIndex(left+5*GetDevicePixelRatio()); //间距都空点 和主指标区分开
}
this.OnDrawEventCallback=function(drawData)
{
if (!this.OnDrawEvent || !this.OnDrawEvent.Callback) return;
var data={ Draw: drawData, Name:'DynamicChartTitlePainting'};
this.OnDrawEvent.Callback(this.OnDrawEvent,data,this);
}
}
//画图工具
function IChartDrawPicture()
{
this.Frame;
this.Canvas;
this.Point=new Array() //画图的点
this.Value=new Array(); //XValue,YValue
this.LinePoint=[];
this.PointCount=2; //画点的个数
this.Status=0; //0=开始画 1=完成第1个点 2=完成第2个点 3=完成第3个点 10=完成 20=移动
this.PointStatus=0; //2=第2个点完成
this.MovePointIndex=null; //移动哪个点 0-10 对应Point索引 100 整体移动
this.ClassName='IChartDrawPicture';
this.FinishedCallback; //画图完成回调通知
this.Guid=Guid(); //ID标识
this.Symbol; //对应的股票
this.Period; //对应的周期
this.IsSelected=false; //是否选中
this.Option;
// this.LineColor=g_JSChartResource.DrawPicture.LineColor[0]; //线段颜色
this.LineColor="#1e90ff"; //线段颜色,input type="color" 不支持rgb和rgba 的格式
this.AreaColor='rgba(25,25,25,0.4)'; //面积颜色
this.PointColor=g_JSChartResource.DrawPicture.PointColor[0];
//接口函数
this.SetLastPoint=null; //this.SetLastPoint=function(obj) obj={X:,Y:}
this.Update=null; //更新数据回调
this.Draw=function()
{
}
//Point => Value
this.PointToValue=function()
{
if (!this.Frame) return false;
var data=this.Frame.Data;
if (!data) return false;
var isHScreen=this.Frame.IsHScreen;
if (isHScreen)
{
for(var i in this.Point)
{
var item=this.Point[i];
var xValue=parseInt(this.Frame.GetXData(item.Y))+data.DataOffset;
var yValue=this.Frame.GetYData(item.X);
this.Value[i]={};
this.Value[i].XValue=xValue;
this.Value[i].YValue=yValue;
}
}
else
{
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;
var isHScreen=this.Frame.IsHScreen;
this.Point=[];
for(var i in this.Value)
{
var item=this.Value[i];
var pt=new Point();
if (isHScreen)
{
pt.Y=this.Frame.GetXFromIndex(item.XValue-data.DataOffset);
pt.X=this.Frame.GetYFromData(item.YValue);
}
else
{
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<this.Point.length)
{
this.Point[index].X+=xStep;
this.Point[index].Y+=yStep;
}
}
else
{
return false;
}
}
this.ClipFrame=function()
{
if (this.Frame.IsHScreen)
{
var left=this.Frame.ChartBorder.GetLeftEx();
var top=this.Frame.ChartBorder.GetTop();
var width=this.Frame.ChartBorder.GetWidthEx();
var height=this.Frame.ChartBorder.GetHeight();
}
else
{
var left=this.Frame.ChartBorder.GetLeft();
var top=this.Frame.ChartBorder.GetTopEx();
var width=this.Frame.ChartBorder.GetWidth();
var height=this.Frame.ChartBorder.GetHeightEx();
}
this.Canvas.save();
this.Canvas.beginPath();
this.Canvas.rect(left,top,width,height);
this.Canvas.clip();
}
//计算需要画的点的坐标option:{IsCheckX:是否检测X值, IsCheckY:是否检测Y值}
this.CalculateDrawPoint=function(option)
{
if (this.Status<2) return null;
if(!this.Point.length || !this.Frame) return null;
var drawPoint=new Array();
if (this.Status==10)
{
var data=this.Frame.Data;
if (!data) return null;
var showCount=this.Frame.XPointCount;
var invaildX=0; //超出范围的x点个数
var isHScreen=this.Frame.IsHScreen;
for(var i in this.Value)
{
var item=this.Value[i];
var dataIndex=item.XValue-data.DataOffset;
if (dataIndex<0 || dataIndex>=showCount) ++invaildX;
var pt=new Point();
if (isHScreen) //横屏X,Y对调
{
pt.Y=this.Frame.GetXFromIndex(item.XValue-data.DataOffset,false);
pt.X=this.Frame.GetYFromData(item.YValue,false);
}
else
{
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 || yValue<this.Frame.HorizontalMin) return false;
return true;
}
this.DrawPoint=function(aryPoint)
{
if (!aryPoint || aryPoint.length<=0) return;
//画点
this.ClipFrame();
var pixel=GetDevicePixelRatio();
for(var i in aryPoint)
{
var item=aryPoint[i];
this.Canvas.beginPath();
this.Canvas.arc(item.X,item.Y,5*pixel,0,360,false);
this.Canvas.fillStyle=this.PointColor; //填充颜色
this.Canvas.fill(); //画实心圆
this.Canvas.closePath();
}
this.Canvas.restore();
}
//计算2个点线的,左右的延长线的点
this.CalculateExtendLinePoint=function(ptStart,ptEnd)
{
var result={};
var left=this.Frame.ChartBorder.GetLeft();
var right=this.Frame.ChartBorder.GetRight();
var top=this.Frame.ChartBorder.GetTopEx();
var bottom=this.Frame.ChartBorder.GetBottom();
var a=ptEnd.X-ptStart.X;
var b=ptEnd.Y-ptStart.Y;
if (a>0)
{
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;
var radius=5;
if (this.Option) radius+=this.Option.Zoom;
var isHScreen=this.Frame.IsHScreen;
radius*=GetDevicePixelRatio();
for(var i=0;i<this.Value.length; ++i) //是否在点上
{
var item=this.Value[i];
var pt=new Point();
if (isHScreen)
{
pt.Y=this.Frame.GetXFromIndex(item.XValue-data.DataOffset);
pt.X=this.Frame.GetYFromData(item.YValue);
}
else
{
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,radius,0,360);
if (this.Canvas.isPointInPath(x,y)) return i;
}
return -1;
}
//坐标是否在线段上 返回在第几个线段上
this.IsPointInLine=function(x,y)
{
if (!this.LinePoint) return -1;
var lineWidth=5;
if (this.Option) lineWidth+=this.Option.Zoom;
var pixel=GetDevicePixelRatio();
lineWidth*=pixel;
for(var i in this.LinePoint)
{
var item=this.LinePoint[i];
var ptStart=item.Start;
var ptEnd=item.End;
this.Canvas.beginPath();
if (ptStart.X==ptEnd.X) //竖线
{
this.Canvas.moveTo(ptStart.X-lineWidth,ptStart.Y);
this.Canvas.lineTo(ptStart.X+lineWidth,ptStart.Y);
this.Canvas.lineTo(ptEnd.X+lineWidth,ptEnd.Y);
this.Canvas.lineTo(ptEnd.X-lineWidth,ptEnd.Y);
}
else
{
this.Canvas.moveTo(ptStart.X,ptStart.Y+lineWidth);
this.Canvas.lineTo(ptStart.X,ptStart.Y-lineWidth);
this.Canvas.lineTo(ptEnd.X,ptEnd.Y-lineWidth);
this.Canvas.lineTo(ptEnd.X,ptEnd.Y+lineWidth);
}
this.Canvas.closePath();
if (this.Canvas.isPointInPath(x,y))
return i;
}
return -1;
}
//0-10 鼠标对应的点索引 100=鼠标在正个图形上 -1 鼠标不在图形上
this.IsPointIn_XYValue_Line=function(x,y)
{
if (this.Status!=10) return -1;
var value=this.IsPointInXYValue(x,y);
if (value>=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();
/*
if (this.IsSelected)
{
this.Canvas.strokeStyle='rgba(255,0,0,0.5)';
this.Canvas.lineWidth=20 * GetDevicePixelRatio();
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 nIndex=this.IsPointInXYValue(x,y);
if (nIndex>=0) return nIndex;
var aryPoint=this.CalculateDrawPoint({IsCheckX:true, IsCheckY:true});
if (!aryPoint || aryPoint.length!=2) return -1;
//是否在矩形边框上
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)
{
var radius=5;
if (this.Option) radius+=this.Option.Zoom;
var pixel=GetDevicePixelRatio();
radius*=pixel;
this.Canvas.beginPath();
this.Canvas.moveTo(aryPoint[0].X,aryPoint[0].Y+radius);
this.Canvas.lineTo(aryPoint[0].X,aryPoint[0].Y-radius);
this.Canvas.lineTo(aryPoint[1].X,aryPoint[1].Y-radius);
this.Canvas.lineTo(aryPoint[1].X,aryPoint[1].Y+radius);
this.Canvas.closePath();
if (this.Canvas.isPointInPath(x,y))
return true;
}
//垂直线段
this.IsPointInLine2=function(aryPoint,x,y)
{
var radius=5;
if (this.Option) radius+=this.Option.Zoom;
var pixel=GetDevicePixelRatio();
radius*=pixel;
this.Canvas.beginPath();
this.Canvas.moveTo(aryPoint[0].X-radius,aryPoint[0].Y);
this.Canvas.lineTo(aryPoint[0].X+radius,aryPoint[0].Y);
this.Canvas.lineTo(aryPoint[1].X+radius,aryPoint[1].Y);
this.Canvas.lineTo(aryPoint[1].X-radius,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 nIndex=this.IsPointInXYValue(x,y);
if (nIndex>=0) return nIndex;
var aryPoint=this.CalculateDrawPoint({IsCheckX:true, IsCheckY:true});
if (!aryPoint || aryPoint.length!=2) return -1;
//是否在弧线上
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<this.Point.length; ++i)
{
var item=this.Point[i];
var pt=new Point();
pt.X=item.X;
pt.Y=item.Y;
drawPoint.push(pt);
}
}
if (drawPoint.length>=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);
//JSConsole.Chart.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)
{
this.Point[this.MovePointIndex].X+=xStep;
this.Point[this.MovePointIndex].Y+=yStep;
}
}
else if (this.MovePointIndex==2) //宽度的点要计算
{
this.Point[this.MovePointIndex].X+=xStep;
this.Point[this.MovePointIndex].Y+=yStep;
var x=this.Point[1].X-this.Point[0].X;
var y=this.Point[1].Y-this.Point[0].Y;
var angle=Math.atan(Math.abs(x/y));
var yMove=this.ChannelWidth/Math.sin(angle)-yStep;
this.ChannelWidth=Math.sin(angle)*yMove;
}
}
//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;
//是否在点上
for(var i=0;i<this.Value.length; ++i)
{
var item=this.Value[i];
var pt=new Point();
if (i<2)
{
pt.X=this.Frame.GetXFromIndex(item.XValue-data.DataOffset);
pt.Y=this.Frame.GetYFromData(item.YValue);
}
else //第3个点使用实际坐标
{
if (i>=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()
{
JSConsole.Chart.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();
var isHScreen=this.Frame.IsHScreen;
var pixel=GetDevicePixelRatio();
this.Canvas.fillStyle=this.LineColor;
this.Canvas.textAlign="center";
this.Canvas.textBaseline="bottom";
this.Canvas.font=font;
if (isHScreen)
{
this.Canvas.translate(drawPoint[0].X, drawPoint[0].Y);
this.Canvas.rotate(90 * Math.PI / 180);
this.Canvas.fillText(this.Text,0,0);
}
else
{
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*pixel;
this.TextRect.Width=textWidth;
this.TextRect.Height=this.FontOption.Size*pixel;
//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;
var offset=0;
if (this.Option && this.Option.Zoom>=1)
{
offset=this.Option.Zoom*GetDevicePixelRatio();
}
this.Canvas.beginPath();
this.Canvas.rect(this.TextRect.Left-offset,this.TextRect.Top-offset,this.TextRect.Width+offset*2,this.TextRect.Height+offset*2);
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.X<ptEnd.X && ptStart.Y>ptEnd.Y) return 1;
else if (ptStart.X<ptEnd.X && ptStart.Y>ptEnd.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.CalculateHSCreenLines=function(ptStart,ptEnd)
{
var sectionData=this.GetSectionData();
var left=this.Frame.ChartBorder.GetTop();
var right=this.Frame.ChartBorder.GetBottom();
var lineHeight=ptStart.X-ptEnd.X;
for(var i=0;i<sectionData.length;++i)
{
var yMove=lineHeight*sectionData[i];
var line={Start:new Point(), End:new Point()};
line.Start.X=ptStart.X-yMove;
line.Start.Y=left;
line.End.X=ptStart.X-yMove;
line.End.Y=right;
var text='';
if (i==0) text='Base '
else text=(sectionData[i]*100).toFixed(2)+'% ';
var yValue=this.Frame.GetYData(line.Start.Y);
text+=yValue.toFixed(2);
line.Text=text;
this.LinePoint.push(line);
}
}
this.CalculateLines=function(ptStart,ptEnd)
{
if (this.Frame.IsHScreen)
{
this.CalculateHSCreenLines(ptStart,ptEnd);
return;
}
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<sectionData.length;++i)
{
var yMove=lineHeight*sectionData[i];
var line={Start:new Point(), End:new Point()};
line.Start.Y=ptStart.Y-yMove;
line.Start.X=left;
line.End.Y=ptStart.Y-yMove;
line.End.X=right;
var text='';
if (i==0) text='Base '
else text=(sectionData[i]*100).toFixed(2)+'% ';
var yValue=this.Frame.GetYData(line.Start.Y);
text+=yValue.toFixed(2);
line.Text=text;
this.LinePoint.push(line);
}
}
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.DrawTitle=function(pt,text)
{
this.Canvas.fillStyle=this.LineColor;
this.Canvas.textAlign="left";
this.Canvas.textBaseline="bottom";
this.Canvas.font=this.Font;
if (this.Frame.IsHScreen)
{
this.Canvas.save();
this.Canvas.translate(pt.X,pt.Y);
this.Canvas.rotate(90 * Math.PI / 180);
this.Canvas.fillText(text,0,0);
this.Canvas.restore();
}
else
{
this.Canvas.fillText(text,pt.X,pt.Y);
}
}
}
//百分比线
function ChartDrawPicturePercentage()
{
this.newMethod=ChartDrawPictureGoldenSection; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartDrawPicturePercentage';
this.GetSectionData=function()
{
const GOLDEN_SECTION_DATA= [0, 0.25, 0.333, 0.50, 1];
return GOLDEN_SECTION_DATA;
}
}
//波段线
function ChartDrawPictureWaveBand()
{
this.newMethod=ChartDrawPictureGoldenSection; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartDrawPictureWaveBand';
this.GetSectionData=function()
{
const GOLDEN_SECTION_DATA= [0,0.125, 0.25, 0.375, 0.50, 0.625, 0.75, 0.875,1];
return GOLDEN_SECTION_DATA;
}
}
//三角形
function ChartDrawPictureTriangle()
{
this.newMethod=IChartDrawPicture; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartDrawPictureTriangle';
this.PointCount=3;
this.Font=16*GetDevicePixelRatio() +"px 微软雅黑";
this.IsPointIn=this.IsPointIn_XYValue_Line;
this.LastPoint;
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(points);
for(var i in this.LinePoint)
{
var item=this.LinePoint[i];
this.DrawLine(item.Start,item.End);
}
this.DrawArea(points);
this.DrawPoint(points); //画点
this.DrawTitle(points);
this.Canvas.restore();
}
this.DrawArea=function(points)
{
if (points.length!=3) return;
this.Canvas.fillStyle=this.AreaColor;
this.Canvas.beginPath();
this.Canvas.moveTo(points[0].X,points[0].Y);
this.Canvas.lineTo(points[1].X,points[1].Y);
this.Canvas.lineTo(points[2].X,points[2].Y);
this.Canvas.lineTo(points[0].X,points[0].Y);
this.Canvas.closePath();
this.Canvas.fill();
}
//显示角度数据
this.DrawTitle=function(points)
{
if (this.Status!=10) return; //拖拽完成以后才显示角度数据
//输出3个点的角度
/*
this.Canvas.fillStyle=this.LineColor;
this.Canvas.textAlign="left";
this.Canvas.textBaseline="bottom";
this.Canvas.font=this.Font;
this.Canvas.fillText('∠60',points[0].X,points[0].Y);
*/
}
this.SetLastPoint=function(obj)
{
this.LastPoint={X:obj.X,Y:obj.Y};
}
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 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);
}
else if (points.length===3)
{
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);
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);
line={Start:new Point(), End:new Point()};
line.Start.Y=points[2].Y;
line.Start.X=points[2].X;
line.End.Y=points[0].Y;
line.End.X=points[0].X;
this.LinePoint.push(line);
}
}
}
//对称角度
function ChartDrawPictureSymmetryAngle()
{
this.newMethod=IChartDrawPicture; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartDrawPictureSymmetryAngle';
this.PointCount=2;
this.Font=16*GetDevicePixelRatio() +"px 微软雅黑";
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.DrawArea();
this.DrawPoint(drawPoint); //画点
this.DrawTitle(drawPoint);
this.Canvas.restore();
}
this.CalculateLines=function(points)
{
if (points.length!=2) return;
if (!this.Frame) return;
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);
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[0].X;
this.LinePoint.push(line);
var xMove=points[0].X-points[1].X;
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[0].X+xMove;
this.LinePoint.push(line);
}
this.DrawArea=function()
{
if (this.LinePoint.length!=3) 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[2].End.X,this.LinePoint[2].End.Y);
this.Canvas.moveTo(this.LinePoint[0].Start.X,this.LinePoint[0].Start.Y);
this.Canvas.closePath();
this.Canvas.fill();
}
//显示角度数据
this.DrawTitle=function(points)
{
if (this.Status!=10) return; //拖拽完成以后才显示角度数据
//输出点的角度
/*
this.Canvas.fillStyle=this.LineColor;
this.Canvas.textAlign="left";
this.Canvas.textBaseline="bottom";
this.Canvas.font=this.Font;
this.Canvas.fillText('∠60',points[0].X,points[0].Y);
*/
}
}
//圆
function ChartDrawPictureCircle()
{
this.newMethod=IChartDrawPicture; //派生
this.newMethod();
delete this.newMethod;
this.ClassName='ChartDrawPictureCircle';
this.PointCount=2;
this.CircleData;
this.Draw=function()
{
this.LinePoint=[];
var drawPoint=this.CalculateDrawPoint({IsCheckX:true, IsCheckY:true});
if (!drawPoint || drawPoint.length!=2) return;
this.AreaColor=IChartDrawPicture.ColorToRGBA(this.LineColor,0.3);
this.ClipFrame();
var x=drawPoint[0].X-drawPoint[1].X;
var y=drawPoint[0].Y-drawPoint[1].Y;
var r=Math.sqrt(x*x+y*y);
this.Canvas.fillStyle=this.AreaColor;
this.Canvas.strokeStyle=this.LineColor;
this.DrawLine(drawPoint[0],drawPoint[1]);
this.Canvas.beginPath();
this.Canvas.arc(drawPoint[0].X,drawPoint[0].Y,r,0,2*Math.PI);
this.Canvas.stroke();
this.Canvas.fill();
this.CircleData={X:drawPoint[0].X, Y:drawPoint[0].Y, R:r};
this.DrawPoint(drawPoint); //画点
this.Canvas.restore();
}
//0-10 鼠标对应的点索引 100=鼠标在正个图形上 -1 鼠标不在图形上
this.IsPointIn=function(x,y)
{
if (this.Status!=10) return -1;
var value=this.IsPointInXYValue(x,y);
if (value>=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 (r<this.CircleData.R && r>this.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;
if (this.Frame.IsHScreen)
{
this.Canvas.save();
this.Canvas.translate(pt.X,pt.Y);
this.Canvas.rotate(90 * Math.PI / 180);
this.Canvas.fillText(text,2,10);
this.Canvas.restore();
}
else
{
this.Canvas.fillText(text,pt.X+2,pt.Y+10);
}
}
this.CalculateHSCreenLines=function()
{
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].Y))+data.DataOffset;
}
var top=this.Frame.ChartBorder.GetRightEx();
var bottom=this.Frame.ChartBorder.GetLeftEx();
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<LINE_DATA.length;++i)
{
var xValue=xStart+LINE_DATA[i];
var dataIndex=xValue-data.DataOffset;
if (dataIndex<0 || dataIndex>=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.X=top;
line.Start.Y=x;
line.End.X=bottom;
line.End.Y=x;
this.LinePoint.push(line);
}
}
this.CalculateLines=function()
{
if (this.Status<2) return;
if (!this.Frame) return;
var data=this.Frame.Data;
if (!data) return;
if (this.Frame.IsHScreen)
{
this.CalculateHSCreenLines();
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<LINE_DATA.length;++i)
{
var xValue=xStart+LINE_DATA[i];
var dataIndex=xValue-data.DataOffset;
if (dataIndex<0 || dataIndex>=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];
JSConsole.Chart.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)
}
JSConsole.Chart.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)) //更新
{
JSConsole.Chart.Log('[ChartDrawStorage::SaveDrawData] Upate: key, drawPicture, data', strKey, drawPicture,data);
this.DrawData.get(strKey).set(data.Guid, data);
}
else //新增
{
JSConsole.Chart.Log('[ChartDrawStorage::SaveDrawData] Insert: key, drawPicture, data', strKey, drawPicture,data);
var newData=new Map();
newData.set(data.Guid, data);
this.DrawData.set(strKey,newData);
}
JSConsole.Chart.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.Minute.PositionColor='rgb(218,165,32)'; //持仓量
this.DefaultTextColor="rgb(43,54,69)";
this.DefaultTextFont=14*GetDevicePixelRatio() +'px 微软雅黑';
this.TitleFont=13*GetDevicePixelRatio() +'px 微软雅黑';
this.IndexTitleBGColor='rgb(217,219,220)'; //指标名字背景色
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.Frame={
XBottomOffset:1*GetDevicePixelRatio() //X轴文字向下偏移
};
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.CorssCursorHPenColor="rgb(130,130,130)"; //十字光标线段颜色(水平)
this.CorssCursorVPenColor="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.Minute.PositionColor) this.Minute.PositionColor = style.Minute.PositionColor;
}
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.Frame)
{
if (style.Frame.XBottomOffset) this.Frame.XBottomOffset=style.Frame.XBottomOffset;
}
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.CorssCursorVPenColor) this.CorssCursorVPenColor = style.CorssCursorVPenColor;
if (style.CorssCursorHPenColor) this.CorssCursorHPenColor = style.CorssCursorHPenColor;
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:'}],
['Tooltip-Position',{CN:'持:', EN:'P:'}],
['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:"2W"}],
['月线', {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'}],
['自定义秒', {CN:'秒', EN:'S'}]
]);
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(;offset<data.length;++offset)
{
if (data[offset]!=null && !isNaN(data[offset]))
break;
}
var p1Index=offset;
var p2Index=offset+1;
result[p1Index]=data[p1Index];
for(var i=offset+1;i<data.length;++i,++p1Index,++p2Index)
{
result[p2Index]=((2*data[p2Index]+(dayCount-1)*result[p1Index]))/(dayCount+1);
}
return result;
}
HQIndexFormula.SMA=function(data,n,m)
{
var result = [];
var i=0;
var lastData=null;
for(;i<data.length; ++i)
{
if (data[i]==null || isNaN(data[i])) continue;
lastData=data[i];
result[i]=lastData; //第一天的数据
break;
}
for(++i;i<data.length;++i)
{
result[i]=(m*data[i]+(n-m)*lastData)/n;
lastData=result[i];
}
return result;
}
/*
求动态移动平均.
用法: DMA(X,A),求X的动态移动平均.
算法: 若Y=DMA(X,A)则 Y=A*X+(1-A)*Y',其中Y'表示上一周期Y值,A必须小于1.
例如:DMA(CLOSE,VOL/CAPITAL)表示求以换手率作平滑因子的平均价
*/
HQIndexFormula.DMA=function(data,data2)
{
var result = [];
if (data.length<0 || data.length!=data2.length) return result;
var index=0;
for(;index<data.length;++index)
{
if (data[index]!=null && !isNaN(data[index]) && data2[index]!=null && !isNaN(data2[index]))
{
result[index]=data[index];
break;
}
}
for(index=index+1;index<data.length;++index)
{
if (data[index]==null || data2[index]==null)
result[index]=null;
else
{
if (data[index]<1)
result[index]=(data2[index]*data[index])+(1-data2[index])*result[index-1];
else
result[index]= data[index];
}
}
return result;
}
HQIndexFormula.HHV=function(data,n)
{
var result = [];
if (n>data.length) return result;
var max=-10000;
for(var i=n,j=0;i<data.length;++i,++j)
{
if(i<n+max)
{
max=data[i]<data[max]?max:i;
}
else
{
for(j=(max=i-n+1)+1;j<=i;++j)
{
if(data[j]>data[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;i<data.length;++i,++j)
{
if(i<n+min)
{
min=data[i]>data[min]?min:i;
}
else
{
for(var j=(min=i-n+1)+1;j<=i;++j)
{
if(data[j]<data[min])
min = j;
}
}
result[i] = data[min];
}
return result;
}
HQIndexFormula.REF=function(data,n)
{
var result=[];
if (data.length<=0) return result;
if (n>=data.length) return result;
result=data.slice(0,data.length-n);
for(var i=0;i<n;++i)
result.unshift(null);
return result;
}
HQIndexFormula.REFDATE=function(data,n)
{
var result=[];
if (data.length<=0) return result;
//暂时写死取最后一个
n=data.length-1;
for(var i in data)
{
result[i]=data[n];
}
return result;
}
HQIndexFormula.SUM=function(data,n)
{
var result=[];
if (n==0)
{
result[0]=data[0];
for (var i=1; i<data.length; ++i)
{
result[i] = result[i-1]+data[i];
}
}
else
{
for(var i=n-1,j=0;i<data.length;++i,++j)
{
for(var k=0;k<n;++k)
{
if (k==0) result[i]=data[k+j];
else result[i]+=data[k+j];
}
}
}
return result;
}
//两个数组相减
HQIndexFormula.ARRAY_SUBTRACT=function(data,data2)
{
var result=[];
var IsNumber=typeof(data2)=="number";
if (IsNumber)
{
for(var i in data)
{
if (data[i]==null || isNaN(data[i]))
result[i]=null;
else
result[i]=data[i]-data2;
}
}
else
{
var count=Math.max(data.length,data2.length)
for(var i=0;i<count;++i)
{
if (i<data.length && i<data2.length)
{
if (data[i]==null || data2[i]==null) result[i]=null;
else result[i]=data[i]-data2[i];
}
else
result[i]=null;
}
}
return result;
}
//数组 data>data2比较 返回 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;i<count;++i)
{
if (i<data.length && i<data2.length)
result[i]=data[i]>data2[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<count;++i)
{
if (i<data.length && i<data2.length)
result[i]=data[i]>=data2[i] ? 1:0;
else
result[i]=null;
}
}
return result;
}
//数组 data<data2比较 返回 0/1 数组
HQIndexFormula.ARRAY_LT=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<count;++i)
{
if (i<data.length && i<data2.length)
result[i]=data[i]<data2[i] ? 1:0;
else
result[i]=null;
}
}
return result;
}
//数组 data<=data2比较 返回 0/1 数组
HQIndexFormula.ARRAY_LTE=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<count;++i)
{
if (i<data.length && i<data2.length)
result[i]=data[i]<=data2[i] ? 1:0;
else
result[i]=null;
}
}
return result;
}
//数组 data==data2比较 返回 0/1 数组
HQIndexFormula.ARRAY_EQ=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<count;++i)
{
if (i<data.length && i<data2.length)
result[i]=(data[i]==data2[i] ? 1:0);
else
result[i]=null;
}
}
return result;
}
HQIndexFormula.ARRAY_IF=function(data,trueData,falseData)
{
var result=[];
var IsNumber=[typeof(trueData)=="number",typeof(falseData)=="number"];
for(var i in data)
{
if (data[i])
{
if (IsNumber[0]) result[i]=trueData;
else result[i]=trueData[i];
}
else
{
if (IsNumber[1]) result[i]=falseData;
else result[i]=falseData[i];
}
}
return result;
}
HQIndexFormula.ARRAY_AND=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<count;++i)
{
if (i<data.length && i<data2.length)
result[i]=(data[i] && data2[i] ? 1:0);
else
result[i]=0;
}
}
return result;
}
HQIndexFormula.ARRAY_OR=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<count;++i)
{
if (i < data.length && data[i])
{
result[i] = 1;
continue;
}
if (i < data2.length && data2[i])
{
result[i] = 1;
continue;
}
result[i] = 0;
}
}
return result;
}
//数组相乘
//支持多个参数累乘 如:HQIndexFormula.ARRAY_MULTIPLY(data,data2,data3,data3) =data*data2*data3*data4
HQIndexFormula.ARRAY_MULTIPLY=function(data,data2)
{
if (arguments.length==2)
{
var result=[];
var IsNumber=typeof(data2)=="number";
if (IsNumber)
{
for(var i in data)
{
if (data[i]==null || isNaN(data[i]))
result[i]=null;
else
result[i]=data[i]*data2;
}
}
else
{
var count=Math.max(data.length,data2.length);
for(var i=0;i<count;++i)
{
if (i<data.length && i<data2.length)
result[i]=data[i]*data2[i];
else
result[i]=null;
}
}
return result;
}
var result=HQIndexFormula.ARRAY_MULTIPLY(arguments[0],arguments[1]);
for(var i=2;i<arguments.length;++i)
{
result=HQIndexFormula.ARRAY_MULTIPLY(result,arguments[i]);
}
return result;
}
//数组相除
HQIndexFormula.ARRAY_DIVIDE=function(data,data2)
{
var result=[];
var IsNumber=typeof(data2)=="number";
if (IsNumber)
{
for(var i in data)
{
result[i]=data[i]/data2;
}
}
else
{
var count=Math.max(data.length,data2.length);
for(var i=0;i<count;++i)
{
if (i<data.length && i<data2.length)
{
if(data[i]==null || data2[i]==null || isNaN(data[i]) || isNaN(data2[i]))
result[i]=null;
else if (data2[i]==0)
result[i]=null;
else
result[i]=data[i]/data2[i];
}
else
result[i]=null;
}
}
return result;
}
//数组相加
//支持多个参数累加 如:HQIndexFormula.ARRAY_ADD(data,data2,data3,data3) =data+data2+data3+data4
HQIndexFormula.ARRAY_ADD=function(data,data2)
{
if (arguments.length==2)
{
var result=[];
var IsNumber=typeof(data2)=="number";
if (IsNumber)
{
for(var i in data)
{
result[i]=data[i]+data2;
}
}
else
{
var count=Math.max(data.length,data2.length);
for(var i=0;i<count;++i)
{
if (i<data.length && i<data2.length)
{
if (data[i]==null || data2[i]==null || isNaN(data[i]) || isNaN(data2[i])) result[i]=null
else result[i]=data[i]+data2[i];
}
else
{
result[i]=null;
}
}
}
return result;
}
var result=HQIndexFormula.ARRAY_ADD(arguments[0],arguments[1]);
for(var i=2;i<arguments.length;++i)
{
result=HQIndexFormula.ARRAY_ADD(result,arguments[i]);
}
return result;
}
HQIndexFormula.MAX=function(data,data2)
{
var result=[];
var IsNumber=typeof(data2)=="number";
if (IsNumber)
{
for(var i in data)
{
if (data[i]==null) result[i]=null;
else result[i]=Math.max(data[i],data2);
}
}
else
{
var count=Math.max(data.length,data2.length);
for(var i=0;i<count;++i)
{
if (i<data.length && i<data2.length)
{
if (data[i]==null || data2[i]==null) result[i]=null;
else result[i]=Math.max(data[i],data2[i]);
}
else
result[i]=null;
}
}
return result;
}
HQIndexFormula.MIN=function(data,data2)
{
var result=[];
var IsNumber=typeof(data2)=="number";
if (IsNumber)
{
for(var i in data)
{
if (data[i]==null) result[i]=null;
else result[i]=Math.min(data[i],data2);
}
}
else
{
var count=Math.max(data.length,data2.length);
for(var i=0;i<count;++i)
{
if (i<data.length && i<data2.length)
{
if (data[i]==null || data2[i]==null) result[i]=null;
else result[i]=Math.min(data[i],data2[i]);
}
else
result[i]=null;
}
}
return result;
}
HQIndexFormula.ABS=function(data)
{
var result=[];
for(var i in data)
{
if (data[i]==null) result[i]=null;
else result[i]=Math.abs(data[i]);
}
return result;
}
HQIndexFormula.MA=function(data,dayCount)
{
var result=[];
for (var i = 0, len = data.length; i < len; i++)
{
if (i < dayCount)
{
result[i]=null;
continue;
}
var sum = 0;
for (var j = 0; j < dayCount; j++)
{
sum += data[i - j];
}
result[i]=sum / dayCount;
}
return result;
}
/*
加权移动平均
返回加权移动平均
用法:EXPMA(X,M):X的M日加权移动平均
EXPMA[i]=buffer[i]*para+(1-para)*EXPMA[i-1] para=2/(1+__para)
*/
HQIndexFormula.EXPMA=function(data,dayCount)
{
var result=[];
if (dayCount>=data.length) return result;
var i=dayCount;
for(;i<data.length;++i) //获取第1个有效数据
{
if (data[i]!=null)
{
result[i]=data[i];
break;
}
}
for (i=i+1; i < data.length; ++i)
{
if (result[i-1]!=null && data[i]!=null)
result[i]=(2*data[i]+(dayCount-1)*result[i-1])/(dayCount+1);
else if (result[i-1]!=null)
result[i]=result[i-1];
}
return result;
}
//加权平滑平均,MEMA[i]=SMA[i]*para+(1-para)*SMA[i-1] para=2/(1+__para)
HQIndexFormula.EXPMEMA=function(data,dayCount)
{
var result=[];
if (dayCount>=data.length) return result;
var index=0;
for(;index<data.length;++index)
{
if (data[index] && !isNaN(data[index])) break;
}
var sum=0;
for(var i=0; index<data.length && i<dayCount;++i, ++index)
{
if (data[index] && !isNaN(data[index]))
sum+=data[index];
else
sum+=data[index-1];
}
result[index-1]=sum/dayCount;
for(;index<data.length;++index)
{
if(result[index-1]!=null && data[index]!=null)
result[index]=(2*data[index]+(dayCount-1)*result[index-1])/(dayCount+1);
else if(result[index-1]!=null)
result[index] = result[index-1];
}
return result;
}
HQIndexFormula.STD=function(data,n)
{
var result=[];
var total=0;
var averageData=[]; //平均值
for(var i=n-1;i<data.length;++i)
{
total=0;
for(var j=0;j<n;++j)
{
total+=data[i-j];
}
averageData[i]=total/n;
}
for(var i=n-1;i<data.length;++i)
{
total=0;
for(var j=0;j<n;++j)
{
total+=Math.pow((data[i-j]-averageData[i]),2);
}
result[i]=Math.sqrt(total/n);
}
return result;
}
//平均绝对方差
HQIndexFormula.AVEDEV=function(data,n)
{
var result=[];
var total=0;
var averageData=[]; //平均值
for(var i=n-1;i<data.length;++i)
{
total=0;
for(var j=0;j<n;++j)
{
total+=data[i-j];
}
averageData[i]=total/n;
}
for(var i=n-1;i<data.length;++i)
{
total=0;
for(var j=0;j<n;++j)
{
total+=Math.abs(data[i-j]-averageData[i]);
}
result[i]=total/n;
}
return result;
}
HQIndexFormula.COUNT=function(data,n)
{
var result=[];
for(var i=n-1;i<data.length;++i)
{
var count=0;
for(var j=0;j<n;++j)
{
if (data[i-j]) ++count;
}
result[i]=count;
}
return result;
}
//上穿
HQIndexFormula.CROSS=function(data,data2)
{
var result=[];
if (data.length!=data2.length) return result=[];
var index=0;
for(;index<data.length;++index)
{
if (data[index]!=null && !isNaN(data[index]) && data2[index]!=null && isNaN(data2[index]))
break;
}
for(++index;index<data.length;++index)
{
result[index]= (data[index]>data2[index]&&data[index-1]<data2[index-1])?1:0;
}
return result;
}
//累乘
HQIndexFormula.MULAR=function(data,n)
{
var result=[];
if(data.length<n) return result;
var index=n;
for(;index<data.length;++index)
{
if (data[index]!=null && !isNaN(data[index]))
{
result[index]=data[index];
break;
}
}
for(++index;index<data.length;++index)
{
result[index]=result[index-1]*data[index];
}
return result;
}
HQIndexFormula.STICKLINE=function(data,price1,price2)
{
var result=[];
if(data.length<=0) return result;
var IsNumber=typeof(price1)=="number";
var IsNumber2=typeof(price2)=="number";
for(var i in data)
{
result[i]=null;
if (isNaN(data[i])) continue;
if (!data[i]) continue;
if (IsNumber && IsNumber2)
{
result[i]={Value:price1,Value2:price2};
}
else if (IsNumber && !IsNumber2)
{
if (isNaN(price2[i])) continue;
result[i]={Value:price1,Value2:price2[i]};
}
else if (!IsNumber && IsNumber2)
{
if (isNaN(price1[i])) continue;
result[i]={Value:price1[i],Value2:price2};
}
else
{
if (isNaN(price1[i]) || isNaN(price2[i])) continue;
result[i]={Value:price1[i],Value2:price2[i]};
}
}
return result;
}
/////////////////////////////////////////////////////////////////////////////////////////////
// K线图 控件
// this.ChartPaint[0] K线画法 这个不要修改
//
//
function KLineChartContainer(uielement)
{
var _self =this;
this.newMethod=JSChartContainer; //派生
this.newMethod(uielement);
delete this.newMethod;
this.ClassName='KLineChartContainer';
this.WindowIndex=new Array();
this.ColorIndex; //五彩K线
this.TradeIndex; //交易指标/专家系统
this.Symbol;
this.Name;
this.Period=0; //周期 0=日线 1=周线 2=月线 3=年线 4=1分钟 5=5分钟 6=15分钟 7=30分钟 8=60分钟 9=季线 10=分笔线 11=120分钟 12=240分钟
this.IsApiPeriod=false; //使用API计算周期
this.Right=0; //复权 0 不复权 1 前复权 2 后复权
this.SourceData; //原始的历史数据
this.MaxReqeustDataCount=3000; //数据个数
this.MaxRequestMinuteDayCount=5; //分钟数据请求的天数
this.PageSize=200; //每页数据个数
this.KLineDrawType=0;
this.ScriptErrorCallback; //脚本执行错误回调
this.FlowCapitalReady=false; //流通股本是否下载完成
this.ChartDrawStorage=new ChartDrawStorage();
this.ChartDrawStorageCache=null; //首次需要创建的画图工具数据
this.RightSpaceCount=0; //右侧空白个数
this.SourceDataLimit=new Map(); //每个周期缓存数据最大个数 key=周期 value=最大个数
this.CustomShow=null; //首先显示的K线的起始日期 { Date:日期 PageSize:}
this.OverlayIndexFrameWidth=60; //叠加指标框架宽度
this.Page= {
Day:{ Enable:false, Index:0, Finish:false }, //日线
Minute:{ Enable:false, Index:0, Finish:false } //分钟
}; //分页下载 Enable:是否分页下载 Index:已下载到第几页 Finish:是否所有分页完成
this.DragDownload= {
Day:{ Enable:false, IsEnd:false, Status:0 }, //日线数据拖拽下载 Status: 0空闲 1 下载中
Minute: { Enable:false, IsEnd:false, status:0 } //分钟数据拖拽下载
};
//自动更新设置
this.IsAutoUpdate=false; //是否自动更新行情数据
this.AutoUpdateFrequency=30000; //30秒更新一次数据
this.AutoUpdateTimer; //自动更新定时器
//this.KLineApiUrl="http://opensource.zealink.com/API/KLine2"; //历史K线api地址
this.KLineApiUrl=g_JSChartResource.Domain+"/API/KLine2"; //历史K线api地址
this.MinuteKLineApiUrl=g_JSChartResource.Domain+'/API/KLine3'; //历史分钟数据
this.DragMinuteKLineApiUrl=g_JSChartResource.Domain+'/API/KLine4'; //拖动1分钟K数据下载
this.DragKLineApiUrl=g_JSChartResource.Domain+'/API/KLine5'; //拖动日K数据下载
this.RealtimeApiUrl=g_JSChartResource.Domain+"/API/Stock"; //实时行情api地址
this.KLineMatchUrl=g_JSChartResource.Domain+"/API/KLineMatch"; //形态匹配
this.StockHistoryDayApiUrl= g_JSChartResource.Domain+'/API/StockHistoryDay'; //股票历史数据
this.TickApiUrl=g_JSChartResource.Domain+'/API/StockDetail'; //当天分笔数据
this.MinuteDialog; //双击历史K线 弹出分钟走势图
this.RightMenu; //右键菜单
this.ChartPictureMenu; //画图工具 单个图形设置菜单
this.ResetDragDownload=function()
{
this.DragDownload.Day.Status=0;
this.DragDownload.Day.IsEnd=false;
this.DragDownload.Minute.Status=0;
this.DragDownload.Minute.IsEnd=false;
}
this.ResetPage=function() //重置分页下载
{
this.Page.Day.Finish=false;
this.Page.Day.Index=0;
this.Page.Minute.Finish=false;
this.Page.Minute.Index=0;
}
this.StopAutoUpdate=function()
{
this.CancelAutoUpdate();
this.AutoUpdateEvent(false,'KLineChartContainer::StopAutoUpdate');
if (!this.IsAutoUpdate) return;
this.IsAutoUpdate=false;
}
this.ChartOperator=function(obj) //图形控制函数 {ID:JSCHART_OPERATOR_ID, ...参数 }
{
var id=obj.ID;
if (id===JSCHART_OPERATOR_ID.OP_SCROLL_LEFT || id===JSCHART_OPERATOR_ID.OP_SCROLL_RIGHT ) //左右移动 { Step:移动数据个数 }
{
var isLeft=(id===JSCHART_OPERATOR_ID.OP_SCROLL_LEFT ? true:false);
var step=1;
if (obj.Step>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;
JSConsole.Chart.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)
{
JSConsole.Chart.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", (e)=>{ this.OnKeyDown(e); }, true); //键盘消息
this.UIElement.addEventListener("wheel", (e)=>{ this.OnWheel(e); }, true); //上下滚动消息
}
//创建子窗口
this.CreateChildWindow=function(windowCount)
{
for(var i=0;i<windowCount;++i)
{
var border=new ChartBorder();
border.UIElement=this.UIElement;
var frame=new KLineFrame();
frame.Canvas=this.Canvas;
frame.ChartBorder=border;
frame.Identify=i; //窗口序号
if (this.ModifyIndexDialog) frame.ModifyIndexEvent=this.ModifyIndexDialog.DoModal; //绑定菜单事件
if (this.ChangeIndexDialog) frame.ChangeIndexEvent=this.ChangeIndexDialog.DoModal;
frame.HorizontalMax=20;
frame.HorizontalMin=10;
if (i==0)
{
frame.YSplitOperator=new FrameSplitKLinePriceY();
frame.YSplitOperator.FrameSplitData=this.FrameSplitData.get('price');
frame.YSplitOperator.FrameSplitData2=this.FrameSplitData.get('double');
var pixelTatio = GetDevicePixelRatio(); //获取设备的分辨率
border.BottomSpace=12*pixelTatio; //主图上下留空间
border.TopSpace=12*pixelTatio;
}
else
{
frame.YSplitOperator=new FrameSplitY();
frame.YSplitOperator.FrameSplitData=this.FrameSplitData.get('double');
frame.YSplitOperator.LanguageID=this.LanguageID;
//frame.IsLocked = true;
}
frame.YSplitOperator.Frame=frame;
frame.YSplitOperator.ChartBorder=border;
frame.XSplitOperator=new FrameSplitKLineX();
frame.XSplitOperator.Frame=frame;
frame.XSplitOperator.ChartBorder=border;
frame.XSplitOperator.LanguageID=this.LanguageID;
if (i!=windowCount-1) frame.XSplitOperator.ShowText=false;
for(var j=frame.HorizontalMin;j<=frame.HorizontalMax;j+=1)
{
frame.HorizontalInfo[j]= new CoordinateInfo();
frame.HorizontalInfo[j].Value=j;
if (i==0 && j==frame.HorizontalMin) continue;
frame.HorizontalInfo[j].Message[1]=j.toString();
frame.HorizontalInfo[j].Font="14px 微软雅黑";
}
var subFrame=new SubFrameItem();
subFrame.Frame=frame;
if (i==0)
subFrame.Height=20;
else
subFrame.Height=10;
this.Frame.SubFrame[i]=subFrame;
}
}
this.CreateSubFrameItem=function(id)
{
var border=new ChartBorder();
border.UIElement=this.UIElement;
var frame=new KLineFrame();
frame.Canvas=this.Canvas;
frame.ChartBorder=border;
frame.Identify=id; //窗口序号
if (this.ModifyIndexDialog) frame.ModifyIndexEvent=this.ModifyIndexDialog.DoModal; //绑定菜单事件
if (this.ChangeIndexDialog) frame.ChangeIndexEvent=this.ChangeIndexDialog.DoModal;
frame.HorizontalMax=20;
frame.HorizontalMin=10;
frame.YSplitOperator=new FrameSplitY();
frame.YSplitOperator.LanguageID=this.LanguageID;
frame.YSplitOperator.FrameSplitData=this.FrameSplitData.get('double');
frame.YSplitOperator.Frame=frame;
frame.YSplitOperator.ChartBorder=border;
frame.XSplitOperator=new FrameSplitKLineX();
frame.XSplitOperator.Frame=frame;
frame.XSplitOperator.ChartBorder=border;
frame.XSplitOperator.ShowText=false;
//K线数据绑定
var xPointCouont=this.Frame.SubFrame[0].Frame.XPointCount;
frame.XPointCount=xPointCouont;
frame.Data=this.ChartPaint[0].Data;
for(var j=frame.HorizontalMin;j<=frame.HorizontalMax;j+=1)
{
frame.HorizontalInfo[j]= new CoordinateInfo();
frame.HorizontalInfo[j].Value=j;
frame.HorizontalInfo[j].Message[1]=j.toString();
frame.HorizontalInfo[j].Font="14px 微软雅黑";
}
var subFrame=new SubFrameItem();
subFrame.Frame=frame;
subFrame.Height=10;
return subFrame;
}
//创建主图K线画法
this.CreateMainKLine=function()
{
var kline=new ChartKLine();
kline.Canvas=this.Canvas;
kline.ChartBorder=this.Frame.SubFrame[0].Frame.ChartBorder;
kline.ChartFrame=this.Frame.SubFrame[0].Frame;
kline.Name="Main-KLine";
kline.DrawType=this.KLineDrawType;
this.ChartPaint[0]=kline;
this.TitlePaint[0]=new DynamicKLineTitlePainting();
this.TitlePaint[0].Frame=this.Frame.SubFrame[0].Frame;
this.TitlePaint[0].Canvas=this.Canvas;
this.TitlePaint[0].OverlayChartPaint=this.OverlayChartPaint; //绑定叠加
this.TitlePaint[0].LanguageID=this.LanguageID;
}
//绑定主图K线数据
this.BindMainData=function(hisData,showCount)
{
this.ChartPaint[0].Data=hisData;
this.ChartPaint[0].Symbol=this.Symbol;
for(var i in this.Frame.SubFrame)
{
var item =this.Frame.SubFrame[i].Frame;
item.XPointCount=showCount+this.RightSpaceCount;
item.Data=this.ChartPaint[0].Data;
item.XSplitOperator.Symbol=this.Symbol;
item.XSplitOperator.Period=this.Period;
}
this.TitlePaint[0].Data=this.ChartPaint[0].Data; //动态标题
this.TitlePaint[0].Symbol=this.Symbol;
this.TitlePaint[0].Name=this.Name;
this.TitlePaint[0].Period=this.Period;
this.ChartCorssCursor.StringFormatX.Data=this.ChartPaint[0].Data; //十字光标
this.Frame.Data=this.ChartPaint[0].Data;
for(var i in this.OverlayChartPaint) //K线叠加 主图股票数据绑定到叠加上
{
var item=this.OverlayChartPaint[i];
item.MainData=this.ChartPaint[0].Data;
}
var dataOffset=hisData.Data.length-showCount;
if (dataOffset<0) dataOffset=0;
this.ChartPaint[0].Data.DataOffset=dataOffset;
this.ChartPaint[0].Period=this.Period;
this.ChartCorssCursor.StringFormatY.Symbol=this.Symbol;
this.CursorIndex=showCount;
if (this.CursorIndex+dataOffset>=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;
JSConsole.Chart.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<hisData.Data.length;++i)
{
var item=hisData.Data[i];
if (item.Date>=firstDate)
{
index=i;
break;
}
}
if (index===null)
{
JSConsole.Chart.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 (count<pageSize.Min) customShowCount=pageSize.Min;
for(var i in this.Frame.SubFrame)
{
var item =this.Frame.SubFrame[i].Frame;
item.XPointCount=customShowCount;
}
this.ChartPaint[0].Data.DataOffset=index;
this.CursorIndex=0.6;
}
//创建指定窗口指标
this.CreateWindowIndex=function(windowIndex)
{
this.WindowIndex[windowIndex].Create(this,windowIndex);
}
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.BindOverlayIndexData=function(overlayItem, windowIndex, hisData)
{
if (!overlayItem.Script) return;
if (typeof(overlayItem.Script.RequestData)=='function')
{
overlayItem.Script.RequestData(this,windowIndex,hisData);
return;
}
if (typeof(overlayItem.Script.ExecuteScript)=='function')
{
overlayItem.Script.ExecuteScript(this,windowIndex,hisData);
return;
}
overlayItem.Script.BindData(this,windowIndex,hisData);
}
//执行指示(专家指示 五彩K线)
this.BindInstructionIndexData=function(hisData)
{
if (this.ColorIndex && typeof(this.ColorIndex.ExecuteScript)=='function') //五彩K线
{
this.ColorIndex.ExecuteScript(this,0,hisData);
}
if (this.TradeIndex && typeof(this.TradeIndex.ExecuteScript)=='function') //交易指标
{
this.TradeIndex.ExecuteScript(this,0,hisData);
}
}
//获取子窗口的所有画法
this.GetChartPaint=function(windowIndex)
{
var paint=new Array();
for(var i in this.ChartPaint)
{
if (i==0) continue; //第1个K线数据除外
var item=this.ChartPaint[i];
if (item.ChartFrame==this.Frame.SubFrame[windowIndex].Frame)
paint.push(item);
}
return paint;
}
this.AutoUpdateEvent=function(bStart, explain) //自定更新事件, 是给websocket使用
{
var eventID=bStart ? JSCHART_EVENT_ID.RECV_START_AUTOUPDATE:JSCHART_EVENT_ID.RECV_STOP_AUTOUPDATE;
if (!this.mapEvent.has(eventID)) return;
var self=this;
var event=this.mapEvent.get(eventID);
var data={ Stock:{ Symbol:this.Symbol, Name:this.Name, Right:this.Right, Period:this.Period }, Explain: explain };
if (bStart)
{
data.Callback=function(data) //数据到达更新回调
{
if (ChartData.IsDayPeriod(self.Period,true)) self.RecvRealtimeData(data);
else if (ChartData.IsMinutePeriod(self.Period,true)) self.RecvMinuteRealtimeData(data);
else if (ChartData.IsSecondPeriod(self.Period)) self.RecvMinuteRealtimeData(data);
}
}
event.Callback(event,data,this);
}
this.SendKLineUpdateEvent=function(bindData)
{
var event=this.GetEventCallback(JSCHART_EVENT_ID.RECV_KLINE_UPDATE_DATA);
if (event && event.Callback)
{
var data={ HistoryData:bindData, Stock:{Symbol:this.Symbol, Name:this.Name } }
event.Callback(event,data,this);
return true;
}
return false;
}
this.RequestHistoryData=function()
{
var self=this;
this.ChartSplashPaint.IsEnableSplash = true;
this.FlowCapitalReady=false;
this.ResetPage(); //重置分页
this.ResetDragDownload();
this.Draw();
if (this.NetworkFilter)
{
var obj=
{
Name:'KLineChartContainer::RequestHistoryData', //类名::
Explain:'日K数据',
Request:{ Url:self.KLineApiUrl, Type:'POST' ,
Data: { symbol:self.Symbol, count:self.MaxReqeustDataCount, field: ["name","symbol","yclose","open","price","high","low","vol"] } },
Self:this,
PreventDefault:false
};
this.NetworkFilter(obj, function(data)
{
self.ChartSplashPaint.IsEnableSplash = false;
self.RecvHistoryData(data);
var page=self.Page.Day;
if (page.Enable==true && page.Finish==false)
{
self.RequestHistoryPageData();
}
else
{
self.AutoUpdateEvent(true,'KLineChartContainer::RequestHistoryData');
self.AutoUpdate();
}
});
if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求
}
JSNetwork.HttpRequest({
url: this.KLineApiUrl,
data:
{
"field": ["name","symbol","yclose","open","price","high","low","vol"],
"symbol": self.Symbol,
"start": -1,
"count": self.MaxReqeustDataCount
},
type:"post",
dataType: "json",
async:true,
success: function (data)
{
self.ChartSplashPaint.IsEnableSplash = false;
self.RecvHistoryData(data);
var page=self.Page.Day;
if (page.Enable==true && page.Finish==false)
{
self.RequestHistoryPageData();
}
else
{
self.AutoUpdateEvent(true,'KLineChartContainer::RequestHistoryData');
self.AutoUpdate();
}
}
});
}
this.RecvHistoryData=function(data)
{
var aryDayData=KLineChartContainer.JsonDataToHistoryData(data);
//原始数据
var sourceData=new ChartData();
sourceData.Data=aryDayData;
sourceData.DataType=0; //0=日线数据 1=分钟数据
sourceData.Symbol=data.symbol;
//显示的数据
var bindData=new ChartData();
bindData.Data=aryDayData;
bindData.Right=this.Right;
bindData.Period=this.Period;
bindData.DataType=0;
bindData.Symbol=data.symbol;
if (bindData.Right>0 && !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; i<this.Frame.SubFrame.length; ++i) //执行指标
{
if (i==0) firstSubFrame=this.Frame.SubFrame[i].Frame;
this.BindIndexData(i,bindData);
}
if (firstSubFrame && firstSubFrame.YSplitOperator)
{
firstSubFrame.YSplitOperator.Symbol=this.Symbol;
firstSubFrame.YSplitOperator.Data=this.ChartPaint[0].Data; //K线数据
firstSubFrame.YSplitOperator.Period=this.Period; //周期
}
var page=this.Page.Day;
if (page.Enable==false || (page.Enable==true && page.Finish==true)) //分页下载 这些数据迁移到分页下载完以后下载
{
this.RequestFlowCapitalData(); //请求流通股本数据 (主数据下载完再下载)
this.RequestOverlayHistoryData(); //请求叠加数据 (主数据下载完再下载)
this.CreateChartDrawPictureByStorage(); //创建画图工具
}
if (page.Enable) page.Index=1; //第一页下载完成
//刷新画图
this.UpdataDataoffset(); //更新数据偏移
this.UpdateFrameMaxMin(); //调整坐标最大 最小值
this.Frame.SetSizeChage(true);
this.Draw();
this.UpdatePointByCursorIndex(); //更新十字光标位子
//叠加指标
for(var i=0;i<this.Frame.SubFrame.length;++i)
{
var item=this.Frame.SubFrame[i];
for(var j in item.OverlayIndex)
{
var overlayItem=item.OverlayIndex[j];
this.BindOverlayIndexData(overlayItem,i,bindData)
}
}
if (this.mapEvent.has(JSCHART_EVENT_ID.RECV_HISTROY_DATA))
{
var event=this.mapEvent.get(JSCHART_EVENT_ID.RECV_HISTROY_DATA);
var data={ HistoryData:bindData, Stock:{Symbol:this.Symbol, Name:this.Name } }
event.Callback(event,data,this);
}
}
this.RequestHistoryPageData=function() //请求分页
{
var self=this;
if (this.NetworkFilter)
{
var firstItem=this.SourceData.Data[0]; //最新的一条数据
var obj=
{
Name:'KLineChartContainer::RequestHistoryPageData', //类名::
Explain:'日K数据分页',
Request:{ Url:'none', Type:'POST' ,
Data: { symbol:self.Symbol, index:self.Page.Day.Index, field: ["name","symbol","yclose","open","price","high","low","vol"], firstDate:firstItem.Date, first:{ date: firstItem.Date } } },
Page:self.Page.Day,
Self:this,
PreventDefault:false
};
this.NetworkFilter(obj, function(data)
{
self.RecvHistoryPageData(data);
var page=self.Page.Day;
if (page.Enable==true && page.Finish==false)
self.RequestHistoryPageData(); //继续下载
else
self.AutoUpdate();
});
if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求
}
//模拟异步请求
setTimeout(function()
{
var page=self.Page.Day;
page.Finish=true;
var data= //测试数据
{
data:
[
[ 20150218, 12.54, 12.5, 12.74, 11.95, 12.27, 117632441, 1459671045 ],
[ 20150219, 12.27, 12.1, 12.23, 11.9, 12.23, 95889423, 1157078548 ],
[ 20150220, 12.23, 12.17, 12.17, 11.9, 12.05, 67763439, 815652761]
],
symbol:self.Symbol,
name:self.Name
};
self.RecvHistoryPageData(data);
if (page.Enable==true && page.Finish==false)
self.RequestHistoryPageData();
else
self.AutoUpdate();
},500)
}
this.RecvHistoryPageData=function(data)
{
var aryDayData=KLineChartContainer.JsonDataToHistoryData(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;
if (bindData.Right>0 && 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; i<this.Frame.SubFrame.length; ++i)
{
this.BindIndexData(i,bindData);
}
var page=this.Page.Day;
++page.Index;
if (page.Enable==true && page.Finish==true) //分页下载 这些数据迁移到分页下载完以后下载
{
this.RequestFlowCapitalData(); //请求流通股本数据 (主数据下载完再下载)
this.RequestOverlayHistoryData(); //请求叠加数据 (主数据下载完再下载)
this.CreateChartDrawPictureByStorage(); //创建画图工具
}
//刷新画图
this.UpdataDataoffset(); //更新数据偏移
this.UpdatePointByCursorIndex(); //更新十字光标位子
this.UpdateFrameMaxMin(); //调整坐标最大 最小值
this.Frame.SetSizeChage(true);
this.Draw();
}
this.ReqeustHistoryMinuteData=function()
{
var self=this;
this.ChartSplashPaint.IsEnableSplash = true;
this.FlowCapitalReady=false;
this.ResetPage(); //重置分页
this.ResetDragDownload();
this.Draw();
if (this.NetworkFilter)
{
var obj=
{
Name:'KLineChartContainer::ReqeustHistoryMinuteData', //类名::
Explain:'1分钟K线数据',
Request:{ Url:self.MinuteKLineApiUrl, Type:'POST',
Data: { symbol:self.Symbol, count:self.MaxRequestMinuteDayCount, field: ["name","symbol", "yclose","open","price","high","low","vol"] } },
Self:this,
PreventDefault:false
};
this.NetworkFilter(obj, function(data)
{
self.ChartSplashPaint.IsEnableSplash = false;
self.RecvMinuteHistoryData(data);
var page=self.Page.Minute;
if (page.Enable==true && page.Finish==false)
{
self.ReqeustHistoryMinutePageData();
}
else
{
self.AutoUpdateEvent(true,'KLineChartContainer::ReqeustHistoryMinuteData');
self.AutoUpdate();
}
});
if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求
}
JSNetwork.HttpRequest({
url: this.MinuteKLineApiUrl,
data:
{
"field": ["name","symbol", "yclose","open","price","high","low","vol"],
"symbol": self.Symbol,
"start": -1,
"count": self.MaxRequestMinuteDayCount
},
type:"post",
dataType: "json",
async:true,
success: function (data)
{
self.ChartSplashPaint.IsEnableSplash = false;
self.RecvMinuteHistoryData(data);
var page=self.Page.Minute;
if (page.Enable==true && page.Finish==false)
{
self.ReqeustHistoryMinutePageData();
}
else
{
self.AutoUpdateEvent(true,'KLineChartContainer::ReqeustHistoryMinuteData');
self.AutoUpdate();
}
}
});
}
this.RecvMinuteHistoryData=function(data)
{
var aryDayData=KLineChartContainer.JsonDataToMinuteHistoryData(data);
//原始数据
var sourceData=new ChartData();
sourceData.Data=aryDayData;
sourceData.DataType=1; //0=日线数据 1=分钟数据
sourceData.Symbol=data.symbol;
//显示的数据
var bindData=new ChartData();
bindData.Data=aryDayData;
bindData.Right=this.Right;
bindData.Period=this.Period;
bindData.DataType=1;
bindData.Symbol=data.symbol;
if (ChartData.IsMinutePeriod(bindData.Period,false) && !this.IsApiPeriod) //周期数据
{
var periodData=sourceData.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; i<this.Frame.SubFrame.length; ++i) //执行指标
{
if (i==0) firstSubFrame=this.Frame.SubFrame[i].Frame;
this.BindIndexData(i,bindData);
}
if (firstSubFrame && firstSubFrame.YSplitOperator)
{
firstSubFrame.YSplitOperator.Symbol=this.Symbol;
firstSubFrame.YSplitOperator.Data=this.ChartPaint[0].Data; //K线数据
firstSubFrame.YSplitOperator.Period=this.Period; //周期
}
for(var i in this.OverlayChartPaint) //分钟数据不支持叠加 清空
{
var item=this.OverlayChartPaint[i];
item.Data=null;
//item.Status=OVERLAY_STATUS_ID.STATUS_NONE_ID;
}
var page=this.Page.Minute;
if (page.Enable==false || (page.Enable==true && page.Finish==true) )
{
this.RequestFlowCapitalData(); //请求流通股本数据 (主数据下载完再下载)
this.RequestOverlayHistoryMinuteData(); //请求叠加数据 (主数据下载完再下载)
this.CreateChartDrawPictureByStorage(); //创建画图工具
}
if (page.Enable) ++page.Index;
//刷新画图
this.UpdataDataoffset(); //更新数据偏移
this.UpdatePointByCursorIndex(); //更新十字光标位子
this.UpdateFrameMaxMin(); //调整坐标最大 最小值
this.Frame.SetSizeChage(true);
this.Draw();
//叠加指标
for(var i=0;i<this.Frame.SubFrame.length;++i)
{
var item=this.Frame.SubFrame[i];
for(var j in item.OverlayIndex)
{
var overlayItem=item.OverlayIndex[j];
this.BindOverlayIndexData(overlayItem,i,bindData)
}
}
if (this.mapEvent.has(JSCHART_EVENT_ID.RECV_HISTROY_DATA))
{
var event=this.mapEvent.get(JSCHART_EVENT_ID.RECV_HISTROY_DATA);
var data={ HistoryData:bindData, Stock:{Symbol:this.Symbol, Name:this.Name } }
event.Callback(event,data,this);
}
}
this.ReqeustHistoryMinutePageData=function()
{
var self=this;
if (this.NetworkFilter)
{
var firstItem=this.SourceData.Data[0]; //最新的一条数据
var obj=
{
Name:'KLineChartContainer::RecvHistoryMinutePageData', //类名::
Explain:'1分钟K线数据分页',
Request:{ Url:'none', Type:'POST' ,
Data: { symbol:self.Symbol, index:self.Page.Minute.Index, field: ["name","symbol","yclose","open","price","high","low","vol"], firstDate:firstItem.Date, first:{ date: firstItem.Date, time:firstItem.Time } } },
Page:self.Page.Minute,
Self:this,
PreventDefault:false
};
this.NetworkFilter(obj, function(data)
{
self.RecvHistoryMinutePageData(data);
var page=self.Page.Minute;
if (page.Enable==true && page.Finish==false)
self.ReqeustHistoryMinutePageData(); //继续下载
else
self.AutoUpdate();
});
if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求
}
//模拟异步请求
setTimeout(function()
{
var page=self.Page.Minute;
page.Finish=true;
var data= //测试数据
{
data:
[
[ 20190906,14.58,14.71,14.71,14.71,14.71,1096425,16128411,925],
[ 20190906,14.71,14.73,14.74,14.71,14.71,2154859,31731820,930],
[ 20190906,14.71,14.71,14.71,14.68,14.69,1427516,20989208,931],
[ 20190906,14.69,14.69,14.71,14.68,14.7, 1680503,24694143,932],
[ 20190906,14.7,14.69,14.7,14.65,14.65,1315900,19310964,933],
[ 20190906,14.65,14.66,14.69,14.65,14.68,702955,10313842,934],
[ 20190906,14.68,14.7,14.71,14.67, 14.67,1735266,25495875,935],
[ 20190906,14.67,14.68,14.7,14.67,14.67,739000,10845398,936],
[ 20190906,14.67,14.67,14.68,14.67,14.68,389800,5721266,937],
[ 20190906,14.68,14.68,14.7,14.68,14.69,648477,9527859,938],
[ 20190906,14.69,14.7,14.71,14.69,14.7,1128400,16589794,939],
[ 20190906,14.7,14.7,14.71,14.69,14.71,714858,10509708,940],
[ 20190906,14.71,14.71,14.71,14.69,14.69,401500,5900477,941],
[ 20190906,14.69,14.69,14.71,14.69,14.69,1165684,17131034,942],
[ 20190906,14.69, 14.69,14.7,14.67,14.67,498516, 7321024,943],
[ 20190906,14.67,14.68,14.68,14.67,14.67,350126,5139012,944],
[ 20190906,14.67,14.67,14.69,14.67,14.69,561600,8246789,945]
]
//symbol:'600000.sh',
//name:'浦发行情'
};
self.RecvHistoryMinutePageData(data);
if (page.Enable==true && page.Finish==false)
self.ReqeustHistoryMinutePageData();
else
self.AutoUpdate();
},500)
}
this.RecvHistoryMinutePageData=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;
if (bindData.Right>0 && 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; i<this.Frame.SubFrame.length; ++i)
{
this.BindIndexData(i,bindData);
}
var page=this.Page.Minute;
if (page.Enable==false || (page.Enable==true && page.Finish==true) )
{
this.RequestFlowCapitalData(); //请求流通股本数据 (主数据下载完再下载)
this.CreateChartDrawPictureByStorage(); //创建画图工具
}
if (page.Enable) ++page.Index;
//刷新画图
this.UpdataDataoffset(); //更新数据偏移
this.UpdatePointByCursorIndex(); //更新十字光标位子
this.UpdateFrameMaxMin(); //调整坐标最大 最小值
this.Frame.SetSizeChage(true);
this.Draw();
}
//请求实时行情数据
this.RequestRealtimeData=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::RequestRealtimeData', //类名::函数名
Explain:'当天最新日线数据',
Request:{ Url:self.RealtimeApiUrl, Data:{ symbol: arySymbol,
field:["name","symbol","yclose","open","price","high","low","vol","amount","date","time"] }, Type:'POST' },
Self:this,
PreventDefault:false
};
this.NetworkFilter(obj, function(data)
{
self.RecvRealtimeData(data);
self.AutoUpdate();
});
if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求
}
JSNetwork.HttpRequest({
url: this.RealtimeApiUrl,
data:
{
"field": ["name","symbol","yclose","open","price","high","low","vol","amount","date","time"],
"symbol": arySymbol,
"start": -1
},
type:"post",
dataType: "json",
async:true,
success: function (data)
{
self.RecvRealtimeData(data);
self.AutoUpdate();
}
});
}
this.RecvRealtimeData=function(data)
{
if (this.IsOnTouch==true) return; //正在操作中不更新数据
var realtimeData=KLineChartContainer.JsonDataToRealtimeData(data,this.Symbol);
if (!realtimeData) return;
var item=this.SourceData.Data[this.SourceData.Data.length-1]; //最新的一条数据
var lastDataCount=this.GetHistoryDataCount(); //保存下上一次的数据个数
if (item.Date==realtimeData.Date) //实时行情数据更新
{
JSConsole.Chart.Log('[KLineChartContainer::RecvRealtimeData] update kline by minute data',realtimeData);
item.Close=realtimeData.Close;
item.High=realtimeData.High;
item.Low=realtimeData.Low;
item.Vol=realtimeData.Vol;
item.Amount=realtimeData.Amount;
}
else if (item.Date<realtimeData.Date) //新增加数据
{
JSConsole.Chart.Log('[KLineChartContainer::RecvRealtimeData] insert kline by minute data',realtimeData);
var newItem =new HistoryData();
newItem.YClose=realtimeData.YClose;
newItem.Open=realtimeData.Open;
newItem.Close=realtimeData.Close;
newItem.High=realtimeData.High;
newItem.Low=realtimeData.Low;
newItem.Vol=realtimeData.Vol;
newItem.Amount=realtimeData.Amount;
newItem.Date=realtimeData.Date;
this.SourceData.Data.push(newItem);
}
else
{
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.UpdateMainData(bindData,lastDataCount);//更新主图数据
this.UpdateOverlayRealtimeData(data); //更新叠加股票数据
this.BindInstructionIndexData(bindData); //执行指示脚本
for(var i=0; i<this.Frame.SubFrame.length; ++i)
{
this.BindIndexData(i,bindData);
}
//刷新画图
this.UpdataDataoffset(); //更新数据偏移
this.UpdatePointByCursorIndex(); //更新十字光标位子
this.UpdateFrameMaxMin(); //调整坐标最大 最小值
this.Frame.SetSizeChage(true);
this.Draw();
this.SendKLineUpdateEvent(bindData);
}
this.UpdateOverlayRealtimeData=function(data)
{
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;
var realtimeData=KLineChartContainer.JsonDataToRealtimeData(data,item.Symbol); //获取叠加股票的最新数据
if (!realtimeData) continue;
var sourceData=item.SourceData; //叠加股票的所有数据
var latestData=sourceData.Data[sourceData.Data.length-1]; //最新的一条数据
if (latestData.Date==realtimeData.Date) //实时行情数据更新
{
JSConsole.Chart.Log('[KLineChartContainer::UpdateOverlayRealtimeData] update kline by minute data',realtimeData);
latestData.Close=realtimeData.Close;
latestData.High=realtimeData.High;
latestData.Low=realtimeData.Low;
latestData.Vol=realtimeData.Vol;
latestData.Amount=realtimeData.Amount;
}
else if (item.Date<realtimeData.Date) //新增加数据
{
JSConsole.Chart.Log('[KLineChartContainer::UpdateOverlayRealtimeData] insert kline by minute data',realtimeData);
var newItem =new HistoryData();
newItem.YClose=realtimeData.YClose;
newItem.Open=realtimeData.Open;
newItem.Close=realtimeData.Close;
newItem.High=realtimeData.High;
newItem.Low=realtimeData.Low;
newItem.Vol=realtimeData.Vol;
newItem.Amount=realtimeData.Amount;
newItem.Date=realtimeData.Date;
sourceData.Data.push(newItem);
}
else
{
continue;
}
var bindData=new ChartData();
bindData.Data=sourceData.Data;
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;
}
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.SetSourceDatatLimit=function(aryLimit)
{
this.SourceDataLimit=new Map();
for(var i in aryLimit)
{
var item=aryLimit[i];
this.SourceDataLimit.set(item.Period, item.MaxCount); //每个周期缓存数据最大个数 key=周期 value=最大个数
JSConsole.Chart.Log(`[KLineChartContainer::SetSourceDatatLimit] Period=${item.Period}, MaxCount=${item.MaxCount}`);
}
}
this.ReduceSourceData=function()
{
if (!this.SourceDataLimit) return;
if (!this.SourceDataLimit.has(this.Period)) return;
var limitCount=this.SourceDataLimit.get(this.Period);
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;
if (limitCount<50) return;
var dataOffset=frameHisdata.DataOffset;
var removeCount=0;
while(this.SourceData.Data.length>limitCount)
{
this.SourceData.Data.shift();
--dataOffset;
++removeCount;
}
if (removeCount>0)
{
if (dataOffset<0) dataOffset=0;
frameHisdata.DataOffset=dataOffset;
JSConsole.Chart.Log(`[KLineChartContainer::ReduceSourceData] remove data ${removeCount}, dataOffset=${dataOffset}`);
}
}
this.RecvMinuteRealtimeDataV2=function(data) //新版本的
{
if (this.IsOnTouch==true) return; //正在操作中不更新数据
var aryMinuteData=KLineChartContainer.JsonDataToMinuteHistoryData(data);
if (!aryMinuteData || aryMinuteData.length<=0) return;
if (this.IsApiPeriod) this.ReduceSourceData(); //减少数据
var lastDataCount=this.GetHistoryDataCount(); //保存下上一次的数据个数
if (!this.SourceData.MergeMinuteData(aryMinuteData)) return;
JSConsole.Chart.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.Frame.SubFrame.length; ++i)
{
this.BindIndexData(i,bindData);
}
//刷新画图
this.UpdataDataoffset(); //更新数据偏移
this.UpdatePointByCursorIndex(); //更新十字光标位子
this.UpdateFrameMaxMin(); //调整坐标最大 最小值
this.Frame.SetSizeChage(true);
this.Draw();
this.SendKLineUpdateEvent(bindData);
}
this.RecvMinuteRealtimeData=function(data)
{
if (this.IsOnTouch==true) return; //正在操作中不更新数据
if (data.ver==2.0)
{
this.RecvMinuteRealtimeDataV2(data);
return;
}
var realtimeData=KLineChartContainer.JsonDataToMinuteRealtimeData(data, this.Symbol);
if (!realtimeData) return;
if (this.IsApiPeriod) this.ReduceSourceData(); //减少数据
var lastDataCount=this.GetHistoryDataCount(); //保存下上一次的数据个数
var lastSourceDataCount=this.SourceData.Data.length;
if (!this.SourceData.MergeMinuteData(realtimeData)) return;
JSConsole.Chart.Log(`[KLineChartContainer::RecvMinuteRealtimeData] update kline by 1 minute data [${lastSourceDataCount}->${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; i<this.Frame.SubFrame.length; ++i)
{
this.BindIndexData(i,bindData);
}
//刷新画图
this.UpdataDataoffset(); //更新数据偏移
this.UpdatePointByCursorIndex(); //更新十字光标位子
this.UpdateFrameMaxMin(); //调整坐标最大 最小值
this.Frame.SetSizeChage(true);
this.Draw();
this.SendKLineUpdateEvent(bindData);
}
//更新当天的全量分钟数据
this.UpdateOverlayMinuteRealtimeData=function(data)
{
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;
var realtimeData=KLineChartContainer.JsonDataToMinuteRealtimeData(data,item.Symbol); //获取叠加股票的最新数据
if (!realtimeData) continue;
var sourceData=item.SourceData; //叠加股票的所有数据
if (!sourceData.MergeMinuteData(realtimeData)) return;
var bindData=new ChartData();
bindData.Data=sourceData.Data;
bindData.Period=this.Period;
bindData.Right=this.Right;
bindData.DataType=0;
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;
}
item.Data=bindData;
}
}
this.GetHistoryDataCount=function()
{
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 -1;
var lastDataCount=frameHisdata.Data.length; //上一个的数据长度
return lastDataCount;
}
this.GetRequestDataCount=function() //K线请求数据个数 (由于可以拖拽下载历史数据,所有原来固定个数的就不能用了)
{
var result={MaxRequestDataCount:this.MaxReqeustDataCount, MaxRequestMinuteDayCount:this.MaxRequestMinuteDayCount };
if (!this.SourceData || !this.SourceData.Data || this.SourceData.Data.length<=0) return result;
if (ChartData.IsDayPeriod(this.Period,true))
{
var lCount=this.SourceData.Data.length;
if (lCount>result.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; i<this.Frame.SubFrame.length; ++i) //执行指标
{
if (i==0) firstSubFrame=this.Frame.SubFrame[i].Frame;
this.BindIndexData(i,bindData);
}
if (firstSubFrame && firstSubFrame.YSplitOperator)
{
firstSubFrame.YSplitOperator.Symbol=this.Symbol;
firstSubFrame.YSplitOperator.Data=this.ChartPaint[0].Data; //K线数据
firstSubFrame.YSplitOperator.Period=this.Period; //周期
firstSubFrame.YSplitOperator.KLineChart=this.ChartPaint[0]; //绑定K线图形
}
//this.CreateChartDrawPictureByStorage(); //创建画图工具
//刷新画图
this.UpdataDataoffset(); //更新数据偏移
this.UpdateFrameMaxMin(); //调整坐标最大 最小值
this.Frame.SetSizeChage(true);
this.Draw();
this.UpdatePointByCursorIndex(); //更新十字光标位子
if (this.mapEvent.has(JSCHART_EVENT_ID.RECV_HISTROY_DATA))
{
var event=this.mapEvent.get(JSCHART_EVENT_ID.RECV_HISTROY_DATA);
var data={ HistoryData:bindData, Stock:{Symbol:this.Symbol, Name:this.Name } }
event.Callback(event,data,this);
}
}
//请求最新的分笔数据
this.RequestTickRealtimeData=function()
{
var self=this;
var start=0;
if (this.SourceData && this.SourceData.Data) start=this.SourceData.Data.length;
if (this.NetworkFilter)
{
var obj=
{
Name:'KLineChartContainer::RequestTickRealtimeData', //类名::
Explain:'当天最新分笔数据',
Request:{ Url:self.TickApiUrl, Data:{ symbol: self.Symbol, start:start, end:start+1000 }, Type:'POST' },
Self:this,
PreventDefault:false
};
this.NetworkFilter(obj, function(data)
{
self.ChartSplashPaint.IsEnableSplash=false;
self.RecvTickData(data);
self.AutoUpdate();
});
if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求
}
JSNetwork.HttpRequest({
url: self.TickApiUrl,
data:{"symbol":self.Symbol, start:start-10, end:start+1000 },
type:"post",
dataType: "json",
async:true,
success: function (data)
{
self.ChartSplashPaint.IsEnableSplash=false;
self.RecvTickRealtimeData(data);
self.AutoUpdate();
}
});
}
this.RecvTickRealtimeData=function(data)
{
var aryDayData=KLineChartContainer.JsonDataToTickData(data); //增量数据
if (!aryDayData || aryDayData.length<=0) return;
//更新原始数据
var source=this.SourceData.Data;
var lastDataCount=this.SourceData.Data.length; //上一个的数据长度
var lastTime=0;
if (source.length>0) 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; i<this.Frame.SubFrame.length; ++i)
{
this.BindIndexData(i,bindData);
}
//this.CreateChartDrawPictureByStorage(); //创建画图工具
//刷新画图
this.UpdataDataoffset(); //更新数据偏移
this.UpdateFrameMaxMin(); //调整坐标最大 最小值
this.Frame.SetSizeChage(true);
this.Draw();
this.UpdatePointByCursorIndex(); //更新十字光标位子
}
//周期切换
this.ChangePeriod=function(period)
{
if (this.Period==period) return;
var isDataTypeChange=false;
if (period>CUSTOM_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) ||
(period>CUSTOM_SECOND_PERIOD_START && period<=CUSTOM_SECOND_PERIOD_END))
{
if (this.SourceData.DataType!=1) isDataTypeChange=true;
}
else
{
switch(period)
{
case 0: //日线
case 1: //周
case 2: //月
case 3: //年
case 9: //季线
case 21: //双周
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) || ChartData.IsSecondPeriod(this.Period))
{
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;
if (!this.IsApiPeriod)
{
this.Update();
return;
}
else //API周期数据 重新请求数据
{
if (ChartData.IsDayPeriod(this.Period,true))
{
this.CancelAutoUpdate(); //先停止定时器
this.AutoUpdateEvent(false,'KLineChartContainer::ChangeRight'); //切换复权先停止更新
this.ResetOverlaySymbolStatus();
this.RequestHistoryData(); //请求日线数据
}
else if (ChartData.IsMinutePeriod(this.Period,true) || ChartData.IsSecondPeriod(this.Period))
{
this.CancelAutoUpdate(); //先停止定时器
this.AutoUpdateEvent(false,'KLineChartContainer::ChangeRight'); //切换复权先停止更新
this.ResetOverlaySymbolStatus();
this.ReqeustHistoryMinuteData(); //请求分钟数据
}
}
}
//设置第1屏的起始日期
this.SetFirstShowDate=function(obj)
{
if (!obj || !obj.Date) return;
JSConsole.Chart.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;
if (ChartData.IsDayPeriod(this.Period,true))
{
for(var i=0;i<hisData.Data.length;++i)
{
var item=hisData.Data[i];
if (item.Date>=obj.Date)
{
index=i;
break;
}
}
}
else if (ChartData.IsMinutePeriod(this.Period,true))
{
let findTime=obj.Time;
if (!IFrameSplitOperator.IsPlusNumber(obj.Time)) findTime=0;
for(var i=0;i<hisData.Data.length;++i)
{
var item=hisData.Data[i];
if (item.Date>=obj.Date && item.Time>=findTime)
{
index=i;
break;
}
}
}
if (index===null)
{
JSConsole.Chart.Log(`[KLineChartContainer::SetFirstShowDate] an't find first date=${obj.Date} time=${obj.Time}`, 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;
this.LastPoint.X=null;
this.LastPoint.Y=null;
JSConsole.Chart.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();
}
//切换api指标
this.ChangeAPIIndex=function(windowIndex,indexData)
{
this.DeleteIndexPaint(windowIndex);
//使用API挂接指标数据 API:{ Name:指标名字, Script:指标脚本可以为空, Args:参数可以为空, Url:指标执行地址 }
var apiItem=indexData.API;
this.WindowIndex[windowIndex]=new APIScriptIndex(apiItem.Name,apiItem.Script,apiItem.Args,indexData);
var bindData=this.ChartPaint[0].Data;
this.BindIndexData(windowIndex,bindData); //执行脚本
this.UpdataDataoffset(); //更新数据偏移
this.UpdateFrameMaxMin(); //调整坐标最大 最小值
this.Draw();
}
//切换指标 指定切换窗口指标
this.ChangeIndex=function(windowIndex,indexName,option)
{
if (option && option.API) //切换api指标
return this.ChangeAPIIndex(windowIndex,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;
if (option.TitleFont) indexData.TitleFont=option.TitleFont;
if (option.IsShortTitle) indexData.IsShortTitle=option.IsShortTitle;
}
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.UpdateFrameMaxMin(); //调整坐标最大 最小值
this.Frame.SetSizeChage(true);
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;i<this.Frame.SubFrame.length;++i)
{
var item=this.Frame.SubFrame[i].Frame;
if (i==this.Frame.SubFrame.length-1) item.XSplitOperator.ShowText=true;
else item.XSplitOperator.ShowText=false;
}
}
else
{
//创建新的指标窗口
for(var i=currentLength;i<count;++i)
{
var subFrame=this.CreateSubFrameItem(i);
this.Frame.SubFrame[i]=subFrame;
var titlePaint=new DynamicChartTitlePainting();
titlePaint.Frame=this.Frame.SubFrame[i].Frame;
titlePaint.Canvas=this.Canvas;
titlePaint.LanguageID=this.LanguageID;
this.TitlePaint[i+1]=titlePaint;
}
//创建指标
const indexName=["RSI","MACD","VOL","UOS","CHO","BRAR"];
let scriptData = new JSIndexScript();
for(var i=currentLength;i<count;++i)
{
var name=indexName[i%indexName.length];
let indexInfo = scriptData.Get(name);
this.WindowIndex[i] = new ScriptIndex(indexInfo.Name, indexInfo.Script, indexInfo.Args,indexInfo); //脚本执行
var bindData=this.ChartPaint[0].Data;
this.BindIndexData(i,bindData); //执行脚本
}
//最后一个显示X轴坐标
for(var i=0;i<this.Frame.SubFrame.length;++i)
{
var item=this.Frame.SubFrame[i].Frame;
if (i==this.Frame.SubFrame.length-1) item.XSplitOperator.ShowText=true;
else item.XSplitOperator.ShowText=false;
}
this.UpdataDataoffset(); //更新数据偏移
}
this.Frame.SetSizeChage(true);
this.ResetFrameXYSplit();
this.UpdateFrameMaxMin(); //调整坐标最大 最小值
this.Draw();
}
this.ChangeIndexTemplate=function(option) //切换指标模板 可以设置指标窗口个数 每个窗口的指标
{
if (!option.Windows) return;
var count=option.Windows.length;
if (count<=0) return;
var currentLength=this.Frame.SubFrame.length;
//清空所有的指标图型
for(var i=0;i<currentLength;++i)
{
this.DeleteIndexPaint(i);
var frame=this.Frame.SubFrame[i];
frame.YSpecificMaxMin=null;
frame.IsLocked=false;
frame.YSplitScale = null;
}
if (currentLength>count)
{
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<count;++i) //创建新的指标窗口
{
var subFrame=this.CreateSubFrameItem(i);
this.Frame.SubFrame[i]=subFrame;
var titlePaint=new DynamicChartTitlePainting();
titlePaint.Frame=this.Frame.SubFrame[i].Frame;
titlePaint.Canvas=this.Canvas;
titlePaint.LanguageID=this.LanguageID;
this.TitlePaint[i+1]=titlePaint;
}
}
var systemScript = new JSIndexScript();
var bindData=this.ChartPaint[0].Data;
for(var i=0;i<count;++i)
{
var windowIndex=i;
var indexID=option.Windows[i].Index;
var indexItem=JSIndexMap.Get(indexID);
var titleIndex=windowIndex+1;
this.TitlePaint[titleIndex].Data=[];
this.TitlePaint[titleIndex].Title=null;
if (indexItem)
{
this.WindowIndex[i]=indexItem.Create();
this.CreateWindowIndex(windowIndex);
this.BindIndexData(windowIndex,bindData);
}
else
{
var indexInfo = systemScript.Get(indexID);
if (indexInfo)
{
var args=indexInfo.Args;
if (option.Windows[i].Args) args=option.Windows[i].Args;
let indexData =
{
Name:indexInfo.Name, Script:indexInfo.Script, Args: args, ID:indexID ,
//扩展属性 可以是空
KLineType:indexInfo.KLineType, YSpecificMaxMin:indexInfo.YSpecificMaxMin, YSplitScale:indexInfo.YSplitScale,
FloatPrecision:indexInfo.FloatPrecision, Condition:indexInfo.Condition
};
this.WindowIndex[i]=new ScriptIndex(indexData.Name,indexData.Script,indexData.Args,indexData); //脚本执行
this.BindIndexData(windowIndex,bindData); //执行脚本
}
}
}
//最后一个显示X轴坐标
for(var i=0;i<this.Frame.SubFrame.length;++i)
{
var item=this.Frame.SubFrame[i].Frame;
if (i==this.Frame.SubFrame.length-1) item.XSplitOperator.ShowText=true;
else item.XSplitOperator.ShowText=false;
}
this.UpdataDataoffset(); //更新数据偏移
this.Frame.SetSizeChage(true);
this.ResetFrameXYSplit();
this.UpdateFrameMaxMin(); //调整坐标最大 最小值
this.Draw();
}
this.RemoveIndexWindow=function(id)
{
JSConsole.Chart.Log('[KLineChartContainer::RemoveIndexWindow] remove id', id);
if (id==0) return;
if (!this.Frame.SubFrame) return;
if (id>=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;i<this.Frame.SubFrame.length;++i)
{
var item=this.Frame.SubFrame[i].Frame;
if (i==this.Frame.SubFrame.length-1) item.XSplitOperator.ShowText=true;
else item.XSplitOperator.ShowText=false;
item.Identify=i;
}
if (this.ChartDrawPicture.length>0)
{
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':
if (option.Create && typeof(option.Create)=='function') chart=option.Create();
else 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.DragMode==JSCHART_DRAG_ID.CLICK_TOUCH_MODE_ID)
{
if (this.TouchStatus.CorssCursorShow==true && this.TouchDrawCount>0) return;
this.TouchStatus.CorssCursorShow=false;
this.DrawDynamicInfo();
return;
}
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.TryClickIndexTitle=function(x,y)
{
for(var i in this.TitlePaint)
{
var item=this.TitlePaint[i];
if (!item.IsClickTitle) continue;
if (!item.IsClickTitle(x,y)) continue;
var data={ Point:{X:x, Y:y}, Title:item.Title, FrameID:item.Frame.Identify };
JSConsole.Chart.Log('[KLineChartContainer::TryClickIndexTitle] click title ', data);
var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_CLICK_INDEXTITLE);
if (event && event.Callback) event.Callback(event,data,this);
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; i<this.Frame.SubFrame.length; ++i)
{
this.BindIndexData(i,bindData);
}
//叠加数据周期调整
for(var i in this.OverlayChartPaint)
{
var item=this.OverlayChartPaint[i];
if (!item.SourceData) continue;
if(ChartData.IsMinutePeriod(this.Period,true)) //分钟不支持 清空掉
{
var bindData=new ChartData();
bindData.Data=item.SourceData.Data;
bindData.Period=this.Period;
bindData.Right=this.Right;
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;
}
item.Data=bindData;
}
else //日线叠加
{
var bindData=new ChartData();
bindData.Data=item.SourceData.Data;
bindData.Period=this.Period;
bindData.Right=this.Right;
if (bindData.Right>0 && 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;i<this.Frame.SubFrame.length;++i)
{
var item=this.Frame.SubFrame[i];
for(var j in item.OverlayIndex)
{
var overlayItem=item.OverlayIndex[j];
this.BindOverlayIndexData(overlayItem,i,bindData)
}
}
}
//切换股票代码
this.ChangeSymbol=function(symbol)
{
this.CancelAutoUpdate(); //先停止定时器
this.AutoUpdateEvent(false,'KLineChartContainer::ChangeSymbol');
this.Symbol=symbol;
if (MARKET_SUFFIX_NAME.IsSHSZIndex(symbol)) this.Right=0; //指数没有复权
//清空指标
if (this.Frame && this.Frame.SubFrame)
{
for(var i=0;i<this.Frame.SubFrame.length;++i)
{
this.DeleteIndexPaint(i);
}
}
this.ReloadChartDrawPicture();
if (ChartData.IsDayPeriod(this.Period,true))
{
this.RequestHistoryData(); //请求日线数据
this.ReqeustKLineInfoData();
}
else if (ChartData.IsMinutePeriod(this.Period,true) || ChartData.IsSecondPeriod(this.Period))
{
this.ReqeustHistoryMinuteData(); //请求分钟数据
}
else if (ChartData.IsTickPeriod(this.Period))
{
this.RequestTickData();
}
}
this.ReqeustKLineInfoData=function()
{
if (this.ChartPaint.length>0)
{
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;
if (option && option.Color) paint.Color=option.Color;
else 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)) //数字货币不需要下载流通股本
{
JSConsole.Chart.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.SetChartDrawOption=function(option)
{
if (IFrameSplitOperator.IsBool(option.IsLockScreen)) this.ChartDrawOption.IsLockScreen=option.IsLockScreen;
if (IFrameSplitOperator.IsNumber(option.Zoom) && option.Zoom>=0) this.ChartDrawOption.Zoom=option.Zoom;
}
//创建画图工具
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;
drawPicture.Option=this.ChartDrawOption;
if (callback) drawPicture.FinishedCallback=callback; //完成通知上层回调
self=this;
drawPicture.Update=function() //更新回调函数
{
self.DrawDynamicInfo();
};
this.CurrentChartDrawPicture=drawPicture;
//JSConsole.Chart.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个点完成
return true;
}
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个点
return true;
}
//设置第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个点
return true;
}
//xStep,yStep 移动的偏移量
this.MoveChartDrawPicture=function(xStep,yStep)
{
var drawPicture=this.CurrentChartDrawPicture;
if (!drawPicture) return false;
//JSConsole.Chart.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;
//通知上层画好了
let event=this.GetEventCallback(JSCHART_EVENT_ID.ON_FINISH_DRAWPICTURE); //完成画图工具事件
if (event && event.Callback)
{
let sendData={ DrawPicture: drawPicture };
event.Callback(event,sendData,this);
}
else 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<item.FrameID) continue;
var drawPicture=IChartDrawPicture.CreateChartDrawPrictrue(item);
if (!drawPicture) continue;
drawPicture.Canvas=this.Canvas;
drawPicture.Status=10;
drawPicture.Frame=this.Frame.SubFrame[item.FrameID].Frame; //绑定框架坐标
drawPicture.ValueToPoint();
if (drawPicture.ClassName==='ChartDrawPictureText') drawPicture.IsInitialized=true;
this.ChartDrawPicture.push(drawPicture);
}
this.ChartDrawStorageCache=null; //清空缓存
}
//选中画图工具事件
this.OnSelectChartPicture=function(chart)
{
}
//形态匹配
// scope.Plate 板块范围 scope.Symbol 股票范围
// sample 样本数据
this.RequestKLineMatch=function(sample,param)
{
var self =this;
var scope=param.Scope;
var waitDailog=param.WaitDialog;
JSConsole.Chart.Log('[KLineChartContainer::RequestKLineMatch',sample,scope)
var aryDate=new Array();
var aryValue=new Array();
for(var i=sample.Start;i<sample.End && i<sample.Data.Data.length;++i)
{
var item=sample.Data.Data[i];
aryDate.push(item.Date);
aryValue.push(item.Close);
}
var sampleData=
{
Stock:sample.Stock,
Index:{Start:sample.Start, End:sample.End}, //数据索引
Date:{Start:aryDate[0], End:aryDate[aryDate.length-1]}, //起始 结束日期
Minsimilar:scope.Minsimilar, //相似度
Plate:scope.Plate,
DayRegion:300
};
//请求数据
$.ajax({
url: this.KLineMatchUrl,
data:
{
"userid": "guest",
"plate": scope.Plate,
"period": this.Period,
"right": this.Right,
"dayregion": sampleData.DayRegion,
"minsimilar": scope.Minsimilar,
"sampledate":aryDate,
"samplevalue":aryValue
},
type:"post",
dataType: "json",
async:true,
success: function (data)
{
if (waitDailog) waitDailog.Close();
self.RecvKLineMatchData(data,sampleData);
},
error:function(jqXHR, textStatus, errorThrown)
{
console.warn('[KLineChartContainer::RequestKLineMatch] failed',jqXHR,textStatus, errorThrown);
if (waitDailog) waitDailog.Close();
}
});
}
//接收形态选股结果
this.RecvKLineMatchData=function(data,sample)
{
JSConsole.Chart.Log('[KLineChartContainer::RecvKLineMatchData] recv',data,sample);
var filterData=[]; //结果数据
for(var i in data.match)
{
var item=data.match[i];
if (item.symbol==sample.Stock.Symbol) continue;
for(var j in item.data)
{
var dataItem=item.data[j];
var newItem={Symbol:item.symbol, Name:item.name,Similar:dataItem.similar, Start:dataItem.start, End:dataItem.end};
filterData.push(newItem);
}
}
filterData.sort(function(a,b){return b.Similar-a.Similar;}); //排序
JSConsole.Chart.Log('[KLineChartContainer::RecvKLineMatchData] filterData',filterData);
if (this.mapEvent.has(JSCHART_EVENT_ID.RECV_KLINE_MATCH))
{
var item=this.mapEvent.get(JSCHART_EVENT_ID.RECV_KLINE_MATCH);
var data={Sample:sample, Match:filterData, Source:data}
item.Callback(item,data,this);
}
else
{
var dlg=new KLineMatchDialog(this.Frame.ChartBorder.UIElement.parentNode);
var event={ data:{ Chart:this, MatchData:filterData, Sample:sample, Source:data} };
dlg.DoModal(event);
}
}
//更新信息地雷
this.UpdataChartInfo=function()
{
//TODO: 根据K线数据日期来做map, 不在K线上的合并到下一个k线日期里面
var mapInfoData=null;
if (this.Period==0) //日线数据 根据日期
{
mapInfoData=new Map();
for(var i in this.ChartInfo)
{
var infoData=this.ChartInfo[i].Data;
for(var j in infoData)
{
var item=infoData[j];
if (mapInfoData.has(item.Date.toString()))
{
mapInfoData.get(item.Date.toString()).Data.push(item);
}
else
{
mapInfoData.set(item.Date.toString(),{Data:new Array(item)});
}
}
}
}
else if (ChartData.IsDayPeriod(this.Period,false))
{
mapInfoData=new Map();
var hisData=this.ChartPaint[0].Data;
//增加一个临时数据索引
for(var i in this.ChartInfo)
{
this.ChartInfo[i].TempID=this.ChartInfo[i].Data.length-1;
}
for(var i=0;i<hisData.Data.length;++i)
{
var kItem=hisData.Data[i]; //K线数据
for(var j in this.ChartInfo)
{
var info=this.ChartInfo[j];
var infoData=info.Data;
for(; info.TempID>=0; --info.TempID) //信息地雷是倒叙排的
{
var infoItem=infoData[info.TempID];
if (infoItem.Date>kItem.Date) break;
//信息地雷日期<K线上的日期 就是属于这个K线上的
if (mapInfoData.has(kItem.Date.toString()))
{
mapInfoData.get(kItem.Date.toString()).Data.push(infoItem);
}
else
{
mapInfoData.set(kItem.Date.toString(),{Data:new Array(infoItem)});
}
}
}
//JSConsole.Chart.Log('[KLineChartContainer::UpdataChartInfo]',item);
}
//清空临时变量
for(var i in this.ChartInfo)
{
delete this.ChartInfo[i].TempID;
}
}
var klinePaint=this.ChartPaint[0];
klinePaint.InfoData=mapInfoData;
}
//更新窗口指标
this.UpdateWindowIndex=function(index)
{
var bindData=new ChartData();
bindData.Data=this.SourceData.Data;
bindData.Period=this.Period;
bindData.Right=this.Right;
if (bindData.Right>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)
{
JSConsole.Chart.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) //盘前
{
this.AutoUpdateTimer=setTimeout(function()
{
self.AutoUpdate();
},frequency);
}
else if (marketStatus==2) //盘中
{
this.AutoUpdateTimer=setTimeout(function()
{
if (ChartData.IsDayPeriod(self.Period,true))
{
self.RequestRealtimeData(); //更新最新行情
//self.ReqeustKLineInfoData();
}
else if (ChartData.IsMinutePeriod(self.Period,true) || ChartData.IsSecondPeriod(self.Period))
{
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;
JSConsole.Chart.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)) //下载分钟数据
{
JSConsole.Chart.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))
{
JSConsole.Chart.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; i<this.Frame.SubFrame.length; ++i)
{
this.BindIndexData(i,bindData);
}
//刷新画图
this.UpdataDataoffset(); //更新数据偏移
this.UpdatePointByCursorIndex(); //更新十字光标位子
this.UpdateFrameMaxMin(); //调整坐标最大 最小值
this.Frame.SetSizeChage(true);
this.Draw();
}
this.RequestDragDayData=function()
{
var self=this;
this.AutoUpdateEvent(false,'KLineChartContainer::RequestDragDayData'); //停止自动更新
this.CancelAutoUpdate();
var download=this.DragDownload.Day;
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,
"count": self.MaxReqeustDataCount,
"first":{ date: firstItem.Date }
};
if (this.NetworkFilter)
{
var obj=
{
Name:'KLineChartContainer::RequestDragDayData', //类名::函数
Explain:'拖拽日K数据下载',
Request:{ Url:this.DragKLineApiUrl, Type:'POST' , Data: postData },
DragDownload:download,
Self:this,
PreventDefault:false
};
this.NetworkFilter(obj, function(data)
{
self.RecvDragDayData(data);
download.Status=0;
self.AutoUpdateEvent(true,'KLineChartContainer::RequestDragDayData'); //自动更新
self.AutoUpdate();
});
if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求
}
JSNetwork.HttpRequest({
url: this.DragKLineApiUrl,
data:postData,
type:"post",
dataType: "json",
async:true,
success: function(data)
{
self.RecvDragDayData(data);
download.Status=0;
self.AutoUpdateEvent(true,'KLineChartContainer::RequestDragDayData'); //自动更新
self.AutoUpdate();
}
});
}
this.RecvDragDayData=function(data)
{
var aryDayData=KLineChartContainer.JsonDataToHistoryData(data);
if (aryDayData.length<=0)
{
this.DragDownload.Day.IsEnd=true; //下完了
return;
}
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; i<this.Frame.SubFrame.length; ++i)
{
this.BindIndexData(i,bindData);
}
//刷新画图
this.UpdataDataoffset(); //更新数据偏移
this.UpdatePointByCursorIndex(); //更新十字光标位子
this.UpdateFrameMaxMin(); //调整坐标最大 最小值
this.Frame.SetSizeChage(true);
this.Draw();
}
this.SetCustomVerical=function(windowId, data)
{
if (!this.Frame) return;
if (windowId>=this.Frame.SubFrame.length) return;
var item=this.Frame.SubFrame[windowId];
if (item.Frame) item.Frame.CustomVerticalInfo=data;
}
}
//API 返回数据 转化为array[]
KLineChartContainer.JsonDataToHistoryData=function(data)
{
var aryDayData=[];
if (!data.data) return aryDayData;
var list = data.data;
var date = 0, yclose = 1, open = 2, high = 3, low = 4, close = 5, vol = 6, amount = 7;
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];
item.Vol = list[i][vol]; //原始单位股
item.Amount = list[i][amount];
if (isNaN(item.Open) || item.Open<=0) continue; //停牌的数据剔除
aryDayData.push(item);
}
return aryDayData;
}
KLineChartContainer.JsonDataToRealtimeData=function(data, symbol)
{
if (!data.stock) return null;
var stock;
for(var i in data.stock) //查找对应的股票数据
{
var stockItem=data.stock[i];
if (stockItem && stockItem.symbol==symbol)
{
stock=stockItem;
break;
}
}
if (!stock) return null;
var upperSymbol=symbol.toUpperCase();
var isSHSZ=MARKET_SUFFIX_NAME.IsSHSZ(upperSymbol);
var item=new HistoryData();
item.Date=stock.date;
item.Open=stock.open;
item.YClose=stock.yclose;
item.High=stock.high;
item.Low=stock.low;
if (isSHSZ) item.Vol=stock.vol/100; //原始单位股
else item.Vol=stock.vol;
item.Amount=stock.amount;
item.Close=stock.price;
return item;
}
KLineChartContainer.JsonDataToMinuteRealtimeData=function(data,symbol)
{
if (!data.stock) return null;
var stock;
for(var i in data.stock) //查找对应的股票数据
{
var stockItem=data.stock[i];
if (stockItem && stockItem.symbol==symbol)
{
stock=stockItem;
break;
}
}
if (!stock) return null;
var upperSymbol=symbol.toUpperCase();
var isSHSZ=MARKET_SUFFIX_NAME.IsSHSZ(upperSymbol);
var isFutures=MARKET_SUFFIX_NAME.IsChinaFutures(upperSymbol);
var aryMinuteData=new Array();
var preClose=stock.yclose; //前一个数据价格
var date=stock.date;
if (isFutures && stock.yclearing)preClose=stock.yclearing; //期货使用昨结算价
for(var i in stock.minute)
{
var jsData=stock.minute[i];
var item = new HistoryData();
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) item.Date=jsData.date;
else item.Date=date;
item.Time=jsData.time;
item.YClose=preClose;
if (!item.Close) //当前没有价格 使用上一个价格填充
{
item.Close=preClose;
item.Open=item.High=item.Low=item.Close;
}
//价格是0的 都用空
if (item.Open<=0) item.Open=null;
if (item.Close<=0) item.Close=null;
if (item.High<=0) item.High=null;
if (item.Low<=0) item.Low=null;
//上次价格
if (jsData.price>0) 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 )
{
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;
}
//手势
this.OnTouchStart=function(e)
{
if(this.DragMode==0) return;
this.IsOnTouch=true;
this.TouchDrawCount=0;
this.PhonePinch=null;
this.StopDragTimer();
if (this.EnableScrollUpDown==false) e.preventDefault(); //上下拖动图形不能阻止事件
if (this.IsPhoneDragging(e))
{
var drag= { Click:{}, LastMove:{} };//LastMove=最后移动的位置
var touches=this.GetToucheData(e,this.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 (self.ChartCorssCursor.IsShow === true) //移动十字光标
{
var pixelTatio = GetDevicePixelRatio();
var x = drag.Click.X-uielement.getBoundingClientRect().left*pixelTatio;
var y = drag.Click.Y-uielement.getBoundingClientRect().top*pixelTatio;
self.OnMouseMove(x, y, e);
}
}
if (this.EnableScrollUpDown==true)
{
this.DragTimer=setTimeout(function()
{
if (drag.Click.X==drag.LastMove.X && drag.Click.Y==drag.LastMove.Y)
{
var mouseDrag=self.MouseDrag;
self.MouseDrag=null;
T_ShowCorssCursor();
self.PreventTouchEvent(e)
}
}, 800);
}
this.MouseDrag=drag;
this.SelectChartDrawPicture=null;
if (this.EnableScrollUpDown==false)
T_ShowCorssCursor(); //移动十字光标
}
}
this.OnTouchMove=function(e)
{
var touches=this.GetToucheData(e,this.IsForceLandscape);
if (this.IsPhoneDragging(e))
{
var drag=this.MouseDrag;
if (drag==null)
{
var pixelTatio = GetDevicePixelRatio();
var x = touches[0].clientX-uielement.getBoundingClientRect().left*pixelTatio;
var y = touches[0].clientY-uielement.getBoundingClientRect().top*pixelTatio;
this.OnMouseMove(x,y,e);
}
else
{
var moveAngle=this.GetMoveAngle(drag.LastMove,{X:touches[0].clientX, Y:touches[0].clientY});
var moveSetp=Math.abs(drag.LastMove.X-touches[0].clientX);
var moveUpDown=Math.abs(drag.LastMove.Y-touches[0].clientY);
moveSetp=parseInt(moveSetp);
//上下滚动
if ( ((moveUpDown>0 && moveSetp<=3) || moveAngle<=this.TouchMoveMinAngle) && this.EnableScrollUpDown==true )
{
this.StopDragTimer();
return;
}
this.PreventTouchEvent(e);
this.MouseDrag=null;
var pixelTatio = GetDevicePixelRatio();
var x = touches[0].clientX-uielement.getBoundingClientRect().left*pixelTatio;
var y = touches[0].clientY-uielement.getBoundingClientRect().top*pixelTatio;
this.OnMouseMove(x,y,e);
}
}
if (this.EnableScrollUpDown==false)
{
e.preventDefault();
}
else
{
if (drag==null)
{
this.PreventTouchEvent(e); //十字光标出来了,阻止消息
}
else
{
this.StopDragTimer(); //上下推动图片,停止定时器,消息传递下去
}
}
}
this.OnTouchEnd=function(e)
{
JSConsole.Chart.Log('[MinuteChartContainer::OnTouchEnd]',e);
this.IsOnTouch = false;
this.StopDragTimer();
this.OnTouchFinished();
this.TouchDrawCount=0;
}
//键盘左右移动十字光标
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<windowCount;++i)
{
var border=new ChartBorder();
border.UIElement=this.UIElement;
var frame=new MinuteFrame();
frame.Canvas=this.Canvas;
frame.ChartBorder=border;
if (i<2) frame.ChartBorder.TitleHeight=0;
frame.XPointCount=243;
var DEFAULT_HORIZONTAL=[9,8,7,6,5,4,3,2,1];
frame.HorizontalMax=DEFAULT_HORIZONTAL[0];
frame.HorizontalMin=DEFAULT_HORIZONTAL[DEFAULT_HORIZONTAL.length-1];
if (i==0)
{
frame.YSplitOperator=new FrameSplitMinutePriceY();
frame.YSplitOperator.FrameSplitData=this.FrameSplitData.get('price');
}
else
{
frame.YSplitOperator=new FrameSplitY();
frame.YSplitOperator.LanguageID=this.LanguageID;
frame.YSplitOperator.FrameSplitData=this.FrameSplitData.get('double');
}
frame.YSplitOperator.Frame=frame;
frame.YSplitOperator.ChartBorder=border;
frame.XSplitOperator=new FrameSplitMinuteX();
frame.XSplitOperator.Frame=frame;
frame.XSplitOperator.ChartBorder=border;
if (i!=windowCount-1) frame.XSplitOperator.ShowText=false;
frame.XSplitOperator.Operator();
for(var j in DEFAULT_HORIZONTAL)
{
frame.HorizontalInfo[j]= new CoordinateInfo();
frame.HorizontalInfo[j].Value=DEFAULT_HORIZONTAL[j];
if (i==0 && j==frame.HorizontalMin) continue;
frame.HorizontalInfo[j].Message[1]=DEFAULT_HORIZONTAL[j].toString();
frame.HorizontalInfo[j].Font="14px 微软雅黑";
}
var subFrame=new SubFrameItem();
subFrame.Frame=frame;
if (i==0)
subFrame.Height=20;
else
subFrame.Height=10;
this.Frame.SubFrame[i]=subFrame;
}
}
this.CreateSubFrameItem=function(id)
{
var border=new ChartBorder();
border.UIElement=this.UIElement;
var frame=new MinuteFrame();
frame.Canvas=this.Canvas;
frame.ChartBorder=border;
frame.Identify=id; //窗口序号
frame.XPointCount=243;
var DEFAULT_HORIZONTAL=[9,8,7,6,5,4,3,2,1];
frame.HorizontalMax=DEFAULT_HORIZONTAL[0];
frame.HorizontalMin=DEFAULT_HORIZONTAL[DEFAULT_HORIZONTAL.length-1];
frame.YSplitOperator=new FrameSplitY();
frame.YSplitOperator.LanguageID=this.LanguageID;
frame.YSplitOperator.FrameSplitData=this.FrameSplitData.get('double');
frame.YSplitOperator.Frame=frame;
frame.YSplitOperator.ChartBorder=border;
frame.XSplitOperator=new FrameSplitMinuteX();
frame.XSplitOperator.Frame=frame;
frame.XSplitOperator.ChartBorder=border;
frame.XSplitOperator.ShowText=false;
//K线数据绑定
var xPointCouont=this.Frame.SubFrame[0].Frame.XPointCount;
frame.XPointCount=xPointCouont;
frame.Data=this.ChartPaint[0].Data;
for(var j in DEFAULT_HORIZONTAL)
{
frame.HorizontalInfo[j]= new CoordinateInfo();
frame.HorizontalInfo[j].Value=DEFAULT_HORIZONTAL[j];
frame.HorizontalInfo[j].Message[1]=DEFAULT_HORIZONTAL[j].toString();
frame.HorizontalInfo[j].Font="14px 微软雅黑";
}
var subFrame=new SubFrameItem();
subFrame.Frame=frame;
subFrame.Height=10;
return subFrame;
}
//删除某一个窗口的指标
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.ChartPaint=paint;
//清空东条标题
var titleIndex=windowIndex+1;
this.TitlePaint[titleIndex].Data=[];
this.TitlePaint[titleIndex].Title=null;
}
this.CreateStockInfo=function()
{
this.ExtendChartPaint[0]=new StockInfoExtendChartPaint();
this.ExtendChartPaint[0].Canvas=this.Canvas;
this.ExtendChartPaint[0].ChartBorder=this.Frame.ChartBorder;
this.ExtendChartPaint[0].ChartFrame=this.Frame;
this.Frame.ChartBorder.Right=300;
}
//创建主图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;
minuteLine.AreaColor=g_JSChartResource.Minute.AreaPriceColor;
this.ChartPaint[0]=minuteLine;
//分钟线均线
var averageLine=new ChartMinutePriceLine();
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;
averageLine.IsDrawArea=false;
this.ChartPaint[1]=averageLine;
//成交量
var volLine=new ChartMinuteVolumBar();
volLine.Color=g_JSChartResource.Minute.VolBarColor;
volLine.Canvas=this.Canvas;
volLine.ChartBorder=this.Frame.SubFrame[1].Frame.ChartBorder;
volLine.ChartFrame=this.Frame.SubFrame[1].Frame;
volLine.Name="Minute-Vol-Bar";
this.ChartPaint[2]=volLine;
this.TitlePaint[0]=new DynamicMinuteTitlePainting();
this.TitlePaint[0].Frame=this.Frame.SubFrame[0].Frame;
this.TitlePaint[0].Canvas=this.Canvas;
this.TitlePaint[0].OverlayChartPaint=this.OverlayChartPaint; //绑定叠加
this.TitlePaint[0].LanguageID=this.LanguageID;
}
//切换成 脚本指标
this.ChangeScriptIndex=function(windowIndex,indexData)
{
this.DeleteIndexPaint(windowIndex);
this.WindowIndex[windowIndex]=new ScriptIndex(indexData.Name,indexData.Script,indexData.Args,indexData); //脚本执行
var bindData=this.SourceData;
this.BindIndexData(windowIndex,bindData); //执行脚本
this.UpdataDataoffset(); //更新数据偏移
this.UpdateFrameMaxMin(); //调整坐标最大 最小值
this.Draw();
}
this.ChangeIndex=function(windowIndex,indexName,option)
{
if (this.Frame.SubFrame.length<3) return;
//查找系统指标
let scriptData = new JSIndexScript();
let indexInfo = scriptData.Get(indexName);
if (!indexInfo) return;
if (windowIndex<2) windowIndex=2;
if (windowIndex>=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;i<count;++i)
{
var subFrame=this.CreateSubFrameItem(i);
this.Frame.SubFrame[i]=subFrame;
var titlePaint=new DynamicChartTitlePainting();
titlePaint.Frame=this.Frame.SubFrame[i].Frame;
titlePaint.Canvas=this.Canvas;
titlePaint.LanguageID=this.LanguageID;
this.TitlePaint[i+1]=titlePaint;
}
//创建指标
const indexName=["RSI","MACD","DMA","DMI","KDJ","WR"];
let scriptData = new JSIndexScript();
for(var i=currentLength;i<count;++i)
{
var name=indexName[i%indexName.length];
let indexInfo = scriptData.Get(name);
this.WindowIndex[i] = new ScriptIndex(indexInfo.Name, indexInfo.Script, indexInfo.Args,indexInfo); //脚本执行
var bindData=this.SourceData;
this.BindIndexData(i,bindData); //执行脚本
}
//最后一个显示X轴坐标
for(var i=0;i<this.Frame.SubFrame.length;++i)
{
var item=this.Frame.SubFrame[i].Frame;
if (i==this.Frame.SubFrame.length-1) item.XSplitOperator.ShowText=true;
else item.XSplitOperator.ShowText=false;
}
this.UpdataDataoffset(); //更新数据偏移
}
this.Frame.SetSizeChage(true);
this.ResetFrameXYSplit();
this.UpdateFrameMaxMin(); //调整坐标最大 最小值
this.Draw();
}
//切换股票代码
this.ChangeSymbol=function(symbol)
{
this.CancelAutoUpdate();
this.Symbol=symbol;
this.ResetOverlaySymbolStatus();
this.ChartSplashPaint.IsEnableSplash = true; //增加下载动画
this.Draw();
this.RequestData();
}
this.ChangeDayCount=function(count)
{
if (count<0 || count>10) return;
this.DayCount=count;
this.ResetOverlaySymbolStatus();
this.RequestData();
}
//叠加股票
this.OverlaySymbol=function(symbol,option)
{
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;
if (option && option.Color) paint.Color=option.Color; //外部设置颜色
else 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.RecvMinuteDataEvent();
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);
var upperSymbol=this.Symbol.toUpperCase();
//外汇 均线暂时不用
if (MARKET_SUFFIX_NAME.IsForeignExchange(upperSymbol)) this.ChartPaint[1].Data=null;
if (this.Frame.SubFrame.length>2)
{
var bindData=new ChartData();
bindData.Data=allMinuteData;
for(var i=2; i<this.Frame.SubFrame.length; ++i)
{
this.BindIndexData(i,bindData);
}
}
for(let i in this.Frame.SubFrame)
{
var item=this.Frame.SubFrame[i];
item.Frame.XSplitOperator.Symbol=this.Symbol;
item.Frame.XSplitOperator.DayCount=this.DayData.length;
item.Frame.XSplitOperator.DayData=this.DayData;
item.Frame.XSplitOperator.Operator(); //调整X轴个数
item.Frame.XSplitOperator.IsBeforeData=this.IsBeforeData;
item.Frame.YSplitOperator.Symbol=this.Symbol;
item.Frame.IsBeforeData=this.IsBeforeData;
for(var j in item.OverlayIndex) //子坐标X轴个数同步
{
var overlayItem=item.OverlayIndex[j];
overlayItem.Frame.XPointCount=item.Frame.XPointCount;
overlayItem.Frame.MinuteCount=item.Frame.MinuteCount;
}
}
this.ChartCorssCursor.StringFormatY.Symbol=this.Symbol;
this.ChartCorssCursor.StringFormatX.Symbol=this.Symbol;
this.ChartCorssCursor.StringFormatX.IsBeforeData=this.IsBeforeData;
this.TitlePaint[0].IsShowDate=true;
this.UpdateFrameMaxMin(); //调整坐标最大 最小值
this.Frame.SetSizeChage(true);
this.Draw();
}
this.HistoryMinuteDataToArray=function(data)
{
var result=[];
for(var i=data.length-1; 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.RecvMinuteDataEvent=function()
{
if (!this.mapEvent.has(JSCHART_EVENT_ID.RECV_MINUTE_DATA)) return;
var event=this.mapEvent.get(JSCHART_EVENT_ID.RECV_MINUTE_DATA);
var data={ MinuteData:this.SourceData, Stock:{Symbol:this.Symbol, Name:this.Name } }
event.Callback(event,data,this);
}
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.RecvMinuteDataEvent();
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); //计算涨停价格
var extendData={ High:data.stock[0].high, Low:data.stock[0].low };
this.BindMainData(sourceData,yClose, extendData);
if (this.Frame.SubFrame.length>2)
{
var bindData=new ChartData();
bindData.Data=aryMinuteData;
for(var i=2; i<this.Frame.SubFrame.length; ++i)
{
this.BindIndexData(i,bindData);
}
}
for(let i in this.Frame.SubFrame)
{
var item=this.Frame.SubFrame[i];
item.Frame.XSplitOperator.Symbol=this.Symbol;
item.Frame.XSplitOperator.DayCount=1;
item.Frame.XSplitOperator.Operator(); //调整X轴个数
item.Frame.XSplitOperator.IsBeforeData=this.IsBeforeData;
item.Frame.YSplitOperator.Symbol=this.Symbol;
item.Frame.IsBeforeData=this.IsBeforeData;
for(var j in item.OverlayIndex) //子坐标X轴个数同步
{
var overlayItem=item.OverlayIndex[j];
overlayItem.Frame.XPointCount=item.Frame.XPointCount;
overlayItem.Frame.MinuteCount=item.Frame.MinuteCount;
}
}
this.ChartCorssCursor.StringFormatY.Symbol=this.Symbol;
this.ChartCorssCursor.StringFormatX.Symbol=this.Symbol;
this.ChartCorssCursor.StringFormatX.IsBeforeData=this.IsBeforeData;
if (MARKET_SUFFIX_NAME.IsSHSZ(upperSymbol)) this.TitlePaint[0].IsShowDate=false;
var chartInfo=this.GetChartMinuteInfo();
if (chartInfo) chartInfo.SourceData=this.SourceData; //数据绑定到信息地雷上
this.RecvMinuteDataEvent();
this.RequestMinuteInfoData();
this.RequestOverlayMinuteData();//请求叠加数据 (主数据下载完再下载))
this.UpdateFrameMaxMin(); //调整坐标最大 最小值
this.Frame.SetSizeChage(true);
this.Draw();
this.AutoUpdate();
}
this.CaclutateLimitPrice=function(yClose, limitData)
{
this.LimitPrice=null;
//var limitData=data.stock[0].limitprice;
if (limitData && limitData.max>0 && 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)
{
JSConsole.Chart.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) };
JSConsole.Chart.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));
JSConsole.Chart.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) continue; //已被上层替换,不调用默认的网络请求
}
//请求数据
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, extendData)
{
//分钟数据
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;
var upperSymbol=this.Symbol.toUpperCase();
if (MARKET_SUFFIX_NAME.IsForeignExchange(upperSymbol)) //外汇没有均线
this.ChartPaint[1].Data=null;
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;
if (extendData)
{
this.Frame.SubFrame[0].Frame.YSplitOperator.High=extendData.High;
this.Frame.SubFrame[0].Frame.YSplitOperator.Low=extendData.Low;
}
//成交量
this.ChartPaint[2].Data=minuteData;
this.ChartPaint[2].YClose=yClose;
if(MARKET_SUFFIX_NAME.IsChinaFutures(this.Symbol)) this.BindOverlayMainData(minuteData,yClose); //期货持仓量
else this.ClearBindOverlayMainData();
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.BindOverlayMainData=function(minuteData,yClose)
{
if (this.Frame.SubFrame.length<2) return;
var chart=null;
var frame=null;
var subFrame=this.Frame.SubFrame[1]; //第2个窗口
if (subFrame.OverlayIndex.length<=0)
{
var overlayFrame=new OverlayIndexItem();
overlayFrame.Identify='Position_Line_Frame';
frame=new OverlayMinuteFrame();
frame.Canvas=this.Canvas;
frame.MainFrame=subFrame.Frame;
frame.ChartBorder=subFrame.Frame.ChartBorder;
overlayFrame.Frame=frame;
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;
var chart=new ChartLine();
chart.Canvas=this.Canvas
chart.Name='Position-Line';
chart.ChartBorder=frame.ChartBorder;
chart.ChartFrame=frame
chart.Identify=overlayFrame.Identify;
chart.Color=g_JSChartResource.Minute.PositionColor;
overlayFrame.ChartPaint.push(chart);
subFrame.OverlayIndex.push(overlayFrame);
subFrame.Frame.RightFrame=frame; //右边坐标绑定到主坐标上
}
else
{
chart=subFrame.OverlayIndex[0].ChartPaint[0];
frame=subFrame.OverlayIndex[0].Frame;
}
var xPointCouont=this.Frame.SubFrame[0].Frame.XPointCount;
frame.XPointCount=xPointCouont;
var bindData=new ChartData();
bindData.Data=minuteData.GetPosition();
chart.Data=bindData;
}
this.ClearBindOverlayMainData=function()
{
if (this.Frame.SubFrame.length<2) return;
var subFrame=this.Frame.SubFrame[1]; //第2个窗口
subFrame.Frame.RightFrame=null;
subFrame.OverlayIndex=[];
}
//获取子窗口的所有画法
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 (isFutures) item.Position=jsData.position;
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);
//JSConsole.Chart.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];
if (isSHSZ) item.Vol=jsData[5]/100; //原始单位股
else item.Vol=jsData[5];
item.Amount=jsData[6];
if (7<jsData.length && jsData[7]>0) item.AvPrice=jsData[7]; //均价
item.DateTime=date.toString()+" "+jsData[0].toString();
item.Date=date;
item.Time=jsData[0];
if (8<jsData.length && jsData[8]>0) item.Date=jsData[8]; //日期
if (isFutures && 9<jsData.length) item.Position=jsData[9]; //持仓
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; i<this.Frame.SubFrame.length; ++i)
{
this.BindIndexData(i,bindData);
}
}
this.UpdateFrameMaxMin(); //调整坐标最大 最小值
this.Frame.SetSizeChage(true);
this.Draw();
//this.AutoUpdata();
}
}
//API 返回数据 转化为array[]
HistoryMinuteChartContainer.JsonDataToMinuteData=function(data)
{
var aryMinuteData=[];
for(var i in data.minute.time)
{
var item=new MinuteData();
if (data.minute.price[i]<=0 && i>0) //当前这一分钟价格为空,使用上一分钟的数据
{
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; i<this.Frame.SubFrame.length; ++i)
{
this.BindIndexData(i,bindData);
}
//刷新画图
this.UpdataDataoffset(); //更新数据偏移
this.UpdatePointByCursorIndex(); //更新十字光标位子
this.UpdateFrameMaxMin(); //调整坐标最大 最小值
this.Frame.SetSizeChage(true);
this.Draw();
}
}
////////////////////////////////////////////////////////////////////////////////
// K线训练
//
function KLineTrainChartContainer(uielement, bHScreen)
{
if (bHScreen===true)
{
this.newMethod=KLineChartHScreenContainer; //派生
this.newMethod(uielement);
delete this.newMethod;
}
else
{
this.newMethod=KLineChartContainer; //派生
this.newMethod(uielement);
delete this.newMethod;
}
this.BuySellPaint; //买卖点画法
this.TrainDataCount=300; //训练数据个数
this.AutoRunTimer=null; //K线自动前进定时器
this.BuySellData=[]; //模拟买卖数据 {Buy:{Price:价格,Date:日期, Time:时间} , Sell:{Price:价格,Date:日期, Time:时间}
this.TrainDataIndex; //当前训练的数据索引
this.TrainCallback; //训练回调 (K线每前进一次就调用一次)
this.DragMode=0;
this.TrainStartEnd={};
this.OnKeyDown=function(e)
{
var keyID = e.keyCode ? e.keyCode :e.which;
//只支持放大缩小
switch(keyID)
{
case 37: //left
if (this.CursorIndex>1) //十字光标只能在当前屏移动
{
--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) //十字光标只能在当前屏移动
{
//判断是否在最后一个数据上
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;
}
//不让滚动条滚动
if(e.preventDefault) e.preventDefault();
else e.returnValue = false;
}
//手机拖拽
uielement.ontouchstart=(e)=> { this.OnTouchStart(e); }
uielement.ontouchmove=(e)=> { this.OnTouchMove(e); }
uielement.ontouchend=(e)=> { this.OnTouchEnd(e); }
this.OnTouchStart=function(e)
{
this.PhonePinch=null;
this.IsOnTouch=true;
this.TouchDrawCount=0;
e.preventDefault();
if (this.IsPhoneDragging(e))
{
var drag=
{
"Click":{},
"LastMove":{} //最后移动的位置
};
var touches=this.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-this.UIElement.getBoundingClientRect().left*pixelTatio;
var y = drag.Click.Y-this.UIElement.getBoundingClientRect().top*pixelTatio;
this.OnMouseMove(x,y,e);
}
this.SelectChartDrawPicture=null;
}
else if (this.IsPhonePinching(e))
{
var phonePinch=
{
"Start":{},
"Last":{}
};
var touches=this.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.PhonePinch=phonePinch;
this.SelectChartDrawPicture=null;
}
}
this.OnTouchMove=function(e)
{
e.preventDefault();
var touches=this.GetToucheData(e,false);
if (this.IsPhoneDragging(e))
{
var drag=this.MouseDrag;
if (drag==null)
{
var pixelTatio = GetDevicePixelRatio();
var x = touches[0].clientX-this.UIElement.getBoundingClientRect().left*pixelTatio;
var y = touches[0].clientY-this.UIElement.getBoundingClientRect().top*pixelTatio;
this.OnMouseMove(x,y,e);
}
else
{
}
}
else if (this.IsPhonePinching(e))
{
phonePinch.Last={"X":touches[0].pageX,"Y":touches[0].pageY,"X2":touches[1].pageX,"Y2":touches[1].pageY};
}
}
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 isMinutePeriod=ChartData.IsMinutePeriod(this.Period,true);
var buySellPaint=this.ChartPaintEx[0];
var lastData=buySellPaint.LastData.Data;
var buySellData=this.GetLastBuySellData();
if (buySellData && buySellData.Buy && !buySellData.Sell)
{
var key=lastData.Date*10000;
buySellData.Sell={Price:lastData.Close,Date:lastData.Date};
if (isMinutePeriod)
{
buySellData.Sell.Time=lastData.Time;
key+=lastData.Time;
}
buySellPaint.BuySellData.set(key,{Op:1});
this.MoveNextKLineData();
return;
}
var key=lastData.Date*10000;
var newItem={ Buy:{Price:lastData.Close,Date:lastData.Date}, Sell:null };
if (isMinutePeriod)
{
newItem.Buy.Time=lastData.Time;
key+=lastData.Time;
}
this.BuySellData.push(newItem);
buySellPaint.BuySellData.set(key,{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.Y<e.clientY) isLeft=false;//右移数据
if(this.JSChartContainer.DataMove(moveSetp,isLeft))
{
this.JSChartContainer.UpdataDataoffset();
this.JSChartContainer.UpdatePointByCursorIndex();
this.JSChartContainer.UpdateFrameMaxMin();
this.JSChartContainer.ResetFrameXYSplit();
this.JSChartContainer.Draw();
}
drag.LastMove.X=e.clientX;
drag.LastMove.Y=e.clientY;
}
};
document.onmouseup=function(e)
{
//清空事件
document.onmousemove=null;
document.onmouseup=null;
//清空数据
this.JSChartContainer.MouseDrag=null;
this.JSChartContainer.CurrentChartDrawPicture=null;
this.JSChartContainer=null;
}
}
//手机拖拽
this.OnTouchStart=function(e)
{
this.PhonePinch=null;
this.IsOnTouch=true;
this.TouchDrawCount=0;
this.StopDragTimer();
var isSingleTouch=this.IsSingleTouch(e);
if (e.cancelable) e.preventDefault();
if (this.IsPhoneDragging(e))
{
if (this.TryClickLock || this.TryClickIndexTitle) //指标枷锁区域, 指标标题点击
{
var touches = this.GetToucheData(e, this.IsForceLandscape);
var x = touches[0].clientX;
var y = touches[0].clientY;
var pixelTatio = GetDevicePixelRatio();
x -= uielement.getBoundingClientRect().left*pixelTatio; //减去控件的偏移偏移量
y -= uielement.getBoundingClientRect().top*pixelTatio;
if (this.TryClickLock && this.TryClickLock(x, y)) return;
if (this.TryClickIndexTitle && this.TryClickIndexTitle(x,y)) return;
}
var bStartTimer=true;
if (this.ChartDrawOption.IsLockScreen)
{
bStartTimer=false;
}
else if (this.DragMode==JSCHART_DRAG_ID.CLICK_TOUCH_MODE_ID)
{
if (this.TouchStatus.CorssCursorShow==true) bStartTimer=false;
}
else if (this.DragMode==JSCHART_DRAG_ID.DISABLE_DRAG_ID)
{
bStartTimer=false;
}
else
{
if (!isSingleTouch) bStartTimer=false;
}
var drag= { Click:{}, LastMove:{} }; //LastMove=最后移动的位置
var touches=this.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;
this.MouseDrag=drag;
if (this.SelectChartDrawPicture) this.SelectChartDrawPicture.IsSelected=false;
this.SelectChartDrawPicture=null;
if (this.CurrentChartDrawPicture) //画图工具模式
{
var drawPicture=this.CurrentChartDrawPicture;
if (drawPicture.Status==2)
this.SetChartDrawPictureThirdPoint(drag.Click.X,drag.Click.Y);
else
{
this.SetChartDrawPictureFirstPoint(drag.Click.X,drag.Click.Y);
//只有1个点 直接完成
if (this.FinishChartDrawPicturePoint()) this.DrawDynamicInfo({Corss:false, Tooltip:false});
}
if (e.cancelable) e.preventDefault();
return;
}
else
{
var drawPictrueData={};
var pixelTatio = GetDevicePixelRatio(); //鼠标移动坐标是原始坐标 需要乘以放大倍速
drawPictrueData.X=(touches[0].clientX-uielement.getBoundingClientRect().left);
drawPictrueData.Y=(touches[0].clientY-uielement.getBoundingClientRect().top);
if (this.GetChartDrawPictureByPoint(drawPictrueData))
{
drawPictrueData.ChartDrawPicture.Status=20;
drawPictrueData.ChartDrawPicture.ValueToPoint();
drawPictrueData.ChartDrawPicture.MovePointIndex=drawPictrueData.PointIndex;
drawPictrueData.ChartDrawPicture.IsSelected=true;
this.CurrentChartDrawPicture=drawPictrueData.ChartDrawPicture;
this.SelectChartDrawPicture=drawPictrueData.ChartDrawPicture;
let event=this.GetEventCallback(JSCHART_EVENT_ID.ON_CLICK_DRAWPICTURE); //选中画图工具事件
if (event && event.Callback)
{
let sendData={ DrawPicture: drawPictrueData.ChartDrawPicture };
event.Callback(event,sendData,this);
}
if (e.cancelable) e.preventDefault();
return;
}
}
if (bStartTimer) //长按2秒,十字光标
{
var self=this;
this.DragTimer=setTimeout(function()
{
if (drag.Click.X==drag.LastMove.X && drag.Click.Y==drag.LastMove.Y) //手指没有移动,出现十字光标
{
var mouseDrag=self.MouseDrag;
self.MouseDrag=null;
self.MoveCorssCursor(drag.Click,e);//移动十字光标
}
}, self.PressTime);
}
if (this.ChartDrawOption.IsLockScreen)
{
this.MouseDrag=null;
}
else if (this.DragMode==JSCHART_DRAG_ID.CLICK_TOUCH_MODE_ID)
{
}
else if (this.DragMode==JSCHART_DRAG_ID.DISABLE_DRAG_ID)
{
this.MouseDrag=null;
this.MoveCorssCursor(drag.Click,e);
}
else if (this.IsClickShowCorssCursor)
{
this.MoveCorssCursor(drag.Click,e);
}
}
else if (this.IsPhonePinching(e))
{
var phonePinch=
{
"Start":{},
"Last":{}
};
var touches=this.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.PhonePinch=phonePinch;
this.SelectChartDrawPicture=null;
}
}
this.OnTouchMove=function(e)
{
if (e.cancelable) e.preventDefault();
var touches=this.GetToucheData(e,false);
if (this.IsPhoneDragging(e))
{
var drag=this.MouseDrag;
if (drag==null)
{
if (!this.ChartDrawOption.IsLockScreen) this.MoveCorssCursor({X:touches[0].clientX, Y:touches[0].clientY},e);
}
else
{
var moveSetp=Math.abs(drag.LastMove.Y-touches[0].clientY);
var moveUpDown=Math.abs(drag.LastMove.X-touches[0].clientX);
var isMoveCorssCursor=(this.DragMode==JSCHART_DRAG_ID.CLICK_TOUCH_MODE_ID && this.TouchStatus.CorssCursorShow==true); //是否移动十字光标
if (this.CurrentChartDrawPicture)
{
var drawPicture=this.CurrentChartDrawPicture;
if (drawPicture.Status==1 || drawPicture.Status==2)
{
if(moveSetp<5 && moveUpDown<5) return;
if(this.SetChartDrawPictureSecondPoint(touches[0].clientX,touches[0].clientY))
{
this.DrawDynamicInfo();
}
}
else if (drawPicture.Status==3)
{
if(this.SetChartDrawPictureThirdPoint(touches[0].clientX,touches[0].clientY))
{
this.DrawDynamicInfo();
}
}
else if (drawPicture.Status==20) //画图工具移动
{
if(moveSetp<5 && moveUpDown<5) return;
if(this.MoveChartDrawPicture(touches[0].clientX-drag.LastMove.X,touches[0].clientY-drag.LastMove.Y))
{
this.DrawDynamicInfo();
}
}
drag.LastMove.X=touches[0].clientX;
drag.LastMove.Y=touches[0].clientY;
}
if (isMoveCorssCursor) //点击模式下 十字光标显示 左右移动十字光标
{
var mouseDrag=this.MouseDrag;
this.MouseDrag=null;
this.MoveCorssCursor(drag.Click,e); //移动十字光标
}
else if (this.DragMode==1 || isMoveCorssCursor==false) //数据左右拖拽
{
if (moveSetp<5) return;
var isLeft=true;
if (drag.LastMove.Y<touches[0].clientY) isLeft=false;//右移数据
if(this.DataMove(moveSetp,isLeft))
{
this.UpdataDataoffset();
this.UpdatePointByCursorIndex();
this.UpdateFrameMaxMin();
this.ResetFrameXYSplit();
this.Draw();
}
else
{
if (this.DragDownloadData) this.DragDownloadData();
}
drag.LastMove.X=touches[0].clientX;
drag.LastMove.Y=touches[0].clientY;
}
}
}
else if (this.IsPhonePinching(e))
{
if (this.DragMode==JSCHART_DRAG_ID.DISABLE_DRAG_ID) return;
var phonePinch=this.PhonePinch;
if (!phonePinch) return;
var yHeight=Math.abs(touches[0].pageX-touches[1].pageX);
var yLastHeight=Math.abs(phonePinch.Last.X-phonePinch.Last.X2);
var yStep=yHeight-yLastHeight;
if (Math.abs(yStep)<5) return;
if (yStep>0) //放大
{
var cursorIndex={};
cursorIndex.Index=parseInt(Math.abs(this.CursorIndex-0.5).toFixed(0));
if (!this.Frame.ZoomUp(cursorIndex)) return;
this.CursorIndex=cursorIndex.Index;
this.UpdatePointByCursorIndex();
this.UpdataDataoffset();
this.UpdateFrameMaxMin();
this.Draw();
this.ShowTooltipByKeyDown();
}
else //缩小
{
var cursorIndex={};
cursorIndex.Index=parseInt(Math.abs(this.CursorIndex-0.5).toFixed(0));
if (!this.Frame.ZoomDown(cursorIndex)) return;
this.CursorIndex=cursorIndex.Index;
this.UpdataDataoffset();
this.UpdatePointByCursorIndex();
this.UpdateFrameMaxMin();
this.Draw();
this.ShowTooltipByKeyDown();
}
phonePinch.Last={"X":touches[0].pageX,"Y":touches[0].pageY,"X2":touches[1].pageX,"Y2":touches[1].pageY};
}
}
this.OnTouchEnd=function(e)
{
JSConsole.Chart.Log('[KLineChartHScreenContainer:OnTouchEnd]',e);
var bClearDrawPicture=true;
if (this.CurrentChartDrawPicture)
{
var drawPicture=this.CurrentChartDrawPicture;
if (drawPicture.Status==2 || drawPicture.Status==1 || drawPicture.Status==3)
{
drawPicture.PointStatus=drawPicture.Status;
if (this.FinishChartDrawPicturePoint())
this.DrawDynamicInfo();
else
bClearDrawPicture=false;
}
else if (drawPicture.Status==20)
{
if (this.FinishMoveChartDrawPicture())
this.DrawDynamicInfo();
}
}
this.IsOnTouch = false;
this.StopDragTimer();
this.OnTouchFinished();
this.TouchDrawCount=0;
}
//创建
//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;i<windowCount;++i)
{
var border=new ChartBorder();
border.UIElement=this.UIElement;
var frame=new KLineHScreenFrame();
frame.Canvas=this.Canvas;
frame.ChartBorder=border;
frame.Identify=i; //窗口序号
if (this.ModifyIndexDialog) frame.ModifyIndexEvent=this.ModifyIndexDialog.DoModal; //绑定菜单事件
if (this.ChangeIndexDialog) frame.ChangeIndexEvent=this.ChangeIndexDialog.DoModal;
frame.HorizontalMax=20;
frame.HorizontalMin=10;
if (i==0)
{
frame.YSplitOperator=new FrameSplitKLinePriceY();
frame.YSplitOperator.FrameSplitData=this.FrameSplitData.get('price');
//主图上下间距
var pixelTatio = GetDevicePixelRatio(); //获取设备的分辨率
border.TopSpace=12*pixelTatio;
border.BottomSpace=12*pixelTatio;
}
else
{
frame.YSplitOperator=new FrameSplitY();
frame.YSplitOperator.LanguageID=this.LanguageID;
frame.YSplitOperator.FrameSplitData=this.FrameSplitData.get('double');
//frame.IsLocked = true;
}
frame.YSplitOperator.Frame=frame;
frame.YSplitOperator.ChartBorder=border;
frame.XSplitOperator=new FrameSplitKLineX();
frame.XSplitOperator.Frame=frame;
frame.XSplitOperator.ChartBorder=border;
if (i!=windowCount-1) frame.XSplitOperator.ShowText=false;
for(var j=frame.HorizontalMin;j<=frame.HorizontalMax;j+=1)
{
frame.HorizontalInfo[j]= new CoordinateInfo();
frame.HorizontalInfo[j].Value=j;
if (i==0 && j==frame.HorizontalMin) continue;
frame.HorizontalInfo[j].Message[1]=j.toString();
frame.HorizontalInfo[j].Font="14px 微软雅黑";
}
var subFrame=new SubFrameItem();
subFrame.Frame=frame;
if (i==0)
subFrame.Height=20;
else
subFrame.Height=10;
this.Frame.SubFrame[i]=subFrame;
}
}
}
////////////////////////////////////////////////////////////////////////////////
// 走势图横屏显示
//
function MinuteChartHScreenContainer(uielement)
{
this.newMethod=MinuteChartContainer; //派生
this.newMethod(uielement);
delete this.newMethod;
this.ClassName='MinuteChartHScreenContainer';
this.OnMouseMove=function(x,y,e)
{
this.LastPoint.X=x;
this.LastPoint.Y=y;
this.CursorIndex=this.Frame.GetXData(y);
this.DrawDynamicInfo();
}
//创建
//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.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=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<windowCount;++i)
{
var border=new ChartBorder();
border.UIElement=this.UIElement;
var frame=new MinuteHScreenFrame();
frame.Canvas=this.Canvas;
frame.ChartBorder=border;
if (i<2) frame.ChartBorder.TitleHeight=0;
frame.XPointCount=243;
var DEFAULT_HORIZONTAL=[9,8,7,6,5,4,3,2,1];
frame.HorizontalMax=DEFAULT_HORIZONTAL[0];
frame.HorizontalMin=DEFAULT_HORIZONTAL[DEFAULT_HORIZONTAL.length-1];
if (i==0)
{
frame.YSplitOperator=new FrameSplitMinutePriceY();
frame.YSplitOperator.FrameSplitData=this.FrameSplitData.get('price');
}
else
{
frame.YSplitOperator=new FrameSplitY();
frame.YSplitOperator.LanguageID=this.LanguageID;
frame.YSplitOperator.FrameSplitData=this.FrameSplitData.get('double');
}
frame.YSplitOperator.Frame=frame;
frame.YSplitOperator.ChartBorder=border;
frame.XSplitOperator=new FrameSplitMinuteX();
frame.XSplitOperator.Frame=frame;
frame.XSplitOperator.ChartBorder=border;
if (i!=windowCount-1) frame.XSplitOperator.ShowText=false;
frame.XSplitOperator.Operator();
for(var j in DEFAULT_HORIZONTAL)
{
frame.HorizontalInfo[j]= new CoordinateInfo();
frame.HorizontalInfo[j].Value=DEFAULT_HORIZONTAL[j];
if (i==0 && j==frame.HorizontalMin) continue;
frame.HorizontalInfo[j].Message[1]=DEFAULT_HORIZONTAL[j].toString();
frame.HorizontalInfo[j].Font="14px 微软雅黑";
}
var subFrame=new SubFrameItem();
subFrame.Frame=frame;
if (i==0)
subFrame.Height=20;
else
subFrame.Height=10;
this.Frame.SubFrame[i]=subFrame;
}
}
}
////////////////////////////////////////////////////////////////////////////////
// 简单的图形框架
//
function SimlpleChartContainer(uielement)
{
this.newMethod=JSChartContainer; //派生
this.newMethod(uielement);
delete this.newMethod;
this.MainDataControl; //主数据类(对外的接口类)
//this.SubDataControl=new Array();
//创建
this.Create=function()
{
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 SimpleChartFrame();
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;
if (this.ChartCorssCursor) this.ChartCorssCursor.Frame=this.Frame; //十字光标绑定框架
this.ChartSplashPaint.Frame = this.Frame;
this.CreateMainChart();
this.UIElement.addEventListener("keydown", OnKeyDown, true); //键盘消息
}
this.SetMainDataConotrl=function(dataControl)
{
if (!dataControl) return;
this.MainDataControl=dataControl;
this.ChartPaint=[]; //图形
this.CreateMainChart();
this.Draw();
this.RequestData();
}
//创建主数据画法
this.CreateMainChart=function()
{
if (!this.MainDataControl) return;
for(let i in this.MainDataControl.DataType)
{
let item=this.MainDataControl.DataType[i];
if (item.Type=="BAR")
{
var chartItem=new ChartBar();
chartItem.Canvas=this.Canvas;
chartItem.ChartBorder=this.Frame.ChartBorder;
chartItem.ChartFrame=this.Frame;
chartItem.Name=item.Name;
if (item.Color) chartItem.UpBarColor=item.Color;
if (item.Color2) chartItem.DownBarColor=item.Color2;
this.ChartPaint.push(chartItem);
}
else if (item.Type=="LINE")
{
var chartItem=new ChartLine();
chartItem.Canvas=this.Canvas;
chartItem.ChartBorder=this.Frame.ChartBorder;
chartItem.ChartFrame=this.Frame;
chartItem.Name=item.Name;
if (item.Color) chartItem.Color=item.Color;
this.ChartPaint.push(chartItem);
}
}
this.Frame.YSplitOperator=new FrameSplitY();
this.Frame.YSplitOperator.FrameSplitData=this.FrameSplitData.get('double');
this.Frame.YSplitOperator.Frame=this.Frame;
this.Frame.YSplitOperator.ChartBorder=this.Frame.ChartBorder;
this.Frame.XSplitOperator=new FrameSplitXData();
this.Frame.XSplitOperator.Frame=this.Frame;
this.Frame.XSplitOperator.ChartBorder=this.Frame.ChartBorder;
// this.TitlePaint[0]=new DynamicKLineTitlePainting();
// this.TitlePaint[0].Frame=this.Frame.SubFrame[0].Frame;
// this.TitlePaint[0].Canvas=this.Canvas;
}
this.RequestData=function()
{
if(!this.MainDataControl) return;
this.MainDataControl.JSChartContainer=this;
this.MainDataControl.RequestData();
}
this.UpdateMainData=function(dataControl)
{
let lCount=0;
for(let i in dataControl.Data)
{
let itemData=new ChartData();
itemData.Data=dataControl.Data[i];
this.ChartPaint[i].Data=itemData;
if (lCount<itemData.Data.length) lCount=itemData.Data.length;
}
this.Frame.XPointCount=lCount;
this.Frame.Data=this.ChartPaint[0].Data;
this.Frame.XData=dataControl.XData;
this.UpdateFrameMaxMin(); //调整坐标最大 最小值
this.Frame.SetSizeChage(true);
this.Draw();
}
}
////////////////////////////////////////////////////////////////////////////////
// 饼图图形框架
//
function PieChartContainer(uielement)
{
this.Radius; //半径
this.newMethod=JSChartContainer; //派生
this.newMethod(uielement);
delete this.newMethod;
this.MainDataControl; //主数据类(对外的接口类)
//鼠标移动
this.OnMouseMove=function(x,y,e)
{
}
//创建
this.Create=function()
{
this.UIElement.JSChartContainer=this;
//创建等待提示
this.ChartSplashPaint = new ChartSplashPaint();
this.ChartSplashPaint.Canvas = this.Canvas;
//创建框架容器
this.Frame=new NoneFrame();
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.ChartSplashPaint.Frame = this.Frame;
this.CreateMainChart();
}
this.SetMainDataConotrl=function(dataControl)
{
if (!dataControl) return;
this.MainDataControl=dataControl;
this.ChartPaint=[]; //图形
this.CreateMainChart();
this.Draw();
this.RequestData();
}
//创建主数据画法
this.CreateMainChart=function()
{
if (!this.MainDataControl) return;
for(let i in this.MainDataControl.DataType)
{
let item=this.MainDataControl.DataType[i];
if (item.Type=="PIE") //饼图
{
var chartItem=new ChartPie();
chartItem.Canvas=this.Canvas;
chartItem.ChartBorder=this.Frame.ChartBorder;
chartItem.ChartFrame=this.Frame;
chartItem.Name=item.Name;
if(this.Radius) chartItem.Radius = this.Radius;
this.ChartPaint.push(chartItem);
}
else if (item.Type=='RADAR') //雷达图
{
var chartItem=new ChartRadar();
chartItem.Canvas=this.Canvas;
chartItem.ChartBorder=this.Frame.ChartBorder;
chartItem.ChartFrame=this.Frame;
chartItem.Name=item.Name;
if (item.StartAngle) chartItem.StartAngle=item.StartAngle;
this.ChartPaint.push(chartItem);
}
}
// this.TitlePaint[0]=new DynamicKLineTitlePainting();
// this.TitlePaint[0].Frame=this.Frame.SubFrame[0].Frame;
// this.TitlePaint[0].Canvas=this.Canvas;
}
this.RequestData=function()
{
if(!this.MainDataControl) return;
this.MainDataControl.JSChartContainer=this;
this.MainDataControl.RequestData();
}
this.UpdateMainData=function(dataControl)
{
for(let i in dataControl.Data)
{
let itemData=new ChartData();
itemData.Data=dataControl.Data[i];
this.ChartPaint[i].Data=itemData;
}
this.Frame.SetSizeChage(true);
this.Draw();
}
}
//地图
function MapChartContainer(uielement)
{
this.newMethod=JSChartContainer; //派生
this.newMethod(uielement);
delete this.newMethod;
this.MainDataControl; //主数据类(对外的接口类)
//鼠标移动
this.OnMouseMove=function(x,y,e)
{
}
//创建
this.Create=function()
{
this.UIElement.JSChartContainer=this;
//创建等待提示
this.ChartSplashPaint = new ChartSplashPaint();
this.ChartSplashPaint.Canvas = this.Canvas;
//创建框架容器
this.Frame=new NoneFrame();
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.ChartSplashPaint.Frame = this.Frame;
this.CreateMainChart();
}
this.SetMainDataConotrl=function(dataControl)
{
if (!dataControl) return;
this.MainDataControl=dataControl;
this.ChartPaint=[]; //图形
this.CreateMainChart();
this.Draw();
this.RequestData();
}
//创建主数据画法
this.CreateMainChart=function()
{
if (!this.MainDataControl) return;
let chartItem=new ChartChinaMap();
chartItem.Canvas=this.Canvas;
chartItem.ChartBorder=this.Frame.ChartBorder;
chartItem.ChartFrame=this.Frame;
chartItem.Name=this.MainDataControl.DataType[0].Name;
if(this.Radius) chartItem.Radius = this.Radius;
this.ChartPaint.push(chartItem);
// this.TitlePaint[0]=new DynamicKLineTitlePainting();
// this.TitlePaint[0].Frame=this.Frame.SubFrame[0].Frame;
// this.TitlePaint[0].Canvas=this.Canvas;
}
this.RequestData=function()
{
if(!this.MainDataControl) return;
this.MainDataControl.JSChartContainer=this;
this.MainDataControl.RequestData();
}
this.UpdateMainData=function(dataControl)
{
this.ChartPaint[0].Data=dataControl.Data[0];
this.Frame.SetSizeChage(true);
this.Draw();
}
}
//////////////////////////////////////////////////////////
//
// 指标信息
//
function IndexInfo(name,param)
{
this.Name=name; //名字
this.Param=param; //参数
this.LineColor; //线段颜色
this.ReqeustData=null; //数据请求
}
function BaseIndex(name)
{
this.Index; //指标阐述
this.Name=name; //指标名字
this.Script=null; //通达信脚本
this.OverlayIndex=null; //叠加指标{ IsOverlay:true, Identify:overlayFrame.Identify, WindowIndex:windowIndex, Frame:overlayFrame }
//默认创建都是线段
this.Create=function(hqChart,windowIndex)
{
}
//指标不支持 周期/复权/股票等
this.NotSupport=function(hqChart,windowIndex,message)
{
var isOverlay=this.IsOverlay();
if (isOverlay) return;
hqChart.DeleteIndexPaint(windowIndex); //清空
var frame=hqChart.Frame.SubFrame[windowIndex].Frame;
var paint=new ChartErrorMessage();
paint.Canvas=hqChart.Canvas;
paint.ChartBorder=frame.ChartBorder;
paint.ChartFrame=frame;
paint.NotSupportMessage=message;
hqChart.ChartPaint.push(paint);
}
//格式化指标名字+参数
//格式:指标名(参数1,参数2,参数3,...)
this.FormatIndexTitle=function()
{
var title=this.Name;
var param=null;
for(var i in this.Index)
{
var item = this.Index[i];
if (item.Param==null) continue;
if (param)
param+=','+item.Param.toString();
else
param=item.Param.toString();
}
if (param)
{
title+='('+param+')';
}
return title;
}
this.IsOverlay=function() //是否是叠加指标
{
if (!this.OverlayIndex || this.OverlayIndex.IsOverlay!=true) return false;
return true;
}
this.CreateChart=function(id) //创建图形
{
return new ChartLine();
}
this.CreatePaints=function(hqChart,windowIndex)
{
var frame=null;
var isOverlay=this.IsOverlay();
if (isOverlay)
{
frame=this.OverlayIndex.Frame.Frame;
this.OverlayIndex.Frame.ChartPaint=[]; //清空
}
else
{
frame=hqChart.Frame.SubFrame[windowIndex].Frame;
hqChart.DeleteIndexPaint(windowIndex); //清空
}
var aryPaint=[];
for(var i in this.Index)
{
var paint=this.CreateChart(i);
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);
aryPaint.push(paint);
}
return aryPaint;
}
this.SendEvent=function(hqChart,windowIndex,hisData, error)
{
if (!hqChart.GetIndexEvent) return;
var event=hqChart.GetIndexEvent(); //指标计算完成回调
if (!event) return;
var data={ Data:this.GetOutData(), WindowIndex: windowIndex, Name: this.Name, HistoryData: hisData,
Stock: {Symbol:hqChart.Symbol,Name:hqChart.Name} };
if (error) data.Error=error;
event.Callback(event,data,self);
}
this.GetOutData=function()
{
return null;
}
}
//市场多空
function MarketLongShortIndex()
{
this.newMethod=BaseIndex; //派生
this.newMethod('Long-Short');
delete this.newMethod;
this.Index=new Array(
new IndexInfo("多头区域",null),
new IndexInfo("空头区域",null),
new IndexInfo("市场多空指标",null),
);
this.Index[0].LineColor=g_JSChartResource.UpBarColor;
this.Index[1].LineColor=g_JSChartResource.DownBarColor;
this.Index[2].LineColor=g_JSChartResource.Index.LineColor[0];
this.LongShortData; //多空数据
this.CreateChart=function(id)
{
if (id==2){
var newChartLine = new ChartLine();
newChartLine.LineWidth = 2;
return newChartLine;
}
return new ChartStraightLine();
}
this.GetOutData=function()
{
return { LongShortData:this.LongShortData };
}
//请求数据
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();
this.SendEvent(hqChart,windowIndex,hisData,"不支持周期切换");
return false;
}
//请求数据
JSNetwork.HttpRequest({
url: g_JSChartResource.Index.MarketLongShortApiUrl,
data:
{
},
type:"post",
dataType: "json",
async:true,
success: function (recvData)
{
self.RecvData(recvData,param);
self.SendEvent(hqChart,windowIndex,hisData);
}
});
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=this.CreatePaints(hqChart,windowIndex);
var isOverlay=this.IsOverlay();
if (paint.length!=this.Index.length) return false;
//paint[0].Data.Data=SWLData;
paint[2].Data.Data=this.LongShortData;
paint[0].Data.Data[0]=8;
paint[1].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!=2) 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!=2) 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.CreateChart=function(id)
{
return new ChartMACD();
}
this.GetOutData=function()
{
return { TimingData:this.TimingData };
}
//请求数据
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();
this.SendEvent(hqChart,windowIndex,hisData,"不支持周期切换");
return false;
}
//请求数据
JSNetwork.HttpRequest({
url: g_JSChartResource.Index.MarketLongShortApiUrl,
data:
{
},
type:"post",
dataType: "json",
async:true,
success: function (recvData)
{
self.RecvData(recvData,param);
self.SendEvent(hqChart,windowIndex,hisData);
}
});
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=this.CreatePaints(hqChart,windowIndex);
var isOverlay=this.IsOverlay();
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.CreateChart=function(id)
{
return new ChartMACD();
}
this.GetOutData=function()
{
return { Data:this.Data };
}
//调整框架
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();
this.SendEvent(hqChart,windowIndex,hisData,"不支持周期切换");
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);
self.SendEvent(hqChart,windowIndex,hisData);
}
});
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=this.CreatePaints(hqChart,windowIndex);
var isOverlay=this.IsOverlay();
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.CreateChart=function(id)
{
if (id==0) return new ChartMACD();
return new ChartLine();
}
//请求数据
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=this.CreatePaints(hqChart,windowIndex);
var isOverlay=this.IsOverlay();
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;
//JSConsole.Chart.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<paint.length;++i)
{
let name=this.Index[i].Name; //显示的名字特殊处理
if (name=='MA') name="MA"+this.Index[i].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].Title='热度'+'('+this.Index[0].Param+','+this.Index[1].Param+','+this.Index[2].Param+','+this.Index[3].Param+')';
return true;
}
}
/*
本福特系数(财务粉饰)
*/
function BenfordIndex()
{
this.newMethod=BaseIndex; //派生
this.newMethod('财务粉饰');
delete this.newMethod;
this.Index = new Array(
new IndexInfo('区域', null),
new IndexInfo("系数", null)
);
this.Data; //财务数据
this.ApiUrl=g_JSChartResource.Index.StockHistoryDayApiUrl;
this.Index[0].LineColor=g_JSChartResource.Index.LineColor[0];
this.Index[1].LineColor='rgb(105,105,105)';
this.CreateChart=function(id)
{
if (id==0) return new ChartStraightArea();
return new ChartLineMultiData();
}
this.GetOutData=function()
{
return { Data:this.Data };
}
//请求数据
this.RequestData=function(hqChart,windowIndex,hisData)
{
var self = this;
var param=
{
HQChart:hqChart,
WindowIndex:windowIndex,
HistoryData:hisData
};
this.Data=[];
if (param.HQChart.Period!=2) //周期数据
{
this.NotSupport(param.HQChart,param.WindowIndex,"只支持月线");
param.HQChart.Draw();
this.SendEvent(hqChart,windowIndex,hisData,"只支持月线");
return false;
}
var aryField=["finance.benford","announcement2.quarter","announcement1.quarter","announcement3.quarter","announcement4.quarter"];
var aryCondition=
[
{item:["date","int32","gte","20130101"]},
{item:[ "announcement1.year","int32","gte",0,
"announcement2.year","int32","gte",0,
"announcement3.year","int32","gte",0,
"announcement4.year","int32","gte",0,
"or"]}
];
//请求数据
JSNetwork.HttpRequest({
url: this.ApiUrl,
data:
{
"symbol":[param.HQChart.Symbol],
"field":aryField,
"condition":aryCondition
},
type:"post",
dataType: "json",
async:true,
success: function (recvData)
{
self.RecvData(recvData,param);
self.SendEvent(hqChart,windowIndex,hisData);
}
});
return true;
}
this.JsonDataToMapSingleData=function(recvData)
{
var stockData=recvData.stock[0].stockday;
var mapData=new Map();
for(var i in stockData)
{
var item=stockData[i];
var indexData=new SingleData();
indexData.Date=item.date;
indexData.Value=new Array();
if (item.finance1!=null && item.announcement1!=null)
{
let year=item.announcement1.year;
let quarter=item.announcement1.quarter;
let value=item.finance1.benford;
indexData.Value.push({Year:year,Quarter:quarter,Value:value});
}
if (item.finance2!=null && item.announcement2!=null)
{
let year=item.announcement2.year;
let quarter=item.announcement2.quarter;
let value=item.finance2.benford;
indexData.Value.push({Year:year,Quarter:quarter,Value:value});
}
if (item.finance3!=null && item.announcement3!=null)
{
let year=item.announcement3.year;
let quarter=item.announcement3.quarter;
let value=item.finance3.benford;
indexData.Value.push({Year:year,Quarter:quarter,Value:value});
}
if (item.finance4!=null && item.announcement4!=null)
{
let year=item.announcement4.year;
let quarter=item.announcement4.quarter;
let value=item.finance4.benford;
indexData.Value.push({Year:year,Quarter:quarter,Value:value});
}
mapData.set(indexData.Date,indexData);
}
var aryData=new Array();
for( var item of mapData)
{
aryData.push(item[1]);
}
return aryData;
}
this.RecvData=function(recvData,param)
{
JSConsole.Chart.Log(recvData);
if (recvData.stock==null || recvData.stock.length<=0) return;
var aryData=this.JsonDataToMapSingleData(recvData);
var aryFittingData=param.HistoryData.GetFittingMonthData(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=this.CreatePaints(hqChart,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: '安全区', TitleColor:'rgb(245,255 ,250)'},
{ Value: 0.2, Value2: 0.4, Color: 'rgb(255,140,0)', Title: '预警区', TitleColor:'rgb(245,255 ,250)'},
{ Value: 0.4, Value2: 1, Color: 'rgb(255,106,106)', Title: '警示区', TitleColor:'rgb(245,255 ,250)'}
];
paint[1].Data.Data = this.Data;
//指定框架最大最小[0,1]
hqChart.Frame.SubFrame[windowIndex].Frame.YSpecificMaxMin = { Max: 1, Min: 0, Count: 3 };
var titleIndex = windowIndex + 1;
hqChart.TitlePaint[titleIndex].Data[1] = new DynamicTitleData(paint[1].Data, this.Index[1].Name, this.Index[1].LineColor);
hqChart.TitlePaint[titleIndex].Data[1].DataType = "MultiReport";
hqChart.TitlePaint[titleIndex].Title = this.FormatIndexTitle();
return true;
}
}
///////////////////////////////////////////////////////////////////////
// 能图指标
//
/*
大盘趋势函数
个股趋势函数
上线:=SMA(C,6.5,1);
下线:=SMA(C,13.5,1);
STICKLINE(上线>下线 , 上线,下线 ,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)
{
//JSConsole.Chart.Log(h);
},
error: function(http,e)
{
self.RecvError(http,e,param);;
}
});
return true;
}
this.RecvError=function(http,e,param)
{
JSConsole.Chart.Log("[PyScriptIndex::RecvError] error",e);
if (param.HQChart.ScriptErrorCallback) param.HQChart.ScriptErrorCallback(e);
}
this.RecvData=function(recvData,param)
{
if (recvData.code!=0)
{
JSConsole.Chart.Log("[PyScriptIndex::RecvData] failed.", recvData);
if (param.HQChart.ScriptErrorCallback) param.HQChart.ScriptErrorCallback(recvData.msg);
return; //失败了
}
JSConsole.Chart.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<aryDate.length && j<aryDate.length;++j)
{
if (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=[];
var postData=
{
filed: ["question","answerdate","symbol","id"],
symbol: [param.HQChart.Symbol],
querydate:{"StartDate":this.StartDate,"EndDate":this.GetToday()},
start:0,
end:this.MaxReqeustDataCount,
};
if (hqChart.NetworkFilter)
{
var obj=
{
Name:'InvestorInfo::RequestData', //类名::函数
Explain:'互动易',
Request:{ Url:g_JSChartResource.KLine.Info.Investor.ApiUrl, Type:'post', Data: { postData } },
Self:this,
HQChart:hqChart,
PreventDefault:false
};
hqChart.NetworkFilter(obj, function(data)
{
self.RecvData(data,param);
});
if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求
}
//请求数据
JSNetwork.HttpRequest({
url: g_JSChartResource.KLine.Info.Investor.ApiUrl,
data:postData,
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 (Array.isArray(item))
{
if (item.length<2) continue;
var info={Date:event.date, Time:item[0], Title:item[1], Type:0};
if (item.length>=3 && item[2] && typeof(item[2])=='string') info.Color=item[2]; //[3]=字体颜色
if (item.length>=4 && item[3] && typeof(item[3])=='string') info.BGColor=item[3]; //[3]=背景颜色
this.Data.push(info);
}
else //新格式
{
if (!IFrameSplitOperator.IsNumber(item.Date) || !IFrameSplitOperator.IsNumber(item.Time) || !item.Title) continue;
var info={ Date:item.Date, Time:item.Time, Title:item.Title, Type:0 };
if (item.Color) info.Color=item.Color;
if (item.BGColor) info.BGColor=item.BGColor;
if (IFrameSplitOperator.IsNumber(item.Price)) info.Price=item.Price;
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=
"<div class='parameter'>\
<div class='parameter-header'>\
<span></span>\
<strong id='close' class='icon iconfont icon-close'></strong>\
</div>\
<div class='parameter-content'><input/>MA</div>\
<div class='parameter-footer'>\
<button class='submit' >确定</button>\
<button class='cancel' >取消</button>\
</div>\
</div>";
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 = '<input class="row-line" id="'+guid+'" value="'+item.Value+'" type="number" step="1"/>'+ item.Name +'<br>';
$("#"+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 pixelTatio = GetDevicePixelRatio();
var border=chart.Frame.ChartBorder;
var scrollPos=GetScrollPosition();
var left=(border.GetLeft()+border.GetWidth()/2)/pixelTatio;
var top=(border.GetTop()+border.GetHeight()/2)/pixelTatio;
//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=
'<div class="target-panel">\n' +
' <div class="target-header">\n' +
' <span>换指标</span>\n' +
' <strong class="close-tar icon iconfont icon-close"></strong>\n' +
' </div>\n' +
' <div class="target-content">\n' +
' <div class="target-left">\n' +
' <input type="text">\n' +
' <ul></ul>\n' +
' </div>\n' +
' <div class="target-right">\n' +
' <ul></ul>\n' +
' </div>\n' +
' </div>\n' +
' </div>';
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 = '<li>' + result.node + '</li>';
$(".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 = '<li id='+res.id+'>'+ res.name +'</li>';
$(".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 = '<li id='+res.id+'>'+ res.name +'</li>';
$(".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 = '<li id='+name+'>'+ name +'</li>';
$(".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 pixelTatio = GetDevicePixelRatio();
var border=chart.Frame.ChartBorder;
var scrollPos=GetScrollPosition();
var left=(border.GetLeft()+border.GetWidth()/2)/pixelTatio;
var top=(border.GetTop()+border.GetHeight()/2)/pixelTatio;
//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="<div class='title-length'></div>";
this.DivElement.appendChild(div);
}
this.BindInfoList=function(infoType,infoList)
{
var strBox="<div class='total-list'>共"+infoList.length+"条</div>";
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+="一周后涨幅:<i class='increase' style='color:"+this.GetColor(item.ExtendData.FWeek.Week1.toFixed(2))+"'>"+ item.ExtendData.FWeek.Week1.toFixed(2)+"%</i>";
if (item.ExtendData.FWeek.Week4!=null) weekData+=" 四周后涨幅:<i class='increase' style='color:"+this.GetColor(item.ExtendData.FWeek.Week4.toFixed(2))+"'>"+ item.ExtendData.FWeek.Week4.toFixed(2)+"%</i>";
if (weekData.length>0) weekData="<br/> <i class='prorecast-week'>"+weekData+"</i>";
}
var strDate=item.Date.toString();
var strNew=strDate.substring(0,4)+"-"+strDate.substring(4,6)+"-"+strDate.substring(6,8); //转换时间格式
strText+="<span>"+strNew+" "+year+reportType+item.Title+" "+weekData+"</span>";
}
else if (infoType==KLINE_INFO_TYPE.RESEARCH) //调研单独处理
{
var levels=item.ExtendData.Level;
var recPerson=[];
if(levels.length==0){
recPerson = "<i>无</i>"
}else{
for(var j in levels)
{
if(levels[j]==0){
recPerson+="<i style='color:#00a0e9'>证券代表 </i>";
}else if(levels[j]==1){
recPerson+="<i>董秘 </i>";
}else if(levels[j]==2){
recPerson+="<i style='color:#00a0e9'>总经理 </i>";
}else if(levels[j]==3){
recPerson+="<i style='color:#00a0e9'>董事长 </i>";
}
}
}
var strDate=item.Date.toString();
var strNew=strDate.substring(0,4)+"-"+strDate.substring(4,6)+"-"+strDate.substring(6,8); //转换时间格式
strText+="<span>"+strNew+" 接待: "+recPerson+"</span>";
}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+="<span><i class='date-tipbox'>"+strNew+"</i> <i class='tipBoxTitle'>成交价: "+showPriceInfo.Price.toFixed(2)+"</i><i class='tipBoxTitle'>收盘价: "+showPriceInfo.ClosePrice.toFixed(2)+
"</i><br/><i class='rate-discount tipBoxTitle'>溢折价率: <strong style='color:"+ this.GetColor(showPriceInfo.Premium.toFixed(2))+"'>"+
showPriceInfo.Premium.toFixed(2)+"%</strong></i><i class='tipBoxTitle'>成交量(万股): "+showPriceInfo.Vol.toFixed(2)+"</i></span>";
}
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 += "<i>"+detail[i].TypeExplain+"</i><br/>"
// reasons += detail[i] + "<br/>"
}
strText = "<span><i class='trade-time'>"+strNew+" 上榜原因: </i><i class='reason-list'>"+reasons+"</i><br/><i class='trade-detall'>一周后涨幅: <strong style='color:"+
this.GetColor(item.ExtendData.FWeek.Week1.toFixed(2))+"'>"+ item.ExtendData.FWeek.Week1.toFixed(2)+
"%</strong> 四周后涨幅: <strong style='color:"+this.GetColor(item.ExtendData.FWeek.Week4.toFixed(2))+";'>"+
item.ExtendData.FWeek.Week4.toFixed(2)+"%</strong></i></span>";
}
else
{
var str=strOld.toString();
var strNew=str.substring(0,4)+"-"+str.substring(4,6)+"-"+str.substring(6,8); //转换时间格式
strText+="<span>"+strNew+" "+item.Title+"</span>";
}
}
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><div class='minute-dialog-title'><span></span><strong class='close-munite icon iconfont icon-close'></strong></div><div class='minute-hqchart' id='${hqchartID}' ></div></div>`;
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<yclse) return this.DownColor;
else return this.UnchagneColor;
}
var strName = event.data.Chart.Name;
var strData=event.data.Tooltip.Data;
var date=new Date(parseInt(strData.Date/10000),(strData.Date/100%100-1),strData.Date%100);
var strDate = strData.Date.toString();
var strNewDate=strDate.substring(0,4)+"-"+strDate.substring(4,6)+"-"+strDate.substring(6,8); //转换时间格式
var str = "<span>"+strName+"</span>"+"<span>"+strNewDate+"</span> "+
"<span style='color:"+this.GetColor(strData.Open,strData.YClose)+";'>开:"+strData.Open.toFixed(2)+"</span>"+
"<span style='color:"+this.GetColor(strData.High,strData.YClose)+";'>高:"+strData.High.toFixed(2)+"</span>"+
"<span style='color:"+this.GetColor(strData.Low,strData.YClose)+";'>低:"+strData.Low.toFixed(2)+"</span>"+
"<span style='color:"+this.GetColor(strData.Close,strData.YClose)+";'>收:"+strData.Close.toFixed(2)+"</span>"+
"<span style='color:"+this.VolColor+";'>量:"+IFrameSplitOperator.FormatValueString(strData.Vol,2)+"</span>"+
"<span style='color:"+this.AmountColor+";'>额:"+IFrameSplitOperator.FormatValueString(strData.Amount,2)+"</span>";
$(".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=
"<div class='parameter jchart-select-section'>\
<div class='parameter-header'>\
<span>区间统计</span>\
<strong id='close' class='icon iconfont icon-close'></strong>\
</div>\
<div class='parameter-content'>统计数据</div>\
<div class='parameter-footer'>\
<button id='close' class='submit' >确定</button>\
<button id='match' class='submit' >形态匹配</button>\
</div>\
</div>";
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 && i<hqData.Data.length; ++i)
{
var item=hqData.Data[i];
if (i==start)
{
showData.Date.Start=item.Date;
showData.Open=item.Open;
showData.High=item.High;
showData.Low=item.Low;
showData.YClose=item.YClose;
}
showData.Date.End=item.Date;
showData.Close=item.Close;
showData.Vol+=item.Vol;
showData.Amount+=item.Amount;
++showData.Count;
if (showData.High<item.High) showData.High=item.High;
if(showData.Low>item.Low) showData.Low=item.Low;
if (item.Close>item.Open) ++showData.KLine.Up;
else if (item.Close<item.Open) ++showData.KLine.Down;
else ++showData.KLine.Unchanged;
}
if (showData.Vol>0) 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; //振幅
}
// JSConsole.Chart.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=
'<div class="jchart-select-date">\n' +
' <span>开始: '+ startDate +'<i class="start-date-left '+ startLeftClass +'"><</i><i class="start-date-right '+ startRightClass +'">></i></span>\n' +
' <span>结束: '+ endDate +'<i class="end-date-left '+ endLeftClass +'"><</i><i class="end-date-right '+ endRightClass +'">></i></span>\n' +
' <span>总个数: '+ showData.Count +'</span>\n' +
' </div>\n' +
' <table>\n' +
' <tr><td><strong>起始价: </strong><span>'+ showData.YClose.toFixed(defaultfloatPrecision) +'</span></td>' +
' <td><strong>最终价: </strong><span>'+ showData.Close.toFixed(defaultfloatPrecision) +'</span></td>' +
' <td><strong>均价: </strong><span>'+ showData.AvPrice.toFixed(defaultfloatPrecision) +'</span></td></tr>\n' +
' <tr><td><strong>最低价: </strong><span>'+ showData.Low.toFixed(defaultfloatPrecision) +'</span></td>' +
' <td><strong>最高价: </strong><span>'+ showData.High.toFixed(defaultfloatPrecision) +'</span></td>' +
' <td><strong>涨跌幅: </strong><span class="'+ IFrameSplitOperator.FormatValueColor(showData.Increase) +'">'+ showData.Increase.toFixed(2) +'%</span></td></tr>\n' +
' <tr><td><strong>振幅: </strong><span>'+ showData.Amplitude.toFixed(2) +'%</span></td>' +
' <td><strong>成交量: </strong><span>'+ IFrameSplitOperator.FormatValueString(showData.Vol,2) +'股</span></td>' +
' <td><strong>金额: </strong><span>'+ IFrameSplitOperator.FormatValueString(showData.Amount,2) +'元</span></td></tr>\n' +
' <tr><td><strong>阴线: </strong><span>'+ showData.KLine.Up +'</span></td>' +
' <td><strong>阳线: </strong><span>'+ showData.KLine.Down +'</span></td>' +
' <td><strong>平线: </strong><span>'+ showData.KLine.Unchanged +'</span></td></tr>\n' +
' </table>';
$(".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=
`<div class='parameter jchart-kline-match-box'>
<div class='parameter-header'>
<span>形态匹配</span>
<strong id='close' class='icon iconfont icon-close'></strong>
</div>
<div class='parameter-content'>
<p class='dataCount'></p>
<table class='matchTable'>
<thead>
<tr>
<td>股票名称</td>
<td>匹配度</td>
<td>时间段</td>
</tr>
</thead>
<tbody>
</tbody>
</table>
<div class='pagination' data-current='1'></div>
</div>
<div class='parameter-footer'>
<button id='close' class='submit' >确定</button>
</div>
</div>`.trim();
this.DivElement.appendChild(div);
this.Dialog=div;
//关闭按钮
$("#"+this.ID+" #close").click(
{
divBox:this,
},
function(event)
{
event.data.divBox.Close();
});
}
this.BindData=function()
{
JSConsole.Chart.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;
JSConsole.Chart.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];
JSConsole.Chart.Log('[KLineMatchDialog::RenderDom currentPageData]',currentPageData);
let bodyHtml = '';
for(let i = 0; i < currentPageData.length; i++){
bodyHtml += `<tr>
<td class=${currentPageData[i].Color}>${currentPageData[i].Name}</td>
<td class=${currentPageData[i].Color}>${currentPageData[i].Rate}</td>
<td class=${currentPageData[i].Color}>${currentPageData[i].Date}</td>
</tr>`.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 ? "<span>" + (j + 1) + "</span>" : "<span class='active'>" + (j + 1) + "</span>";
}
} else {
for (var j = 0; j < maxPageNum; j++) { //上 1 2 3 4 5 下
spanStr += (j + 1) != currentPageNum ? "<span>" + (j + 1) + "</span>" : "<span class='active'>" + (j + 1) + "</span>";
}
}
} else { //大于5时,最终页数是当前页数加1
lastPageNum = (currentPageNum + 1) > maxPageNum ? currentPageNum : (currentPageNum + 1);
for (var i = currentPageNum - 3; i <= lastPageNum; i++) { //含最终项之前的五项
spanStr += i != currentPageNum ? "<span>" + i + "</span>" : "<span class='active'>" + i + "</span>";
}
}
spanStr = "<span class='beforePage'>上一页</span>" + spanStr + "<span class='nextPage'>下一页</span>";
$(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();
JSConsole.Chart.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=
`<div class='parameter jchart-kline-match-box'>
<div class='parameter-header'>
<span>${this.Title}</span>
</div>
</div>`.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 = $("<div />");
$topMenu.attr("id", "topMenu_"+_self.ID).addClass("context-menu-wrapper topmenu").hide();
$body.append($topMenu);
var $topTable = $("<table />");
$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 = $("<div />");
$childMenu.attr({ id: "childMenu_"+_self.ID + i, "data-index": i }).addClass("context-menu-wrapper").hide();
$body.append($childMenu);
var $childTable = $("<table />");
$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 />");
$tr.addClass("font_Arial context-menu");
if (isBorder)
$tr.addClass("border");
var $td1 = $("<td />");
if(list[i].selected){
$td1.addClass("spacer context-menu").html("√");
}else{
$td1.addClass("spacer context-menu");
}
var $td2 = $("<td />");
$td2.addClass("text").html(list[i].text);
var $td3 = $("<td />");
$td3.addClass("right shortcut");
var $td4 = $("<td />");
$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:21,
click: function () { chart.ChangePeriod(21); }
},
{
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.Right<data.length) data[chart.Right].selected=true;
return data;
}
//指标
this.GetIndex=function (chart)
{
return [{
text: "均线",
click: function (windowIndex) {
chart.ChangeIndex(windowIndex, '均线')
}
}, {
text: "BOLL",
click: function (windowIndex) {
chart.ChangeIndex(windowIndex, 'BOLL')
},
isBorder:true
}, {
text: "MACD",
click: function (windowIndex) {
chart.ChangeIndex(windowIndex, 'MACD')
}
}, {
text: "KDJ",
click: function (windowIndex) {
chart.ChangeIndex(windowIndex, 'KDJ')
}
}, {
text: "VOL",
click: function (windowIndex) {
chart.ChangeIndex(windowIndex, 'VOL')
}
}, {
text: "RSI",
click: function (windowIndex) {
chart.ChangeIndex(windowIndex, 'RSI')
}
}, {
text: "BRAR",
click: function (windowIndex) {
chart.ChangeIndex(windowIndex, 'BRAR')
}
}, {
text: "WR",
click: function (windowIndex) {
chart.ChangeIndex(windowIndex, 'WR')
}
}, {
text: "BIAS",
click: function (windowIndex) {
chart.ChangeIndex(windowIndex, 'BIAS')
}
}, {
text: "OBV",
click: function (windowIndex) {
chart.ChangeIndex(windowIndex, 'OBV')
}
}, {
text: "DMI",
click: function (windowIndex) {
chart.ChangeIndex(windowIndex, 'DMI')
}
}, {
text: "CR",
click: function (windowIndex) {
chart.ChangeIndex(windowIndex, 'CR')
}
}, {
text: "PSY",
click: function (windowIndex) {
chart.ChangeIndex(windowIndex, 'PSY')
}
}, {
text: "CCI",
click: function (windowIndex) {
chart.ChangeIndex(windowIndex, 'CCI')
}
}, {
text: "DMA",
click: function (windowIndex) {
chart.ChangeIndex(windowIndex, 'DMA')
}
}, {
text: "TRIX",
click: function (windowIndex) {
chart.ChangeIndex(windowIndex, 'TRIX')
}
}, {
text: "VR",
click: function (windowIndex) {
chart.ChangeIndex(windowIndex, 'VR')
}
}, {
text: "EMV",
click: function (windowIndex) {
chart.ChangeIndex(windowIndex, 'EMV')
}
}, {
text: "ROC",
click: function (windowIndex) {
chart.ChangeIndex(windowIndex, 'ROC')
}
}, {
text: "MIM",
click: function (windowIndex) {
chart.ChangeIndex(windowIndex, 'MIM')
}
}, {
text: "FSL",
click: function (windowIndex) {
chart.ChangeIndex(windowIndex, 'FSL')
}
} ]
}
//五彩K线
this.GetColorIndex=function (chart)
{
var data=
[
{
text: "十字星",
click: function (windowIndex) { chart.ChangeInstructionIndex('五彩K线-十字星') }
},
{
text: "早晨之星",
click: function (windowIndex) { chart.ChangeInstructionIndex('五彩K线-早晨之星') },
},
{
text: "垂死十字",
click: function (windowIndex) { chart.ChangeInstructionIndex('五彩K线-垂死十字') },
},
{
text: "三只乌鸦",
click: function (windowIndex) { chart.ChangeInstructionIndex('五彩K线-三只乌鸦') }
},
{
text: "光脚阴线",
click: function (windowIndex) { chart.ChangeInstructionIndex('五彩K线-光脚阴线') }
},
{
text: "黄昏之星",
click: function (windowIndex) { chart.ChangeInstructionIndex('五彩K线-黄昏之星') }
}
];
if (chart.ColorIndex)
{
data[data.length-1].isBorder=true;
data.push(
{
text: "删除五彩K线",
click: function (windowIndex) { chart.CancelInstructionIndex() }
});
}
return data;
}
//专家系统
this.GetTradeIndex=function(chart)
{
var data=
[
{
text: "BIAS",
click: function (windowIndex) { chart.ChangeInstructionIndex('交易系统-BIAS') }
},
{
text: "CCI",
click: function (windowIndex) { chart.ChangeInstructionIndex('交易系统-CCI') }
},
{
text: "DMI",
click: function (windowIndex) { chart.ChangeInstructionIndex('交易系统-DMI') }
},
{
text: "KD",
click: function (windowIndex) { chart.ChangeInstructionIndex('交易系统-KD') }
},
{
text: "BOLL",
click: function (windowIndex) { chart.ChangeInstructionIndex('交易系统-BOLL') }
},
{
text: "KDJ",
click: function (windowIndex) { chart.ChangeInstructionIndex('交易系统-KDJ') }
}
];
if (chart.TradeIndex)
{
data[data.length-1].isBorder=true;
data.push(
{
text: "删除专家系统",
click: function (windowIndex) { chart.CancelInstructionIndex()}
});
}
return data;
}
//叠加
this.GetOverlay=function (chart)
{
var data=
[
{
text: "上证指数",
click: function () { chart.OverlaySymbol('000001.sh'); }
},
{
text: "深证成指",
click: function () { chart.OverlaySymbol('399001.sz'); }
},
{
text: "中小板指",
click: function () { chart.OverlaySymbol('399005.sz'); }
},
{
text: "创业板指",
click: function () { chart.OverlaySymbol('399006.sz'); }
},
{
text: "沪深300",
click: function () { chart.OverlaySymbol('000300.sh'); },
}
];
for(var i in chart.OverlayChartPaint)
{
var item=chart.OverlayChartPaint[i];
var symbol=item.Symbol;
const mapSymbol=new Map([['000001.sh',0],['399001.sz',1],['399005.sz',2],['399006.sz',3],['000300.sh',4]]);
if (mapSymbol.has(symbol))
{
var menuItem=data[mapSymbol.get(symbol)];
let delSymbol=symbol;
menuItem.selected=true;
menuItem.click=function () { chart.DeleteOverlaySymbol(delSymbol); };
}
}
if (chart.OverlayChartPaint && chart.OverlayChartPaint.length>0)
{
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)<data.length) data[count-1].selected=true; //选中
return data;
}
//坐标类型
this.GetCoordinateType=function(chart)
{
var data=
[
{
text: "普通坐标",
click: function () { chart.ChangeCoordinateType(0); }
},
{
text: "百分比坐标",
click: function () { chart.ChangeCoordinateType(1); }
},
{
text: "反转坐标",
click: function () { chart.ChangeCoordinateType(2); }
}
];
if (chart.Frame && chart.Frame.SubFrame && chart.Frame.SubFrame.length>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.DragMode<data.length) data[chart.DragMode].selected=true; //选中
return data;
}
//工具
this.GetTools=function(chart)
{
var data=[];
var drawTools=chart.GetExtendChartByClassName('DrawToolsButton');
if (drawTools)
{
data.push(
{
text: "关闭画图工具",
click: function ()
{
var toolsWidth=drawTools.Chart.Width;
var toolsIndex=parseInt(drawTools.Index);
for(var i=toolsIndex+1; i<chart.ExtendChartPaint.length; ++i) //在画图工具后面创建的需要减去工具的宽度
{
var item=chart.ExtendChartPaint[i];
if (item.ClassName=='StockChip')
{
item.Left-=toolsWidth;
}
}
chart.DeleteExtendChart(drawTools);
chart.Frame.ChartBorder.Right-=toolsWidth;
chart.SetSizeChage(true);
chart.Draw();
}
}
);
}
else
{
data.push(
{
text: "画图工具",
click: function () {
var option={Name:'画图工具', Top:chart.Frame.ChartBorder.Top };
var extendChart=chart.CreateExtendChart(option.Name, option); //创建扩展图形
chart.SetSizeChage(true);
chart.Draw();
}
}
);
}
var StockChip=chart.GetExtendChartByClassName('StockChip');
if (StockChip)
{
data.push(
{
text: "关闭移动筹码",
click: function ()
{
var chipWidth=StockChip.Chart.Width;
var chipIndex=parseInt(StockChip.Index);
for(var i=chipIndex+1; i<chart.ExtendChartPaint.length; ++i) //在筹码后面创建的需要筹码的宽度
{
var item=chart.ExtendChartPaint[i];
if (item.ClassName=='DrawToolsButton')
{
item.Left-=chipWidth;
}
}
chart.DeleteExtendChart(StockChip);
chart.Frame.ChartBorder.Right-=chipWidth;
chart.SetSizeChage(true);
chart.Draw();
}
}
);
}
else
{
data.push(
{
text: "移动筹码",
click: function () {
var option={Name:'筹码分布', ShowType:1, Width:230 };
var extendChart=chart.CreateExtendChart(option.Name, option); //创建扩展图形
chart.SetSizeChage(true);
chart.Draw();
}
}
);
}
return data;
}
this.GetKLineInfo=function(chart)
{
var setInfo=new Set();
for(var i in chart.ChartInfo)
{
var item=chart.ChartInfo[i];
setInfo.add(item.ClassName);
}
var aryKLineInfo=["公告","业绩预告","调研","大宗交易","龙虎榜","互动易"]
var data=[];
for(var i in aryKLineInfo)
{
var infoName=aryKLineInfo[i];
var classInfo=JSKLineInfoMap.GetClassInfo(infoName);
if (!classInfo) continue;
var item=this.CreateKlineInfoItem(infoName, setInfo.has(classInfo.ClassName), chart);
data.push(item);
}
if (chart.ChartInfo.length>0)
{
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);
}
JSConsole.Chart.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 ()
{
JSConsole.Chart.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;
JSConsole.Chart.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)<data.length) data[chart.DayCount-1].selected=true;
return data;
}
this.GetIndex=function (chart)
{
var data=
[
{
text: "MACD",
click: function (windowIndex) { chart.ChangeIndex(windowIndex, 'MACD') }
},
{
text: "DMI",
click: function (windowIndex) { chart.ChangeIndex(windowIndex, 'DMI') }
},
{
text: "DMA",
click: function (windowIndex) { chart.ChangeIndex(windowIndex, 'DMA') }
},
{
text: "BRAR",
click: function (windowIndex) { chart.ChangeIndex(windowIndex, 'BRAR') }
},
{
text: "KDJ",
click: function (windowIndex) { chart.ChangeIndex(windowIndex, 'KDJ') }
},
{
text: "RSI",
click: function (windowIndex) { chart.ChangeIndex(windowIndex, 'RSI') }
},
{
text: "WR",
click: function (windowIndex) { chart.ChangeIndex(windowIndex, 'WR') }
},
{
text: "CCI",
click: function (windowIndex) { chart.ChangeIndex(windowIndex, 'CCI') }
},
{
text: "TRIX",
click: function (windowIndex) { chart.ChangeIndex(windowIndex, 'TRIX') }
}
];
return data;
}
this.GetShowBeforeData=function(chart) //是否显示集合竞价
{
if (chart.IsShowBeforeData)
{
var data=
[
{
text: "隐藏",
click: function () { chart.ShowBeforeData(false); },
}
];
return data;
}
else
{
var data=
[
{
text: "显示",
click: function () { chart.ShowBeforeData(true); },
}
];
return data;
}
}
//指标窗口个数
this.GetIndexWindowCount=function(chart)
{
var data=
[
{
text: "1个窗口",
click: function () { chart.ChangeIndexWindowCount(2); }
},
{
text: "2个窗口",
click: function () { chart.ChangeIndexWindowCount(3); }
},
{
text: "3个窗口",
click: function () { chart.ChangeIndexWindowCount(4); }
}
];
var count=chart.Frame.SubFrame.length-1;
if ((count-1)>=0 && (count-1)<data.length) data[count-1].selected=true; //选中
return data;
}
}
//画图工具 单个图形设置
function ChartPictureSettingMenu(divElement)
{
this.newMethod=IDivDialog; //派生
this.newMethod(divElement);
delete this.newMethod;
this.HQChart;
this.ChartPicture;
this.SubToolsDiv;
this.SettingMenu;
this.DoModal=function(event)
{
var $body;
if (!this.SubToolsDiv)
{
this.ID=Guid();
var div=document.createElement("div");
div.className='subTolls';
div.id=this.ID;
this.DivElement.appendChild(div);
//$body = $("."+event.data.HQChart.ClassName).context.body;
//$body.append(div);
this.SubToolsDiv=div;
}
this.HQChart=event.data.HQChart;
this.ChartPicture=event.data.ChartPicture;
var frame=this.HQChart.Frame.SubFrame[0].Frame;
// var top=frame.ChartBorder.GetTopTitle();
var top=frame.ChartBorder.Top + 40;
// var right=frame.ChartBorder.GetRight();
var right=frame.ChartBorder.Right;
var left=frame.ChartBorder.GetLeft();
var className = this.ChartPicture.ClassName; //='ChartDrawPictureText'时加“设置”
var toolsDiv = "";
if(className === 'ChartDrawPictureText'){
toolsDiv = '<span class="changes-color" title="改变图形颜色">'+
'<i class="iconfont icon-bianji"></i>'+
'<input type="color" name="color" id="color" class="change-color" value="'+ this.ChartPicture.LineColor +'">'+
'</span>\n' +
'<span class="subtool-set" title="设置"><i class="iconfont icon-shezhi"></i></span>'+
'<span class="subtool-del"><i class="iconfont icon-recycle_bin"></i></span>';
}else{
toolsDiv =
'<p class="changes-color" title="改变图形颜色"><i class="iconfont icon-bianji"></i>' +
'<input type="color" name="color" id="color" class="change-color" value="'+ this.ChartPicture.LineColor +'"></p>\n' +
' <p class="subtool-del"><i class="iconfont icon-recycle_bin"></i></p>';
}
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); //保存下
});
})
JSConsole.Chart.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 }
};
JSConsole.Chart.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 = '<div class="titleWrap">'+
'<span class="titleName">样式设置</span>'+
'<i class="closeBtn iconfont icon-close"></i>'+
'</div>';
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 ? '<p>'+item+'</P>' : '<p class="active">'+item+'</P>';
});
fontSizeArray.forEach(function(item,index){
sizeListStr += index !== 5 ? '<p>'+item+'</P>' : '<p class="active">'+item+'</P>';
});
var contentContainerStr = '<div class="contentWrap">'+
'<div class="styleOptions">'+
'<span class="colorPicker"><input type="color" id="fontColor" value="#1e90ff"></span>'+
'<div class="likeSelect fontSelect"><span class="choicedText">微软雅黑</span><div class="selectList">'+fontListStr+'</div><i class="iconfont icon-xia"></i></div>'+
'<div class="likeSelect fontSizeSelect"><span class="choicedText">20</span><div class="selectList">'+sizeListStr+'</div><i class="iconfont icon-xia"></i></div>'+
'<span class="strongFont likeBtn"><i class="iconfont icon-jiacu"></i></span>'+
'<span class="italicsFont likeBtn"><i class="iconfont icon-qingxieL"></i></span>'+
'</div>'+
'<textarea class="tArea" id="tArea" placeholder="Text"></textarea>'+
'</div>';
var btnContainer = '<div class="btnsContainer">'+
'<span class="okBtn btn">确认</span>'+
'<span class="cancelBtn btn">取消</span>'+
'</div>';
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){
JSConsole.Chart.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', //数字货币
FOREX:'.FOREX', //外汇 (Foreign Exchange)
ET:'.ET', //其他未知的品种
IsET:function(upperSymbol)
{
if (!upperSymbol) return false;
return upperSymbol.indexOf(this.ET) > 0;
},
IsETShowAvPrice:function(upperSymbol) //是否显示均价
{
return false;
},
IsForeignExchange(upperSymbol)
{
if (!upperSymbol) return false;
return upperSymbol.indexOf(this.FOREX) > 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.IsForeignExchange(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;
},
GetForeignExchangeDecimal:function(symbol)
{
return 4;
},
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.ForeEx=null; //外汇
this.Initialize = function () //初始化 默认只初始化沪深的 其他市场动态生成
{
//this.SHSZ = this.CreateSHSZData();
//this.HK = this.CreateHKData();
}
this.GetET=function(upperSymbol) //当天所有的分钟
{
throw {Name:'MinuteTimeStringData::GetET', Error:'not implement'};
}
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.GetForeignExchange=function()
{
if (!this.ForeEx) this.ForeEx=this.CreateForeignExchangeData();
return this.ForeEx;
}
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.CreateForeignExchangeData=function()
{
//外汇 7:00 - 6:59
const TIME_SPLIT=
[
{ Start:600, End:2359 },
{ Start:0, End:559 },
];
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();
if (MARKET_SUFFIX_NAME.IsForeignExchange(upperSymbol)) return this.GetForeignExchange();
if (MARKET_SUFFIX_NAME.IsET(upperSymbol)) return this.GetET(upperSymbol);
}
}
//走势图刻度分钟线
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;
}
}
//外汇
const FOREX_MINUTE_X_COORDINATE=
{
Full: //完整模式
[
[0, 1, "RGB(200,200,200)", "06:00"],
[120, 1, "RGB(200,200,200)", "08:00"],
[240, 1, "RGB(200,200,200)", "10:00"],
[360, 1, "RGB(200,200,200)", "12:00"],
[480, 0, "RGB(200,200,200)", "14:00"],
[600, 1, "RGB(200,200,200)", "16:00"],
[720, 1, "RGB(200,200,200)", "18:00"],
[840, 1, "RGB(200,200,200)", "20:00"],
[960, 1, "RGB(200,200,200)", "22:00"],
[1080, 1, "RGB(200,200,200)", "0:00"],
[1200, 1, "RGB(200,200,200)", "02:00"],
[1320, 1, "RGB(200,200,200)", "04:00"],
],
Simple: //简洁模式
[
[0, 1, "RGB(200,200,200)", "06:00"],
[240, 1, "RGB(200,200,200)", "10:00"],
[480, 0, "RGB(200,200,200)", "14:00"],
[720, 1, "RGB(200,200,200)", "18:00"],
[960, 1, "RGB(200,200,200)", "22:00"],
[1200, 1, "RGB(200,200,200)", "02:00"],
],
Min: //最小模式
[
[0, 1, "RGB(200,200,200)", "06:00"],
[480, 0, "RGB(200,200,200)", "14:00"],
[960, 1, "RGB(200,200,200)", "22:00"],
],
Count: 1440,
MiddleCount: 600,
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))
data=this.GetFTSEData(upperSymbol,width);
else if (MARKET_SUFFIX_NAME.IsFHK(upperSymbol))
data=this.GetFHKData(upperSymbol,width);
else if (MARKET_SUFFIX_NAME.IsForeignExchange(upperSymbol))
data=this.GetForeignExchangeData(upperSymbol,width);
else if (MARKET_SUFFIX_NAME.IsET(upperSymbol))
data=this.GetETData(upperSymbol,width);
}
//JSConsole.Chart.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<stringData.length;++i)
{
var value = stringData[i];
for(var j=0;j<coordinate.length;++j)
{
var coordinateItem = coordinate[j];
if (value == coordinateItem.Value)
{
var item = [i, 0, 'RGB(200,200,200)', coordinateItem.Text];
data.push(item);
break;
}
}
}
result.Data = data;
return result;
}
this.GetFTSEData=function(upperSymbol,width)
{
var result=FTSE_MINUTE_X_COORDINATE;
return result;
}
this.GetFHKData=function(upperSymbol,width)
{
var result=FHK_MINUTE_X_COORDINATE;
return result
}
this.GetForeignExchangeData=function(upperSymbol,width)
{
var result=FOREX_MINUTE_X_COORDINATE;
return result;
}
this.GetETData=function(upperSymbol,width)
{
throw {Name:'MinuteCoordinateData::GetETData', Error:'not implement'};
}
}
//期货不同品种 交易时间数据
function FuturesTimeData()
{
const TIME_SPLIT=
[
{
Name:'9:00-10:15,10:30-11:30,13:30-15:00',
Data:
[
//9:00-10:15,10:30-11:30,13:30-15:00
{ Start: 900, End: 1015 },
{ Start: 1031, End: 1130 },
{ Start: 1331, End: 1500 }
],
Coordinate:
{
Full://完整模式
[
{ Value: 900, Text: '9:00' },
{ Value: 930, Text: '9:30' },
{ Value: 1000, Text: '10:00' },
{ Value: 1030, Text: '10:30' },
{ Value: 1100, Text: '11:00' },
{ Value: 1330, Text: '13:30' },
{ Value: 1400, Text: '14:00' },
{ Value: 1430, Text: '14:30' },
{ Value: 1500, Text: '15:00' },
],
Simple: //简洁模式
[
{ Value: 900, Text: '9:00' },
{ Value: 1000, Text: '10:00' },
{ Value: 1330, Text: '13:30' },
{ Value: 1430, Text: '14:30' },
{ Value: 1500, Text: '15:00' },
],
Min: //最小模式
[
{ Value: 900, Text: '9:00' },
{ Value: 1330, Text: '13:30' },
{ Value: 1500, Text: '15:00' },
]
}
},
{
Name:'9:15-11:30,13:00-15:15',
Data:
[
{ Start: 915, End: 1130 },
{ Start: 1301, End: 1515 }
],
Coordinate:
{
Full://完整模式
[
{ Value: 930, Text: '9:30' },
{ Value: 1000, Text: '10:00' },
{ Value: 1030, Text: '10:30' },
{ Value: 1100, Text: '11:00' },
{ Value: 1300, Text: '13:00' },
{ Value: 1330, Text: '13:30' },
{ Value: 1400, Text: '14:00' },
{ Value: 1430, Text: '14:30' },
{ Value: 1515, Text: '15:15' },
],
Simple: //简洁模式
[
{ Value: 930, Text: '9:30' },
{ Value: 1030, Text: '10:30' },
{ Value: 1300, Text: '13:00' },
{ Value: 1400, Text: '14:00' },
{ Value: 1515, Text: '15:15' },
],
Min: //最小模式
[
{ Value: 930, Text: '9:30' },
{ Value: 1300, Text: '13:00' },
{ Value: 1515, Text: '15:15' },
]
}
},
{
Name:'9:30-11:30,13:00-15:00',
Data:
[
{ Start: 930, End: 1130 },
{ Start: 1301, End: 1500 }
],
Coordinate:
{
Full://完整模式
[
{ Value: 930, Text: '9:30' },
{ Value: 1000, Text: '10:00' },
{ Value: 1030, Text: '10:30' },
{ Value: 1100, Text: '11:00' },
{ Value: 1300, Text: '13:00' },
{ Value: 1330, Text: '13:30' },
{ Value: 1400, Text: '14:00' },
{ Value: 1430, Text: '14:30' },
{ Value: 1500, Text: '15:00' },
],
Simple: //简洁模式
[
{ Value: 930, Text: '9:30' },
{ Value: 1030, Text: '10:30' },
{ Value: 1300, Text: '13:00' },
{ Value: 1400, Text: '14:00' },
{ Value: 1500, Text: '15:00' },
],
Min: //最小模式
[
{ Value: 930, Text: '9:30' },
{ Value: 1300, Text: '13:00' },
{ Value: 1500, Text: '15:00' },
]
}
},
{
Name:'21:00-23:30,9:00-10:15,10:30-11:30,13:30-15:00',
Data:
[
{ Start: 2100, End: 2330 },
{ Start: 901, End: 1015 },
{ Start: 1031, End: 1130 },
{ Start: 1331, End: 1500 }
],
Coordinate:
{
Full://完整模式
[
{ Value: 2100, Text: '21:00' },
{ Value: 2200, Text: '22:00' },
{ Value: 2300, Text: '23:00' },
{ Value: 901, Text: '9:00' },
{ Value: 1031, Text: '10:30' },
{ Value: 1331, Text: '13:30' },
{ Value: 1430, Text: '14:30' },
{ Value: 1500, Text: '15:00' },
],
Simple: //简洁模式
[
{ Value: 2100, Text: '21:00' },
{ Value: 901, Text: '9:00' },
{ Value: 1331, Text: '13:30' },
{ Value: 1500, Text: '15:00' },
],
Min: //最小模式
[
{ Value: 2100, Text: '21:00' },
{ Value: 901, Text: '9:00' },
{ Value: 1500, Text: '15:00' },
]
}
},
{
Name:'21:00-1:00,9:00-10:15,10:30-11:30,13:30-15:00',
Data:
[
{ Start: 2100, End: 2359 },
{ Start: 0, End: 100 },
{ Start: 901, End: 1015 },
{ Start: 1031, End: 1130 },
{ Start: 1331, End: 1500 }
],
Coordinate:
{
Full://完整模式
[
{ Value: 2100, Text: '21:00' },
{ Value: 2200, Text: '22:00' },
{ Value: 2300, Text: '23:00' },
{ Value: 901, Text: '9:00' },
{ Value: 1031, Text: '10:30' },
{ Value: 1331, Text: '13:30' },
{ Value: 1500, Text: '15:00' },
],
Simple: //简洁模式
[
{ Value: 2100, Text: '21:00' },
{ Value: 2300, Text: '23:00' },
{ Value: 901, Text: '9:00' },
{ Value: 1031, Text: '10:30' },
{ Value: 1500, Text: '15:00' },
],
Min: //最小模式
[
{ Value: 2100, Text: '21:00' },
{ Value: 901, Text: '9:00' },
{ Value: 1500, Text: '15:00' },
]
}
},
{
Name:'21:00-2:30,9:00-10:15,10:30-11:30,13:30-15:00',
Data:
[
{ Start: 2100, End: 2359 },
{ Start: 0, End: 230 },
{ Start: 901, End: 1015 },
{ Start: 1031, End: 1130 },
{ Start: 1331, End: 1500 }
],
Coordinate:
{
Full://完整模式
[
{ Value: 2100, Text: '21:00' },
{ Value: 2300, Text: '23:00' },
{ Value: 100, Text: '1:00' },
{ Value: 901, Text: '9:00' },
{ Value: 1031, Text: '10:30' },
{ Value: 1331, Text: '13:30' },
{ Value: 1500, Text: '15:00' },
],
Simple: //简洁模式
[
{ Value: 2100, Text: '21:00' },
{ Value: 2300, Text: '23:00' },
{ Value: 901, Text: '9:00' },
{ Value: 1100, Text: '11:00' },
{ Value: 1500, Text: '15:00' },
],
Min: //最小模式
[
{ Value: 2100, Text: '21:00' },
{ Value: 901, Text: '9:00' },
{ Value: 1500, Text: '15:00' },
]
}
},
{
Name:'21:00-23:00,9:00-10:15,10:30-11:30,13:30-15:00',
Data:
[
{ Start: 2100, End: 2300 },
{ Start: 901, End: 1015 },
{ Start: 1031, End: 1130 },
{ Start: 1331, End: 1500 }
],
Coordinate:
{
Full://完整模式
[
{ Value: 2100, Text: '21:00' },
{ Value: 2200, Text: '22:00' },
{ Value: 2300, Text: '23:00' },
{ Value: 1030, Text: '10:30' },
{ Value: 1331, Text: '13:30' },
{ Value: 1430, Text: '14:30' },
{ Value: 1500, Text: '15:00' },
],
Simple: //简洁模式
[
{ Value: 2100, Text: '21:00' },
{ Value: 2300, Text: '23:00' },
{ Value: 1331, Text: '13:30' },
{ Value: 1500, Text: '15:00' },
],
Min: //最小模式
[
{ Value: 2100, Text: '21:00' },
{ Value: 2300, Text: '23:00' },
{ Value: 1500, Text: '15:00' },
]
}
}
];
const MAP_TWOWORDS=new Map([
//大连商品交易所
[MARKET_SUFFIX_NAME.DCE + '-JD', {Time:0,Decimal:0}],
[MARKET_SUFFIX_NAME.DCE + '-FB', {Time:0,Decimal:2}],
[MARKET_SUFFIX_NAME.DCE + '-BB', {Time:0,Decimal:2}],
[MARKET_SUFFIX_NAME.DCE + '-PP', {Time:0,Decimal:0}],
[MARKET_SUFFIX_NAME.DCE + '-JM', {Time:3,Decimal:1}],
//上期所
[MARKET_SUFFIX_NAME.SHFE + '-CU', {Time:4,Decimal:0}],
[MARKET_SUFFIX_NAME.SHFE + '-AL', {Time:4,Decimal:0}],
[MARKET_SUFFIX_NAME.SHFE + '-NI', {Time:4,Decimal:0}],
[MARKET_SUFFIX_NAME.SHFE + '-SN', {Time:4,Decimal:0}],
[MARKET_SUFFIX_NAME.SHFE + '-ZN', {Time:4,Decimal:0}],
[MARKET_SUFFIX_NAME.SHFE + '-PB', {Time:4,Decimal:0}],
[MARKET_SUFFIX_NAME.SHFE + '-RU', {Time:6,Decimal:0}],
[MARKET_SUFFIX_NAME.SHFE + '-FU', {Time:6,Decimal:0}],
[MARKET_SUFFIX_NAME.SHFE + '-RB', {Time:6,Decimal:0}],
[MARKET_SUFFIX_NAME.SHFE + '-BU', {Time:6,Decimal:0}],
[MARKET_SUFFIX_NAME.SHFE + '-HC', {Time:6,Decimal:0}],
[MARKET_SUFFIX_NAME.SHFE + '-WR', {Time:0,Decimal:0}],
[MARKET_SUFFIX_NAME.SHFE + '-AG', {Time:5,Decimal:0}],
[MARKET_SUFFIX_NAME.SHFE + '-AU', {Time:5,Decimal:2}],
[MARKET_SUFFIX_NAME.SHFE + '-NR', {Time:5,Decimal:1}],
[MARKET_SUFFIX_NAME.SHFE + '-SC', {Time:5,Decimal:1}],
//郑州期货交易所
[MARKET_SUFFIX_NAME.CZCE + '-CF', {Time:3,Decimal:0}],
[MARKET_SUFFIX_NAME.CZCE + '-SR', {Time:3,Decimal:0}],
[MARKET_SUFFIX_NAME.CZCE + '-MA', {Time:3,Decimal:0}],
[MARKET_SUFFIX_NAME.CZCE + '-ZC', {Time:3,Decimal:1}],
[MARKET_SUFFIX_NAME.CZCE + '-TA', {Time:3,Decimal:0}],
[MARKET_SUFFIX_NAME.CZCE + '-RM', {Time:3,Decimal:0}],
[MARKET_SUFFIX_NAME.CZCE + '-OI', {Time:3,Decimal:0}],
[MARKET_SUFFIX_NAME.CZCE + '-ME', {Time:3,Decimal:0}],
[MARKET_SUFFIX_NAME.CZCE + '-FG', {Time:3,Decimal:0}],
[MARKET_SUFFIX_NAME.CZCE + '-WS', {Time:0,Decimal:0}],
[MARKET_SUFFIX_NAME.CZCE + '-WT', {Time:0,Decimal:0}],
[MARKET_SUFFIX_NAME.CZCE + '-GN', {Time:0,Decimal:0}],
[MARKET_SUFFIX_NAME.CZCE + '-RO', {Time:0,Decimal:0}],
[MARKET_SUFFIX_NAME.CZCE + '-RS', {Time:0,Decimal:0}],
[MARKET_SUFFIX_NAME.CZCE + '-ER', {Time:0,Decimal:0}],
[MARKET_SUFFIX_NAME.CZCE + '-RI', {Time:0,Decimal:0}],
[MARKET_SUFFIX_NAME.CZCE + '-WH', {Time:0,Decimal:0}],
[MARKET_SUFFIX_NAME.CZCE + '-AP', {Time:0,Decimal:0}],
[MARKET_SUFFIX_NAME.CZCE + '-PM', {Time:0,Decimal:0}],
[MARKET_SUFFIX_NAME.CZCE + '-QM', {Time:0,Decimal:0}],
[MARKET_SUFFIX_NAME.CZCE + '-TC', {Time:0,Decimal:0}],
[MARKET_SUFFIX_NAME.CZCE + '-JR', {Time:0,Decimal:0}],
[MARKET_SUFFIX_NAME.CZCE + '-LR', {Time:0,Decimal:0}],
[MARKET_SUFFIX_NAME.CZCE + '-SF', {Time:0,Decimal:0}],
[MARKET_SUFFIX_NAME.CZCE + '-SM', {Time:0,Decimal:0}],
//中期所
[MARKET_SUFFIX_NAME.CFFEX + '-TF', {Time:1,Decimal:3}],
[MARKET_SUFFIX_NAME.CFFEX + '-TS', {Time:1,Decimal:3}],
[MARKET_SUFFIX_NAME.CFFEX + '-IH', {Time:2,Decimal:1}],
[MARKET_SUFFIX_NAME.CFFEX + '-IC', {Time:2,Decimal:1}],
[MARKET_SUFFIX_NAME.CFFEX + '-IF', {Time:2,Decimal:1}],
]);
const MAP_ONEWORD=new Map([
//大连商品交易所
[MARKET_SUFFIX_NAME.DCE + '-C', {Time:0,Decimal:0}],
[MARKET_SUFFIX_NAME.DCE + '-L', {Time:0,Decimal:0}],
[MARKET_SUFFIX_NAME.DCE + '-V', {Time:0,Decimal:0}],
[MARKET_SUFFIX_NAME.DCE + '-A', {Time:3,Decimal:0}],
[MARKET_SUFFIX_NAME.DCE + '-B', {Time:3,Decimal:0}],
[MARKET_SUFFIX_NAME.DCE + '-M', {Time:3,Decimal:0}],
[MARKET_SUFFIX_NAME.DCE + '-Y', {Time:3,Decimal:0}],
[MARKET_SUFFIX_NAME.DCE + '-P', {Time:3,Decimal:0}],
[MARKET_SUFFIX_NAME.DCE + '-J', {Time:3,Decimal:1}],
[MARKET_SUFFIX_NAME.DCE + '-I', {Time:3,Decimal:1}],
//中期所
[MARKET_SUFFIX_NAME.CFFEX + '-T', {Time:1,Decimal:3}],
]);
this.GetData=function(upperSymbol)
{
var oneWord = upperSymbol.charAt(0);
var twoWords = upperSymbol.substr(0,2);
var oneWordName = null, twoWordsName=null;
if (MARKET_SUFFIX_NAME.IsDCE(upperSymbol)) //大连商品交易所
{
oneWordName = MARKET_SUFFIX_NAME.DCE+'-'+oneWord;
twoWordsName = MARKET_SUFFIX_NAME.DCE + '-' + twoWords;
}
else if (MARKET_SUFFIX_NAME.IsSHFE(upperSymbol)) //上期所
{
oneWordName = MARKET_SUFFIX_NAME.SHFE + '-' + oneWord;
twoWordsName = MARKET_SUFFIX_NAME.SHFE + '-' + twoWords;
}
else if (MARKET_SUFFIX_NAME.IsCFFEX(upperSymbol)) //中期所
{
oneWordName = MARKET_SUFFIX_NAME.CFFEX + '-' + oneWord;
twoWordsName = MARKET_SUFFIX_NAME.CFFEX + '-' + twoWords;
}
else if (MARKET_SUFFIX_NAME.IsCZCE(upperSymbol)) //郑州期货交易所
{
oneWordName = MARKET_SUFFIX_NAME.CZCE + '-' + oneWord;
twoWordsName = MARKET_SUFFIX_NAME.CZCE + '-' + twoWords;
}
if (MAP_TWOWORDS.has(twoWordsName))
{
return MAP_TWOWORDS.get(twoWordsName);
}
if (MAP_ONEWORD.has(oneWordName))
{
return MAP_ONEWORD.get(oneWordName);
}
return null;
}
this.GetSplitData = function (upperSymbol)
{
var data=this.GetData(upperSymbol);
if (!data) return null;
return TIME_SPLIT[data.Time];
}
this.GetDecimal=function(upperSymbol)
{
var data=this.GetData(upperSymbol);
if (!data) return 2;
return data.Decimal;
}
}
var g_MinuteTimeStringData = new MinuteTimeStringData();
var g_MinuteCoordinateData = new MinuteCoordinateData();
var g_FuturesTimeData = new FuturesTimeData();
function GetfloatPrecision(symbol) //获取小数位数
{
var defaultfloatPrecision=2; //默认2位
if (!symbol) return defaultfloatPrecision;
var upperSymbol=symbol.toUpperCase();
if (MARKET_SUFFIX_NAME.IsSHSZFund(upperSymbol)) defaultfloatPrecision=3; //基金3位小数
else if (MARKET_SUFFIX_NAME.IsChinaFutures(upperSymbol)) defaultfloatPrecision=g_FuturesTimeData.GetDecimal(upperSymbol); //期货小数位数读配置
else if (MARKET_SUFFIX_NAME.IsFHK(upperSymbol)) defaultfloatPrecision=MARKET_SUFFIX_NAME.GetFHKDecimal(upperSymbol);
else if (MARKET_SUFFIX_NAME.IsFTSE(upperSymbol)) defaultfloatPrecision=MARKET_SUFFIX_NAME.GetFTSEDecimal(upperSymbol);
else if (MARKET_SUFFIX_NAME.IsBIT(upperSymbol)) defaultfloatPrecision=MARKET_SUFFIX_NAME.GetBITDecimal(upperSymbol);
else if (MARKET_SUFFIX_NAME.IsET(upperSymbol)) defaultfloatPrecision=MARKET_SUFFIX_NAME.GetETDecimal(upperSymbol);
else if (MARKET_SUFFIX_NAME.IsForeignExchange(upperSymbol)) defaultfloatPrecision=MARKET_SUFFIX_NAME.GetForeignExchangeDecimal(upperSymbol);
return defaultfloatPrecision;
}
function GetLocalTime(i) //得到标准时区的时间的函数
{
if (typeof i !== 'number') return;
var d = new Date();
//得到1970年一月一日到现在的秒数
var len = d.getTime();
//本地时间与GMT时间的时间偏移差
var offset = d.getTimezoneOffset() * 60000;
//得到现在的格林尼治时间
var utcTime = len + offset;
return new Date(utcTime + 3600000 * i);
}
/*
Copyright (c) 2018 jones
http://www.apache.org/licenses/LICENSE-2.0
开源项目 https://github.com/jones2000/HQChart
jones_2000@163.com
分析家语法编译执行器 (H5版本)
*/
//日志输出类
if (!JSConsole)
{
var JSConsole=
{
Chart:{ Log:console.log }, //图形日志
Complier:{ Log:console.log } //编译器日志
};
}
//API默认地址
var g_JSComplierResource=
{
Domain : "https://opensource.zealink.com", //API域名
CacheDomain : "https://opensourcecache.zealink.com", //缓存域名
DrawIcon:
{
Family:'iconfont',
Data:new Map([
[1, { Text:'\ue625', Color:'rgb(255,106,106)'}], //向上箭头
[2, { Text:'\ue68b', Color:'rgb(46,139,87)'}], //向下箭头
[11,{ Text:'\ue624', Color:'rgb(245,159,40)'}], //点赞
[12,{ Text:'\ue600', Color:'rgb(245,159,40)'}],
[13,{Text:'\ue70f',Color:'rgb(209,37,35)'}, ], //B
[14,{Text:'\ue64c',Color:'rgb(127,209,59)'} ], //S
[9, {Text:'\ue626',Color:'rgb(245,159,40)'} ], //$
[36,{Text:'\ue68c',Color:'rgb(255,106,106)'} ], //关闭 红色
[37,{Text:'\ue68c',Color:'rgb(46,139,87)'} ], //关闭 绿色
[38,{Text:'\ue68d',Color:'rgb(238,44,44)'} ], //▲
[39,{Text:'\ue68e',Color:'rgb(0,139,69)'} ], //▼
[46,{Text:'\ue64d',Color:'rgb(51,51,51)'} ], //message
])
},
CustomDrawIcon:
{
Data:new Map() //自定义图标 key=id value={ID:, Text:, Color, Family: }
},
CustomFunction: //定制函数
{
Data:new Map() //自定义函数 key=函数名, Value:{ID:函数名, Callback: }
},
CustomVariant: //自定义变量
{
Data:new Map() //自定义函数 key=变量名, Value:{ID:变量名, Callback: }
},
GetDrawIcon:function(id)
{
var icon;
if (g_JSComplierResource.CustomDrawIcon.Data.has(id))
{
const iconfont=g_JSComplierResource.CustomDrawIcon.Data.get(id);
icon={ Symbol:iconfont.Text, Color:iconfont.Color, Family:iconfont.Family, IconFont:true, ID:id };
return icon;
}
if (g_JSComplierResource.DrawIcon.Data.has(id))
{
const iconfont=g_JSComplierResource.DrawIcon.Data.get(id);
icon={ Symbol:iconfont.Text, Color:iconfont.Color, Family:g_JSComplierResource.DrawIcon.Family, IconFont:true, ID:id };
return icon;
}
return null;
},
IsCustomFunction:function(name)
{
if (g_JSComplierResource.CustomFunction.Data.has(name)) return true;
return false;
},
IsCustomVariant:function(name)
{
if (g_JSComplierResource.CustomVariant.Data.has(name)) return true;
return false;
}
}
var Messages = {
BadGetterArity: 'Getter must not have any formal parameters',
BadSetterArity: 'Setter must have exactly one formal parameter',
BadSetterRestParameter: 'Setter function argument must not be a rest parameter',
ConstructorIsAsync: 'Class constructor may not be an async method',
ConstructorSpecialMethod: 'Class constructor may not be an accessor',
DeclarationMissingInitializer: 'Missing initializer in %0 declaration',
DefaultRestParameter: 'Unexpected token =',
DuplicateBinding: 'Duplicate binding %0',
DuplicateConstructor: 'A class may only have one constructor',
DuplicateProtoProperty: 'Duplicate __proto__ fields are not allowed in object literals',
ForInOfLoopInitializer: '%0 loop variable declaration may not have an initializer',
GeneratorInLegacyContext: 'Generator declarations are not allowed in legacy contexts',
IllegalBreak: 'Illegal break statement',
IllegalContinue: 'Illegal continue statement',
IllegalExportDeclaration: 'Unexpected token',
IllegalImportDeclaration: 'Unexpected token',
IllegalLanguageModeDirective: 'Illegal \'use strict\' directive in function with non-simple parameter list',
IllegalReturn: 'Illegal return statement',
InvalidEscapedReservedWord: 'Keyword must not contain escaped characters',
InvalidHexEscapeSequence: 'Invalid hexadecimal escape sequence',
InvalidLHSInAssignment: 'Invalid left-hand side in assignment',
InvalidLHSInForIn: 'Invalid left-hand side in for-in',
InvalidLHSInForLoop: 'Invalid left-hand side in for-loop',
InvalidModuleSpecifier: 'Unexpected token',
InvalidRegExp: 'Invalid regular expression',
LetInLexicalBinding: 'let is disallowed as a lexically bound name',
MissingFromClause: 'Unexpected token',
MultipleDefaultsInSwitch: 'More than one default clause in switch statement',
NewlineAfterThrow: 'Illegal newline after throw',
NoAsAfterImportNamespace: 'Unexpected token',
NoCatchOrFinally: 'Missing catch or finally after try',
ParameterAfterRestParameter: 'Rest parameter must be last formal parameter',
Redeclaration: '%0 \'%1\' has already been declared',
StaticPrototype: 'Classes may not have static property named prototype',
StrictCatchVariable: 'Catch variable may not be eval or arguments in strict mode',
StrictDelete: 'Delete of an unqualified identifier in strict mode.',
StrictFunction: 'In strict mode code, functions can only be declared at top level or inside a block',
StrictFunctionName: 'Function name may not be eval or arguments in strict mode',
StrictLHSAssignment: 'Assignment to eval or arguments is not allowed in strict mode',
StrictLHSPostfix: 'Postfix increment/decrement may not have eval or arguments operand in strict mode',
StrictLHSPrefix: 'Prefix increment/decrement may not have eval or arguments operand in strict mode',
StrictModeWith: 'Strict mode code may not include a with statement',
StrictOctalLiteral: 'Octal literals are not allowed in strict mode.',
StrictParamDupe: 'Strict mode function may not have duplicate parameter names',
StrictParamName: 'Parameter name eval or arguments is not allowed in strict mode',
StrictReservedWord: 'Use of future reserved word in strict mode',
StrictVarName: 'Variable name may not be eval or arguments in strict mode',
TemplateOctalLiteral: 'Octal literals are not allowed in template strings.',
UnexpectedEOS: 'Unexpected end of input',
UnexpectedIdentifier: 'Unexpected identifier',
UnexpectedNumber: 'Unexpected number',
UnexpectedReserved: 'Unexpected reserved word',
UnexpectedString: 'Unexpected string',
UnexpectedTemplate: 'Unexpected quasi %0',
UnexpectedToken: 'Unexpected token %0',
UnexpectedTokenIllegal: 'Unexpected token ILLEGAL',
UnknownLabel: 'Undefined label \'%0\'',
UnterminatedRegExp: 'Invalid regular expression: missing /'
};
var Regex = {
// Unicode v8.0.0 NonAsciiIdentifierStart:
NonAsciiIdentifierStart: /[\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0-\u08B4\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0AF9\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D\u0C58-\u0C5A\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D5F-\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2118-\u211D\u2124\u2126\u2128\u212A-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303C\u3041-\u3096\u309B-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FD5\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA69D\uA6A0-\uA6EF\uA717-\uA71F\uA722-\uA788\uA78B-\uA7AD\uA7B0-\uA7B7\uA7F7-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA8FD\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uA9E0-\uA9E4\uA9E6-\uA9EF\uA9FA-\uA9FE\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA7E-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB65\uAB70-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDD40-\uDD74\uDE80-\uDE9C\uDEA0-\uDED0\uDF00-\uDF1F\uDF30-\uDF4A\uDF50-\uDF75\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF\uDFD1-\uDFD5]|\uD801[\uDC00-\uDC9D\uDD00-\uDD27\uDD30-\uDD63\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC60-\uDC76\uDC80-\uDC9E\uDCE0-\uDCF2\uDCF4\uDCF5\uDD00-\uDD15\uDD20-\uDD39\uDD80-\uDDB7\uDDBE\uDDBF\uDE00\uDE10-\uDE13\uDE15-\uDE17\uDE19-\uDE33\uDE60-\uDE7C\uDE80-\uDE9C\uDEC0-\uDEC7\uDEC9-\uDEE4\uDF00-\uDF35\uDF40-\uDF55\uDF60-\uDF72\uDF80-\uDF91]|\uD803[\uDC00-\uDC48\uDC80-\uDCB2\uDCC0-\uDCF2]|\uD804[\uDC03-\uDC37\uDC83-\uDCAF\uDCD0-\uDCE8\uDD03-\uDD26\uDD50-\uDD72\uDD76\uDD83-\uDDB2\uDDC1-\uDDC4\uDDDA\uDDDC\uDE00-\uDE11\uDE13-\uDE2B\uDE80-\uDE86\uDE88\uDE8A-\uDE8D\uDE8F-\uDE9D\uDE9F-\uDEA8\uDEB0-\uDEDE\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3D\uDF50\uDF5D-\uDF61]|\uD805[\uDC80-\uDCAF\uDCC4\uDCC5\uDCC7\uDD80-\uDDAE\uDDD8-\uDDDB\uDE00-\uDE2F\uDE44\uDE80-\uDEAA\uDF00-\uDF19]|\uD806[\uDCA0-\uDCDF\uDCFF\uDEC0-\uDEF8]|\uD808[\uDC00-\uDF99]|\uD809[\uDC00-\uDC6E\uDC80-\uDD43]|[\uD80C\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD811[\uDC00-\uDE46]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDED0-\uDEED\uDF00-\uDF2F\uDF40-\uDF43\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDF00-\uDF44\uDF50\uDF93-\uDF9F]|\uD82C[\uDC00\uDC01]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB]|\uD83A[\uDC00-\uDCC4]|\uD83B[\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1]|\uD87E[\uDC00-\uDE1D]/,
// Unicode v8.0.0 NonAsciiIdentifierPart:
NonAsciiIdentifierPart: /[\xAA\xB5\xB7\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0300-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u0483-\u0487\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u05D0-\u05EA\u05F0-\u05F2\u0610-\u061A\u0620-\u0669\u066E-\u06D3\u06D5-\u06DC\u06DF-\u06E8\u06EA-\u06FC\u06FF\u0710-\u074A\u074D-\u07B1\u07C0-\u07F5\u07FA\u0800-\u082D\u0840-\u085B\u08A0-\u08B4\u08E3-\u0963\u0966-\u096F\u0971-\u0983\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BC-\u09C4\u09C7\u09C8\u09CB-\u09CE\u09D7\u09DC\u09DD\u09DF-\u09E3\u09E6-\u09F1\u0A01-\u0A03\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A3C\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A59-\u0A5C\u0A5E\u0A66-\u0A75\u0A81-\u0A83\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABC-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0AD0\u0AE0-\u0AE3\u0AE6-\u0AEF\u0AF9\u0B01-\u0B03\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3C-\u0B44\u0B47\u0B48\u0B4B-\u0B4D\u0B56\u0B57\u0B5C\u0B5D\u0B5F-\u0B63\u0B66-\u0B6F\u0B71\u0B82\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD0\u0BD7\u0BE6-\u0BEF\u0C00-\u0C03\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C58-\u0C5A\u0C60-\u0C63\u0C66-\u0C6F\u0C81-\u0C83\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBC-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5\u0CD6\u0CDE\u0CE0-\u0CE3\u0CE6-\u0CEF\u0CF1\u0CF2\u0D01-\u0D03\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D-\u0D44\u0D46-\u0D48\u0D4A-\u0D4E\u0D57\u0D5F-\u0D63\u0D66-\u0D6F\u0D7A-\u0D7F\u0D82\u0D83\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0DCA\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DE6-\u0DEF\u0DF2\u0DF3\u0E01-\u0E3A\u0E40-\u0E4E\u0E50-\u0E59\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB9\u0EBB-\u0EBD\u0EC0-\u0EC4\u0EC6\u0EC8-\u0ECD\u0ED0-\u0ED9\u0EDC-\u0EDF\u0F00\u0F18\u0F19\u0F20-\u0F29\u0F35\u0F37\u0F39\u0F3E-\u0F47\u0F49-\u0F6C\u0F71-\u0F84\u0F86-\u0F97\u0F99-\u0FBC\u0FC6\u1000-\u1049\u1050-\u109D\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u135D-\u135F\u1369-\u1371\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1714\u1720-\u1734\u1740-\u1753\u1760-\u176C\u176E-\u1770\u1772\u1773\u1780-\u17D3\u17D7\u17DC\u17DD\u17E0-\u17E9\u180B-\u180D\u1810-\u1819\u1820-\u1877\u1880-\u18AA\u18B0-\u18F5\u1900-\u191E\u1920-\u192B\u1930-\u193B\u1946-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u19D0-\u19DA\u1A00-\u1A1B\u1A20-\u1A5E\u1A60-\u1A7C\u1A7F-\u1A89\u1A90-\u1A99\u1AA7\u1AB0-\u1ABD\u1B00-\u1B4B\u1B50-\u1B59\u1B6B-\u1B73\u1B80-\u1BF3\u1C00-\u1C37\u1C40-\u1C49\u1C4D-\u1C7D\u1CD0-\u1CD2\u1CD4-\u1CF6\u1CF8\u1CF9\u1D00-\u1DF5\u1DFC-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u200C\u200D\u203F\u2040\u2054\u2071\u207F\u2090-\u209C\u20D0-\u20DC\u20E1\u20E5-\u20F0\u2102\u2107\u210A-\u2113\u2115\u2118-\u211D\u2124\u2126\u2128\u212A-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D7F-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2DE0-\u2DFF\u3005-\u3007\u3021-\u302F\u3031-\u3035\u3038-\u303C\u3041-\u3096\u3099-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FD5\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA62B\uA640-\uA66F\uA674-\uA67D\uA67F-\uA6F1\uA717-\uA71F\uA722-\uA788\uA78B-\uA7AD\uA7B0-\uA7B7\uA7F7-\uA827\uA840-\uA873\uA880-\uA8C4\uA8D0-\uA8D9\uA8E0-\uA8F7\uA8FB\uA8FD\uA900-\uA92D\uA930-\uA953\uA960-\uA97C\uA980-\uA9C0\uA9CF-\uA9D9\uA9E0-\uA9FE\uAA00-\uAA36\uAA40-\uAA4D\uAA50-\uAA59\uAA60-\uAA76\uAA7A-\uAAC2\uAADB-\uAADD\uAAE0-\uAAEF\uAAF2-\uAAF6\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB65\uAB70-\uABEA\uABEC\uABED\uABF0-\uABF9\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE00-\uFE0F\uFE20-\uFE2F\uFE33\uFE34\uFE4D-\uFE4F\uFE70-\uFE74\uFE76-\uFEFC\uFF10-\uFF19\uFF21-\uFF3A\uFF3F\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDD40-\uDD74\uDDFD\uDE80-\uDE9C\uDEA0-\uDED0\uDEE0\uDF00-\uDF1F\uDF30-\uDF4A\uDF50-\uDF7A\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF\uDFD1-\uDFD5]|\uD801[\uDC00-\uDC9D\uDCA0-\uDCA9\uDD00-\uDD27\uDD30-\uDD63\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC60-\uDC76\uDC80-\uDC9E\uDCE0-\uDCF2\uDCF4\uDCF5\uDD00-\uDD15\uDD20-\uDD39\uDD80-\uDDB7\uDDBE\uDDBF\uDE00-\uDE03\uDE05\uDE06\uDE0C-\uDE13\uDE15-\uDE17\uDE19-\uDE33\uDE38-\uDE3A\uDE3F\uDE60-\uDE7C\uDE80-\uDE9C\uDEC0-\uDEC7\uDEC9-\uDEE6\uDF00-\uDF35\uDF40-\uDF55\uDF60-\uDF72\uDF80-\uDF91]|\uD803[\uDC00-\uDC48\uDC80-\uDCB2\uDCC0-\uDCF2]|\uD804[\uDC00-\uDC46\uDC66-\uDC6F\uDC7F-\uDCBA\uDCD0-\uDCE8\uDCF0-\uDCF9\uDD00-\uDD34\uDD36-\uDD3F\uDD50-\uDD73\uDD76\uDD80-\uDDC4\uDDCA-\uDDCC\uDDD0-\uDDDA\uDDDC\uDE00-\uDE11\uDE13-\uDE37\uDE80-\uDE86\uDE88\uDE8A-\uDE8D\uDE8F-\uDE9D\uDE9F-\uDEA8\uDEB0-\uDEEA\uDEF0-\uDEF9\uDF00-\uDF03\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3C-\uDF44\uDF47\uDF48\uDF4B-\uDF4D\uDF50\uDF57\uDF5D-\uDF63\uDF66-\uDF6C\uDF70-\uDF74]|\uD805[\uDC80-\uDCC5\uDCC7\uDCD0-\uDCD9\uDD80-\uDDB5\uDDB8-\uDDC0\uDDD8-\uDDDD\uDE00-\uDE40\uDE44\uDE50-\uDE59\uDE80-\uDEB7\uDEC0-\uDEC9\uDF00-\uDF19\uDF1D-\uDF2B\uDF30-\uDF39]|\uD806[\uDCA0-\uDCE9\uDCFF\uDEC0-\uDEF8]|\uD808[\uDC00-\uDF99]|\uD809[\uDC00-\uDC6E\uDC80-\uDD43]|[\uD80C\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD811[\uDC00-\uDE46]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDE60-\uDE69\uDED0-\uDEED\uDEF0-\uDEF4\uDF00-\uDF36\uDF40-\uDF43\uDF50-\uDF59\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDF00-\uDF44\uDF50-\uDF7E\uDF8F-\uDF9F]|\uD82C[\uDC00\uDC01]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99\uDC9D\uDC9E]|\uD834[\uDD65-\uDD69\uDD6D-\uDD72\uDD7B-\uDD82\uDD85-\uDD8B\uDDAA-\uDDAD\uDE42-\uDE44]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB\uDFCE-\uDFFF]|\uD836[\uDE00-\uDE36\uDE3B-\uDE6C\uDE75\uDE84\uDE9B-\uDE9F\uDEA1-\uDEAF]|\uD83A[\uDC00-\uDCC4\uDCD0-\uDCD6]|\uD83B[\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1]|\uD87E[\uDC00-\uDE1D]|\uDB40[\uDD00-\uDDEF]/
}
var Character =
{
FromCodePoint: function (cp) {
return (cp < 0x10000) ? String.fromCharCode(cp) :
String.fromCharCode(0xD800 + ((cp - 0x10000) >> 10)) +
String.fromCharCode(0xDC00 + ((cp - 0x10000) & 1023));
},
//是否是空格 https://tc39.github.io/ecma262/#sec-white-space
IsWhiteSpace:function(cp)
{
return (cp === 0x20) || (cp === 0x09) || (cp === 0x0B) || (cp === 0x0C) || (cp === 0xA0) ||
(cp >= 0x1680 && [0x1680, 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, 0x2007, 0x2008, 0x2009, 0x200A, 0x202F, 0x205F, 0x3000, 0xFEFF].indexOf(cp) >= 0);
},
//是否换行 https://tc39.github.io/ecma262/#sec-line-terminators
IsLineTerminator:function(cp)
{
return (cp === 0x0A) || (cp === 0x0D) || (cp === 0x2028) || (cp === 0x2029);
},
// https://tc39.github.io/ecma262/#sec-names-and-keywords
IsIdentifierStart:function(cp)
{
return (cp === 0x24) || (cp === 0x5F) ||
(cp >= 0x41 && cp <= 0x5A) ||
(cp >= 0x61 && cp <= 0x7A) ||
(cp === 0x5C) ||
((cp >= 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 */] = '<end>';
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.IsNeedLatestIndexData=false; //是否需要下载最新大盘数据
this.IsNeedLatestData=false; //是否需要最新的个股行情数据
this.IsNeedSymbolData=false; //是否需要下载股票数据
this.IsNeedSymbolDayData=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});
if (this.IsNeedSymbolDayData) jobs.push({ID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SYMBOL_DAY_DATA});
if (this.IsNeedLatestIndexData) jobs.push({ID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_LATEST_INDEX_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 (varName=='FROMOPEN')
{
this.IsNeedLatestIndexData=true;
return;
}
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=='COVER_C' || callee.Name=='COVER_O' || callee.Name=='COVER_H' || callee.Name=='COVER_L' || callee.Name=='COVER_A' || callee.Name=='COVER_V') //跨周期函数
{
var periodName=args[0].Value;
if (periodName=='DAY' || periodName=='WEEK' || periodName=='YEAR' || periodName=='MONTH')
this.IsNeedSymbolDayData=true;
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;i<count;++i)
{
result[i]=null; //初始化
if (i<data.length && i<data2.length)
{
if ( this.IsNumber(data[i]) && this.IsNumber(data2[i]) ) result[i]=data[i]+data2[i];
}
}
return result;
}
//单数据和数组相加
let value;
let aryData;
if (isNumber)
{
value=data;
aryData=data2;
}
else
{
value=data2;
aryData=data;
}
for(let i in aryData)
{
result[i]=null;
if (this.IsNumber(aryData[i]) && this.IsNumber(value)) result[i]=value+aryData[i];
}
return result;
}
//相减
this.Subtract=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;i<count;++i)
{
result[i]=null; //初始化
if (i<data.length && i<data2.length)
{
if ( this.IsNumber(data[i]) && this.IsNumber(data2[i]) ) result[i]=data[i]-data2[i];
}
}
return result;
}
if (isNumber) //单数据-数组
{
for(let i in data2)
{
result[i]=null;
if (this.IsNumber(data) && this.IsNumber(data2[i])) result[i]=data-data2[i];
}
}
else //数组-单数据
{
for(let i in data)
{
result[i]=null;
if (this.IsNumber(data[i]) && this.IsNumber(data2)) result[i]=data[i]-data2;
}
}
return result;
}
//相乘
this.Multiply=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;i<count;++i)
{
result[i]=null; //初始化
if (i<data.length && i<data2.length)
{
if ( this.IsNumber(data[i]) && this.IsNumber(data2[i]) ) result[i]=data[i]*data2[i];
}
}
return result;
}
//单数据和数组相乘
let value;
let aryData;
if (isNumber)
{
value=data;
aryData=data2;
}
else
{
value=data2;
aryData=data;
}
for(let i in aryData)
{
result[i]=null;
if (this.IsNumber(aryData[i]) && this.IsNumber(value)) result[i]=value*aryData[i];
}
return result;
}
//相除
this.Divide=function(data,data2)
{
let isNumber=typeof(data)=='number';
let isNumber2=typeof(data2)=='number';
//单数值相除
if (isNumber && isNumber2)
{
if (data2==0) return null; //除0判断
return data/data2;
}
//都是数组相除
let result=[];
if (!isNumber && !isNumber2)
{
let count=Math.max(data.length, data2.length);
for(let i=0;i<count;++i)
{
result[i]=null; //初始化
if (i<data.length && i<data2.length)
{
if ( this.IsNumber(data[i]) && this.IsDivideNumber(data2[i]) ) result[i]=data[i]/data2[i];
}
}
return result;
}
if (isNumber) //单数据-数组
{
for(let i in data2)
{
result[i]=null;
if ( this.IsNumber(data) && this.IsDivideNumber(data2[i]) ) result[i]=data/data2[i];
}
}
else //数组-单数据
{
for(let i in data)
{
result[i]=null;
if ( this.IsNumber(data[i]) && this.IsDivideNumber(data2) ) result[i]=data[i]/data2;
}
}
return result;
}
//大于
this.GT=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<count;++i)
{
result[i]=null; //初始化
if (i<data.length && i<data2.length)
{
if ( !isNaN(data[i]) && !isNaN(data2[i]) ) result[i]=(data[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.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<count;++i)
{
result[i]=null; //初始化
if (i<data.length && i<data2.length)
{
if ( !isNaN(data[i]) && !isNaN(data2[i]) ) result[i]=(data[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;i<count;++i)
{
result[i]=null; //初始化
if (i<data.length && i<data2.length)
{
if ( !isNaN(data[i]) && !isNaN(data2[i]) ) result[i]=(data[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.LTE=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<count;++i)
{
result[i]=null; //初始化
if (i<data.length && i<data2.length)
{
if ( !isNaN(data[i]) && !isNaN(data2[i]) ) result[i]=(data[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.EQ=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<count;++i)
{
result[i]=null; //初始化
if (i<data.length && i<data2.length)
{
if ( !isNaN(data[i]) && !isNaN(data2[i]) ) result[i]=(data[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.NEQ=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<count;++i)
{
result[i]=null; //初始化
if (i<data.length && i<data2.length)
{
if ( !isNaN(data[i]) && !isNaN(data2[i]) ) result[i]=(data[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;
}
//AND &&
this.And=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<count;++i)
{
result[i]=null; //初始化
if (i<data.length && i<data2.length)
{
if ( !isNaN(data[i]) && !isNaN(data2[i]) ) result[i]=(data[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;
}
//OR ||
this.Or=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<count;++i)
{
result[i]=null; //初始化
if (i<data.length && i<data2.length)
{
if ( !isNaN(data[i]) && !isNaN(data2[i]) ) result[i]=(data[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.IF=function(data,trueData,falseData)
{
let isNumber=typeof(data)=='number';
let isNumber2=typeof(trueData)=='number';
let isNumber3=typeof(falseData)=='number';
//单数值
if (isNumber)
{
if (isNumber2 && isNumber3) return data?trueData:falseData;
return data? trueData:falseData;
}
//都是数组
let result=[];
for(let i in data)
{
if (data[i])
{
if (isNumber2) result[i]=trueData;
else result[i]=trueData[i];
}
else
{
if (isNumber3) result[i]=falseData;
else result[i]=falseData[i];
}
}
return result;
}
/*
根据条件求不同的值,同IF判断相反.
用法: IFN(X,A,B)若X不为0则返回B,否则返回A
例如: IFN(CLOSE>OPEN,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;++i)
result.unshift(null);
}
else //n 为数组的情况
{
for(let i=0;i<data.length;++i)
{
result[i]=null;
if (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<count;++i)
{
result[i]=null; //初始化
if (i<data.length && i<data2.length)
{
if ( !isNaN(data[i]) && !isNaN(data2[i]) ) result[i]=Math.max(data[i], data2[i]);
}
}
return result;
}
if (isNumber) //单数据-数组
{
for(let i in data2)
{
result[i]=null;
if ( !isNaN(data) && !isNaN(data2[i]) ) result[i]=Math.max(data, data2[i]);
}
}
else //数组-单数据
{
for(let i in data)
{
result[i]=null;
if ( !isNaN(data[i]) && !isNaN(data2) ) result[i]=Math.max(data[i], data2);
}
}
return result;
}
this.MIN=function(data,data2)
{
let isNumber=typeof(data)=='number';
let isNumber2=typeof(data2)=='number';
//单数值
if (isNumber && isNumber2) return Math.min(data,data2);
//都是数组
let result=[];
if (!isNumber && !isNumber2)
{
let count=Math.max(data.length, data2.length);
for(let i=0;i<count;++i)
{
result[i]=null; //初始化
if (i<data.length && i<data2.length)
{
if ( !isNaN(data[i]) && !isNaN(data2[i]) ) result[i]=Math.min(data[i], data2[i]);
}
}
return result;
}
if (isNumber) //单数据-数组
{
for(let i in data2)
{
result[i]=null;
if ( !isNaN(data) && !isNaN(data2[i]) ) result[i]=Math.min(data, data2[i]);
}
}
else //数组-单数据
{
for(let i in data)
{
result[i]=null;
if ( !isNaN(data[i]) && !isNaN(data2) ) result[i]=Math.min(data[i], data2);
}
}
return result;
}
//取正数
this.ABS=function(data)
{
let result=[];
for(let i in data)
{
result[i]=null;
if (!isNaN(data[i])) result[i]=Math.abs(data[i]);
}
return result;
}
this.MA=function(data,dayCount)
{
let result=[];
if (!Array.isArray(dayCount))
{
if (dayCount<=0) dayCount=1;
if (!data || !data.length) return result;
for(var i=0;i<data.length;++i)
{
result[i]=null;
if (this.IsNumber(data[i])) break;
}
var data=data.slice(0); //复制一份数据出来
for(var days=0;i<data.length;++i,++days)
{
if (days<dayCount-1)
{
result[i]=null;
continue;
}
let preValue=data[i-(dayCount-1)];
let sum=0;
for(let j=dayCount-1;j>=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<data.length;++i)
{
result[i]=null;
if (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<sumCount;--j,++k)
{
sum+=data[j];
}
result[i]=sum/sumCount;
}
}
return result;
}
//指数平均数指标 EMA(close,10)
this.EMA=function(data,dayCount)
{
var result = [];
var offset=0;
if (offset>=data.length) return result;
//取首个有效数据
for(;offset<data.length;++offset)
{
if (data[offset]!=null && !isNaN(data[offset]))
break;
}
var p1Index=offset;
var p2Index=offset+1;
result[p1Index]=data[p1Index];
for(var i=offset+1;i<data.length;++i,++p1Index,++p2Index)
{
result[p2Index]=((2*data[p2Index]+(dayCount-1)*result[p1Index]))/(dayCount+1);
}
return result;
}
/*
SMA 移动平均
返回移动平均。
用法: SMA(X,N,M) X的M日移动平均,M为权重,如Y=(X*M+Y'*(N-M))/N
*/
this.SMA=function(data,n,m)
{
var result = [];
var i=0;
var lastData=null;
for(;i<data.length; ++i)
{
if (data[i]==null || isNaN(data[i])) continue;
lastData=data[i];
result[i]=lastData; //第一天的数据
break;
}
for(++i;i<data.length;++i)
{
result[i]=(m*data[i]+(n-m)*lastData)/n;
lastData=result[i];
}
return result;
}
/*
求动态移动平均.
用法: DMA(X,A),求X的动态移动平均.
算法: 若Y=DMA(X,A)则 Y=A*X+(1-A)*Y',其中Y'表示上一周期Y值,A必须小于1.
例如:DMA(CLOSE,VOL/CAPITAL)表示求以换手率作平滑因子的平均价
*/
this.DMA=function(data,data2)
{
var result = [];
if (data.length<0 || data.length!=data2.length) return result;
var index=0;
for(;index<data.length;++index)
{
if (data[index]!=null && !isNaN(data[index]) && data2[index]!=null && !isNaN(data2[index]))
{
result[index]=data[index];
break;
}
}
for(index=index+1;index<data.length;++index)
{
if (data[index]==null || data2[index]==null)
result[index]=null;
else
{
if (data2[index]<1)
result[index]=(data2[index]*data[index])+(1-data2[index])*result[index-1];
else
result[index]= data[index];
}
}
return result;
}
/*
返回加权移动平均
用法:WMA(X,N):X的N日加权移动平均.
算法:Yn=(1*X1+2*X2+...+n*Xn)/(1+2+...+n)
*/
this.WMA=function(data, dayCount)
{
let result=[];
if (!data || !data.length) return result;
if (dayCount < 1) dayCount = 1;
var i = 0;
for(i = 0; i < data.length && !this.IsNumber(data[i]); ++i)
{
result[i] = null;
}
var data = data.slice(0);
for(var days=0; i < data.length; ++i,++days)
{
if (days < dayCount-1)
{
result[i] = null;
continue;
}
var preValue = data[i - (dayCount-1)];
var sum = 0;
var count = 0;
for (var j = dayCount-1; j >= 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;++i) //获取第1个有效数据
{
if (data[i]!=null)
{
result[i]=data[i];
break;
}
}
for (i=i+1; i < data.length; ++i)
{
if (result[i-1]!=null && data[i]!=null)
result[i]=(2*data[i]+(dayCount-1)*result[i-1])/(dayCount+1);
else if (result[i-1]!=null)
result[i]=result[i-1];
}
return result;
}
//加权平滑平均,MEMA[i]=SMA[i]*para+(1-para)*SMA[i-1] para=2/(1+__para)
this.EXPMEMA=function(data,dayCount)
{
var result=[];
if (dayCount>=data.length) return result;
var index=0;
for(;index<data.length;++index)
{
if (data[index] && !isNaN(data[index])) break;
}
var sum=0;
for(var i=0; index<data.length && i<dayCount;++i, ++index)
{
if (data[index] && !isNaN(data[index]))
sum+=data[index];
else
sum+=data[index-1];
}
result[index-1]=sum/dayCount;
for(;index<data.length;++index)
{
if(result[index-1]!=null && data[index]!=null)
result[index]=(2*data[index]+(dayCount-1)*result[index-1])/(dayCount+1);
else if(result[index-1]!=null)
result[index] = result[index-1];
}
return result;
}
/*
向前累加到指定值到现在的周期数.
用法:SUMBARS(X,A):将X向前累加直到大于等于A,返回这个区间的周期数
例如:SUMBARS(VOL,CAPITAL)求完全换手到现在的周期数
*/
this.SUMBARS=function(data, data2)
{
var result = [];
if (!data || !data.length || !data2 || !data2.length) return result;
var start = 0, i = 0, j = 0;
for(; start < data.length && !this.IsNumber(data[start]); ++start)
{
result[start] = null;
}
for (i = data.length-1; i >= 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<data.length && !this.isNumber(data[i]); ++i)
{
result[i] = null;
}
for (; i < data.length; ++i)
{
if (!this.isNumber(data[i]))
result[i] = null;
else
result[i] = 0-data[i];
}
return result;
}
this.COUNT=function(data,n)
{
let result=[];
for(let i=0; i<data.length; ++i)
{
let count=0;
for(let j=0;j<n && i-j>=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<data.length;++i)
{
result[i]=null;
if (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 || max<data[j]) max=data[j];
}
}
else
{
count=i;
for(j=0;j<=i;++j)
{
if (max==null || max<data[j]) max=data[j];
}
}
result[i]=max;
}
}
else
{
if (n>data.length) return result;
if (n<=0) n=data.length-1;
var nMax=0;
for(nMax=0;nMax<data.length;++nMax)
{
if (this.IsNumber(data[nMax])) break;
}
if (nMax<data.length) result[nMax]=data[nMax];
for(var i=nMax+1,j=2;i<data.length && j<n;++i,++j)
{
if (data[i]>=data[nMax]) nMax=i;
result[i]=data[nMax];
}
for(;i<data.length;++i)
{
if (i-nMax<n)
{
nMax=data[i]<data[nMax]?nMax:i;
}
else
{
for(j=nMax=(i-n+2);j<=i;++j)
{
nMax=data[j]<data[nMax]?nMax:j;
}
}
result[i]=data[nMax];
}
}
return result;
}
/*
LLV 最低值
求最低值。
用法: LLV(X,N) 求N周期内X最低值,N=0则从第一个有效值开始。
例如: LLV(LOW,0) 表示求历史最低价。
*/
this.LLV=function(data,n)
{
var result = [];
if (Array.isArray(n))
{
for(var i=0;i<data.length;++i)
{
result[i]=null;
if (i>=n.length) continue;
var min=null;
var count=n[i];
if (count>0 && count<=i)
{
for(var j=i-count;j<=i;++j)
{
if (min==null || min>data[j]) min=data[j];
}
}
else
{
count=i;
for(var j=0;j<=i;++j)
{
if (min==null || min>data[j]) min=data[j];
}
}
result[i]=min;
}
}
else
{
if (n>data.length) return result;
if (n<=0) n=data.length-1;
var min=null;
for(var i=n;i<data.length;++i,++j)
{
if(min==null || i<n+min) //最小值是否在当前周期里面
{
min=data[i]>data[min]?min:i;
}
else
{
for(var j=(min=i-n+1)+1;j<=i;++j)
{
if(data[j]<data[min])
min = j;
}
}
result[i] = data[min];
}
}
return result;
}
this.STD=function(data,n)
{
var result=[];
var total=0;
var averageData=[]; //平均值
for(var i=n-1;i<data.length;++i)
{
total=0;
for(var j=0;j<n;++j)
{
total+=data[i-j];
}
averageData[i]=total/n;
}
for(var i=n-1;i<data.length;++i)
{
total=0;
for(var j=0;j<n;++j)
{
total+=Math.pow((data[i-j]-averageData[i]),2);
}
result[i]=Math.sqrt(total/n);
}
return result;
}
//平均绝对方差
this.AVEDEV=function(data,n)
{
var result=[];
var total=0;
var averageData=[]; //平均值
for(var i=n-1;i<data.length;++i)
{
total=0;
for(var j=0;j<n;++j)
{
total+=data[i-j];
}
averageData[i]=total/n;
}
for(var i=n-1;i<data.length;++i)
{
total=0;
for(var j=0;j<n;++j)
{
total+=Math.abs(data[i-j]-averageData[i]);
}
result[i]=total/n;
}
return result;
}
//上穿
this.CROSS=function(data,data2)
{
var result=[];
if (Array.isArray(data) && Array.isArray(data2))
{
if (data.length!=data2.length) return result=[];
var index=0;
for(;index<data.length;++index)
{
if (this.IsNumber(data[index]) && this.IsNumber(data2[index]))
break;
}
for(++index;index<data.length;++index)
{
result[index]= (data[index]>data2[index] && data[index-1]<data2[index-1]) ? 1:0;
}
}
else if (Array.isArray(data) && typeof(data2)=='number')
{
var index=0;
for(;index<data.length;++index)
{
if (this.IsNumber(data[index])) break;
}
for(++index;index<data.length;++index)
{
result[index]= (data[index]>data2 && data[index-1]<data2) ? 1:0;
}
}
else if (typeof(data)=='number' && Array.isArray(data2))
{
var index=0;
for(;index<data2.length;++index)
{
if (this.IsNumber(data2[index])) break;
}
for(++index;index<data2.length;++index)
{
result[index]= (data2[index]<data && data2[index-1]>data) ? 1:0;
}
}
return result;
}
//累乘
this.MULAR=function(data,n)
{
var result=[];
if(data.length<n) return result;
var index=n;
for(;index<data.length;++index)
{
if (data[index]!=null && !isNaN(data[index]))
{
result[index]=data[index];
break;
}
}
for(++index;index<data.length;++index)
{
result[index]=result[index-1]*data[index];
}
return result;
}
this.SUM=function(data,n)
{
var result=[];
if (!Array.isArray(n))
{
if (n==0)
{
result[0]=data[0];
for (var i=1; i<data.length; ++i)
{
result[i] = result[i-1]+data[i];
}
}
else
{
for(var i=n-1,j=0;i<data.length;++i,++j)
{
for(var k=0;k<n;++k)
{
if (k==0) result[i]=data[k+j];
else result[i]+=data[k+j];
}
}
}
}
else
{
for(var i=0;i<data.length;++i)
{
result[i]=null;
var totalCount=n[i];
if (!(totalCount>0)) continue;
for(var j=i, k=0 ;j>=0 && k<totalCount ;--j,++k)
{
if (k==0) result[i]=data[j];
else result[i]+=data[j];
}
}
}
return result;
}
/*
BARSCOUNT 有效数据周期数
求总的周期数。
用法: BARSCOUNT(X) 第一个有效数据到当前的天数。
例如: BARSCOUNT(CLOSE) 对于日线数据取得上市以来总交易日数,对于分笔成交取得当日成交笔数,对于1分钟线取得当日交易分钟数。
*/
this.BARSCOUNT=function(data)
{
let result=[];
let days=null;
for(let i in data)
{
result[i]=0;
if (days==null)
{
if (!this.IsNumber(data[i])) continue;
days=0;
}
result[i]=days;
++days;
}
return result;
}
//DEVSQ 数据偏差平方和
//DEVSQ(X,N) 返回数据偏差平方和。
this.DEVSQ=function(data,n)
{
var result=[];
if (typeof(n)!='number') n=parseInt(n); //字符串的转成数值型
var num = n;
var datanum = data.length;
var i = 0, j = 0, k = 0;
var E = 0, DEV = 0;
for(i = 0; i < datanum && !this.isNumber(data[i]); ++i)
{
result[i] = null;
}
if (num < 1 || i+num>datanum) 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<data.length;++i,++start)
{
result[i]=null;
if (this.IsNumber(data[i])) break;
}
let x,y,xy,xx;
for(let i=start+n-1;i<data.length;++i)
{
result[i]=null;
x=y=xy=xx=0;
for(var j=0;j<n && j<=i; ++j)
{
x+=(i-j); //数据索引相加
y+=data[i-j]; //数据相加
}
x=x/n; y=y/n;
for(j=0;j<n && j<=i; ++j)
{
xy+=(i-j-x)*(data[i-j]-y);
xx+=(i-j-x)*(i-j-x);
}
if (xx) result[i]= xy/xx;
else if (i) result[i]=result[i-1];
}
return result;
}
//STDP 总体标准差
//STDP(X,N) 返回总体标准差。
this.STDP=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, 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 A<C;
this.RANGE=function(data,range,range2)
{
let isNumber=typeof(data)=='number';
let isNumber2=typeof(range)=='number';
let isNumber3=typeof(range2)=='number';
if (isNumber && isNumber2 && isNumber3)
{
if (data>Math.min(range,range2) && data<Math.max(range,range2)) return 1;
else return 0;
}
let result=[];
let value, rangeValue,rangValue2;
for(let i=0; i<data.length; ++i)
{
result[i]=null;
value=data[i];
if (!this.IsNumber(value)) continue;
if (!isNumber2)
{
if (i>=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) && value<Math.max(rangeValue,rangeValue2)) ? 1:0;
}
return result;
}
this.EXIST=function(data,n)
{
n=parseInt(n);
if (typeof(data)=='number') return 0;
var latestID=null; //最新满足条件的数据索引
var result=[];
var value;
for(let i=0;i<data.length;++i)
{
result[i]=null;
value=data[i];
if (this.IsNumber(value) && value>0) latestID=i;
if (latestID!=null && i-latestID<n) result[i]=1;
else result[i]=0;
}
return result;
}
this.TFILTER=function(data,data2,n)
{
n=parseInt(n);
var result=[];
let isNumber=typeof(data)=='number';
let isNumber2=typeof(range)=='number';
let count=Math.max(data.length, data2.length);
for(let i=0;i<count;++i)
{
}
return result;
}
/*
过滤连续出现的信号.
用法:FILTER(X,N):X满足条件后,将其后N周期内的数据置为0,N为常量.
例如:
FILTER(CLOSE>OPEN,5)查找阳线,5天内再次出现的阳线不被记录在内
*/
this.FILTER=function(data,n)
{
var result=[];
for(let i=0,j=0; i<data.length; ++i)
{
if (data[i])
{
result[i]=1;
for(j=0;j<n && j+i+1<data.length;++j)
{
result[j+i+1]=0;
}
i+=n;
}
else
{
result[i]=0;
}
}
return result;
}
this.BARSLAST=function(data)
{
var result=[];
if (!data) return result;
let day=null;
for(let i=0;i<data.length;++i)
{
result[i]=null;
if (data[i]>0) 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;i<data.length;++i)
{
result[i]=null;
if (day==null)
{
if (data[i]) day=0;
}
else
{
if (data[i])
{
if (day+1<n) ++day;
}
else
{
day=null;
}
}
if (day) result[i]=day;
}
return result;
}
/*
第一个条件成立到当前的周期数.
用法:
BARSSINCE(X):第一次X不为0到现在的天数
例如:
BARSSINCE(HIGH>10)表示股价超过10元时到当前的周期数
*/
this.BARSSINCE=function(data)
{
var result=[];
var day=null;
for(let i=0;i<data.length;++i)
{
result[i]=null;
if (day==null)
{
if (data[i]) day=0;
}
else
{
++day;
}
if (day) result[i]=day;
}
return result;
}
/*三角函数调用 func 三角函数
反正切值. 用法: ATAN(X)返回X的反正切值
反余弦值. 用法: ACOS(X)返回X的反余弦值
反正弦值. 用法: ASIN(X)返回X的反正弦值
余弦值. 用法: COS(X)返回X的余弦值
正弦值. 用法: SIN(X)返回X的正弦值
正切值. 用法: TAN(X)返回X的正切值
求自然对数. 用法: LN(X)以e为底的对数 例如: LN(CLOSE)求收盘价的对数
求10为底的对数. 用法: LOG(X)取得X的对数 例如: LOG(100)等于2
指数. 用法: EXP(X)为e的X次幂 例如: EXP(CLOSE)返回e的CLOSE次幂
开平方. 用法: SQRT(X)为X的平方根 例如: SQRT(CLOSE)收盘价的平方根
*/
this.Trigonometric=function(data,func)
{
if (!Array.isArray(data))
{
if (this.IsNumber(data)) return func(data);
return null;
}
else
{
var result=[];
for(let i in data)
{
var item=data[i];
if (this.IsNumber(item)) result[i]=func(item);
else result[i]=null;
}
return result;
}
}
/*
LAST(X,A,B):持续存在.
用法:
LAST(CLOSE>OPEN,10,5)
表示从前10日到前5日内一直阳线
若A为0,表示从第一天开始,B为0,表示到最后日止
*/
this.LAST=function(data,n,n2)
{
var result=[];
if (n2<=0) n2=data.length-1;
if (n2>n) return result;
var day=0;
for(let i=0,j=0;i<data.length;++i)
{
result[i]=0;
day=0;
var start=i-n;
var end=i-n2;
if (start<0 || end<0) continue;
for(j=start;j<data.length && j<=end;++j,++day)
{
if (!data[j]) break;
}
if (day==end-start+1) //[start,end]
result[i]=1;
}
return result;
}
/*
属于未来函数,之字转向.
用法: ZIG(K,N),当价格变化量超过N%时转向,K表示0:开盘价,1:最高价,2:最低价,3:收盘价,其余:数组信息
例如: ZIG(3,5)表示收盘价的5%的ZIG转向
*/
this.ZIG=function(data,n)
{
var hisData=this.SymbolData.Data;
var result=[];
if (typeof(data)=='number')
{
switch(data)
{
case 0:
data=hisData.GetOpen();
break;
case 1:
data=hisData.GetHigh();
break;
case 2:
data=hisData.GetLow();
break;
case 3:
data=hisData.GetClose();
break;
default:
return result;
}
}
var bFirstPoint=false;
var bSecondPont=false;
var firstData={}, secondData={}, thridData={};
var lastData={};
for(let i in data)
{
result[i]=null;
var item=data[i];
if (!this.IsNumber(item)) continue;
if (bFirstPoint==false)
{
bFirstPoint=true;
firstData={ID:parseInt(i), Value:item}; //第1个点
}
else if (bFirstPoint==true && bSecondPont==false)
{
var temp=(item-firstData.Value)/firstData.Value*100;
if (temp>n)
{
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 (item<lastData.Value) lastData={ID:parseInt(i), Value:item};
}
}
}
}
//计算最后1组数据
thridData={ID:data.length-1, Value:data[data.length-1], Up:!secondData.Up};
this.CalculateZIGLine(firstData,secondData,thridData,data,result);
return result;
}
this.JSDraw=null;
this.CalculateZIGLine=function(firstData,secondData,thridData,data,result)
{
if (this.JSDraw==null) this.JSDraw=new JSDraw(this.ErrorHandler);
var isUp=secondData.Up;
var findData=firstData;
if (isUp)
{
for(var i=firstData.ID+1;i<thridData.ID;++i) //查找最高点
{
var subItem=data[i];
if (!this.IsNumber(subItem)) continue;
if (findData.Value<subItem) findData={ID:i, Value:subItem};
}
}
else
{
for(var i=firstData.ID+1;i<thridData.ID;++i) //查找最低点
{
var subItem=data[i];
if (!this.IsNumber(subItem)) continue;
if (findData.Value>subItem) findData={ID:i, Value:subItem};
}
}
secondData.Value=findData.Value;
secondData.ID=findData.ID;
var lineCache={ Start:{ID:firstData.ID, Value:firstData.Value}, End:{ID:secondData.ID,Value:secondData.Value}};
var lineData=this.JSDraw.CalculateDrawLine(lineCache);//计算2个点的线上 其他点的数值
for(var i in lineData)
{
var lineItem=lineData[i];
result[lineItem.ID]=lineItem.Value;
}
if (thridData.ID==data.length-1) //最后一组数据
{
//最后2个点的数据连成线
lineCache={ Start:{ID:secondData.ID, Value:secondData.Value}, End:{ID:thridData.ID,Value:thridData.Value} };
lineData=this.JSDraw.CalculateDrawLine(lineCache);//计算2个点的线上 其他点的数值
for(var i in lineData)
{
var lineItem=lineData[i];
result[lineItem.ID]=lineItem.Value;
}
}
else
{
firstData.ID=secondData.ID;
firstData.Value=secondData.Value;
secondData.ID=thridData.ID;
secondData.Value=thridData.Value;
secondData.Up=firstData.Value < secondData.Value;
}
}
/*
属于未来函数,前M个ZIG转向波谷到当前距离.
用法:
TROUGHBARS(K,N,M)表示之字转向ZIG(K,N)的前M个波谷到当前的周期数,M必须大于等于1
例如:
TROUGHBARS(2,5,2)表示%5最低价ZIG转向的前2个波谷到当前的周期数
*/
this.TROUGHBARS=function(data,n,n2)
{
var zigData=this.ZIG(data,n); //计算ZIG
var i=0,result=[];
for(i=0;i<zigData.length;++i)
{
result[i]=null;
if (this.IsNumber(zigData[i])) break;
}
var trough=[];
var start=i,j=0;
for(;i<zigData.length;++i) //第1个波谷
{
if (i+1<zigData.length && i-1>=0 && zigData[i]<zigData[i-1] && zigData[i]<zigData[i+1]) //波谷
{
trough[0]=i;
break;
}
}
for(i+=1;i<zigData.length;++i)
{
result[i]=null;
if (i+1<zigData.length && i-1>=0 && zigData[i]<zigData[i-1] && zigData[i]<zigData[i+1]) //波谷
{
JSConsole.Complier.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;
}
/*
属于未来函数,前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<zigData.length;++i)
{
result[i]=null;
if (this.IsNumber(zigData[i])) break;
}
var trough=[];
var start=i,j=0;
for(;i<zigData.length;++i) //第1个波峰
{
if (i+1<zigData.length && i-1>=0 && zigData[i]>zigData[i-1] && zigData[i]>zigData[i+1]) //波峰
{
trough[0]=i;
break;
}
}
for(i+=1;i<zigData.length;++i)
{
result[i]=null;
if (i+1<zigData.length && i-1>=0 && zigData[i]>zigData[i-1] && zigData[i]>zigData[i+1]) //波峰
{
JSConsole.Complier.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<data.length;++i)
{
result[i]=null;
if (this.IsNumber(data[i])) break;
}
var flag=0;
for(;i<data.length;++i)
{
if (data[i]) flag+=1;
else flag=0;
if (flag==n)
{
result[i]=1;
--flag;
}
else
{
result[i]=0;
}
}
return result;
}
/*
成本分布情况.
用法:
COST(10),表示10%获利盘的价格是多少,即有10%的持仓量在该价格以下,其余90%在该价格以上,为套牢盘
该函数仅对日线分析周期有效
*/
this.COST=function(data)
{
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=parseFloat(data);
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=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 (compareData<start) profitVol=0;
else profitVol=item.Vol*(compareData-start+1)/(end-start+1);
vol+=profitVol;
totalVol+=item.Vol;
}
if (totalVol>0) 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 (max<item.High) max=item.High;
if (min==null) min=item.Low;
else if (min<item.Low) min=item.Low;
result.Data[i]=item;
seed*=(1-(exchangeData[i]/100)*dRate); //换手率累乘
}
result.Max=max;
result.Min=min;
return result;
}
/*
返回是否连涨周期数.
用法:
UPNDAY(CLOSE,M)
表示连涨M个周期,M为常量
*/
this.UPNDAY=function(data,n)
{
var result=[];
if (n<1) return result;
if (data==null || n>data.length) return result;
var days=0;
for(let i=0;i<data.length;++i)
{
result[i]=0;
if (i-1<0) continue;
if (!this.IsNumber(data[i]) || !this.IsNumber(data[i-1])) //无效数都不算连涨
{
days=0;
continue;
}
if (data[i]>data[i-1]) ++days;
else days=0;
if (days==n)
{
result[i]=1;
--days;
}
}
return result;
}
/*
返回是否连跌周期.
用法:
DOWNNDAY(CLOSE,M)
表示连跌M个周期,M为常量
*/
this.DOWNNDAY=function(data,n)
{
var result=[];
if (n<1) return result;
if (data==null || n>data.length) return result;
var days=0;
for(let i=0;i<data.length;++i)
{
result[i]=0;
if (i-1<0) continue;
if (!this.IsNumber(data[i]) || !this.IsNumber(data[i-1])) //无效数都不算连涨
{
days=0;
continue;
}
if (data[i]<data[i-1]) ++days;
else days=0;
if (days==n)
{
result[i]=1;
--days;
}
}
return result;
}
/*
返回是否持续存在X>Y
用法:
NDAY(CLOSE,OPEN,3)
表示连续3日收阳线
*/
this.NDAY=function(data,data2,n)
{
var result=[];
if (n<1) return result;
if (!Array.isArray(data) && !Array.isArray(data2)) return result;
if (data==null || data2==null ) return result;
if (Array.isArray(data) && Array.isArray(data2))
{
if (n>=data.length || n>=data2.length) return result;
var count=Math.max(data.length,data2.length);
var days=0;
for(let i=0;i<count;++i)
{
result[i]=0;
if (i>=data.length || i>=data2.length) continue;
if (!this.IsNumber(data[i]) || !this.IsNumber(data2[i]))
{
days=0;
continue;
}
if (data[i]>data2[i]) ++days;
else days=0;
if (days==n)
{
result[i]=1;
--days;
}
}
}
else if (Array.isArray(data) && !Array.isArray(data2))
{
if (n>=data.length || !this.IsNumber(data2)) return;
var days=0;
for(let i in data)
{
result[i]=0;
if (!this.IsNumber(data[i]))
{
days=0;
continue;
}
if (data[i]>data2) ++days;
else days=0;
if (days==n)
{
result[i]=1;
--days;
}
}
}
else if (!Array.isArray(data) && Array.isArray(data2))
{
if (n>=data2.length || !this.IsNumber(data)) return;
var days=0;
for(let i in data2)
{
result[i]=0;
if (!this.IsNumber(data2[i]))
{
days=0;
continue;
}
if (data>data2[i]) ++days;
else days=0;
if (days==n)
{
result[i]=1;
--days;
}
}
}
return result;
}
/*
两条线维持一定周期后交叉.
用法:LONGCROSS(A,B,N)表示A在N周期内都小于B,本周期从下方向上穿过B时返回1,否则返回0
*/
this.LONGCROSS=function(data,data2,n)
{
var result=[];
var count=Math.max(data.length,data2.length);
for(let i=0;i<count;++i)
{
result[i]=0;
if (i-1<0) continue;
if (i>=data.length || i>=data2.length) continue;
if (!this.IsNumber(data[i]) || !this.IsNumber(data2[i]) || !this.IsNumber(data[i-1]) || !this.IsNumber(data2[i-1])) continue;
if (data[i]>data2[i] && data[i-1]<data2[i-1]) result[i]=1;
}
for(let i=0,j=0;i<count;++i)
{
if (!result[i]) continue;
for(j=1;j<=n && i-j>=0;++j)
{
if (data[i-j]>=data2[i-j])
{
result[i]=0;
break;
}
}
}
return result;
}
/*
EXISTR(X,A,B):是否存在(前几日到前几日间).
例如: EXISTR(CLOSE>OPEN,10,5)
表示从前10日内到前5日内存在着阳线
若A为0,表示从第一天开始,B为0,表示到最后日止
*/
this.EXISTR=function(data,n,n2)
{
var result=[];
if (!Array.isArray(data)) return result;
n=parseInt(n);
n2=parseInt(n2);
if (n<=0) n=data.length;
if (n2<=0) n2=1;
if (n2>n) return result;
var result=[];
var value;
for(let i=0,j=0;i<data.length;++i)
{
result[i]=null;
if (i-n<0 || i-n2<0) continue;
result[i]=0;
for(j=n;j>=n2;--j)
{
var value=data[i-j];
if (this.IsNumber(value) && value)
{
result[i]=1;
break;
}
}
}
return result;
}
/*
RELATE(X,Y,N) 返回X和Y的N周期的相关系数
RELATE(X,Y,N)=(∑[(Xi-Avg(X))(Yi-Avg(y))])/N ÷ √((∑(Xi-Avg(X))^2)/N * (∑(Yi-Avg(Y))^2)/N)
其中 avg(x)表示x的N周期均值: avg(X) = (∑Xi)/N
√(...)表示开平方
*/
this.RELATE=function(data,data2,n)
{
var result=[];
if (n<1) n=1;
if (!Array.isArray(data)|| !Array.isArray(data2)) return result;
var dataAverage=this.CalculateAverage(data,n);
var data2Average=this.CalculateAverage(data2,n);
var count=Math.max(data.length,data2.length);
for(let i=0,j=0;i<count;++i)
{
result[i]=null;
if (i>=data.length || i>=data2.length || i>=dataAverage.length || i>=data2Average.length) continue;
var average=dataAverage[i];
var average2=data2Average[i];
var total=0,total2=0,total3=0;
for(j=i-n+1;j<=i;++j)
{
total+=(data[j]-average)*(data2[j]-average2); //∑[(Xi-Avg(X))(Yi-Avg(y))])
total2+=Math.pow(data[j]-average,2); //∑(Xi-Avg(X))^2
total3+=Math.pow(data2[j]-average2,2); //∑(Yi-Avg(Y))^2)
}
result[i]=(total/n)/(Math.sqrt(total2/n)*Math.sqrt(total3/n));
}
return result;
}
//计算数组n周期内的均值
this.CalculateAverage=function(data,n)
{
var result=[];
if (n<1) return result;
var total=0;
for(var i=0;i<data.length;++i) //去掉开始的无效数
{
if (this.IsNumber(data[i])) break;
}
for(;i<data.length && i<n;++i) //计算第1个周期的数据
{
result[i]=null;
var value=data[i];
if (!this.IsNumber(value)) continue;
total+=value;
}
result[i-1]=total/n;
for(;i<data.length;++i) //计算后面的周期数据
{
var value=data[i];
var preValue=data[i-n]; //上一个周期的第1个数据
if (!this.IsNumber(value)) value=0;
if (!this.IsNumber(preValue)) preValue=0;
total=total-preValue+value; //当前周期的数据 等于上一个周期数据 去掉上一个周期的第1个数据 加上这个周期的最后1个数据
result[i]=total/n;
}
return result;
}
/*
COVAR(X,Y,N) 返回X和Y的N周期的协方差
*/
this.COVAR=function(data,data2,n)
{
var result=[];
if (n<1) n=1;
if (!Array.isArray(data)|| !Array.isArray(data2)) return result;
var dataAverage=this.CalculateAverage(data,n);
var data2Average=this.CalculateAverage(data2,n);
var count=Math.max(data.length,data2.length);
var count=Math.max(data.length,data2.length);
for(let i=0,j=0;i<count;++i)
{
result[i]=null;
if (i>=data.length || i>=data2.length || i>=dataAverage.length || i>=data2Average.length) continue;
var average=dataAverage[i];
var average2=data2Average[i];
var total=0;
for(j=i-n+1;j<=i;++j)
{
total+=(data[j]-average)*(data2[j]-average2);
}
result[i]=(total/n);
}
return result;
}
/*
求上一高点到当前的周期数.
用法:
HHVBARS(X,N):求N周期内X最高值到当前周期数,N=0表示从第一个有效值开始统计
例如:
HHVBARS(HIGH,0)求得历史新高到到当前的周期数
*/
this.HHVBARS=function(data,n)
{
var result=[];
if (!Array.isArray(data)) return result;
if (n<1) n=data.length;
var nMax=null; //最大值索引
for(var i=0;i<data.length;++i)
{
result[i]=null;
if (this.IsNumber(data[i]))
{
nMax=i;
break;
}
}
var j=0;
for(i=nMax+1;i<data.length && j<n ;++i,++j) //求第1个最大值
{
if (data[i]>=data[nMax]) nMax=i;
if(n==data.length) result[i]=(i-nMax);
}
for(;i<data.length;++i)
{
if (i-nMax<n)
{
if (data[i]>=data[nMax]) nMax=i;
}
else
{
nMax=i-n+1;
for(j=nMax;j<=i;++j) //计算区间最大值
{
if (data[j]>=data[nMax]) nMax=j;
}
}
result[i]=i-nMax;
}
return result;
}
/*
求上一低点到当前的周期数.
用法: LLVBARS(X,N):求N周期内X最低值到当前周期数,N=0表示从第一个有效值开始统计
例如: LLVBARS(HIGH,20)求得20日最低点到当前的周期数
*/
this.LLVBARS=function(data,n)
{
var result=[];
if (!Array.isArray(data)) return result;
if (n<1) n=data.length;
var nMin=null; //最小值索引
for(var i=0;i<data.length;++i)
{
result[i]=null;
if (this.IsNumber(data[i]))
{
nMin=i;
break;
}
}
var j=0;
for(i=nMin+1;i<data.length && j<n ;++i,++j) //求第1个最大值
{
if (data[i]<=data[nMin]) nMin=i;
if(n==data.length) result[i]=(i-nMin);
}
for(;i<data.length;++i)
{
if (i-nMin<n)
{
if (data[i]<=data[nMin]) nMin=i;
}
else
{
nMin=i-n+1;
for(j=nMin;j<=i;++j) //计算区间最小值
{
if (data[j]<=data[nMin]) nMin=j;
}
}
result[i]=i-nMin;
}
return result;
}
/*
β(Beta)系数
BETA(N) 返回当前证券N周期收益与对应大盘指数收益相比的贝塔系数
需要下载上证指数历史数据
涨幅(X)=(现价-上一个交易日收盘价)/上一个交易日收盘价
公式=股票和指数协方差/指数方差
*/
this.BETA=function(n)
{
var result=[];
var stockData= this.SymbolData.Data;
var indexData=this.SymbolData.IndexData;
if (n<=0) n=1;
var stockProfit=[]; //股票涨幅
var indexProfit=[]; //指数涨幅
for(let i=0;i<stockData.Data.length;++i)
{
stockProfit[i]=0;
indexProfit[i]=0;
var stockItem=stockData.Data[i];
var indexItem=indexData.Data[i];
if (stockItem.Close>0 && stockItem.YClose>0) stockProfit[i]=(stockItem.Close-stockItem.YClose)/stockItem.YClose;
if (indexItem.Close>0 && indexItem.YClose>0) indexProfit[i]=(indexItem.Close-indexItem.YClose)/indexItem.YClose;
}
//计算均值数组
var averageStockProfit=this.CalculateAverage(stockProfit,n);
var averageIndexProfit=this.CalculateAverage(indexProfit,n);
for(var i=0,j=0;i<stockData.Data.length;++i)
{
result[i]=null;
if (i>=stockProfit.length || i>=indexProfit.length || i>=averageStockProfit.length || i>=averageIndexProfit.length) continue;
var averageStock=averageStockProfit[i];
var averageIndex=averageIndexProfit[i];
var covariance=0; //协方差
var variance=0; //方差
for(j=i-n+1;j<=i;++j)
{
var value=(indexProfit[j]-averageIndex);
var value2=(stockProfit[j]-averageStock);
covariance+=value*value2;
variance+=value*value;
}
if (this.IsDivideNumber(variance) && this.IsNumber(covariance))
result[i]=covariance/variance; //(covariance/n)/(variance/n)=covariance/variance;
}
return result;
}
/*
用法:BETA2(X,Y,N)为X与Y的N周期相关放大系数,表示Y变化1%,则X将变化N%
例如:BETA2(CLOSE,INDEXC,10)表示收盘价与大盘指数之间的10周期相关放大率
*/
this.BETA2=function(x,y,n)
{
var result=[];
if (n<=0) n=1;
var xProfit=[null]; //x数据的涨幅
var yProfit=[null]; //y数据的涨幅
var count=Math.max(x.length,y.length);
var lastItem={X:x[0], Y:y[0]};
for(var i=1;i<count;++i)
{
xProfit[i]=0;
yProfit[i]=0;
var xItem=x[i];
var yItem=y[i];
if (lastItem.X>0) xProfit[i]=(xItem-lastItem.X)/lastItem.X;
if (lastItem.Y>0) yProfit[i]=(yItem-lastItem.Y)/lastItem.Y;
lastItem={X:xItem, Y:yItem};
}
//计算均值数组
var averageXProfit=this.CalculateAverage(xProfit,n);
var averageYProfit=this.CalculateAverage(yProfit,n);
for(var i=0,j=0;i<count;++i)
{
result[i]=null;
if (i>=xProfit.length || i>=yProfit.length || i>=averageXProfit.length || i>=averageYProfit.length) continue;
var averageX=averageXProfit[i];
var averageY=averageYProfit[i];
var covariance=0; //协方差
var variance=0; //方差
for(j=i-n+1;j<=i;++j)
{
var value=(xProfit[j]-averageX);
var value2=(yProfit[j]-averageY);
covariance+=value*value2;
variance+=value*value;
}
if (this.IsDivideNumber(variance) && this.IsNumber(covariance))
result[i]=covariance/variance; //(covariance/n)/(variance/n)=covariance/variance;
}
return result;
}
/*
抛物转向.
用法:
SAR(N,S,M),N为计算周期,S为步长,M为极值
例如:
SAR(10,2,20)表示计算10日抛物转向,步长为2%,极限值为20%
*/
this.SAR=function(n,step,exValue)
{
var result=[];
var stockData= this.SymbolData.Data;
if (n>=stockData.Data.length) return result;
var high=null,low=null;
for(var i=0;i<n;++i)
{
var item=stockData.Data[i];
if (high==null) high=item.High;
else if (high<item.High) high=item.High;
if (low==null) low=item.Low;
else if (low>item.Low) low=item.Low;
}
const SAR_LONG=0, SAR_SHORT=1;
var position=SAR_LONG;
result[n-1]=low;
var nextSar=low, sip=stockData.Data[0].High,af=step/100;
for(var i=n;i<stockData.Data.length;++i)
{
var ysip=sip;
var item=stockData.Data[i];
var yitem=stockData.Data[i-1];
if (position==SAR_LONG)
{
if (item.Low<result[i-1])
{
position=SAR_SHORT;
sip=item.Low;
af=step/100;
nextSar =Math.max(item.High,yitem.High);
nextSar =Math.max(nextSar,ysip+af*(sip-ysip));
}
else
{
position = SAR_LONG;
if(item.High>ysip)
{
sip=item.High;
af=Math.min(af+step/100,exValue/100);
}
nextSar=Math.min(item.Low,yitem.Low);
nextSar=Math.min(nextSar,result[i-1]+af*(sip-result[i-1]));
}
}
else if (position==SAR_SHORT)
{
if(item.High>result[i-1])
{
position=SAR_LONG;
sip=item.High;
af=step/100;
nextSar =Math.min(item.Low,yitem.Low);
nextSar =Math.min(nextSar,result[i-1]+af*(sip-ysip));
}
else
{
position = SAR_SHORT;
if(item.Low<ysip)
{
sip=item.Low;
af=Math.min(af+step/100,exValue/100);
}
nextSar=Math.max(item.High,yitem.High);
nextSar=Math.max(nextSar,result[i-1]+af*(sip-result[i-1]));
}
}
result[i]=nextSar;
}
return result;
}
/*
抛物转向点.
用法:
SARTURN(N,S,M),N为计算周期,S为步长,M为极值,若发生向上转向则返回1,若发生向下转向则返回-1,否则为0
其用法与SAR函数相同
*/
this.SARTURN=function(n,step,exValue)
{
var result=[];
var sar=this.SAR(n,step,exValue);
var stockData= this.SymbolData.Data;
var index=0;
for(index=0;index<sar.length;++index)
{
if (this.IsNumber(sar[index])) break;
}
var flag=0;
if (index<stockData.Data.length) flag=stockData.Data[index].Close>sar[index];
for(var i=index+1;i<stockData.Data.length;++i)
{
var item=stockData.Data[i];
if (item.Close<sar[i] && flag) result[i]=-1;
else result[i]= (item.Close>sar[i] && !flag)? 1:0;
flag=item.Close>sar[i];
}
return result;
}
/*
属于未来函数,将当前位置到若干周期前的数据设为1.
用法:
BACKSET(X,N),若X非0,则将当前位置到N周期前的数值设为1.
例如:
BACKSET(CLOSE>OPEN,2)若收阳则将该周期及前一周期数值设为1,否则为0
*/
this.BACKSET=function(condition,n)
{
var result=[];
if (!condition) return result;
var dataCount=condition.length;
if (!this.IsNumber(dataCount) || dataCount<=0) return result;
for(var i=0;i<dataCount;++i) //初始化0
{
result[i]=0;
}
for(var pos=0;pos<dataCount;++pos)
{
if (this.IsNumber(condition[pos])) break;
}
if (pos==dataCount) return result;
var num=Math.min(dataCount-pos,Math.max(n,1));
for(var i=dataCount-1,j=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 (i<data.length-1) left=data[i];
if (isNumber3) right=data2;
else if (i<data2.length-1) right=data2[i];
if (left==null || right==null) continue;
if (left>right)
{
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;
}
////////////////////////////////////////////////////////////////////////
// 跨周期函数COVER_C(), COVER_O(), COVER_H(), COVER_L(), COVER_A(), COVER_V()
this.CoverPeriod=function(name, periodName,n)
{
var periodInfo=this.GetPeriodInfo({Name:periodName});
if (!periodInfo) return null;
var curPeriodInfo=this.GetPeriodInfo({PeriodID:this.SymbolData.Data.Period});
if (!curPeriodInfo) return null;
if (curPeriodInfo.Order>curPeriodInfo.Order) return null; //只能小周期转大周期
var result;
if (curPeriodInfo.Period==periodInfo.Period)
{
result=this.SymbolData.Data;
}
else
{
var hisData;
if (ChartData.IsMinutePeriod(curPeriodInfo.Period,true) && ChartData.IsDayPeriod(periodInfo.Period,true))
{
if (periodInfo.Period==0) hisData=this.SymbolData.DayData.Data; //日线直接用
else hisData=this.SymbolData.DayData.GetPeriodData(periodInfo.Period); //分钟数据不复权 直接算周期就可以了
}
else
{
var bindData=new ChartData();
bindData.Data=this.SymbolData.SourceData.Data;
bindData.Period=this.SymbolData.Period;
bindData.Right=this.SymbolData.Right;
if (ChartData.IsDayPeriod(periodInfo.Period,true) && bindData.Right>0) //日线数据才复权
{
var rightData=bindData.GetRightData(bindData.Right);
bindData.Data=rightData;
}
hisData=bindData.GetPeriodData(periodInfo.Period);
}
var data=this.SymbolData.Data.CoverTo(hisData, curPeriodInfo.Period, periodInfo.Period);
result=new ChartData();
result.Data=data;
}
if (IFrameSplitOperator.IsPlusNumber(n))
{
var refResult=new ChartData();
var data=result.GetRef(n);
refResult.Data=data;
result=refResult;
}
switch(name)
{
case 'COVER_C':
return result.GetClose();
case 'COVER_O':
return result.GetOpen();
case 'COVER_H':
return result.GetHigh();
case 'COVER_L':
return result.GetLow();
case 'COVER_A':
return result.GetAmount();
case 'COVER_V':
return result.GetVol();
default:
return null;
}
}
this.MOD=function(data, data2)
{
var result=[];
let isNumber=typeof(data)=='number';
let isNumber2=typeof(data2)=='number';
//单数值
if (isNumber && isNumber2)
{
return JSAlgorithm.MOD(data,data2);
}
else if (!isNumber && !isNumber2) //都是数组相加
{
let count=Math.max(data.length, data2.length);
for(let i=0;i<count;++i)
{
result[i]=null; //初始化
if (i<data.length && i<data2.length)
{
if ( this.IsNumber(data[i]) && this.IsNumber(data2[i]) ) result[i]=JSAlgorithm.MOD(data[i],data2[i]);
}
}
return result;
}
else if (isNumber && !isNumber2) //单数字 数组
{
for(var i in data2)
{
result[i]=null;
if (this.IsNumber(data) && this.IsNumber(data2[i])) result[i]=JSAlgorithm.MOD(data,data2[i]);
}
return result;
}
else if (!isNumber && isNumber2) //数组 单数字
{
for(var i in data)
{
result[i]=null;
if (this.IsNumber(data[i]) && this.IsNumber(data2)) result[i]=JSAlgorithm.MOD(data[i],data2);
}
return result;
}
return result;
}
this.POW=function(data, n)
{
var result=[];
if (!IFrameSplitOperator.IsNumber(n)) return result;
let isNumber=typeof(data)=='number';
if (isNumber) return Math.pow(data,n);
for(var i in data)
{
var item=data[i];
if (IFrameSplitOperator.IsNumber(item)) result[i]=Math.pow(item,n);
else result[i]=null;
}
return result;
}
this.CEILING=function(data)
{
let isNumber=typeof(data)=='number';
if (isNumber) return parseInt(data);
var result=[];
for(var i in data)
{
var item=data[i];
if (IFrameSplitOperator.IsNumber(item)) result[i]=parseInt(item);
else result[i]=null;
}
return result;
}
this.FLOOR=function(data)
{
let isNumber=typeof(data)=='number';
if (isNumber) return parseInt((data-1));
var result=[];
for(var i in data)
{
var item=data[i];
if (IFrameSplitOperator.IsNumber(item)) result[i]=parseInt((item-1));
else result[i]=null;
}
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 'COVER_C':
case 'COVER_O':
case 'COVER_H':
case 'COVER_L':
case 'COVER_A':
case 'COVER_V':
if (args.length==2) return this.CoverPeriod(name,args[0],args[1]);
return this.CoverPeriod(name,args[0]);
case 'MOD':
return this.MOD(args[0],args[1]);
case 'POW':
return this.POW(args[0],args[1]);
case 'CEILING':
return this.CEILING(args[0]);
case 'FLOOR':
return this.FLOOR(args[0]);
//三角函数
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.GetPeriodInfo=function(obj) //{Name:周期名字 PeriodID:周期ID}
{
const PERIOD_LIST=
[
{Name:'MIN1', Period:4, Order:1},
{Name:'MIN5', Period:5, Order:2},
{Name:'MIN15', Period:6, Order:3},
{Name:'MIN30', Period:7, Order:4},
{Name:'MIN60', Period:8, Order:5},
{Name:'DAY', Period:0, Order:1000},
{Name:'WEEK', Period:1, Order:1001},
{Name:'MONTH', Period:2, Order:1002},
{Name:"YEAR", Period:3, Order:1003}
];
if (obj.Name)
{
for(var i in PERIOD_LIST)
{
if (obj.Name && PERIOD_LIST[i].Name==obj.Name)
return PERIOD_LIST[i];
}
return null;
}
if (IFrameSplitOperator.IsNumber(obj.PeriodID))
{
for(var i in PERIOD_LIST)
{
if (PERIOD_LIST[i].Period==obj.PeriodID)
return PERIOD_LIST[i];
}
return null;
}
return null;
}
//是否有是有效的数字
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;
}
//取模
JSAlgorithm.MOD=function(number,divisor)
{
if( (number < 0 && divisor < 0) || (number >=0 && divisor >= 0)) //同号
{
if(parseInt(number) == number && parseInt(divisor) == divisor) //全为整数
{
return number%divisor;
}
else //被除数-(整商×除数)之后在第一位小数位进行四舍五入
{
var value = parseFloat((number - (Math.floor(number/divisor) * divisor)).toFixed(1));
return value;
}
}
else //异号
{
var absNumber = Math.abs(number); //绝对值
var absDivisor = Math.abs(divisor); //绝对值
var value = Math.abs(Math.abs(divisor) * (Math.floor(absNumber/absDivisor) + 1) - Math.abs(number));
if(divisor < 0) value = -value
return value;
}
}
/*
绘图函数
*/
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;i<count;++i)
{
drawData[i]=null;
if (i<condition.length && i<condition2.length)
{
if (bFirstPoint==false && bSecondPont==false)
{
if (condition[i]==null || !condition[i]) continue;
bFirstPoint=true;
lineCache.Start={ID:i, Value:data[i]}; //第1个点
}
else if (bFirstPoint==true && bSecondPont==false)
{
var bCondition2=(condition2[i]!=null && condition2[i]); //条件2
if (!bCondition2) continue;
if (bCondition2)
{
bSecondPont=true;
lineCache.End={ID:i, Value:data2[i]}; //第2个点
}
}
if (bFirstPoint==true && bSecondPont==true)
{
let lineData=this.CalculateDrawLine(lineCache); //计算2个点的线上 其他点的数值
for(let j in lineData)
{
let item=lineData[j];
drawData[item.ID]=item.Value;
}
bFirstPoint=bSecondPont=false;
lineCache={Start:{ },End:{ }};
}
}
}
return result;
}
/*
画出带状线.
用法: DRAWBAND(VAL1,COLOR1,VAL2,COLOR2),当VAL1>VAL2时,在VAL1和VAL2之间填充COLOR1;当VAL1<VAL2时,填充COLOR2,这里的颜色均使用RGB函数计算得到.
例如: DRAWBAND(OPEN,RGB(0,224,224),CLOSE,RGB(255,96,96));
*/
this.DRAWBAND=function(data,color,data2,color2)
{
let drawData=[];
let result={DrawData:drawData, DrawType:'DRAWBAND', Color:[color.toLowerCase(),color2.toLowerCase()]}; //颜色使用小写字符串
let count=Math.max(data.length, data2.length);
for(let i=0;i<count;++i)
{
let item={Value:null, Value2:null};
if (i<data.length) item.Value=data[i];
if (i<data2.length) item.Value2=data2[i];
drawData.push(item);
}
return result;
}
this.DRAWKLINE=function(high,open,low,close)
{
let drawData=[];
let result={DrawData:drawData, DrawType:'DRAWKLINE'};
let count=Math.max(high.length, open.length,low.length,close.length);
for(let i=0;i<count;++i)
{
let item={Open:null,High:null, Low:null, Close:null};
if (i<high.length && i<open.length && i<low.length && i<close.length)
{
item.Open=open[i];
item.High=high[i];
item.Low=low[i];
item.Close=close[i];
}
drawData[i]=item;
}
return result;
}
//满足条件画一根K线
this.DRAWKLINE_IF=function(condition,high,open,low,close)
{
let drawData=[];
let result={DrawData:drawData, DrawType:'DRAWKLINE_IF'};
let count=Math.max(condition.length,high.length, open.length,low.length,close.length);
for(let i=0;i<count;++i)
{
let item={Open:null,High:null, Low:null, Close:null};
if (i<high.length && i<open.length && i<low.length && i<close.length && i<condition.length)
{
if (condition[i])
{
item.Open=open[i];
item.High=high[i];
item.Low=low[i];
item.Close=close[i];
}
}
drawData[i]=item;
}
return result;
}
/*
PLOYLINE 折线段
在图形上绘制折线段。
用法: PLOYLINE(COND,PRICE),当COND条件满足时,以PRICE位置为顶点画折线连接。
例如: PLOYLINE(HIGH>=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;i<this.SymbolData.Data.Data.length;++i)
{
if (IsNumber)
{
drawData[i]=data;
}
else
{
if (i<data.length && this.IsNumber(data[i])) drawData[i]=data[i];
else drawData[i]=null;
}
}
return result;
}
for(var i in condition)
{
drawData[i]=null;
if (!condition[i]) continue;
if (IsNumber)
{
drawData[i]=data;
}
else
{
if (this.IsNumber(data[i])) drawData[i]=data[i];
}
}
return result;
}
/*
绘制通道
condition:条件
data,data2:通道顶部和底部
borderColor: 通道顶部和底部线段颜色RGB(24,30,40) 不填就不画
borderWidth: 通道顶部和底部线段宽度
areaColor: 通道面积颜色 RGB(200,30,44) 不填使用默认颜色
dotted: 通道顶部和底部虚线设置 '3,4' , 不填默认 3,3
*/
this.DRAWCHANNEL=function(condition, data, data2, borderColor, borderWidth, dotted, areaColor)
{
let drawData=[];
let result={DrawData:drawData, DrawType:'DRAWCHANNEL', Border:{ }};
if (condition.length<=0) return result;
if (borderColor) result.Border.Color=borderColor;
if (areaColor) result.AreaColor=areaColor;
if (borderWidth>0) 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;i<this.SymbolData.Data.Data.length;++i)
{
drawData[i]=null;
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]};
}
}
}
else
{
for(var i=0;i<condition.length;++i)
{
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;
}
this.RGB=function(r,g,b)
{
var rgb=`RGB(${r},${g},${b})`;
return rgb;
}
this.RGBA=function(r,g,b,a)
{
var rgba=`RGB(${r},${g},${b},${a})`;
return rgba;
}
//用法:PARTLINE(PRICE,COND1,COLOR1,COND2,COLOR2...),
//绘制PRICE线,当COND1条件满足时,用COLOR1颜色,当COND2条件满足时,用COLOR2颜色,否则不绘制,从COLOR1之后的参数均可以省略,最多可以有10组条件
//例如:PARTLINE(CLOSE,CLOSE>OPEN,RGB(255,0,0),CLOSE<OPEN,RGB(0,255,0),1,RGB(0,0,255))
//表示画收盘价线,阳线时用红色,阴线时用绿色,平盘用蓝色.注意最后一个条件为1,表示前面都不满足时必然满足这个条件
this.PARTLINE=function(args)
{
let drawData=[];
let result={DrawData:drawData, DrawType:'PARTLINE'};
if (args.length<3) return result;
var data=args[0];
var condition=[];
for(var i=1;i<args.length && i+1<args.length;i+=2)
{
condition.push({Cond:args[i], RGB:args[i+1]});
}
for(var i in data)
{
var drawItem={Value:null, RGB:null};
drawData[i]=drawItem;
var value=data[i];
if (!this.IsNumber(value)) continue;
var rgb=null;
for(var j in condition)
{
var item=condition[j];
if (i<item.Cond.length && item.Cond[i])
{
rgb=item.RGB;
break;
}
}
if (rgb)
{
drawItem.Value=value;
drawItem.RGB=rgb;
}
}
return result;
}
//填充背景.
//用法: DRAWGBK(COND,COLOR1,COLOR2,colorAngle) colorAngle=渐近色角度
//例如: DRAWGBK(O>C,RGB(0,255,0),RGB(255,0,0),0);
this.DRAWGBK=function(condition, color, color2, colorAngle)
{
let drawData={ Color:[], Angle:colorAngle };
if (color) drawData.Color.push(color);
if (color2) drawData.Color.push(color2);
let result={DrawData:null, DrawType:'DRAWGBK'};
if (Array.isArray(condition))
{
for(var i in condition)
{
var item=condition[i];
if (item)
{
result.DrawData=drawData;
break;
}
}
}
else
{
if (condition) result.DrawData=drawData;
}
return result;
}
//画文字 及线段
this.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;i<lineCache.List.length-1;++i)
{
var value=height*(lineCache.List.length-1-i)/width+lineCache.End.Value;
result.push({ID:lineCache.List[i], Value:value});
}
}
else
{
for(let i=1;i<lineCache.List.length-1;++i)
{
var value=height*i/width+lineCache.Start.Value;
result.push({ID:lineCache.List[i], Value:value});
}
}
result.push({ID:lineCache.End.ID, Value:lineCache.End.Value}); //最后一个点
return result;
}
//是否有是有效的数字
JSDraw.prototype.IsNumber=function(value)
{
if (value==null) return false;
if (isNaN(value)) return false;
return true;
}
JSDraw.prototype.IsDrawFunction=function(name)
{
let setFunctionName=new Set(
[
"STICKLINE","DRAWTEXT",'SUPERDRAWTEXT','DRAWLINE','DRAWBAND','DRAWKLINE','DRAWKLINE_IF','PLOYLINE',
'POLYLINE','DRAWNUMBER','DRAWICON','DRAWCHANNEL','PARTLINE','DRAWTEXT_FIX','DRAWGBK','DRAWTEXT_LINE','DRAWRECTREL'
]);
if (setFunctionName.has(name)) return true;
return false;
}
//http://www.newone.com.cn/helpcontroller/index?code=zszy_pc
var DYNAINFO_ARGUMENT_ID=
{
YCLOSE:3,
OPEN:4,
HIGH:5,
LOW:6,
CLOSE:7,
VOL:8,
AMOUNT:10,
AMPLITUDE:13, //振幅
INCREASE:14, //涨幅
EXCHANGERATE:37, //换手率
};
function JSSymbolData(ast,option,jsExecute)
{
this.AST=ast; //语法树
this.Execute=jsExecute;
this.Symbol='600000.sh';
this.Name;
this.Data=null; //个股数据
this.DayData=null; //日线数据
this.SourceData=null; //不复权的个股数据
this.MarketValue=null; //总市值
this.Period=0; //周期
this.Right=0; //复权
this.DataType=0; //默认K线数据 2=分钟走势图数据 3=多日分钟走势图
this.IsBeforeData=false; //当日走势图数据是否包含开盘前数据
this.DayCount; //多日分时图天数
this.KLineApiUrl= g_JSComplierResource.Domain+"/API/KLine2"; //日线
this.MinuteKLineApiUrl= g_JSComplierResource.Domain+'/API/KLine3'; //分钟K线
this.RealtimeApiUrl= g_JSComplierResource.Domain+'/API/stock'; //实时行情
this.HistoryMinuteApiUrl=g_JSChartResource.Domain+'/API/StockMinuteData'; //历史分钟数据(多日分时图)
this.StockHistoryDayApiUrl= g_JSComplierResource.Domain+'/API/StockHistoryDay'; //历史财务数据
this.StockHistoryDay3ApiUrl= g_JSComplierResource.Domain+'/API/StockHistoryDay3'; //历史财务数据
this.StockNewsAnalysisApiUrl= g_JSComplierResource.CacheDomain+'/cache/newsanalyze'; //新闻分析数据
this.HKToSHSZApiUrl= //北上资金
[
g_JSComplierResource.CacheDomain+'/cache/historyday/all/hk2shsz.json', //日线数据
g_JSComplierResource.CacheDomain+'/cache/analyze/hk2shsz/hk2shsz.json', //最新分钟
g_JSComplierResource.Domain+'/API/HKToSHSZMinuteData' //多日分时分钟
] ;
this.MaxRequestDataCount=1000;
this.MaxRequestMinuteDayCount=5;
this.LatestData; //最新行情
this.IndexData; //大盘指数
this.LatestIndexData; //最新大盘数据
this.FinanceData=new Map(); //财务数据
this.MarginData=new Map(); //融资融券
this.HKToSHSZData=new Map(); //北上资金
this.NewsAnalysisData=new Map(); //新闻统计
this.ExtendData=new Map(); //其他的扩展数据
this.UserData=new Map(); //用户数据
this.SectionFinanceData=new Map(); //截面报告数据
this.ThrowSFPeirod=new Set(); //重新获取数据
this.NetworkFilter; //网络请求回调 function(data, callback);
//使用option初始化
if (option)
{
if (option.HQDataType) this.DataType=option.HQDataType;
if (option.Data)
{
this.Data=option.Data;
if (this.DataType!=HQ_DATA_TYPE.MINUTE_ID && this.DataType!=HQ_DATA_TYPE.MULTIDAY_MINUTE_ID && this.DataType!=HQ_DATA_TYPE.HISTORY_MINUTE_ID) //分钟走势图数据 没有周期和复权
{
this.Period=option.Data.Period; //周期
this.Right=option.Data.Right; //复权
}
//this.Data=null;
}
if (option.SourceData) this.SourceData=option.SourceData;
if (option.Symbol) this.Symbol=option.Symbol;
if (option.Name) this.Name=option.Name;
if (option.MaxRequestDataCount>0) 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)
{
JSConsole.Complier.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};
JSConsole.Complier.Log('[JSSymbolData::RecvLatestData]', this.LatestData);
}
this.GetLatestCacheData=function(dataname)
{
if (!this.LatestData) return null;
switch(dataname)
{
case DYNAINFO_ARGUMENT_ID.YCLOSE:
return this.LatestData.YClose;
case DYNAINFO_ARGUMENT_ID.OPEN:
return this.LatestData.Open;
case DYNAINFO_ARGUMENT_ID.HIGH:
return this.LatestData.High;
case DYNAINFO_ARGUMENT_ID.LOW:
return this.LatestData.Low;
case DYNAINFO_ARGUMENT_ID.VOL:
return this.LatestData.Vol;
case DYNAINFO_ARGUMENT_ID.AMOUNT:
return this.LatestData.Amount;
case DYNAINFO_ARGUMENT_ID.INCREASE:
return this.LatestData.Increase;
case DYNAINFO_ARGUMENT_ID.EXCHANGERATE:
return this.LatestData.Exchangerate;
case DYNAINFO_ARGUMENT_ID.AMPLITUDE:
return this.LatestData.Amplitude;
case DYNAINFO_ARGUMENT_ID.CLOSE:
return this.LatestData.Price;
default:
return null;
}
}
this.GetLatestIndexData=function()
{
if (this.LatestIndexData) return this.Execute.RunNextJob();
var self=this;
if (this.NetworkFilter)
{
var obj=
{
Name:'JSSymbolData::GetLatestIndexData', //类名:: 函数
Explain:'最新大盘数据',
Request:{ Url:self.RealtimeApiUrl, Type:'POST' ,
Data: { symbol:['000001.sh'], field: ["name","symbol","yclose","open","price","high","low","vol","amount","date","time","increase","amplitude"] } },
Self:this,
PreventDefault:false
};
this.NetworkFilter(obj, function(data)
{
self.RecvLatestIndexData(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","amplitude"],
"symbol": ['000001.sh']
},
type:"post",
dataType: "json",
async:true,
success: function (recvData)
{
self.RecvLatestIndexData(recvData);
self.Execute.RunNextJob();
},
error: function(request)
{
self.RecvError(request);
}
});
}
this.RecvLatestIndexData=function(data)
{
if (!data.stock || data.stock.length!=1) return;
let stock=data.stock[0];
this.LatestIndexData={ 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, Amplitude:stock.amplitude};
JSConsole.Complier.Log('[JSSymbolData::RecvLatestIndexData]', this.LatestIndexData);
}
this.GetLatestIndexCacheData=function(dataname)
{
if (!this.LatestIndexData) return null;
switch(dataname)
{
case 'FROMOPEN':
{
var value=parseInt(this.LatestIndexData.Time/100);
var time=parseInt(value/100)*60+(value%100); //转化为分钟个数
var index=0;
if(time <= 9 * 60 + 25) index=0;
else if(time < 9 * 60 + 30) index=1;
else if(time <= 11 * 60 + 30) index=(time - (9 * 60 + 30) + 1);
else if(time < 13 * 60) index=121;
else if(time <= 15 * 60) index=(122 + time - 13 * 60);
else index=242;
return index;
}
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;
JSNetwork.HttpRequest({
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);
JSConsole.Complier.Log('[JSSymbolData::RecvVolRateData]', item);
}
this.GetVolRateCacheData=function(node)
{
var key=JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_VOLR_DATA.toString()+'-VolRate-'+this.Symbol;
if (!key || !this.ExtendData.has(key)) this.Execute.ThrowUnexpectedNode(node,'不支持VOLR');
var result=[];
var value=this.ExtendData.get(key);
var avgVol5=value.AvgVol5/241;
var totalVol=0;
//5日成交总量只取了最新一天的,历史的暂时没有取,所以数据计算的时候只计算最新的一天, 其他都空
for(var i=0, j=0;i<this.Data.Data.length;++i)
{
result[i]=null;
var item=this.Data.Data[i];
var dateTime=item.DateTime; //日期加时间
if (!dateTime) continue;
var aryValue=dateTime.split(' ');
if (aryValue.length!=2) continue;
var date=parseInt(aryValue[0]);
if (date!=value.Date) continue;
totalVol+=item.Vol;
if (avgVol5>0) result[i]=totalVol/(j+1)/avgVol5*100;
++j;
}
return result;
}
this.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)
{
JSConsole.Complier.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)
{
JSConsole.Complier.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';
JSConsole.Complier.Log('[JSSymbolData::GetIndexIncreaseData] minute Get url=' , apiUrl);
JSNetwork.HttpRequest({
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线图 日线
{
JSConsole.Complier.Log('[JSSymbolData::GetIndexIncreaseData] K day Get url=' , self.KLineApiUrl);
JSNetwork.HttpRequest({
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)
{
JSConsole.Complier.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)
{
JSConsole.Complier.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;i<this.Data.Data.length;++i)
{
upData[i]=null;
downData[i]=null;
var item=this.Data.Data[i];
if (item.Before) continue; //盘前数据
var dateTime=item.DateTime; //日期加时间
if (!dateTime) continue;
var aryValue=dateTime.split(' ');
if (aryValue.length!=2) continue;
var date=parseInt(aryValue[0]);
if (date!=data.date) continue;
upData[i]=minuteData.up[j];
downData[i]=minuteData.down[j];
++j;
}
}
else
{
for(var i=0, j=0;i<this.Data.Data.length;++i)
{
upData[i]=null;
downData[i]=null;
var item=this.Data.Data[i];
var dateTime=item.DateTime; //日期加时间
if (!dateTime) continue;
var aryValue=dateTime.split(' ');
if (aryValue.length!=2) continue;
var date=parseInt(aryValue[0]);
if (date!=data.date) continue;
upData[i]=minuteData.up[j];
downData[i]=minuteData.down[j];
++j;
}
}
this.ExtendData.set(key.UpKey,upData);
this.ExtendData.set(key.DownKey,downData);
}
//分钟涨幅股票个数统计数据
this.GetIndexIncreaseCacheData=function(funcName,symbol,node)
{
var key;
if (funcName=='UPCOUNT') key=JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_INDEX_INCREASE_DATA.toString()+'-UpCount-'+symbol;
else if (funcName=='DOWNCOUNT') key=JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_INDEX_INCREASE_DATA.toString()+'-DownCount-'+symbol;
if (!key || !this.ExtendData.has(key)) this.Execute.ThrowUnexpectedNode(node,'不支持函数'+funcName+'('+symbol+')');
return this.ExtendData.get(key);
}
this.GetSymbolData=function()
{
if (this.Data) return this.Execute.RunNextJob();
let self=this;
if (this.DataType===HQ_DATA_TYPE.MINUTE_ID) //当天分钟数据
{
JSNetwork.HttpRequest({
url: self.RealtimeApiUrl,
data:
{
"field": ["name","symbol","yclose","open","price","high","low","vol","amount","date","minute","time","minutecount"],
"symbol": [self.Symbol],
"start": -1
},
type:"post",
dataType: "json",
async:true,
success: function (recvData)
{
self.RecvMinuteData(recvData);
self.Execute.RunNextJob();
}
});
return;
}
if (this.DataType===HQ_DATA_TYPE.MULTIDAY_MINUTE_ID)
{
JSNetwork.HttpRequest({
url: self.HistoryMinuteApiUrl,
data:
{
"symbol": self.Symbol,
"daycount": self.DayCount
},
type:"post",
dataType: "json",
async:true,
success: function (recvData)
{
self.RecvMultiDayMinuteData(recvData);
self.Execute.RunNextJob();
}
});
return;
}
if (ChartData.IsDayPeriod(this.Period,true)) //请求日线数据
{
JSNetwork.HttpRequest({
url: self.KLineApiUrl,
data:
{
"field": [ "name", "symbol","yclose","open","price","high","low","vol"],
"symbol": self.Symbol,
"start": -1,
"count": self.MaxRequestDataCount
},
type:"post",
dataType: "json",
async:true,
success: function (recvData)
{
self.RecvHistroyData(recvData);
self.Execute.RunNextJob();
},
error: function(request)
{
self.RecvError(request);
}
});
}
else if (ChartData.IsMinutePeriod(this.Period, true)) //请求分钟数据
{
JSNetwork.HttpRequest({
url: this.MinuteKLineApiUrl,
data:
{
"field": ["name","symbol","yclose","open","price","high","low","vol"],
"symbol": self.Symbol,
"start": -1,
"count": self.MaxRequestMinuteDayCount
},
type:"post",
dataType: "json",
async:true,
success: function (data)
{
self.RecvMinuteHistroyData(data);
self.Execute.RunNextJob();
},
error: function(request)
{
self.RecvError(request);
}
});
}
}
this.RecvHistroyData=function(data)
{
JSConsole.Complier.Log('[JSSymbolData::RecvHistroyData] recv data' , data);
let hisData=this.JsonDataToHistoryData(data);
this.Data=new ChartData();
this.Data.DataType=0; /*日线数据 */
this.Data.Data=hisData;
this.SourceData=new ChartData;
this.SourceData.Data=hisData;
if (this.Right>0) //复权
{
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)
{
JSConsole.Complier.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)
{
JSConsole.Complier.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.GetSymbolDayData=function()
{
//分钟周期才需要下载日线
if (this.DataType!=HQ_DATA_TYPE.KLINE_ID || !ChartData.IsMinutePeriod(this.Period,true) || this.DayData)
return this.Execute.RunNextJob();
var self=this;
JSNetwork.HttpRequest({
url: self.KLineApiUrl,
data:
{
"field": [ "name", "symbol","yclose","open","price","high","low","vol"],
"symbol": self.Symbol,
"start": -1,
"count": self.MaxRequestDataCount
},
type:"post",
dataType: "json",
async:true,
success: function (recvData)
{
self.RecvSymbolDayData(recvData);
self.Execute.RunNextJob();
},
error: function(request)
{
self.RecvError(request);
}
});
}
this.RecvSymbolDayData=function(data)
{
JSConsole.Complier.Log('[JSSymbolData::RecvSymbolDayData] recv data' , data);
let hisData=this.JsonDataToHistoryData(data);
var dayData=new ChartData();
dayData.DataType=0; /*日线数据 */
dayData.Data=hisData; //保存原始数据 不复权
dayData.Right=this.Right;
dayData.Period=this.Period;
this.DayData=dayData;
}
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;i<lCount;++i)
{
if (i==lCount-1) result.push(1);
else result.push(0);
}
return result;
}
//财务函数
this.GetFinanceCacheData=function(id, node)
{
let jobID=JS_EXECUTE_JOB_ID.GetFinnanceJobID(id);
if (!jobID) this.Execute.ThrowUnexpectedNode(node,'不支持FINANCE('+id+')');
if(this.FinanceData.has(jobID)) return this.FinanceData.get(jobID);
return [];
}
this.GetCompanyReleaseDate=function(jobID)
{
if (this.FinanceData.has(jobID)) return this.Execute.RunNextJob();
var self=this;
JSNetwork.HttpRequest({
url: self.RealtimeApiUrl,
data:
{
"field": ["name","symbol","company.releasedate"], //公司上司日期
"symbol": [this.Symbol]
},
type:"post",
dataType: "json",
async:true,
success: function (recvData)
{
self.RecvCompanyReleaseDate(jobID,recvData);
self.Execute.RunNextJob();
},
error: function(request)
{
self.RecvError(request);
}
});
}
this.RecvCompanyReleaseDate=function(jobID,data)
{
if (!data.stock || data.stock.length!=1) return;
let value=data.stock[0].company.releasedate;
let releaseDate=new Date(value/10000,value%10000/100,value%100);
let aryData=[];
for(let i in this.Data.Data)
{
value=this.Data.Data[i].Date;
let date=new Date(value/10000,value%10000/100,value%100);
let item=new SingleData();
item.Date=value;
item.Value=parseInt((date-releaseDate)/(1000 * 60 * 60 * 24));
aryData[i]=item;
}
JSConsole.Complier.Log('[JSSymbolData::RecvCompanyReleaseDate] jobID=', jobID, aryData)
var bindData=new ChartData();
bindData.Data=aryData;
bindData.Period=this.Period; //周期
if (bindData.Period>0) //周期数据
{
var periodData=bindData.GetPeriodSingleData(bindData.Period);
bindData.Data=periodData;
}
let stockData=bindData.GetValue();
this.FinanceData.set(jobID,stockData);
}
//下载财务数据
this.GetFinanceData=function(jobID)
{
if (this.FinanceData.has(jobID)) return this.Execute.RunNextJob();
JSConsole.Complier.Log('[JSSymbolData::GetFinanceData] jobID=', jobID);
var self=this;
let fieldList=["name","date","symbol"];
switch(jobID)
{
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_FLOW_EQUITY_DATA: //流通股本(万股)
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_CAPITAL_DATA: //流通股本(手)
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_FLOW_MARKETVALUE_DATA: //流通市值
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_EXCHANGE_DATA: //换手率
fieldList.push("capital.a");
break;
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_TOTAL_EQUITY_DATA: //总股本(万股)
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARKETVALUE_DATA: //总市值
fieldList.push('capital.total');
break;
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_PER_U_PROFIT_DATA:
fieldList.push('finance.peruprofit');
break;
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_PER_NETASSET_DATA:
fieldList.push('finance.pernetasset');
break;
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_PER_C_RESERVE_DATA:
fieldList.push('finance.percreserve');
break;
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_PER_S_EARNING_DATA:
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_PER_S_EARNING2_DATA:
fieldList.push('finance.persearning');
break;
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_N_PROFIT_DATA:
fieldList.push('finance.nprofit');
break;
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_AL_RATIO_DATA:
fieldList.push('finance.alratio');
break;
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_PROFIT_YOY_DATA:
fieldList.push('finance.profityoy');
break;
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_DIVIDEND_YIELD_DATA: //过去4个季度现金分红总额
fieldList.push('execdividend.quarter4');
break;
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SHAREHOLDER_DATA:
fieldList.push('shareholder'); //股东信息
break;
}
if (this.NetworkFilter)
{
var obj=
{
Name:'JSSymbolData::GetFinanceData', //类名::
Explain:'财务数据',
JobID:jobID,
Request:{ Url:self.StockHistoryDayApiUrl, Type:'POST' ,
Data:{ field: fieldList, symbol: [this.Symbol], orderfield:"date" }, },
Self:this,
PreventDefault:false
};
this.NetworkFilter(obj, function(data)
{
self.RecvFinanceData(data,jobID);
self.Execute.RunNextJob();
});
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.RecvFinanceData(recvData,jobID);
self.Execute.RunNextJob();
}
});
}
this.RecvFinanceData=function(recvData,jobID)
{
switch(jobID)
{
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_FLOW_EQUITY_DATA:
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_CAPITAL_DATA:
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_TOTAL_EQUITY_DATA:
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_PER_U_PROFIT_DATA:
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_PER_NETASSET_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.RecvStockDayData(recvData,jobID);
}
}
this.RecvStockDayData=function(recvData,jobID)
{
//JSConsole.Complier.Log(recvData);
if (!recvData.stock || recvData.stock.length!=1) return;
let stock=recvData.stock[0];
var bFinanceData=false; //是否是定期的财务数据
var bMarketValue=false; //是否计算市值
var aryData=new Array();
for(let i in stock.stockday)
{
var item=stock.stockday[i];
let indexData=new SingleData();
indexData.Date=item.date;
switch(jobID)
{
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_CAPITAL_DATA:
var financeData=item.capital;
if (!financeData) continue;
if (!this.IsNumber(financeData.a)) continue;
indexData.Value=financeData.a/100; //流通股本(手)
bFinanceData=true;
break;
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_TOTAL_EQUITY_DATA:
var financeData=item.capital;
if (!financeData) continue;
if (!this.IsNumber(financeData.total)) continue;
indexData.Value=financeData.total/10000; //总股本(万股)
bFinanceData=true;
break;
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_FLOW_EQUITY_DATA:
var financeData=item.capital;
if (!financeData) continue;
if (!this.IsNumber(financeData.a)) continue;
indexData.Value=financeData.a/10000; //流通股本(万股)
bFinanceData=true;
break;
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_FLOW_MARKETVALUE_DATA: //流通市值
var financeData=item.capital;
if (!financeData) continue;
if (!this.IsNumber(financeData.a)) continue;
indexData.Value=financeData.a; //流通股本
bMarketValue=true;
break;
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARKETVALUE_DATA: //总市值
var financeData=item.capital;
if (!financeData) continue;
if (!this.IsNumber(financeData.total)) continue;
indexData.Value=financeData.total; //总股本
bMarketValue=true;
break;
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_EXCHANGE_DATA: //换手率
var financeData=item.capital;
if (!financeData) continue;
if (!this.IsNumber(financeData.a)) continue;
indexData.Value=financeData.a; //流通股本
bFinanceData=true;
break;
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_PER_U_PROFIT_DATA:
var financeData=this.JsonDataToFinance(item);
if (!financeData) continue;
if (!this.IsNumber(financeData.Finance.peruprofit)) continue;
indexData.Value=financeData.Finance.peruprofit; //每股未分配利润
bFinanceData=true;
break;
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_PER_NETASSET_DATA:
var financeData=this.JsonDataToFinance(item);
if (!financeData) continue;
if (!this.IsNumber(financeData.Finance.pernetasset)) continue;
indexData.Value=financeData.Finance.pernetasset; //每股净资产
bFinanceData=true;
break;
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_PER_C_RESERVE_DATA:
var financeData=this.JsonDataToFinance(item);
if (!financeData) continue;
if (!this.IsNumber(financeData.Finance.percreserve)) continue;
indexData.Value=financeData.Finance.percreserve; //每股资本公积金
bFinanceData=true;
break;
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_PER_S_EARNING_DATA:
var financeData=this.JsonDataToFinance(item);
if (!financeData) continue;
if (!this.IsNumber(financeData.Finance.persearning)) continue;
indexData.Value=financeData.Finance.persearning; //每股收益
bFinanceData=true;
break;
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_PER_S_EARNING2_DATA:
var financeData=this.JsonDataToFinance(item);
if (!financeData) continue;
if (!this.IsNumber(financeData.Finance.persearning)) continue;
indexData.Value=financeData.Finance.persearning/financeData.Announcement.quarter*4; //每股收益(折算为全年收益) 报告期每股收益/报告期*4
bFinanceData=true;
break;
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_N_PROFIT_DATA:
var financeData=this.JsonDataToFinance(item);
if (!financeData) continue;
if (!this.IsNumber(financeData.Finance.nprofit)) continue;
indexData.Value=financeData.Finance.nprofit; //净利润
bFinanceData=true;
break;
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_AL_RATIO_DATA:
var financeData=this.JsonDataToFinance(item);
if (!financeData) continue;
if (!this.IsNumber(financeData.Finance.alratio)) continue;
indexData.Value=financeData.Finance.alratio; //资产负债率
bFinanceData=true;
break;
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_PROFIT_YOY_DATA:
var financeData=this.JsonDataToFinance(item);
if (!financeData) continue;
if (!this.IsNumber(financeData.Finance.profityoy)) continue;
indexData.Value=financeData.Finance.profityoy; //净利润同比增长率
bFinanceData=true;
break;
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_DIVIDEND_YIELD_DATA:
var financeData=item.execdividend;
if (!financeData) continue;
if (!this.IsNumber(financeData.quarter4)) continue;
indexData.Value=financeData.quarter4; //过去4个季度现金分红总额
bFinanceData=true;
break;
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SHAREHOLDER_DATA: //股东人数
var shareHolder=item.shareholder;
if (!shareHolder || !this.IsNumber(shareHolder.count)) continue;
indexData.Value=shareHolder.count;
bFinanceData=true;
break;
default:
continue;
}
aryData.push(indexData);
}
let aryFixedData;
if (bFinanceData)
{
if (this.SourceData) aryFixedData=this.SourceData.GetFittingFinanceData(aryData);
else aryFixedData=this.Data.GetFittingFinanceData(aryData);
}
else if (bMarketValue)
{
if (this.SourceData) aryFixedData=this.SourceData.GetFittingMarketValueData(aryData); //总市值用不复权的价格计算
else aryFixedData=this.Data.GetFittingMarketValueData(aryData);
if (jobID==JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARKETVALUE_DATA) this.MarketValue=aryFixedData; //总市值保存下 算其他数据可能要用
}
else if (jobID==JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_DIVIDEND_YIELD_DATA) //股息率TTM:过去4个季度现金分红总额/总市值 * 100%
{
aryFixedData=this.CalculateDividendYield(aryData);
}
else
{
aryFixedData=this.SourceData.GetFittingData(aryData);
}
//JSConsole.Complier.Log('[JSSymbolData::RecvStockDayData] jobID=' + jobID, aryFixedData)
var bindData=new ChartData();
bindData.Data=aryFixedData;
bindData.Period=this.Period; //周期
if (bindData.Period>0) //周期数据
{
var periodData=bindData.GetPeriodSingleData(bindData.Period);
bindData.Data=periodData;
}
if (jobID==JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_EXCHANGE_DATA) //计算换手率 成交量/流通股本*100
{
for(let i in this.Data.Data)
{
if (!bindData.Data[i]) continue;
if (this.IsNumber(bindData.Data[i].Value) && bindData.Data[i].Value!=0)
bindData.Data[i].Value=this.Data.Data[i].Vol/bindData.Data[i].Value*100;
else
bindData.Data[i].Value=1;
}
}
let data=bindData.GetValue();
this.FinanceData.set(jobID,data);
}
//计算股息率 股息率TTM:过去4个季度现金分红总额/总市值 * 100%
this.CalculateDividendYield=function(cashData)
{
var dividendYield=[];
if (!this.MarketValue) return dividendYield;
for(let i=0,j=0;i<this.Data.Data.length;++i)
{
var day=this.Data.Data[i];
var market=this.MarketValue[i];
if (!day || !market) continue;
let item=new SingleData();
item.Date=day.Date;
item.Value=0;
if (j+1<cashData.length)
{
if (cashData[j].Date<day.Date && cashData[j+1].Date<=day.Date)
{
++j;
--i;
continue;
}
}
if (j<cashData.length)
{
var cash=cashData[j];
var endDate=cash.Date+10000; //1年有效
if (day.Date>=cash.Date && day.Date<=endDate && this.IsDivideNumber(market.Value) && this.IsNumber(cash.Value))
{
item.Value=cash.Value/market.Value*100;
}
}
dividendYield.push(item);
}
return dividendYield;
}
//融资融券函数
this.GetMarginCacheData=function(id, node)
{
let jobID=JS_EXECUTE_JOB_ID.GetMarginJobID(id);
if (!jobID) this.Execute.ThrowUnexpectedNode(node,'不支持MARGIN('+id+')');
if(this.MarginData.has(jobID)) return this.MarginData.get(jobID);
return [];
}
//下融资融券
this.GetMarginData=function(jobID)
{
if (this.MarginData.has(jobID)) return this.Execute.RunNextJob();
JSConsole.Complier.Log('[JSSymbolData::GetMarginData] jobID=', jobID);
var self=this;
let fieldList=["name","date","symbol"];
switch(jobID)
{
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BALANCE: //融资融券余额
fieldList.push("margin.balance");
break;
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_RATE: //融资占比
fieldList.push("margin.rate");
break;
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BUY_BALANCE: //买入信息-融资余额
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BUY_AMOUNT: //买入信息-买入额
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BUY_REPAY: //买入信息-偿还额
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BUY_NET: //买入信息-融资净买入
fieldList.push("margin.buy");
break;
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_SELL_BALANCE: //卖出信息-融券余量
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_SELL_VOLUME: //卖出信息-卖出量
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_SELL_REPAY: //卖出信息-偿还量
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_SELL_NET: //卖出信息-融券净卖出
fieldList.push("margin.sell");
break;
}
//请求数据
JSNetwork.HttpRequest({
url: this.StockHistoryDayApiUrl,
data:
{
"field": fieldList,
"symbol": [this.Symbol],
"orderfield":"date"
},
type:"post",
dataType: "json",
async:true,
success: function (recvData)
{
self.RecvMarginData(recvData,jobID);
self.Execute.RunNextJob();
}
});
}
this.RecvMarginData=function(data,jobID)
{
JSConsole.Complier.Log(data);
if (!data.stock || data.stock.length!=1) return;
let stock=data.stock[0];
var aryData=new Array();
var aryData2=[], aryData3=[], aryData4=[]; //其他3个数据
for(let i in stock.stockday)
{
var item=stock.stockday[i];
var marginData=item.margin;
if (!marginData) continue;
let indexData=new SingleData();
indexData.Date=item.date;
switch(jobID)
{
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BALANCE:
if (!this.IsNumber(marginData.balance)) continue;
indexData.Value=marginData.balance; //融资融券余额
aryData.push(indexData);
break;
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_RATE:
if (!this.IsNumber(marginData.rate)) continue;
indexData.Value=marginData.rate; //融资占比
aryData.push(indexData);
break;
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BUY_BALANCE: //买入信息-融资余额
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BUY_AMOUNT: //买入信息-买入额
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BUY_REPAY: //买入信息-偿还额
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BUY_NET: //买入信息-融资净买入
var buyData=marginData.buy;
if (!buyData) continue;
if (!this.IsNumber(buyData.balance) || !this.IsNumber(buyData.amount) || !this.IsNumber(buyData.repay) || !this.IsNumber(buyData.net)) continue;
indexData.Value=buyData.balance;
var indexData2=new SingleData();
indexData2.Date=item.date;
indexData2.Value=buyData.amount;
var indexData3=new SingleData();
indexData3.Date=item.date;
indexData3.Value=buyData.repay;
var indexData4=new SingleData();
indexData4.Date=item.date;
indexData4.Value=buyData.net;
aryData.push(indexData);
aryData2.push(indexData2);
aryData3.push(indexData3);
aryData4.push(indexData4);
break;
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_SELL_BALANCE: //卖出信息-融券余量
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_SELL_VOLUME: //卖出信息-卖出量
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_SELL_REPAY: //卖出信息-偿还量
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_SELL_NET: //卖出信息-融券净卖出
var sellData=marginData.sell;
if (!sellData) continue;
if (!this.IsNumber(sellData.balance) || !this.IsNumber(sellData.volume) || !this.IsNumber(sellData.repay) || !this.IsNumber(sellData.net)) continue;
indexData.Value=buyData.balance;
var indexData2=new SingleData();
indexData2.Date=item.date;
indexData2.Value=buyData.volume;
var indexData3=new SingleData();
indexData3.Date=item.date;
indexData3.Value=buyData.repay;
var indexData4=new SingleData();
indexData4.Date=item.date;
indexData4.Value=buyData.net;
aryData.push(indexData);
aryData2.push(indexData2);
aryData3.push(indexData3);
aryData4.push(indexData4);
break;
default:
continue;
}
}
var allData=[];
if (jobID===JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BALANCE || jobID===JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_RATE)
{
allData.push({JobID:jobID,Data:aryData});
}
else if (jobID===JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BUY_BALANCE || jobID===JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BUY_AMOUNT ||
jobID===JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BUY_REPAY || jobID===JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BUY_NET)
{
allData.push({JobID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BUY_BALANCE,Data:aryData});
allData.push({JobID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BUY_AMOUNT,Data:aryData2});
allData.push({JobID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BUY_REPAY,Data:aryData3});
allData.push({JobID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BUY_NET,Data:aryData4});
}
else if (jobID===JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_SELL_BALANCE || jobID===JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_SELL_VOLUME ||
jobID===JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_SELL_REPAY || jobID===JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_SELL_NET)
{
allData.push({JobID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_SELL_BALANCE,Data:aryData});
allData.push({JobID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_SELL_VOLUME,Data:aryData2});
allData.push({JobID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_SELL_REPAY,Data:aryData3});
allData.push({JobID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_SELL_NET,Data:aryData4});
}
for(let i in allData)
{
let aryFixedData=this.SourceData.GetFittingData(allData[i].Data);
var bindData=new ChartData();
bindData.Data=aryFixedData;
bindData.Period=this.Period; //周期
if (bindData.Period>0) //周期数据
{
var periodData=bindData.GetPeriodSingleData(bindData.Period);
bindData.Data=periodData;
}
let data=bindData.GetValue();
this.MarginData.set(allData[i].JobID,data);
}
}
this.GetNewsAnalysisCacheData=function(id,node)
{
let jobID=JS_EXECUTE_JOB_ID.GetNewsAnalysisID(id);
if (!jobID) this.Execute.ThrowUnexpectedNode(node,'不支持NEWS('+id+')');
if(this.NewsAnalysisData.has(jobID)) return this.NewsAnalysisData.get(jobID);
return [];
}
this.GetHKToSHSZData=function(jobID)
{
if (this.HKToSHSZData.has(jobID)) return this.Execute.RunNextJob();
var url, dataType=0;
if (this.DataType===HQ_DATA_TYPE.MINUTE_ID) dataType=1;
else if (this.DataType==HQ_DATA_TYPE.MULTIDAY_MINUTE_ID) dataType=2;
else if (this.Period<=3) dataType=0;
url=this.HKToSHSZApiUrl[dataType];
var self=this;
JSConsole.Complier.Log(`[JSSymbolData::GetHKToSHSZData] jobID=${jobID}, url=${url}, dataType=${dataType}`);
if (dataType===2)
{
//请求数据
JSNetwork.HttpRequest({
url: url,
data:
{
"symbol": this.Symbol,
'daycount': this.MaxRequestMinuteDayCount
},
type:"post",
dataType: "json",
async:true,
success: function (recvData)
{
self.RecvMulitMinuteHKToSHSZData(recvData,jobID);
self.Execute.RunNextJob();
}
});
}
else
{
//请求数据
JSNetwork.HttpRequest({
url: url,
type:"get",
dataType: "json",
async:true,
success: function (recvData)
{
if (dataType==0) self.RecvHKToSHSZData(recvData,jobID);
else if (dataType==1) self.RecvMinuteHKToSHSZData(recvData,jobID);
self.Execute.RunNextJob();
}
});
}
}
this.RecvMinuteHKToSHSZData=function(data,jobID)
{
var arySHSZData=[], arySHData=[], arySZData=[];
if (this.IsBeforeData)
{
for( i in this.SourceData.Data)
{
var item=this.SourceData.Data[i];
if (item.Before)
{
arySHSZData.push(null);
arySHData.push(null);
arySZData.push(null);
}
else
{
break;
}
}
for(var i=0;i<data.time.length;++i)
{
var time=data.time[i];
if (time===925) continue;
var SHValue=data.hk2sh[i];
var SZValue=data.hk2sz[i];
var total=SHValue+SZValue;
arySHSZData.push(total);
arySHData.push(SHValue);
arySZData.push(SZValue);
}
}
else
{
for(var i=0;i<data.time.length;++i)
{
var time=data.time[i];
var SHValue=data.hk2sh[i];
var SZValue=data.hk2sz[i];
var total=SHValue+SZValue;
arySHSZData.push(total);
arySHData.push(SHValue);
arySZData.push(SZValue);
}
}
var allData=
[
{Data:arySHSZData, JobID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_HK_TO_SH_SZ},
{Data:arySHData,JobID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_HK_TO_SH},
{Data:arySZData,JobID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_HK_TO_SZ}
];
for(var i in allData)
{
var item=allData[i];
this.HKToSHSZData.set(item.JobID,item.Data);
}
}
this.RecvHKToSHSZData=function(data,jobID)
{
var arySHSZData=[], arySHData=[], arySZData=[];
for(var i=0;i<data.date.length;++i)
{
var date=data.date[i];
var SHValue=data.hk2sh[i]*1000000; //单位是百万
var SZValue=data.hk2sz[i]*1000000; //单位是百万
var total=SHValue+SZValue;
let itemSHSZData=new SingleData();
itemSHSZData.Date=date;
itemSHSZData.Value=total;
let itemSHData=new SingleData();
itemSHData.Date=date;
itemSHData.Value=SHValue;
let itemSZData=new SingleData();
itemSZData.Date=date;
itemSZData.Value=SZValue;
arySHSZData.push(itemSHSZData);
arySHData.push(itemSHData);
arySZData.push(itemSZData);
}
var allData=
[
{Data:arySHSZData, JobID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_HK_TO_SH_SZ},
{Data:arySHData,JobID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_HK_TO_SH},
{Data:arySZData,JobID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_HK_TO_SZ}
];
for(let i in allData)
{
let aryFixedData=this.Data.GetFittingData(allData[i].Data);
var bindData=new ChartData();
bindData.Data=aryFixedData;
bindData.Period=this.Period; //周期
if (bindData.Period>0) //周期数据
{
var periodData=bindData.GetPeriodSingleData(bindData.Period);
bindData.Data=periodData;
}
let data=bindData.GetValue();
this.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;i<this.Data.Data.length && j<data.data.length; )
{
arySHSZData[i]=null;
arySHData[i]=null;
arySZData[i]=null;
var item=this.Data.Data[i];
var dateTime=item.DateTime; //日期加时间
if (!dateTime)
{
++i;
continue;
}
var aryValue=dateTime.split(' ');
if (aryValue.length!=2)
{
++i;
continue;
}
var date=parseInt(aryValue[0]);
var day=data.data[j];
if (!day.minute || day.minute.length<=0)
{
++j;
continue;
}
if (day.date>date)
{
++i;
continue;
}
else if (day.date<date)
{
++j;
continue;
}
for(var k in day.minute)
{
var timeItem=day.minute[k];
var SHValue=timeItem[1];
var SZValue=timeItem[2];
var total=SHValue+SZValue;
arySHSZData[i]=total;
arySHData[i]=SHValue;
arySZData[i]=SZValue;
++i;
}
++j;
}
var allData=
[
{Data:arySHSZData, JobID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_HK_TO_SH_SZ},
{Data:arySHData,JobID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_HK_TO_SH},
{Data:arySZData,JobID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_HK_TO_SZ}
];
for(var i in allData)
{
var item=allData[i];
this.HKToSHSZData.set(item.JobID,item.Data);
}
}
//北上资金函数
this.GetHKToSHSZCacheData=function(id, node)
{
let jobID=JS_EXECUTE_JOB_ID.GetHK2SHSZJobID(id);
if (!jobID) this.Execute.ThrowUnexpectedNode(node,'不支持HK2SHSZ('+id+')');
if(this.HKToSHSZData.has(jobID)) return this.HKToSHSZData.get(jobID);
return [];
}
//下载新闻统计
this.GetNewsAnalysisData=function(jobID)
{
if (this.NewsAnalysisData.has(jobID)) return this.Execute.RunNextJob();
var self=this;
var mapFolder=new Map([
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_NEGATIVE, "negative"],
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_RESEARCH, 'research'],
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_INTERACT, 'interact'],
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_HOLDERCHANGE, 'holderchange'], //NEWS(4) 股东增持
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_HOLDERCHANGE2,'holderchange'], //NEWS(5) 股东减持
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_TRUSTHOLDER, 'trustholder'], //NEWS(6) 信托持股
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_BLOCKTRADING, 'Blocktrading'], //NEWS(7) 大宗交易
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_COMPANYNEWS, 'companynews'], //NEWS(8) 官网新闻
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_TOPMANAGERS, 'topmanagers'], //NEWS(9) 高管要闻
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_PLEDGE, 'Pledge'], //NEWS(10) 股权质押
]);
if (!mapFolder.has(jobID))
{
this.Execute.RunNextJob();
return;
}
var folderName=mapFolder.get(jobID);
var url=this.StockNewsAnalysisApiUrl+'/'+folderName+'/'+this.Symbol+'.json';
//请求数据
JSNetwork.HttpRequest({
url: url,
type:"get",
dataType: "json",
async:true,
success: function (recvData)
{
self.RecvNewsAnalysisData(recvData,jobID);
self.Execute.RunNextJob();
},
error:function(request, textStatus)
{
self.RecvNewsAnalysisDataError(request, textStatus,jobID);
self.Execute.RunNextJob();
}
});
}
this.RecvNewsAnalysisDataError=function(request, textStatus,jobID)
{
JSConsole.Complier.Log('[JSSymbolData::RecvNewsAnalysisDataError] ajax error.',request.status);
//没有新闻使用0数据填充
var aryData=[];
for(var i=0;i<this.Data.Data.length;++i)
{
var item=new SingleData();
item.Date=this.Data.Data[i].Date;
item.Value=0
aryData.push(item);
}
var bindData=new ChartData();
bindData.Data=aryData;
this.NewsAnalysisData.set(jobID,bindData.GetValue());
}
this.RecvNewsAnalysisData=function(data,jobID)
{
if (!data.data || !data.date) return;
if (data.data.length<=0 || data.data.length!=data.date.length) return;
JSConsole.Complier.Log('[JSSymbolData::RecvNewsAnalysisData] jobID',jobID, data.update);
if (jobID==JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_HOLDERCHANGE|| jobID==JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_HOLDERCHANGE2)
{
var aryData=[], aryData2=[];
for(var i=0;i<data.data.length;++i)
{
var item=new SingleData();
item.Date=data.date[i];
item.Value=data.data[i];
if (this.IsNumber(item.Value)) aryData.push(item);
if (i<data.data2.length)
{
item=new SingleData();
item.Date=data.date[i];
item.Value=data.data2[i];
if (this.IsNumber(item.Value)) aryData2.push(item);
}
}
let aryFixedData=this.Data.GetFittingData2(aryData,0);
var bindData=new ChartData();
bindData.Data=aryFixedData;
this.NewsAnalysisData.set(JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_HOLDERCHANGE,bindData.GetValue());
aryFixedData=this.Data.GetFittingData2(aryData2,0);
bindData=new ChartData();
bindData.Data=aryFixedData;
this.NewsAnalysisData.set(JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_HOLDERCHANGE2,bindData.GetValue());
}
else
{
var aryData=[];
for(var i=0;i<data.data.length;++i)
{
var item=new SingleData();
item.Date=data.date[i];
item.Value=data.data[i];
aryData.push(item);
}
let aryFixedData=this.Data.GetFittingData2(aryData,0);
var bindData=new ChartData();
bindData.Data=aryFixedData;
this.NewsAnalysisData.set(jobID,bindData.GetValue());
}
}
this.GetSectionFinanceData=function(job)
{
var sfKey=job.SF[0];
var period=job.SF[1].Period;
if (this.SectionFinanceData.has(sfKey)) return this.Execute.RunNextJob();
JSConsole.Complier.Log(`[JSSymbolData::GetSectionFinanceData] ${period.Year}-${period.Quarter}`);
var fieldName='announcement'+period.Quarter;
var self=this;
var fieldList=["name","date","symbol", fieldName,'finance'+period.Quarter];
var cond=[fieldName+'.year', "int32", "eq", period.Year.toString() ];
//请求数据
JSNetwork.HttpRequest({
url: this.StockHistoryDayApiUrl,
data:
{
"field": fieldList,
"symbol": [this.Symbol],
"condition":[{item:cond}]
},
type:"post",
dataType: "json",
async:true,
success: function (recvData)
{
self.RecvSectionFinanceData(recvData,job);
self.Execute.RunNextJob();
}
});
}
this.RecvSectionFinanceData=function(data,job)
{
if (!data.stock || data.stock.length!=1) return;
var stockItem=data.stock[0];
if (!stockItem.stockday || stockItem.stockday.length<=0) return;
var dayItem=stockItem.stockday[0];
var period=job.SF[1].Period;
var finance=null;
if (period.Quarter===1) finance=dayItem.finance1;
else if (period.Quarter===2) finance=dayItem.finance2;
else if (period.Quarter===3) finance=dayItem.finance3;
else if (period.Quarter===4) finance=dayItem.finance4;
if (!finance) return;
var data=new Map([
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_01,finance.currentassets],
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_02,finance.monetaryfunds],
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_03,finance.inventory],
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_04,finance.currentliabilities],
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_05,finance.ncurrentliabilities],
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_06,finance.expenses3],
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_07,finance.investmentincome],
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_08,finance.pcnprofit],
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_09,finance.nnetprofit],
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_10,finance.npersearning],
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_11,finance.woewa],
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_12,finance.inprocess],
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_13,finance.accdepreciation],
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_14,finance.mholderprofit],
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_15,finance.lossexchange],
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_16,finance.baddebts],
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_17,finance.fixedassets],
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_18,finance.curdepreciation],
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_19,finance.orevenues],
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_20,finance.moprofit],
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_21,finance.oprofit],
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_22,finance.nprofit],
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_23,finance.areceivable],
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_24,finance.financialcost],
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_25,finance.ccfo],
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_26,finance.totalassets],
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_27,finance.totalliabilities],
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_28,finance.totalownersequity],
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_29,finance.grossmargin],
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_30,finance.percreserve],
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_31,finance.peruprofit],
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_32,finance.persearning],
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_33,finance.pernetasset],
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_34,finance.perccfo],
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_38,finance.alratio],
[JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_39,finance.profityoy],
]);
if (period.Quarter===4) //年报才有的数据
{
data.set(JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_35,finance.nnprofitincrease);
data.set(JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_36,finance.nnprofitspeed);
data.set(JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_37,finance.nprofitincrease);
}
var sfKey=job.SF[0];
this.SectionFinanceData.set(sfKey,data);
}
this.GetSectionFinanceCacheData=function(year,quarter,fieldName,node)
{
var period=JS_EXECUTE_JOB_ID.GetSectionReportPeriod(year,quarter);
if (!period) this.Execute.ThrowUnexpectedNode(node,`不支持FS(${year}, ${quarter}, '${fieldName}') 报告期错误`);
var id=JS_EXECUTE_JOB_ID.GetSectionFinanceID(fieldName);
if (!id) this.Execute.ThrowUnexpectedNode(node,`不支持FS(${year}, ${quarter},'${fieldName}') 财务数据字段名称错误`);
var sfKey=period.Year+'-'+period.Quarter;
if (!this.SectionFinanceData.has(sfKey) && !this.ThrowSFPeirod.has(sfKey)) //动态下载的数据, 抛异常以后重新下载执行
{
this.ThrowSFPeirod.add(sfKey); //抛过的异常就不抛了
var job={ID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_SF, SF:[sfKey, {Period:period, Fields:new Set([id])}]};
this.Execute.ThrowDownloadSF(node, job, `FS(${year}, ${quarter}, '${fieldName}') 动态下载`);
}
if (!this.SectionFinanceData.has(sfKey))
return this.Execute.ThrowUnexpectedNode(node,`不支持FS(${year}, ${quarter}, '${fieldName}') 没有这期财务数据`);
var financeData=this.SectionFinanceData.get(sfKey);
if (!financeData.has(id)) this.Execute.ThrowUnexpectedNode(node,`不支持FS(${year}, ${quarter}, '${fieldName}') 没有这期财务数据字段`);
return financeData.get(id);
}
this.DownloadCustomVariantData=function(job)
{
var item=g_JSComplierResource.CustomVariant.Data.get(job.Name);
if (!item || !item.Download) return this.Execute.RunNextJob();
var self=this;
var obj={ Name:job.Name, Symbol:this.Symbol, KData:this.Data, Period:this.Period, Right:this.Right,
Success: function() { self.Execute.RunNextJob() } };
item.Download(obj);
}
this.DownloadCustomFunctionData=function(job)
{
var item=g_JSComplierResource.CustomFunction.Data.get(job.Name);
if (!item || !item.Download) return this.Execute.RunNextJob();
var self=this;
var obj={ Symbol:this.Symbol, KData:this.Data, Period:this.Period, Right:this.Right, Args:job.Args, Name:job.Name,
Success: function() { self.Execute.RunNextJob() } };
item.Download(obj);
}
this.JsonDataToHistoryData=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;
var up=8,down=9,stop=10,unchanged=11;
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];
item.Vol = list[i][vol]; //原始单位股
item.Amount = list[i][amount];
//上涨 下跌家数
if (list[i].length>up) item.Up=list[i][up];
if (list[i].length>down) item.Down=list[i][down];
if (list[i].length>stop) item.Stop=list[i][stop];
if (list[i].length>unchanged) item.Unchanged=list[i][unchanged];
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 (7<jsData.length && jsData[7]>0)
{
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<announcement.year)
financeData={Date:data.date, Finance:finance, Announcement:announcement};
}
else
{
financeData={Date:data.date, Finance:finance, Announcement:announcement};
}
}
return financeData;
}
var JS_EXECUTE_DEBUG_LOG=false;
var JS_EXECUTE_JOB_ID=
{
JOB_DOWNLOAD_SYMBOL_DATA:1, //下载股票的K线数据
JOB_DOWNLOAD_INDEX_DATA:2, //下载大盘的K线数据
JOB_DOWNLOAD_SYMBOL_LATEST_DATA:3, //最新的股票行情数据
JOB_DOWNLOAD_INDEX_INCREASE_DATA:4, //涨跌股票个数统计数据
JOB_DOWNLOAD_VOLR_DATA:5, //5日量比均量下载量比数据
JOB_DOWNLOAD_GROUP_DATA:6, //所属行业|地区|概念
JOB_DOWNLOAD_SYMBOL_DAY_DATA:7, //股票日线数据
JOB_DOWNLOAD_LATEST_INDEX_DATA:8, //下载最新大盘数据
//财务函数
JOB_DOWNLOAD_TOTAL_EQUITY_DATA:100, //总股本(万股)
JOB_DOWNLOAD_FLOW_EQUITY_DATA:101, //流通股本(万股)
JOB_DOWNLOAD_PER_U_PROFIT_DATA:102, //每股未分配利润
JOB_DOWNLOAD_PER_NETASSET_DATA:103, //每股净资产
JOB_DOWNLOAD_PER_C_RESERVE_DATA:104, //每股资本公积金
JOB_DOWNLOAD_PER_S_EARNING_DATA:105, //每股收益
JOB_DOWNLOAD_PER_S_EARNING2_DATA:106, //每股收益(折算为全年收益),对于沪深品种有效
JOB_DOWNLOAD_RELEASE_DATE_DATA:107, //上市的天数
JOB_DOWNLOAD_N_PROFIT_DATA:108, //净利润
JOB_DOWNLOAD_FLOW_MARKETVALUE_DATA:109, //流通市值
JOB_DOWNLOAD_MARKETVALUE_DATA:110, //总市值
JOB_DOWNLOAD_PROFIT_YOY_DATA:111, //利润同比 (Profit year on year)
JOB_DOWNLOAD_AL_RATIO_DATA:112, //资产负债率 (asset-liability ratio)
JOB_DOWNLOAD_DIVIDEND_YIELD_DATA:113, //股息率
JOB_DOWNLOAD_SHAREHOLDER_DATA:114, //股东人数
JOB_DOWNLOAD_CAPITAL_DATA:200, //流通股本(手)
JOB_DOWNLOAD_EXCHANGE_DATA:201, //换手率 成交量/流通股本*100
JOB_DOWNLOAD_MARGIN_BALANCE:1000, //融资融券余额
JOB_DOWNLOAD_MARGIN_RATE:1001, //融资占比
JOB_DOWNLOAD_MARGIN_BUY_BALANCE:1010, //买入信息-融资余额
JOB_DOWNLOAD_MARGIN_BUY_AMOUNT:1011, //买入信息-买入额
JOB_DOWNLOAD_MARGIN_BUY_REPAY:1012, //买入信息-偿还额
JOB_DOWNLOAD_MARGIN_BUY_NET:1013, //买入信息-融资净买入
JOB_DOWNLOAD_MARGIN_SELL_BALANCE:1020, //卖出信息-融券余量
JOB_DOWNLOAD_MARGIN_SELL_VOLUME:1021, //卖出信息-卖出量
JOB_DOWNLOAD_MARGIN_SELL_REPAY:1022, //卖出信息-偿还量
JOB_DOWNLOAD_MARGIN_SELL_NET:1023, //卖出信息-融券净卖出
JOB_DOWNLOAD_NEWS_ANALYSIS_NEGATIVE:2000, //负面新闻统计
JOB_DOWNLOAD_NEWS_ANALYSIS_RESEARCH:2001, //机构调研
JOB_DOWNLOAD_NEWS_ANALYSIS_INTERACT:2002, //互动易
JOB_DOWNLOAD_NEWS_ANALYSIS_HOLDERCHANGE:2003, //股东增持
JOB_DOWNLOAD_NEWS_ANALYSIS_HOLDERCHANGE2:2004, //股东减持
JOB_DOWNLOAD_NEWS_ANALYSIS_TRUSTHOLDER:2005, //信托持股
JOB_DOWNLOAD_NEWS_ANALYSIS_BLOCKTRADING:2006, //大宗交易
JOB_DOWNLOAD_NEWS_ANALYSIS_COMPANYNEWS:2007, //官网新闻
JOB_DOWNLOAD_NEWS_ANALYSIS_TOPMANAGERS:2008, //高管要闻
JOB_DOWNLOAD_NEWS_ANALYSIS_PLEDGE:2009, //股权质押
JOB_DOWNLOAD_HK_TO_SH:2050, //北上流入上证
JOB_DOWNLOAD_HK_TO_SZ:2051, //北上流入深证
JOB_DOWNLOAD_HK_TO_SH_SZ:2052, //北上流总的
JOB_CUSTOM_FUNCTION_DATA:6000, //自定义函数
JOB_CUSTOM_VARIANT_DATA:6001, //自定义变量
//截面数据
//财务数据 SF(公告期,数据名称) 如: SF(201901,"流动资产");
JOB_DOWNLOAD_SECTION_SF:20000,
JOB_DOWNLOAD_SECTION_F_01:20001, //currentassets 流动资产
JOB_DOWNLOAD_SECTION_F_02:20002, //monetaryfunds 货币资金
JOB_DOWNLOAD_SECTION_F_03:20003, //inventory 存货
JOB_DOWNLOAD_SECTION_F_04:20004, //currentliabilities 流动负债
JOB_DOWNLOAD_SECTION_F_05:20005, //ncurrentliabilities 非流动负债
JOB_DOWNLOAD_SECTION_F_06:20006, //3expenses 三项费用
JOB_DOWNLOAD_SECTION_F_07:20007, //investmentincome 投资收益
JOB_DOWNLOAD_SECTION_F_08:20008, //pcnprofit 归母净利润
JOB_DOWNLOAD_SECTION_F_09:20009, //nnetprofit 扣非净利润
JOB_DOWNLOAD_SECTION_F_10:20010, //npersearning 扣非每股收益
JOB_DOWNLOAD_SECTION_F_11:20011, //woewa 加权平均净资产收益
JOB_DOWNLOAD_SECTION_F_12:20012, //inprocess 在建工程
JOB_DOWNLOAD_SECTION_F_13:20013, //accdepreciation 累计折旧
JOB_DOWNLOAD_SECTION_F_14:20014, //mholderprofit 少数股东利润
JOB_DOWNLOAD_SECTION_F_15:20015, //lossexchange 汇兑损益
JOB_DOWNLOAD_SECTION_F_16:20016, //baddebts 坏账计提
JOB_DOWNLOAD_SECTION_F_17:20017, //fixedassets 固定资产
JOB_DOWNLOAD_SECTION_F_18:20018, //curdepreciation 当期折旧
JOB_DOWNLOAD_SECTION_F_19:20019, //orevenues 营业总收入
JOB_DOWNLOAD_SECTION_F_20:20020, //moprofit 主营业务利润
JOB_DOWNLOAD_SECTION_F_21:20021, //oprofit 营业利润
JOB_DOWNLOAD_SECTION_F_22:20022, //nprofit 净利润
JOB_DOWNLOAD_SECTION_F_23:20023, //areceivable 应收账款
JOB_DOWNLOAD_SECTION_F_24:20024, //financialcost 财务费用
JOB_DOWNLOAD_SECTION_F_25:20025, //ccfo 经营性现金流
JOB_DOWNLOAD_SECTION_F_26:20026, //totalassets 资产总计
JOB_DOWNLOAD_SECTION_F_27:20027, //totalliabilities 负债总计
JOB_DOWNLOAD_SECTION_F_28:20028, //totalownersequity 所有者权益总计
JOB_DOWNLOAD_SECTION_F_29:20029, //grossmargin 毛利率
JOB_DOWNLOAD_SECTION_F_30:20030, //percreserve 每股资本公积金
JOB_DOWNLOAD_SECTION_F_31:20031, //peruprofit 每股未分配利润
JOB_DOWNLOAD_SECTION_F_32:20032, //persearning 每股收益
JOB_DOWNLOAD_SECTION_F_33:20033, //pernetasset 每股净资产
JOB_DOWNLOAD_SECTION_F_34:20034, //perccfo 每股经营性现金流
JOB_DOWNLOAD_SECTION_F_35:20035, //nnprofitincrease finance4特有,扣非净利润涨幅
JOB_DOWNLOAD_SECTION_F_36:20036, //nnprofitspeed finance4特有,扣非净利润涨速
JOB_DOWNLOAD_SECTION_F_37:20037, //nprofitincrease finance4特有,净利润涨幅
JOB_DOWNLOAD_SECTION_F_38:20038, //alratio 资产负债率(数值乘以100)
JOB_DOWNLOAD_SECTION_F_39:20039, //profityoy 利润同比%(数值乘以100)
JOB_RUN_SCRIPT:10000, //执行脚本
GetFinnanceJobID:function(value)
{
let dataMap=new Map([
[1,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_TOTAL_EQUITY_DATA], //FINANCE(1) 总股本(万股)
[7,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_FLOW_EQUITY_DATA], //FINANCE(7) 流通股本(万股)
[9,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_AL_RATIO_DATA], //FINANCE(9) 资产负债率 (asset-liability ratio)
[18,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_PER_C_RESERVE_DATA], //FINANCE(18) 每股公积金
[30,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_N_PROFIT_DATA], //FINANCE(30) 净利润
[32,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_PER_U_PROFIT_DATA], //FINANCE(32) 每股未分配利润
[33,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_PER_S_EARNING2_DATA], //FINANCE(33) 每股收益(折算为全年收益),对于沪深品种有效
[34,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_PER_NETASSET_DATA], //FINANCE(34) 每股净资产
[38,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_PER_S_EARNING_DATA], //FINANCE(38) 每股收益(最近一期季报)
[40,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_FLOW_MARKETVALUE_DATA], //FINANCE(40) 流通市值
[41,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARKETVALUE_DATA], //FINANCE(41) 总市值
[42,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_RELEASE_DATE_DATA], //FINANCE(42) 上市的天数
[43,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_PROFIT_YOY_DATA], //FINANCE(43) 利润同比 (Profit year on year)
[45,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_DIVIDEND_YIELD_DATA], //FINANCE(45) 股息率
[100,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SHAREHOLDER_DATA], //FINANCE(100) 股东人数
[200,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_CAPITAL_DATA], //流通股本(手)
[201,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_EXCHANGE_DATA] //换手率 成交量/流通股本
]);
if (dataMap.has(value)) return dataMap.get(value);
return null;
},
//融资融券
GetMarginJobID:function(value)
{
let dataMap=new Map([
[1,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BALANCE], //MARGIN(1) 融资融券余额
[2,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_RATE], //MARGIN(2) 融资占比
[3,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BUY_BALANCE], //MARGIN(3) 买入信息-融资余额
[4,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BUY_AMOUNT], //MARGIN(4) 买入信息-买入额
[5,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BUY_REPAY], //MARGIN(5) 买入信息-偿还额
[6,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BUY_NET], //MARGIN(6) 买入信息-融资净买入
[7,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_SELL_BALANCE], //MARGIN(7) 卖出信息-融券余量
[8,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_SELL_VOLUME], //MARGIN(8) 卖出信息-卖出量
[9,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_SELL_REPAY], //MARGIN(9) 卖出信息-偿还量
[10,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_SELL_NET], //MARGIN(10) 卖出信息-融券净卖出
]);
if (dataMap.has(value)) return dataMap.get(value);
return null;
},
//北上资金
GetHK2SHSZJobID:function(value)
{
let dataMap=new Map([
[1,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_HK_TO_SH_SZ], //HK2SHSZ(1) 北上流总的
[2,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_HK_TO_SH], //HK2SHSZ(2) 北上流入上证
[3,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_HK_TO_SZ], //HK2SHSZ(3) 北上流入深证
]);
if (dataMap.has(value)) return dataMap.get(value);
return null;
},
GetNewsAnalysisID:function(value)
{
let dataMap=new Map([
[1,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_NEGATIVE], //NEWS(1) 负面新闻统计
[2,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_RESEARCH], //NEWS(2) 机构调研统计
[3,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_INTERACT], //NEWS(3) 互动易
[4,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_HOLDERCHANGE], //NEWS(4) 股东增持
[5,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_HOLDERCHANGE2], //NEWS(5) 股东减持
[6,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_TRUSTHOLDER], //NEWS(6) 信托持股
[7,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_BLOCKTRADING], //NEWS(7) 大宗交易
[8,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_COMPANYNEWS], //NEWS(8) 官网新闻
[9,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_TOPMANAGERS], //NEWS(9) 高管要闻
[10,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_PLEDGE], //NEWS(10) 股权质押
]);
if (dataMap.has(value)) return dataMap.get(value);
return null;
},
//财务截面数据 分报告期
GetSectionFinanceID:function(value)
{
let dataMap=new Map([
['流动资产', JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_01],
['货币资金', JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_02],
['存货', JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_03],
['流动负债', JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_04],
['非流动负债',JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_05],
['三项费用',JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_06],
['投资收益',JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_07],
['归母净利润',JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_08],
['扣非净利润',JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_09],
['扣非每股收益',JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_10],
['加权平均净资产收益',JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_11],
['在建工程',JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_12],
['累计折旧',JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_13],
['少数股东利润',JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_14],
['汇兑损益',JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_15],
['坏账计提',JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_16],
['固定资产',JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_17],
['当期折旧',JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_18],
['营业总收入',JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_19],
['主营业务利润',JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_20],
['营业利润',JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_21],
['净利润',JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_22],
['应收账款',JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_23],
['财务费用',JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_24],
['经营性现金流',JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_25],
['资产总计',JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_26],
['负债总计',JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_27],
['所有者权益总计',JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_28],
['毛利率',JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_29],
['每股资本公积金',JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_30],
['每股未分配利润',JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_31],
['每股收益',JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_32],
['每股净资产',JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_33],
['每股经营性现金流',JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_34],
['扣非净利润涨幅',JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_35],
['扣非净利润涨速',JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_36],
['净利润涨幅',JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_37],
['资产负债率',JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_38],
['利润同比',JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_F_39],
]);
if (dataMap.has(value)) return dataMap.get(value);
return null;
},
//获取报告期 2018, 1
GetSectionReportPeriod:function(year,quarter)
{
if (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],
['FROMOPEN',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()
{
JSConsole.Complier.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_SYMBOL_DAY_DATA:
return this.SymbolData.GetSymbolDayData();
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_INDEX_DATA:
return this.SymbolData.GetIndexData();
case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_LATEST_INDEX_DATA:
return this.SymbolData.GetLatestIndexData();
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 'FROMOPEN':
return this.SymbolData.GetLatestIndexCacheData('FROMOPEN');
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<count;++i)
{
result[i]=value;
}
return result;
}
this.RunAST=function()
{
//预定义的变量
for(let i in this.Arguments)
{
let item =this.Arguments[i];
this.VarTable.set(item.Name,item.Value);
}
if (!this.AST) this.ThrowError();
if (!this.AST.Body) this.ThrowError();
for(let i in this.AST.Body)
{
let item =this.AST.Body[i];
this.VisitNode(item);
//输出变量
if (item.Type==Syntax.ExpressionStatement && item.Expression)
{
if (item.Expression.Type==Syntax.AssignmentExpression && item.Expression.Operator==':' && item.Expression.Left)
{
let assignmentItem=item.Expression;
let varName=assignmentItem.Left.Name;
let outVar=this.VarTable.get(varName);
if (!this.IsSectionMode && !Array.isArray(outVar))
{
if (typeof(outVar)=='string') outVar=this.SingleDataToArrayData(parseFloat(outVar));
else outVar=this.SingleDataToArrayData(outVar);
}
this.OutVarTable.push({Name:varName, Data:outVar,Type:0});
}
else if (item.Expression.Type==Syntax.CallExpression)
{
let callItem=item.Expression;
if (this.Draw.IsDrawFunction(callItem.Callee.Name))
{
let draw=callItem.Draw;
draw.Name=callItem.Callee.Name;
this.OutVarTable.push({Name:draw.Name, Draw:draw, Type:1});
}
}
else if (item.Expression.Type==Syntax.SequenceExpression)
{
let varName;
let draw;
let color;
let lineWidth;
let colorStick=false;
let pointDot=false;
let circleDot=false;
let lineStick=false;
let stick=false;
let volStick=false;
let isShow=true;
let isExData=false;
let isDotLine=false;
for(let j in item.Expression.Expression)
{
let itemExpression=item.Expression.Expression[j];
if (itemExpression.Type==Syntax.AssignmentExpression && itemExpression.Operator==':' && itemExpression.Left)
{
varName=itemExpression.Left.Name;
let varValue=this.VarTable.get(varName);
if (!Array.isArray(varValue))
{
varValue=this.SingleDataToArrayData(varValue);
this.VarTable.set(varName,varValue); //把常量放到变量表里
}
}
else if (itemExpression.Type==Syntax.Identifier)
{
let value=itemExpression.Name;
if (value==='COLORSTICK') colorStick=true;
else if (value==='POINTDOT') pointDot=true;
else if (value==='CIRCLEDOT') circleDot=true;
else if (value=='DOTLINE') isDotLine=true;
else if (value==='LINESTICK') lineStick=true;
else if (value==='STICK') stick=true;
else if (value==='VOLSTICK') volStick=true;
else if (value.indexOf('COLOR')==0) color=value;
else if (value.indexOf('LINETHICK')==0) lineWidth=value;
else if (value.indexOf('NODRAW')==0) isShow=false;
else if (value.indexOf('EXDATA')==0) isExData=true; //扩展数据, 不显示再图形里面
}
else if(itemExpression.Type==Syntax.Literal) //常量
{
let aryValue=this.SingleDataToArrayData(itemExpression.Value);
varName=itemExpression.Value.toString();
this.VarTable.set(varName,aryValue); //把常量放到变量表里
}
else if (itemExpression.Type==Syntax.CallExpression && this.Draw.IsDrawFunction(itemExpression.Callee.Name))
{
draw=itemExpression.Draw;
draw.Name=itemExpression.Callee.Name;
}
}
if (pointDot && varName) //圆点
{
let outVar=this.VarTable.get(varName);
if (!Array.isArray(outVar)) outVar=this.SingleDataToArrayData(outVar);
let value={Name:varName, Data:outVar, Radius:2, Type:3};
if (color) value.Color=color;
if (lineWidth) value.LineWidth=lineWidth;
this.OutVarTable.push(value);
}
else if (circleDot && varName) //圆点
{
let outVar=this.VarTable.get(varName);
if (!Array.isArray(outVar)) outVar=this.SingleDataToArrayData(outVar);
let value={Name:varName, Data:outVar, Radius:1.3, Type:3};
if (color) value.Color=color;
if (lineWidth) value.LineWidth=lineWidth;
this.OutVarTable.push(value);
}
else if (lineStick && varName) //LINESTICK 同时画出柱状线和指标线
{
let outVar=this.VarTable.get(varName);
let value={Name:varName, Data:outVar, Type:4};
if (color) value.Color=color;
if (lineWidth) value.LineWidth=lineWidth;
this.OutVarTable.push(value);
}
else if (stick && varName) //STICK 画柱状线
{
let outVar=this.VarTable.get(varName);
let value={Name:varName, Data:outVar, Type:5};
if (color) value.Color=color;
if (lineWidth) value.LineWidth=lineWidth;
this.OutVarTable.push(value);
}
else if (volStick && varName) //VOLSTICK 画彩色柱状线
{
let outVar=this.VarTable.get(varName);
let value={Name:varName, Data:outVar, Type:6};
if (color) value.Color=color;
this.OutVarTable.push(value);
}
else if (varName && color)
{
let outVar=this.VarTable.get(varName);
if (!Array.isArray(outVar)) outVar=this.SingleDataToArrayData(outVar);
let value={Name:varName, Data:outVar, Color:color, Type:0};
if (lineWidth) value.LineWidth=lineWidth;
if (isShow == false) value.IsShow = false;
if (isExData==true) value.IsExData = true;
if (isDotLine==true) value.IsDotLine=true;
this.OutVarTable.push(value);
}
else if (draw) //画图函数
{
var outVar={Name:draw.Name, Draw:draw, Type:1};
if (color) outVar.Color=color;
if (lineWidth) outVar.LineWidth=lineWidth;
this.OutVarTable.push(outVar);
}
else if (colorStick && varName) //CYW: SUM(VAR4,10)/10000, COLORSTICK; 画上下柱子
{
let outVar=this.VarTable.get(varName);
let value={Name:varName, Data:outVar, Color:color, Type:2};
this.OutVarTable.push(value);
}
else if (varName)
{
let outVar=this.VarTable.get(varName);
let value={Name:varName, Data:outVar,Type:0};
if (color) value.Color=color;
if (lineWidth) value.LineWidth=lineWidth;
if (isShow==false) value.IsShow=false;
if (isExData==true) value.IsExData = true;
if (isDotLine==true) value.IsDotLine=true;
this.OutVarTable.push(value);
}
}
}
}
JSConsole.Complier.Log('[JSExecute::Run]', this.VarTable);
return this.OutVarTable;
}
this.Run=function()
{
try
{
let data=this.RunAST();//执行脚本
JSConsole.Complier.Log('[JSComplier.Run] execute finish', data);
if (this.UpdateUICallback)
{
JSConsole.Complier.Log('[JSComplier.Run] invoke UpdateUICallback.');
if (this.CallbackParam && this.CallbackParam.Self && this.CallbackParam.Self.ClassName==='ScriptIndexConsole') this.CallbackParam.JSExecute=this;
this.UpdateUICallback(data,this.CallbackParam);
}
}
catch(error)
{
JSConsole.Complier.Log(error);
if (error.Job)
{
JSConsole.Complier.Log('[JSComplier.Run] download job and reexectue', error.Job);
this.JobList.push(error.Job);
this.JobList.push({ID:JS_EXECUTE_JOB_ID.JOB_RUN_SCRIPT});
this.Execute();
}
else if (this.ErrorCallback)
{
this.ErrorCallback(error);
}
}
}
this.VisitNode=function(node)
{
switch(node.Type)
{
case Syntax.SequenceExpression:
this.VisitSequenceExpression(node);
break;
case Syntax.ExpressionStatement:
this.VisitNode(node.Expression);
break;
case Syntax.AssignmentExpression:
this.VisitAssignmentExpression(node);
break;
case Syntax.BinaryExpression:
case Syntax.LogicalExpression:
this.VisitBinaryExpression(node);
break;
case Syntax.CallExpression:
this.VisitCallExpression(node);
break;
}
}
this.VisitSequenceExpression=function(node)
{
for(let i in node.Expression)
{
let item =node.Expression[i];
this.VisitNode(item);
}
}
//函数调用
this.VisitCallExpression=function(node)
{
let funcName=node.Callee.Name;
let args=[];
for(let i in node.Arguments)
{
let item=node.Arguments[i];
let value;
if (item.Type==Syntax.BinaryExpression || item.Type==Syntax.LogicalExpression)
value=this.VisitBinaryExpression(item);
else if (item.Type==Syntax.CallExpression)
value=this.VisitCallExpression(item);
else
value=this.GetNodeValue(item);
args.push(value);
}
if (JS_EXECUTE_DEBUG_LOG) JSConsole.Complier.Log('[JSExecute::VisitCallExpression]' , funcName, '(', args.toString() ,')');
switch(funcName)
{
case 'DYNAINFO': //行情最新数据
node.Out=this.SymbolData.GetLatestCacheData(args[0]);
break;
case 'STICKLINE':
node.Draw=this.Draw.STICKLINE(args[0],args[1],args[2],args[3],args[4]);
node.Out=[];
break;
case 'DRAWTEXT':
node.Draw=this.Draw.DRAWTEXT(args[0],args[1],args[2]);
node.Out=[];
break;
case 'DRAWTEXT_FIX':
node.Draw=this.Draw.DRAWTEXT_FIX(args[0],args[1],args[2],args[3],args[4]);
node.Out=[];
break;
case 'SUPERDRAWTEXT':
node.Draw=this.Draw.SUPERDRAWTEXT(args[0],args[1],args[2],args[3],args[4]);
node.Out=[];
break;
case 'DRAWICON':
node.Draw=this.Draw.DRAWICON(args[0],args[1],args[2]);
node.Out=[];
break;
case 'DRAWLINE':
node.Draw=this.Draw.DRAWLINE(args[0],args[1],args[2],args[3],args[4]);
node.Out=node.Draw.DrawData;
break;
case 'DRAWBAND':
node.Draw=this.Draw.DRAWBAND(args[0],args[1],args[2],args[3]);
node.Out=[];
break;
case 'DRAWKLINE':
node.Draw=this.Draw.DRAWKLINE(args[0],args[1],args[2],args[3]);
node.Out=[];
break;
case 'DRAWKLINE_IF':
node.Draw=this.Draw.DRAWKLINE_IF(args[0],args[1],args[2],args[3],args[4]);
node.Out=[];
break;
case 'PLOYLINE':
case 'POLYLINE':
node.Draw=this.Draw.POLYLINE(args[0],args[1]);
node.Out=node.Draw.DrawData;
break;
case 'DRAWNUMBER':
node.Draw=this.Draw.DRAWNUMBER(args[0],args[1],args[2]);
node.Out=node.Draw.DrawData.Value;
break;
case "DRAWCHANNEL":
node.Draw=this.Draw.DRAWCHANNEL(args[0],args[1],args[2],args[3],args[4],args[5],args[6]);
node.Out=[];
break;
case 'RGB':
node.Out=this.Draw.RGB(args[0],args[1],args[2]);
break;
case 'PARTLINE':
node.Draw=this.Draw.PARTLINE(args);
node.Out=[];
break;
case 'DRAWGBK':
node.Draw=this.Draw.DRAWGBK(args[0],args[1],args[2],args[3]);
node.Out=[];
break;
case 'DRAWTEXT_LINE':
node.Draw=this.Draw.DRAWTEXT_LINE(args[0],args[1],args[2],args[3],args[4],args[5],args[6]);
node.Out=[];
break;
case 'DRAWRECTREL':
node.Draw=this.Draw.DRAWRECTREL(args[0],args[1],args[2],args[3],args[4]);
node.Out=[];
break;
case 'CODELIKE':
node.Out=this.SymbolData.CODELIKE(args[0]);
break;
case 'NAMELIKE':
node.Out=this.SymbolData.NAMELIKE(args[1]);
break;
case 'REFDATE':
node.Out=this.SymbolData.REFDATE(args[0],args[1]);
break;
case 'FINANCE':
node.Out=this.SymbolData.GetFinanceCacheData(args[0],node);
break;
case "MARGIN":
node.Out=this.SymbolData.GetMarginCacheData(args[0],node);
break;
case "HK2SHSZ":
node.Out=this.SymbolData.GetHKToSHSZCacheData(args[0],node);
break;
case "NEWS":
node.Out=this.SymbolData.GetNewsAnalysisCacheData(args[0],node);
break;
case 'UPCOUNT':
case 'DOWNCOUNT':
node.Out=this.SymbolData.GetIndexIncreaseCacheData(funcName,args[0],node);
break;
case 'SF':
node.Out=this.SymbolData.GetSectionFinanceCacheData(args[0],args[1],args[2],node);
break;
default:
node.Out=this.Algorithm.CallFunction(funcName, args, node, this.SymbolData);
break;
}
return node.Out;
}
//赋值
this.VisitAssignmentExpression=function(node)
{
let left=node.Left;
if (left.Type!=Syntax.Identifier) this.ThrowUnexpectedNode(node);
let varName=left.Name;
let right=node.Right;
let value=null;
if (right.Type==Syntax.BinaryExpression || right.Type==Syntax.LogicalExpression)
value=this.VisitBinaryExpression(right);
else if (right.Type==Syntax.CallExpression)
value=this.VisitCallExpression(right);
else if (right.Type==Syntax.Literal)
value=right.Value;
else if (right.Type==Syntax.Identifier) //右值是变量
value=this.ReadVariable(right.Name,right);
if (JS_EXECUTE_DEBUG_LOG) JSConsole.Complier.Log('[JSExecute::VisitAssignmentExpression]' , varName, ' = ',value);
this.VarTable.set(varName,value);
}
//逻辑运算
this.VisitBinaryExpression=function(node)
{
let stack=[];
stack.push(node);
let temp=null;
while(stack.length!=0)
{
temp=stack[stack.length-1];
if (temp.Left && node!=temp.Left && node!=temp.Right)
{
stack.push(temp.Left);
}
else if (temp.Right && node!=temp.Right)
{
stack.push(temp.Right);
}
else
{
let value=stack.pop();
if (value.Type==Syntax.BinaryExpression) //只遍历操作符就可以
{
let leftValue=this.GetNodeValue(value.Left);
let rightValue=this.GetNodeValue(value.Right);
if (JS_EXECUTE_DEBUG_LOG) JSConsole.Complier.Log('[JSExecute::VisitBinaryExpression] BinaryExpression',value , leftValue, rightValue);
value.Out=null; //保存中间值
switch(value.Operator)
{
case '-':
value.Out=this.Algorithm.Subtract(leftValue,rightValue);
break;
case '*':
value.Out=this.Algorithm.Multiply(leftValue,rightValue);
break;
case '/':
value.Out=this.Algorithm.Divide(leftValue,rightValue)
break;
case '+':
value.Out=this.Algorithm.Add(leftValue,rightValue);
break;
case '>':
value.Out=this.Algorithm.GT(leftValue,rightValue);
break;
case '>=':
value.Out=this.Algorithm.GTE(leftValue,rightValue);
break;
case '<':
value.Out=this.Algorithm.LT(leftValue,rightValue);
break;
case '<=':
value.Out=this.Algorithm.LTE(leftValue,rightValue);
break;
case '==':
case '=': //= 比较
value.Out=this.Algorithm.EQ(leftValue,rightValue);
break;
case '!=':
case '<>':
value.Out=this.Algorithm.NEQ(leftValue,rightValue);
break;
}
if (JS_EXECUTE_DEBUG_LOG) JSConsole.Complier.Log('[JSExecute::VisitBinaryExpression] BinaryExpression',value);
}
else if (value.Type==Syntax.LogicalExpression)
{
let leftValue=this.GetNodeValue(value.Left);
let rightValue=this.GetNodeValue(value.Right);
if (JS_EXECUTE_DEBUG_LOG) JSConsole.Complier.Log('[JSExecute::VisitBinaryExpression] LogicalExpression',value , leftValue, rightValue);
value.Out=null; //保存中间值
switch(value.Operator)
{
case '&&':
case 'AND':
value.Out=this.Algorithm.And(leftValue,rightValue);
break;
case '||':
case 'OR':
value.Out=this.Algorithm.Or(leftValue,rightValue);
break;
}
if (JS_EXECUTE_DEBUG_LOG) JSConsole.Complier.Log('[JSExecute::VisitBinaryExpression] LogicalExpression',value);
}
node=temp;
}
}
return node.Out;
}
this.GetNodeValue=function(node)
{
switch(node.Type)
{
case Syntax.Literal: //数字
return node.Value;
case Syntax.UnaryExpression:
if (node.Operator=='-')
{
let value=this.GetNodeValue(node.Argument);
return this.Algorithm.Subtract(0,value);
}
return node.Argument.Value;
case Syntax.Identifier:
let value=this.ReadVariable(node.Name,node);
return value;
case Syntax.BinaryExpression:
case Syntax.LogicalExpression:
return node.Out;
case Syntax.CallExpression:
return this.VisitCallExpression(node);
default:
this.ThrowUnexpectedNode(node);
}
}
this.ThrowUnexpectedNode=function(node,message)
{
let marker=node.Marker;
let msg=message || "执行异常";
return this.ErrorHandler.ThrowError(marker.Index,marker.Line,marker.Column,msg);
}
this.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)
{
JSConsole.Complier.Log('[JSComplier.Tokenize]', code);
let tokenizer=new Tokenizer(code);
let tokens=[];
try
{
while(true)
{
let token=tokenizer.GetNextToken();
if (!token) break;
tokens.push(token);
}
}
catch(e)
{
}
return tokens;
}
//语法解析 生成抽象语法树(Abstract Syntax Tree)
JSComplier.Parse=function(code)
{
JSConsole.Complier.Log('[JSComplier.Parse]',code);
let parser=new JSParser(code);
parser.Initialize();
let program=parser.ParseScript();
let ast=program;
return ast;
}
/*
执行
option.Symbol=股票代码
option.Name=股票名称
option.Data=这个股票的ChartData
option.Right=复权
option.MaxReqeustDataCount=请求数据的最大个数
*/
function timeout(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}
JSComplier.Execute=function(code,option,errorCallback)
{
//异步调用
//var asyncExecute= async function() es5不能执行 去掉异步
var asyncExecute= function()
{
try
{
JSConsole.Complier.Log('[JSComplier.Execute]',code,option);
JSConsole.Complier.Log('[JSComplier.Execute] parser .....');
let parser=new JSParser(code);
parser.Initialize();
let program=parser.ParseScript();
let ast=program;
JSConsole.Complier.Log('[JSComplier.Execute] parser finish.', ast);
JSConsole.Complier.Log('[JSComplier.Execute] execute .....');
let execute=new JSExecute(ast,option);
execute.ErrorCallback=errorCallback; //执行错误回调
execute.JobList=parser.Node.GetDataJobList();
if (option.ClassName=='ScriptIndexConsole') execute.JobList.unshift({ID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SYMBOL_DATA});
execute.JobList.push({ID:JS_EXECUTE_JOB_ID.JOB_RUN_SCRIPT});
let result=execute.Execute();
}catch(error)
{
JSConsole.Complier.Log(error);
if (errorCallback) errorCallback(error);
}
}
asyncExecute();
JSConsole.Complier.Log('[JSComplier.Execute] async execute.');
}
JSComplier.SetDomain = function (domain, cacheDomain) //修改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;
this.TitleFont=g_JSChartResource.TitleFont; //标题字体
this.IsShortTitle=false; //是否显示指标参数
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.TitleFont) this.TitleFont=option.TitleFont;
if (option.IsShortTitle) this.IsShortTitle=option.IsShortTitle;
}
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)
{
JSConsole.Complier.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 && i<titlePaint.Data.length) //设置标题数值 小数位数和格式
{
if (this.StringFormat>0) 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;
if (!this.IsShortTitle)
{
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+')';
}
if (this.TitleFont) hqChart.TitlePaint[titleIndex].Font=this.TitleFont;
return true;
}
//给一个默认的颜色
this.GetDefaultColor=function(id)
{
let COLOR_ARRAY=null;
//使用全局线段配置
if (g_JSChartResource && g_JSChartResource.Index && g_JSChartResource.Index.LineColor)
{
COLOR_ARRAY=g_JSChartResource.Index.LineColor;
}
if (!COLOR_ARRAY || !Array.isArray(COLOR_ARRAY))
{
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)
{
JSConsole.Complier.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)
{
JSConsole.Complier.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);
JSConsole.Complier.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<time.length) indexItem.Time=time[i];
indexItem.Value=value;
arySingleData.push(indexItem);
}
var aryFittingData;
if (ChartData.IsDayPeriod(hqChart.Period))
aryFittingData=kdata.GetFittingData(arySingleData); //数据和主图K线拟合
else
aryFittingData=kdata.GetMinuteFittingData(arySingleData); //数据和主图K线拟合
var bindData=new ChartData();
bindData.Data=aryFittingData;
var result;
if (arrayType==1) result=bindData.GetObject();
else result=bindData.GetValue();
return result;
}
this.FittingMultiLine=function(sourceData,date,time,hqChart)
{
var kdata=hqChart.ChartPaint[0].Data; //K线
if (ChartData.IsDayPeriod(hqChart.Period,true)) //日线
{
var aryPoint=[];
for(var i in sourceData)
{
var item=sourceData[i];
for(var j in item.Point)
{
var point=item.Point[j];
aryPoint.push(point);
}
}
aryPoint.sort(function(a,b) { return a.Date-b.Date; });
kdata.GetDateIndex(aryPoint);
return sourceData;
}
else if (ChartData.IsMinutePeriod(hqChart.Period,true)) //分钟线
{
var aryPoint=[];
for(var i in sourceData)
{
var item=sourceData[i];
for(var j in item.Point)
{
var point=item.Point[j];
aryPoint.push(point);
}
}
aryPoint.sort(function(a,b)
{
if (a.Date==b.Date) return a.Time-b.Time;
return a.Date-b.Date;
}
);
kdata.GetDateTimeIndex(aryPoint);
return sourceData;
}
return null;
}
this.FittingMultiText=function(sourceData,date,time,hqChart)
{
var kdata=hqChart.ChartPaint[0].Data; //K线
if (ChartData.IsDayPeriod(hqChart.Period,true)) //日线
{
sourceData.sort(function(a,b) { return a.Date-b.Date; });
kdata.GetDateIndex(sourceData);
return sourceData;
}
else if (ChartData.IsMinutePeriod(hqChart.Period,true)) //分钟线
{
sourceData.sort(function(a,b)
{
if (a.Date==b.Date) return a.Time-b.Time;
return a.Date-b.Date;
}
);
kdata.GetDateTimeIndex(sourceData);
return sourceData;
}
return null;
}
this.FittingData=function(jsonData, hqChart)
{
var outVar=jsonData.outvar;
var date=jsonData.date;
var time=jsonData.time;
var kdata=hqChart.ChartPaint[0].Data;
//把数据拟合到kdata上
var result=[];
for(var i in outVar)
{
var item=outVar[i];
var indexData=[];
var outVarItem={Name:item.name,Type:item.type};
if (item.color) outVarItem.Color=item.color;
if (item.data)
{
outVarItem.Data=this.FittingArray(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);
}
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<time.length) indexItem.Time=time[i];
indexItem.Value=value;
arySingleData.push(indexItem);
}
var aryFittingData=minutedata.GetMinuteFittingData(arySingleData); //数据和主图K线拟合
var bindData=new ChartData();
bindData.Data=aryFittingData;
var result=bindData.GetValue();
return result;
}
}
// 本地json数据指标
function LocalJsonDataIndex(name,args,option)
{
this.newMethod=ScriptIndex; //派生
this.newMethod(name,null,args,null);
delete this.newMethod;
this.JsonData; //json格式数据
if (option.JsonData) this.JsonData=option.JsonData;
this.RequestData=function(hqChart,windowIndex,hisData)
{
if (!this.JsonData)
{
console.warn("[LocalJsonDataIndex::RequestData] JsonData is null");
if (param.HQChart.ScriptErrorCallback) param.HQChart.ScriptErrorCallback('json 数据不能为空');
return;
}
this.OutVar=this.FittingData(this.JsonData,hisData);
this.BindData(hqChart,windowIndex,hisData);
}
this.FittingData=function(jsonData, hisData)
{
outVar=jsonData.OutVar;
date=jsonData.Date;
time=jsonData.Time;
result=[];
for(i in outVar)
{
item=outVar[i];
JSConsole.Complier.Log('[LocalJsonDataIndex::FittingData] item', item);
if (item.Type!=0 && item.Type!=3) //复杂的图形不支持
{
console.warn("[LocalJsonDataIndex::FittingData] can't support ", item.Name, item.Type);
continue;
}
var indexData=[];
outVarItem={Name:item.Name,Type:item.Type}
for(j in item.Data)
{
var indexItem=new SingleData(); //单列指标数据
indexItem.Date=date[j];
if (time && j<time.length) indexItem.Time=time[j];
indexItem.Value=item.Data[j];
indexData.push(indexItem);
}
if (hisData.Period<4)
var aryFittingData=hisData.GetFittingData(indexData); //数据和主图K线拟合
else
var aryFittingData=hisData.GetMinuteFittingData(indexData); //数据和主图K线拟合
var bindData=new ChartData();
bindData.Data=aryFittingData;
outVarItem.Data=bindData.GetValue();
result.push(outVarItem)
}
return result;
}
}
////////////////////////////////////////////////////////////////////////
// 无UI指标执行
// obj: { Name:指标名字 , ID:指标ID , Script:指标脚本, Args:指标参数, ErrorCallback:错误回调 }
//
///////////////////////////////////////////////////////////////////////
function ScriptIndexConsole(obj)
{
this.ID; //指标ID
this.Name; //指标名字
this.Script; //脚本
this.Arguments=[]; //参数
this.ClassName='ScriptIndexConsole';
this.ErrorCallback; //执行错误回调
this.FinishCallback; //执行完成回调
this.IsSectionMode=false; //截面报表模式
if (obj)
{
if (obj.Name) this.Name=obj.Name;
if (obj.Script) this.Script=obj.Script;
if (obj.ID) this.ID=obj.ID;
if (obj.Args) this.Arguments=obj.Args;
if (obj.ErrorCallback) this.ErrorCallback=obj.ErrorCallback;
if (obj.FinishCallback) this.FinishCallback=obj.FinishCallback;
if (obj.IsSectionMode) this.IsSectionMode=obj.IsSectionMode;
}
//执行脚本
//obj:
// HQDataType:(HQ_DATA_TYPE), Period:周期, Right:复权
// Stock: {Name:, Symbol:}, Request: { MaxDataCount:请求K线数据个数, MaxMinuteDayCount:请求分钟数据天数, TradeDate: 历史走势图才用}, :
// Data: 当前计算数据(周期|复权以后), Source: 原始股票数据
this.ExecuteScript=function(obj)
{
this.OutVar=[];
let param= { Self:this };
let option=
{
HQDataType:obj.HQDataType,
Symbol:obj.Stock.Symbol,
Name:obj.Stock.Name,
Period:obj.Period,
Right:obj.Right,
Callback:this.RecvResultData, CallbackParam:param,
Async:true,
MaxRequestDataCount:obj.Request.MaxDataCount,
MaxRequestMinuteDayCount:obj.Request.MaxMinuteDayCount,
Arguments:this.Arguments,
IsSectionMode:this.IsSectionMode,
ClassName:'ScriptIndexConsole',
};
if (obj.HQDataType===HQ_DATA_TYPE.HISTORY_MINUTE_ID) option.TrateDate=obj.Request.TradeDate;
if (obj.HQDataType==HQ_DATA_TYPE.MULTIDAY_MINUTE_ID) option.DayCount=obj.DayCount;
let code=this.Script;
let run=JSComplier.Execute(code,option,this.ErrorCallback);
}
this.RecvResultData=function(outVar,param)
{
var self=param.Self;
var jsExec=param.JSExecute;
var date=null;
if (jsExec.SymbolData.Data)
date=jsExec.SymbolData.Data.GetDate();
var result=
{
Out:outVar,
Date:date, //日期对应 上面的数据
Stock:{ Name:jsExec.SymbolData.Name, Symbol:jsExec.SymbolData.Symbol }, //股票信息
Index: { Name:self.Name, ID:self.ID } //指标信息
};
if (jsExec.SymbolData.DataType==HQ_DATA_TYPE.MULTIDAY_MINUTE_ID || jsExec.SymbolData.DataType==HQ_DATA_TYPE.MINUTE_ID) result.Time=jsExec.SymbolData.Data.GetTime();
else if (jsExec.SymbolData.DataType==HQ_DATA_TYPE.KLINE_ID && ChartData.IsMinutePeriod(jsExec.SymbolData.Period,true)) result.Time=jsExec.SymbolData.Data.GetTime();
//JSConsole.Complier.Log('[ScriptIndexConsole::RecvResultData] outVar ', outVar);
if (self.FinishCallback) self.FinishCallback(result, param.JSExecute);
}
}
ScriptIndexConsole.SetDomain = function (domain, cacheDomain) //修改API地址
{
JSComplier.SetDomain(domain,cacheDomain);
}
/* 测试例子
var code1='VARHIGH:IF(VAR1<=REF(HH,-1),REF(H,BARSLAST(VAR1>=REF(HH,1))),DRAWNULL),COLORYELLOW;';
var code2='VAR1=((SMA(MAX((CLOSE - LC),0),3,1) / SMA(ABS((CLOSE - LC)),3,1)) * 100);';
var code3='mm1=1-2*-9+20;';
JSConsole.Complier.Log(code1+code2)
var tokens=JSComplier.Tokenize(code1+code2);
var ast=JSComplier.Parse(code2+code1);
JSConsole.Complier.Log(ast);
*//*
Copyright (c) 2018 jones
http://www.apache.org/licenses/LICENSE-2.0
开源项目 https://github.com/jones2000/HQChart
jones_2000@163.com
配色
*/
/*
不同风格行情配置文件
!!手机上字体大小需要*分辨率比
*/
/* umychart.js 里面已经有了
function GetDevicePixelRatio()
{
return window.devicePixelRatio || 1;
}
*/
//黑色风格
var BLACK_STYLE=
{
BGColor:'rgb(0,0,0)', //背景色
TooltipBGColor: "rgb(255, 255, 255)", //背景色
TooltipAlpha: 0.92, //透明度
SelectRectBGColor: "rgba(1,130,212,0.06)", //背景色
// SelectRectAlpha: 0.06; //透明度
//K线颜色
UpBarColor: "rgb(238,21,21)", //上涨
DownBarColor: "rgb(25,158,0)", //下跌
UnchagneBarColor: "rgb(228,228,228)", //平盘
Minute:
{
VolBarColor: "rgb(255,236,0)",
PriceColor: "rgb(25,180,231)",
AreaPriceColor:"rgba(63,158,255,.3)",
AvPriceColor: "rgb(255,236,0)",
PositionColor:'rgb(218,165,32)',
},
DefaultTextColor: "rgb(101,104,112)",
DefaultTextFont: 14*GetDevicePixelRatio() +'px 微软雅黑',
TitleFont: 13*GetDevicePixelRatio() +'px 微软雅黑', //标题字体(动态标题 K线及指标的动态信息字体)
UpTextColor: "rgb(238,21,21)",
DownTextColor: "rgb(25,158,0)",
UnchagneTextColor: "rgb(101,104,112)",
CloseLineColor: 'rgb(178,34,34)',
FrameBorderPen: "rgba(236,236,236,0.13)", //边框
FrameSplitPen: "rgba(236,236,236,0.13)", //分割线
FrameSplitTextColor: "rgb(101,104,112)", //刻度文字颜色
FrameSplitTextFont: 12*GetDevicePixelRatio() +"px 微软雅黑", //坐标刻度文字字体
FrameTitleBGColor: "rgb(0,0,0)", //标题栏背景色
Frame:{ XBottomOffset:1*GetDevicePixelRatio() }, //X轴文字向下偏移
FrameLatestPrice : {
TextColor:'rgb(255,255,255)', //最新价格文字颜色
UpBarColor:"rgb(238,21,21)", //上涨
DownBarColor:"rgb(25,158,0)", //下跌
UnchagneBarColor:"rgb(190,190,190)", //平盘
BGAlpha:0.6
},
CorssCursorBGColor: "rgb(43,54,69)", //十字光标背景
CorssCursorTextColor: "rgb(255,255,255)",
CorssCursorTextFont: 12*GetDevicePixelRatio() +"px 微软雅黑",
CorssCursorHPenColor: "rgb(130,130,130)", //十字光标线段颜色
CorssCursorVPenColor: "rgb(130,130,130)", //十字光标线段颜色
KLine:
{
MaxMin: { Font: 12*GetDevicePixelRatio() +'px 微软雅黑', Color: 'rgb(111,111,111)' }, //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'},
}
},
Index:
{
LineColor: //指标线段颜色
[
"rgb(255,189,09)",
"rgb(22,198,255)",
"rgb(174,35,161)",
"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)",
],
NotSupport: { Font: "14px 微软雅黑", TextColor: "rgb(52,52,52)" }
},
ColorArray: //自定义指标默认颜色
[
"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)",
],
DrawPicture: //画图工具
{
LineColor: "rgb(30,144,255)",
PointColor: "rgb(105,105,105)",
},
TooltipPaint :
{
BGColor:'rgba(20,20,20,0.8)', //背景色
BorderColor:'rgb(210,210,210)', //边框颜色
TitleColor:'rgb(210,210,210)', //标题颜色
TitleFont:13*GetDevicePixelRatio() +'px 微软雅黑' //字体
},
//走势图 信息地雷
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,1)'
}
};
var STYLE_TYPE_ID=
{
BLACK_ID:1, //黑色风格
}
function HQChartStyle()
{
}
HQChartStyle.GetStyleConfig=function(styleid) //获取一个风格的配置变量
{
switch (styleid)
{
case STYLE_TYPE_ID.BLACK_ID:
return BLACK_STYLE;
default:
return null;
}
}
/*
单独的网络接口
*/
function JSNetwork() { }
JSNetwork.HttpRequest=function(obj) //使用uniapp 网络接口接口 !!每家平台都喜欢自定义接口, 低层不都是一样的嘛
{
let method=obj.type.toUpperCase();
uni.request({
url: obj.url,
data: obj.data,
method:method,
success: (res)=>
{
obj.success(res.data);
},
fail: obj.error,
});
}
//把给外界调用的方法暴露出来
export default {
//类导出
JSChart:JSChart, //行情图形库
ChartData:ChartData,
MARKET_SUFFIX_NAME:MARKET_SUFFIX_NAME, //判断股票属性
IFrameSplitOperator:IFrameSplitOperator, //格式化字符串方法
JSKLineInfoMap:JSKLineInfoMap,
JSCHART_EVENT_ID:JSCHART_EVENT_ID, //可以订阅的事件类型
JSCHART_OPERATOR_ID:JSCHART_OPERATOR_ID, //图形控制类型
JSAlgorithm:JSAlgorithm, //算法类
JSComplier:JSComplier, //指标编译器
JSIndexScript:JSIndexScript, //系统指标库
GetDevicePixelRatio,GetDevicePixelRatio,
ScriptIndexConsole:ScriptIndexConsole, //指标执行 无UI
//style.js相关
STYLE_TYPE_ID:STYLE_TYPE_ID,
HQChartStyle:HQChartStyle, //预定义全局的配色 黑
JSConsole:JSConsole, //日志输出
}