
//日志输出类
var JSConsole=
{ 
    Chart:{ Log:console.log },      //图形日志
    Complier:{ Log:console.log },   //编译器日志
    JSTable:{ 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：指标描述信息
    Args:参数 { Name:名字, Value=值 }
    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:[](支持的周期), Include:[](指定支持的股票,代码全部大写包括后缀)}
    OutName:动态输出变量名字 [{Name:原始变量名, DynamicName:动态名字格式}] 如 {Name:"MA1", DynamicName:"MA{M1}"};
*/

//周期条件枚举
var CONDITION_PERIOD=
{
    MINUTE_ID:101,            //分钟      走势图
    MULTIDAY_MINUTE_ID:102,   //多日分钟  走势图
    HISTORY_MINUTE_ID:103,    //历史分钟  走势图

    //K线周期
    KLINE_DAY_ID:0,
    KLINE_WEEK_ID:1,
    KLINE_TWOWEEK_ID:21,
    KLINE_MONTH_ID:2,
    KLINE_QUARTER_ID:9,
   
    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],
            ["MA4", this.MA4],["MA5", this.MA5],["MA6", this.MA6],["MA7", this.MA7],["MA8", this.MA8],
            ['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],["MACD2", this.MACD2],
            ['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], ["ADL", this.ADL],["SQJZ", this.SQJZ],["XT", this.XT],["CFJT", this.CFJT],["CYX",this.CYX],
            ["WAVE",this.WAVE],
            ['VOL-TDX',this.VOL_TDX],
            ['EMPTY', this.EMPTY],  //什么都不显示的指标
            ['神奇九转', this.NineTurns],

            //通达信特色指标
            ["散户线", this.ShareholderCount],["NXTS", this.NXTS],["FKX", this.FKX],["两融资金", this.Margin4],
            ["ZSDB",this.ZSDB],

            ['CJL2', this.CJL],  //期货持仓量
            ['ASI', this.ASI],['DC', this.DC],['DEMA', this.DEMA],["VWAP", this.VWAP],

            ['飞龙四式', this.Dragon4_Main],['飞龙四式-附图', this.Dragon4_Fig],
            ['资金分析', this.FundsAnalysis],['融资占比',this.MarginProportion],['负面新闻', this.NewsNegative],
            ['涨跌趋势', this.UpDownAnalyze],['北上资金', this.HK2SHSZ],['股东人数', this.ShareHolder],

            ["两融余额", this.Margin2],["两融余额2", this.Margin3],

            ['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} ],
        OutName:[ {Name:'MA1',DynamicName:"MA{M1}" },  {Name:'MA2',DynamicName:"MA{M2}" },{Name:'MA3',DynamicName:"MA{M3}" }],
        Script: //脚本
'MA1:MA(CLOSE,M1);\n\
MA2:MA(CLOSE,M2);\n\
MA3:MA(CLOSE,M3);'

    };

    return data;
}

JSIndexScript.prototype.MA4=function()
{
    let data=
    {
        Name:'MA', Description:'均线', IsMainIndex:true, StringFormat:2,
        Args:[ { Name:'M1', Value:5}, { Name:'M2', Value:10 }, { Name:'M3', Value:20},{ Name:'M4', Value:60} ],
        OutName:[ {Name:'MA1',DynamicName:"MA{M1}" },  {Name:'MA2',DynamicName:"MA{M2}" },{Name:'MA3',DynamicName:"MA{M3}" },{Name:'MA4',DynamicName:"MA{M4}" } ],
        Script: //脚本
'MA1:MA(CLOSE,M1);\n\
MA2:MA(CLOSE,M2);\n\
MA3:MA(CLOSE,M3);\n\
MA4:MA(CLOSE,M4);'

    };

    return data;
}

JSIndexScript.prototype.MA5=function()
{
    let data=
    {
        Name:'MA', Description:'均线', IsMainIndex:true, StringFormat:2,
        Args:[ { Name:'M1', Value:5}, { Name:'M2', Value:10 }, { Name:'M3', Value:20} ,{ Name:'M4', Value:60} ,{ Name:'M5', Value:0}],
        OutName:[ {Name:'MA1',DynamicName:"MA{M1}" },  {Name:'MA2',DynamicName:"MA{M2}" },{Name:'MA3',DynamicName:"MA{M3}" },{Name:'MA4',DynamicName:"MA{M4}" },{Name:'MA5',DynamicName:"MA{M5}" } ],
        Script: //脚本
'MA1:MA(CLOSE,M1);\n\
MA2:MA(CLOSE,M2);\n\
MA3:MA(CLOSE,M3);\n\
MA4:MA(CLOSE,M4);\n\
MA5:MA(CLOSE,M5);'

    };

    return data;
}

JSIndexScript.prototype.MA6=function()
{
    let data=
    {
        Name:'MA', Description:'均线', IsMainIndex:true, StringFormat:2,
        Args:
        [ 
            { Name:'M1', Value:5}, { Name:'M2', Value:10 }, { Name:'M3', Value:20} , { Name:'M4', Value:60} ,
            { Name:'M5', Value:0},{ Name:'M6', Value:0}
        ],
        OutName:[ {Name:'MA1',DynamicName:"MA{M1}" },  {Name:'MA2',DynamicName:"MA{M2}" },{Name:'MA3',DynamicName:"MA{M3}" },{Name:'MA4',DynamicName:"MA{M4}" },
        {Name:'MA5',DynamicName:"MA{M5}" } ,{ Name:'MA6',DynamicName:"MA{M6}" } ],
        Script: //脚本
'MA1:MA(CLOSE,M1);\n\
MA2:MA(CLOSE,M2);\n\
MA3:MA(CLOSE,M3);\n\
MA4:MA(CLOSE,M4);\n\
MA5:MA(CLOSE,M5);\n\
MA6:MA(CLOSE,M6);'

    };

    return data;
}

JSIndexScript.prototype.MA7=function()
{
    let data=
    {
        Name:'MA', Description:'均线', IsMainIndex:true, StringFormat:2,
        Args:
        [ 
            { Name:'M1', Value:5}, { Name:'M2', Value:10 }, { Name:'M3', Value:20}, { Name:'M4', Value:60},
            { Name:'M5', Value:0},{ Name:'M6', Value:0} ,{ Name:'M7', Value:0 } 
        ],
        OutName:[ {Name:'MA1',DynamicName:"MA{M1}" },  {Name:'MA2',DynamicName:"MA{M2}" },{Name:'MA3',DynamicName:"MA{M3}" },{Name:'MA4',DynamicName:"MA{M4}" },
        {Name:'MA5',DynamicName:"MA{M5}" } ,{ Name:'MA6',DynamicName:"MA{M6}" } ,{ Name:'MA7',DynamicName:"MA{M7}" }],
        Script: //脚本
'MA1:MA(CLOSE,M1);\n\
MA2:MA(CLOSE,M2);\n\
MA3:MA(CLOSE,M3);\n\
MA4:MA(CLOSE,M4);\n\
MA5:MA(CLOSE,M5);\n\
MA6:MA(CLOSE,M6);\n\
MA7:MA(CLOSE,M7);'

    };

    return data;
}

JSIndexScript.prototype.MA8=function()
{
    let data=
    {
        Name:'MA', Description:'均线', IsMainIndex:true, StringFormat:2,
        Args:
        [ 
            { Name:'M1', Value:5}, { Name:'M2', Value:10 }, { Name:'M3', Value:20}, { Name:'M4', Value:60},
            { Name:'M5', Value:0},{ Name:'M6', Value:0} ,{ Name:'M7', Value:0 } ,{ Name:'M8', Value:0 } 
        ],
        OutName:[ {Name:'MA1',DynamicName:"MA{M1}" },  {Name:'MA2',DynamicName:"MA{M2}" },{Name:'MA3',DynamicName:"MA{M3}" },{Name:'MA4',DynamicName:"MA{M4}" },
        {Name:'MA5',DynamicName:"MA{M5}" } ,{ Name:'MA6',DynamicName:"MA{M6}" } ,{ Name:'MA7',DynamicName:"MA{M7}" },{ Name:'MA8',DynamicName:"MA{M8}" }],
        Script: //脚本
'MA1:MA(CLOSE,M1);\n\
MA2:MA(CLOSE,M2);\n\
MA3:MA(CLOSE,M3);\n\
MA4:MA(CLOSE,M4);\n\
MA5:MA(CLOSE,M5);\n\
MA6:MA(CLOSE,M6);\n\
MA7:MA(CLOSE,M7);\n\
MA8:MA(CLOSE,M8);'

    };

    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.MACD2=function()
{
    let data=
    {
        Name:'MACD', Description:'平滑异同平均', IsMainIndex:false,
        Args:[ { Name:'SHORT', Value:12}, { Name:'LONG', Value:26}, { Name:'MID', Value:9} ],
        Script: //脚本
'DIF2:=EMA(CLOSE,SHORT)-EMA(CLOSE,LONG);\n\
DEA2:=EMA(DIF2,MID);\n\
MACD:(DIF2-DEA2)*2,COLORSTICK,LINETHICK50;\n\
DIF:DIF2;\n\
DEA:DEA2;'

    };

    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} ],
        OutName:[ {Name:'MA1',DynamicName:"MA{M1}" },  {Name:'MA2',DynamicName:"MA{M2}" }],
        Script: //脚本
'VOL:VOL,VOLSTICK;\n\
MA1:MA(VOL,M1);\n\
MA2:MA(VOL,M2);'

    };

    return data;
}

JSIndexScript.prototype.VOL_TDX=function()
{
    let data=
    {
        Name:'VOL-TDX', Description:'成交量(虚拟)', IsMainIndex:false,FloatPrecision:0,
        Args:[ { Name:'M1', Value:5}, { Name:'M2', Value:10} ],
        Script: //脚本
'TOTAL:=IF(PERIOD=1,5,IF(PERIOD=2,15,IF(PERIOD=3,30,IF(PERIOD=4,60,IF(PERIOD=5,TOTALFZNUM,1)))));\n\
MTIME:=MOD(FROMOPEN,TOTAL);\n\
CTIME:=IF(MTIME<0.5,TOTAL,MTIME);\n\
VVOL:IF((CURRBARSCOUNT=1 AND DYNAINFO(8)>1),VOL*(TOTAL+3)/(CTIME+3),DRAWNULL),NODRAW;\n\
STICKLINE((CURRBARSCOUNT=1 AND DYNAINFO(8)>1),VVOL,0,-1,-1),COLORYELLOW;\n\
VOLUME:VOL,VOLSTICK;\n\
MAVOL1:MA(VOLUME,M1);\n\
MAVOL2:MA(VOLUME,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\
DRAWTEXT_FIX(ISLASTBAR,0,0,0,"说明: 红色柱为吸货量,绿色为出货量,黄色为天量,蓝色为地量"),COLORGRAY;\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,3,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,3,0),COLORRED;\n\
STICKLINE(CROSS(C6,C) AND V>V5*1.2 AND V>V12*1.2,0,VOL,3,0),COLORGREEN;\n\
STICKLINE(VOL>MA(VOL,5)*2 AND V>V34*3 AND C<REF(C,1)*1.05,0,VOL,3,0),COLORYELLOW;\n\
STICKLINE(VOL<MA(VOL,5)/2 AND V<V12/2,0,VOL,3,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,3,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,3,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.Margin2=function()
{
    let data =
    {
        Name: '两融余额', Description: '融资融券余额', IsMainIndex: false, 
        Condition: { Period:[CONDITION_PERIOD.KLINE_DAY_ID] },
        Args: [{ Name: 'N', Value: 5 }],
        Script: //脚本
        'T1:MARGIN(1);\n\
        T2:MA(MARGIN(1),N);'
    };

    return data; 
}

JSIndexScript.prototype.Margin3=function()
{
    let data =
    {
        Name: '两融余额', Description: '融资融券余额', IsMainIndex: false, 
        Condition: { Period:[CONDITION_PERIOD.KLINE_DAY_ID] },
        Args: [{ Name: 'N', Value: 5 }],
        Script: //脚本
        'T1:=MARGIN(1);\n\
        T2:=MA(MARGIN(1),N);\n\
        STICKLINE(T1-T2>=0,0,T1-T2,50,T1>T2),COLORRED;\n\
        STICKLINE(T1-T2<0,T1-T2,0,50,T1>T2),COLORGREEN;'
    };

    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.ADL=function()
{
    let data =
    {
        Name: '腾落指标', Description: '腾落指标', IsMainIndex: false, StringFormat:2,
        Condition: 
        { 
            Period:[CONDITION_PERIOD.KLINE_DAY_ID, CONDITION_PERIOD.KLINE_WEEK_ID, CONDITION_PERIOD.KLINE_TWOWEEK_ID,
                CONDITION_PERIOD.KLINE_MONTH_ID, CONDITION_PERIOD.KLINE_QUARTER_ID ,CONDITION_PERIOD.KLINE_YEAR_ID ],
            Include:["000001.SH", "000003.SH", "000016.SH", "000300.SH", "000905.SH", "399001.SZ", " 399005.SZ", "399006.SZ"] 
        },
        Args: [ { Name: 'M', Value: 7 } ],
        Script: //脚本
"ADL:SUM(ADVANCE-DECLINE,0);\n\
MAADL:MA(ADL,M);"
    }

    return data;
}

JSIndexScript.prototype.EMPTY = function () 
{
    let data =
    {
        Name: '', Description: '空指标', IsMainIndex: true,
        Args: [],
        Script: //脚本
            'VAR2:=C;'
    };

    return data;
}

JSIndexScript.prototype.CJL = function () 
{
    let data =
    {
        Name: 'CJL', Description: '期货持仓量', IsMainIndex: false,
        Args: [],
        Script: //脚本
"成交量:VOL,VOLSTICK;\n\
持仓量:VOLINSTK,LINEOVERLAY;"
    };

    return data;
}

JSIndexScript.prototype.ASI = function () 
{
    let data =
    {
        Name: 'ASI', Description: '振动升降指标', IsMainIndex: false,
        Args: [{ Name: 'N1', Value: 6 }],
        Script: //脚本
"X_1:=REF(CLOSE,1);\n\
X_2:=ABS(HIGH-X_1);\n\
X_3:=ABS(LOW-X_1);\n\
X_4:=ABS(HIGH-REF(LOW,1));\n\
X_5:=ABS(X_1-REF(OPEN,1));\n\
X_6:=IF(X_2>X_3 AND X_2>X_4,X_2+X_3/2+X_5/4,IF(X_3>X_4 AND X_3>X_2,X_3+X_2/2+X_5/4,X_4+X_5/4));\n\
X_7:=CLOSE-X_1+(CLOSE-OPEN)/2+X_1-REF(OPEN,1);\n\
X_8:=8*X_7/X_6*MAX(X_2,X_3);\n\
ASI:SUM(X_8,0),LINETHICK2;\n\
MASI:MA(ASI,N1),LINETHICK2;"
    };

    return data;
}

/*
History
The Donchian Channels (DC) indicator was created by the famous commodities trader Richard Donchian. Donchian would become known as The Father of Trend Following.

Calculation
For this example, a 20 day period is used which is a very commonly used timeframe.

Upper Channel = 20 Day High
Lower Channel = 20 Day Low
Middle Channel = (20 Day High + 20 Day Low)/2
*/
JSIndexScript.prototype.DC = function () 
{
    let data =
    {
        Name: 'DC', Description: '唐奇安通道', IsMainIndex: true,
        Args: [{ Name: 'N1', Value: 20 }],
        Script: //脚本
"UPPER:HHV(H,N1),COLORBLUE,LINETHICK2;\n\
LOWER:LLV(L,N1),COLORBLUE,LINETHICK2;\n\
MIDDLE:(UPPER+LOWER)/2,COLORRED,LINETHICK3;"
    };

    return data;
}

/*
双重指数移动均线(DEMA)由Patrick Mulloy开发并于1994年2月在"股票与商品期货的技术分析"杂志中出版。
用于平滑价格系列并被直接应用到金融证券的价格图表中。此外，它还用于平滑其他指标的价值。

DEMA的优势是在锯齿状的价格移动中清除错误信号并允许趋势强劲时保持仓位。

计算
该指标基于指数移动平均线 (EMA). 从EMA值中查看价格偏差错误：
err(i) = Price(i) - EMA(Price, N, i)

此处:
err(i) ― 当前EMA误差;
Price(i) ― 当前价格;
EMA(Price, N, i) ― 价格系列的以N为周期的EMA的当前值。

添加指数平均线错误值到价格指数移动平均数值，可以获得EDMA；
DEMA(i) = EMA(Price,N,i)+ EMA(err,N,i) = EMA(Price,N,i)+EMA(Price-EMA(Price,N,i),N,i) =
= 2*EMA(Price,N,i)-EMA(Price-EMA(Price,N,i),N,i)=2*EMA(Price,N,i)-EMA2(Price,N,i)

此处:
EMA(err, N, i) ― 误差err的指数均线的当前值;
EMA2(Price, N, i) ― 价格的二重连续平滑的当前值。
*/
JSIndexScript.prototype.DEMA = function () 
{
    let data =
    {
        Name: 'DEMA', Description: '双重指数移动均线', IsMainIndex: true,
        Args: [{ Name: 'N1', Value: 10 }],
        Script: //脚本
"ERR:=C-EMA(C,N1);\n\
DEMA:EMA(C,10)+EMA(ERR,N1);"
    };

    return data;
}

/*
Calculation
There are five steps in calculating VWAP:

Calculate the Typical Price for the period.
    [(High + Low + Close)/3)]
Multiply the Typical Price by the period Volume.
    (Typical Price x Volume)
Create a Cumulative Total of Typical Price.
    Cumulative(Typical Price x Volume)
Create a Cumulative Total of Volume.
    Cumulative(Volume)
Divide the Cumulative Totals.
    VWAP = Cumulative(Typical Price x Volume) / Cumulative(Volume)
*/

JSIndexScript.prototype.VWAP = function () 
{
    let data =
    {
        Name: 'VWAP', Description: '成交量加权平均价', IsMainIndex: true,
        Args: [{ Name: 'N1', Value: 10 }],
        Script: //脚本
"PRICE:=(H+L+C)/3;\n\
T2:=VOL*PRICE;\n\
VWAP:SUM(T2,0)/SUM(VOL,0);"
    };

    return data;
}

JSIndexScript.prototype.SQJZ = function () 
{
    let data =
    {
        Name: 'SQJZ', Description: '神奇九转', IsMainIndex: true,
        Script: //脚本
"B:=C<REF(C,4);\n\
N:=CURRBARSCOUNT;\n\
B1:=(N=6 AND REFXV(COUNT(B,6),5)=6) OR (N=7 AND REFXV(COUNT(B,7),6)=7) OR (N=8 AND REFXV(COUNT(B,8),7)=8) OR (N>=9 AND REFXV(COUNT(B,9),8)=9);\n\
DRAWNUMBER(B1 AND REF(B,1)=0,L,1),COLORMAGENTA;\n\
B2:=(N=5 AND REFXV(COUNT(B,6),4)=6) OR (N=6 AND REFXV(COUNT(B,7),5)=7) OR (N=7 AND REFXV(COUNT(B,8),6)=8) OR (N>=8 AND REFXV(COUNT(B,9),7)=9);\n\
DRAWNUMBER(B2 AND REF(B,2)=0,L,2),COLORMAGENTA;\n\
B8:=(N=1 AND COUNT(B,8)=8) OR (N>=2 AND REFXV(COUNT(B,9),1)=9);\n\
DRAWNUMBER(B8 AND REF(B,8)=0,L,8),COLORMAGENTA;\n\
B9:=(N>=1 AND COUNT(B,9)=9);\n\
DRAWNUMBER(B9 AND REF(B,9)=0,L,9),COLORBROWN;\n\
S:=C>REF(C,4);\n\
S1:=(N=6 AND REFXV(COUNT(S,6),5)=6) OR (N=7 AND REFXV(COUNT(S,7),6)=7) OR (N=8 AND REFXV(COUNT(S,8),7)=8) OR (N>=9 AND REFXV(COUNT(S,9),8)=9);\n\
DRAWNUMBER(S1 AND REF(S,1)=0,H,1),COLORMAGENTA,DRAWABOVE;\n\
S2:=(N=5 AND REFXV(COUNT(S,6),4)=6) OR (N=6 AND REFXV(COUNT(S,7),5)=7) OR (N=7 AND REFXV(COUNT(S,8),6)=8) OR (N>=8 AND REFXV(COUNT(S,9),7)=9);\n\
DRAWNUMBER(S2 AND REF(S,2)=0,H,2),COLORMAGENTA,DRAWABOVE;\n\
S8:=(N=1 AND COUNT(S,8)=8) OR (N>=2 AND REFXV(COUNT(S,9),1)=9);\n\
DRAWNUMBER(S8 AND REF(S,8)=0,H,8),COLORMAGENTA,DRAWABOVE;\n\
S9:=(N>=1 AND COUNT(S,9)=9);\n\
DRAWNUMBER(S9 AND REF(S,9)=0,H,9),COLORGREEN,DRAWABOVE;"
    };

    return data;
}

JSIndexScript.prototype.XT = function () 
{
    let data =
    {
        Name: 'XT', Description: '箱体', IsMainIndex: true,
        Args: [{ Name: 'N', Value: 10 }],
        Script: //脚本
"【箱顶】:PEAK(CLOSE,N,1)*0.98;\n\
【箱底】:TROUGH(CLOSE,N,1)*1.02;\n\
【箱高】:100*(【箱顶】-【箱底】)/【箱底】,NODRAW;"
    };

    return data;
}

JSIndexScript.prototype.CFJT = function () 
{
    let data =
    {
        Name: 'CFJT', Description: '财富阶梯', IsMainIndex: true,
        Script: //脚本
"突破:=REF(EMA(C,14),1);\n\
A1X:=(EMA(C,10)-突破)/突破*100;\n\
多方:=IF(A1X>=0,REF(EMA(C,10),BARSLAST(CROSS(A1X,0))+1),DRAWNULL);\n\
空方:=IF(A1X<0,REF(EMA(C,10),BARSLAST(CROSS(0,A1X))+1),DRAWNULL);\n\
STICKLINE(A1X>=0,多方,突破,110,0),COLORRED;\n\
STICKLINE(A1X<0,空方,突破,110,0),COLORGREEN;"
    };

    return data;
}

JSIndexScript.prototype.CYX = function () 
{
    let data =
    {
        Name: 'CYX', Description: '撑压线', IsMainIndex: true,
        Args: [{ Name: 'N', Value: 7 }],
        Script: //脚本
"Z1:=STRCAT(HYBLOCK,' ');\n\
Z2:=STRCAT(Z1,DYBLOCK);\n\
Z3:=STRCAT(Z2,' ');\n\
DRAWTEXT_FIX(ISLASTBAR,0,0,0,STRCAT(Z3,GNBLOCK)),COLOR00C0C0;\n\
A1:=REF(H,N)=HHV(H,2*N+1);\n\
B1:=FILTER(A1,N);\n\
C1:=BACKSET(B1,N+1);\n\
D1:=FILTER(C1,N);\n\
A2:=REF(L,N)=LLV(L,2*N+1);\n\
B2:=FILTER(A2,N);\n\
C2:=BACKSET(B2,N+1);\n\
D2:=FILTER(C2,N);\n\
E1:=(REF(LLV(L,2*N),1)+REF(HHV(H,2*N),1))/2;\n\
E2:=(H+L)/2;\n\
H1:=(D1 AND NOT(D2 AND E1>=E2)) OR ISLASTBAR OR BARSCOUNT(C)=1;\n\
L1:=(D2 AND NOT(D1 AND E1<E2));\n\
H2:=D1 AND NOT(D2 AND E1>=E2);\n\
X1:=REF(BARSLAST(H1),1)+1;\n\
F1:=BACKSET(H1 AND COUNT(L1,X1)>0,LLVBARS(IF(L1,L,10000),X1));\n\
G1:=F1>REF(F1,1);\n\
I1:=BACKSET(G1,2);\n\
LD:=I1>REF(I1,1);\n\
L2:=LD OR ISLASTBAR OR BARSCOUNT(C)=1;\n\
X2:=REF(BARSLAST(L2),1)+1;\n\
F2:=BACKSET(L2 AND COUNT(H2,X2)>0,HHVBARS(IF(H2,H,0),X2));\n\
G2:=F2>REF(F2,1);\n\
I2:=BACKSET(G2,2);\n\
HD:=I2>REF(I2,1);\n\
R1:=BACKSET(ISLASTBAR,BARSLAST(HD)+1);\n\
S1:=R1>REF(R1,1);\n\
T1:=BACKSET(ISLASTBAR,BARSLAST(LD)+1);\n\
U1:=T1>REF(T1,1);\n\
R2:=BACKSET(S1,REF(BARSLAST(HD),1)+2);\n\
S2:=R2>REF(R2,1);\n\
T2:=BACKSET(U1,REF(BARSLAST(LD),1)+2);\n\
U2:=T2>REF(T2,1);\n\
DRAWLINE(S2,H,S1,H,1),LINETHICK2,COLORRED;\n\
DRAWLINE(U2,L,U1,L,1),LINETHICK2,COLORGREEN;"
    };

    return data;
}

JSIndexScript.prototype.WAVE = function () 
{
    let data =
    {
        Name: 'WAVE', Description: '波浪分析', IsMainIndex: true,
        Args: [{ Name: 'N', Value: 5 }],
        Script: //脚本
"ZIG(3,N);"
    };

    return data;
}

JSIndexScript.prototype.ShareholderCount=function()
{
    let data =
    {
        Name: '散户线', Description: '散户线', IsMainIndex: false,
        Script: //脚本
"GPJYVALUE(1,1,1);"
    };

    return data;
}

JSIndexScript.prototype.NXTS=function()
{
    let data =
    {
        Name: 'NXTS', Description: '牛熊天数', IsMainIndex: false,
        Args: [{ Name: 'N', Value: 20 }],
        Script: //脚本
"Z:=ZIG(C,N);\n\
高点:=Z>REF(Z,1) AND Z>REFX(Z,1);\n\
低点:=Z<REF(Z,1) AND Z<REFX(Z,1);\n\
NG:=BARSLAST(高点);\n\
ND:=BARSLAST(低点);\n\
D0:=DATETODAY(DATE)-DATETODAY(REF(DATE,BARSSINCE(C)));\n\
DG:=DATETODAY(DATE)-DATETODAY(REF(DATE,NG));\n\
DD:=DATETODAY(DATE)-DATETODAY(REF(DATE,ND));\n\
N1:=(NG>ND OR COUNT(高点,0)=0) AND ND>0 AND (HHV(C,ND)-REF(C,ND))/REF(C,ND)>(N/100);\n\
N2:=NG<ND AND NG>0 AND (LLV(C,NG)-REF(C,NG))/REF(C,NG)>=-(N/100);\n\
N3:=NG<ND AND NG=0;\n\
N4:=COUNT(低点 OR 高点,0)=0 AND (HHV(C,0)-REF(C,BARSSINCE(C)))/REF(C,BARSSINCE(C))>(N/100);\n\
N5:=COUNT(低点,0)=0 AND NG>0 AND (LLV(C,NG)-REF(C,NG))/REF(C,NG)>=-(N/100);\n\
N6:=COUNT(低点,0)=0 AND NG=0;\n\
X1:=(NG<ND OR COUNT(低点,0)=0) AND NG>0 AND (LLV(C,NG)-REF(C,NG))/REF(C,NG)<-(N/100);\n\
X2:=NG>ND AND ND>0 AND (HHV(C,ND)-REF(C,ND))/REF(C,ND)<=(N/100);\n\
X3:=NG>ND AND ND=0;\n\
X4:=COUNT(高点 OR 低点,0)=0 AND (LLV(C,0)-REF(C,BARSSINCE(C)))/REF(C,BARSSINCE(C))<-(N/100);\n\
X5:=COUNT(高点,0)=0 AND ND>0 AND (HHV(C,ND)-REF(C,ND))/REF(C,ND)<=(N/100);\n\
X6:=COUNT(高点,0)=0 AND ND=0;\n\
牛市天数:IF(N4 OR N5 OR N6,D0,IF(N1 OR N2 OR N3,DD,0)),COLORRED;\n\
熊市天数:IF(X4 OR X5 OR X6,D0,IF(X1 OR X2 OR X3,DG,0)),COLORGREEN;"
    };

    return data;
}

JSIndexScript.prototype.FKX=function()
{
    let data =
    {
        Name: 'FKX', Description: '反K线', IsMainIndex: false,
        Script: //脚本
"DRAWKLINE(-LOW, -OPEN, -HIGH, -CLOSE);"
    };

    return data;
}

JSIndexScript.prototype.Margin4=function()
{
    let data =
    {
        Name: '两融资金', Description: '两融资金', IsMainIndex: false,
        Script: //脚本
"TMPV:=IF(FINANCE(3)==0,REF(SCJYVALUE(1,1,1),1),REF(GPJYVALUE(3,1,1),1));\n\
TMPV1:=IF(FINANCE(3)==0,SCJYVALUE(1,1,0),GPJYVALUE(3,1,0));\n\
两融:IF(TMPV==0 OR TMPV1==0,DRAWNULL,IF(FINANCE(3)==0,(SCJYVALUE(1,1,1)-REF(SCJYVALUE(1,1,1),1))/10000-(SCJYVALUE(1,2,1)-REF(SCJYVALUE(1,2,1),1))/10000,((GPJYVALUE(3,1,1)-REF(GPJYVALUE(3,1,1),1))-((GPJYVALUE(3,2,1)*C/10000-(REF(GPJYVALUE(3,2,1),1)*REF(C,1)/10000)))))),NODRAW;\n\
STICKLINE(两融>0,0,两融,2,0),COLORRED;\n\
STICKLINE(两融<0,0,两融,2,0),COLORCYAN;"
    };

    return data;
}

JSIndexScript.prototype.ZSDB=function()
{
    let data =
    {
        Name: 'ZSDB', Description: '指数对比(副图,需下载日线)', IsMainIndex: false,
        Script: //脚本
"A:=REF(INDEXC,1);\n\
指数涨幅:IF(A>0,(INDEXC-A)*100/A,0),NODRAW;\n\
DRAWKLINE(INDEXH,INDEXO,INDEXL,INDEXC);"
    };

    return data;
}

JSIndexScript.prototype.NineTurns=function()
{
    let data =
    {
        Name: '神奇九转', Description: '九转指标', IsMainIndex: true,
        Script: //脚本
"A1:=C>REF(C,4);\n\
A2:=C<REF(C,4);\n\
T1:=A2 AND REF(A1,1);\n\
T2:=A2 AND REF(T1,1);\n\
T3:=A2 AND REF(T2,1);\n\
T4:=A2 AND REF(T3,1);\n\
T5:=A2 AND REF(T4,1);\n\
T6:=A2 AND REF(T5,1);\n\
T7:=A2 AND REF(T6,1);\n\
T8:=A2 AND REF(T7,1);\n\
T9:=A2 AND REF(T8,1);\n\
T10:=A2 AND REF(T9,1);\n\
T11:=A2 AND REF(T10,1);\n\
T12:=A2 AND REF(T11,1);\n\
T13:=A2 AND REF(T12,1);\n\
T14:=A2 AND REF(T13,1);\n\
DRAWTEXT(T1,L*0.98,'1'),COLORGREEN;\n\
DRAWTEXT(T2,L*0.98,'2'),COLORGREEN;\n\
DRAWTEXT(T3,L*0.98,'3'),COLORGREEN;\n\
DRAWTEXT(T4,L*0.98,'4'),COLORGREEN;\n\
DRAWTEXT(T5,L*0.98,'5'),COLORGREEN;\n\
DRAWTEXT(T6,L*0.98,'6'),COLORGREEN;\n\
DRAWTEXT(T7,L*0.98,'7'),COLORGREEN;\n\
DRAWTEXT(T8,L*0.98,'8'),COLORGREEN;\n\
DRAWTEXT(T9,L*0.98,'9'),COLORBLUE;\n\
B1:=C<REF(C,4);\n\
B2:=C>REF(C,4);\n\
D1:=B2 AND REF(B1,1);\n\
D2:=B2 AND REF(D1,1);\n\
D3:=B2 AND REF(D2,1);\n\
D4:=B2 AND REF(D3,1);\n\
D5:=B2 AND REF(D4,1);\n\
D6:=B2 AND REF(D5,1);\n\
D7:=B2 AND REF(D6,1);\n\
D8:=B2 AND REF(D7,1);\n\
D9:=B2 AND REF(D8,1);\n\
D10:=B2 AND REF(D9,1);\n\
D11:=B2 AND REF(D10,1);\n\
D12:=B2 AND REF(D11,1);\n\
D13:=B2 AND REF(D12,1);\n\
D14:=B2 AND REF(D13,1);\n\
DRAWTEXT(D1,H*1.010,'1'),COLORBLUE;\n\
DRAWTEXT(D2,H*1.010,'2'),COLORBLUE;\n\
DRAWTEXT(D3,H*1.010,'3'),COLORBLUE;\n\
DRAWTEXT(D4,H*1.010,'4'),COLORBLUE;\n\
DRAWTEXT(D5,H*1.010,'5'),COLORBLUE;\n\
DRAWTEXT(D6,H*1.010,'6'),COLORBLUE;\n\
DRAWTEXT(D7,H*1.010,'7'),COLORBLUE;\n\
DRAWTEXT(D8,H*1.010,'8'),COLORBLUE;\n\
DRAWTEXT(D9,H*1.010,'9'),COLORGREEN;"
    };

    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, Warn:console.warn },      //图形日志
        Complier:{ Log:console.log, Warn:console.warn }    //编译器日志
    };
}


function JSChart(divElement, bOffscreen)
{
    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())
    {
        JSConsole.Chart.Log("[JSChart::JSChart] divElement hasChildNodes", divElement.childNodes);
    }
    divElement.appendChild(this.CanvasElement);

    //离屏
    this.OffscreenCanvasElement;
    if (bOffscreen==true) this.OffscreenCanvasElement=document.createElement("canvas");

    //改参数div
    this.ModifyIndexDialog=new ModifyIndexDialog(divElement);
    this.ChangeIndexDialog=new ChangeIndexDialog(divElement);
    this.MinuteDialog=new MinuteDialog(divElement);

    this.OnSize=function(option) //{ Type:1 新版本OnSize  Redraw:是否重绘 }
    {
        //画布大小通过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;

        if (this.OffscreenCanvasElement)
        {
            this.OffscreenCanvasElement.height=this.CanvasElement.height;
            this.OffscreenCanvasElement.width=this.CanvasElement.width;
        }

        JSConsole.Chart.Log(`[JSChart::OnSize] devicePixelRatio=${window.devicePixelRatio}, height=${this.CanvasElement.height}, width=${this.CanvasElement.width}`);

        if (option && option.Redraw==false) return;

        if (this.JSChartContainer)
        {
            if (this.JSChartContainer.OnSize && option && option.Type==1) 
            {
                this.JSChartContainer.OnSize();
            }
            else
            {
                if (this.JSChartContainer.Frame) this.JSChartContainer.Frame.SetSizeChage(true);
                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(var i=0;i<chart.Frame.SubFrame.length;++i)
        {
            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,this.OffscreenCanvasElement);

        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.EnableZoomUpDown) chart.EnableZoomUpDown=option.EnableZoomUpDown;
        if (IFrameSplitOperator.IsString(option.SplashTitle)) chart.LoadDataSplashTitle=option.SplashTitle;
        if (IFrameSplitOperator.IsBool(option.EnableZoomIndexWindow)) chart.EnableZoomIndexWindow=option.EnableZoomIndexWindow;
        if (IFrameSplitOperator.IsBool(option.IsDrawPictureXY)) chart.IsDrawPictureXY=option.IsDrawPictureXY;

        if (option.EnableYDrag)
        {
            var item=option.EnableYDrag;
            if (IFrameSplitOperator.IsBool(item.Left)) chart.EnableYDrag.Left=item.Left;
            if (IFrameSplitOperator.IsBool(item.Right)) chart.EnableYDrag.Right=item.Right;
        }

        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>19910101) chart.CustomShow={ Date:option.KLine.FirstShowDate, PageSize:option.KLine.PageSize };
            if (option.KLine.RightSpaceCount>0) chart.RightSpaceCount=option.KLine.RightSpaceCount;
            if (option.KLine.ZoomType>0) chart.ZoomType=option.KLine.ZoomType;
            if (option.KLine.DataWidth>=1) chart.KLineSize={ DataWidth:option.KLine.DataWidth };
            if (IFrameSplitOperator.IsNumber(option.KLine.RightFormula)) chart.RightFormula=option.KLine.RightFormula;
        }

        if (option.EnableFlowCapital)
        {
            var item=option.EnableFlowCapital;
            if (item.BIT==true) chart.EnableFlowCapital.BIT=item.BIT;
        }

        if (IFrameSplitOperator.IsBool(option.EnableBorderDrag))
        {
            chart.EnableBorderDrag=option.EnableBorderDrag;
        }

        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;
            else if(option.Language==='TC') chart.LanguageID=JSCHART_LANGUAGE_ID.LANGUAGE_TRADITIONAL_CHINESE_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.DrawTool)    //画图工具
        {
            if (option.DrawTool.StorageKey && chart.ChartDrawStorage) chart.ChartDrawStorage.Load(option.DrawTool.StorageKey);
        }

        if (IFrameSplitOperator.IsNumber(option.StepPixel)) 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, option.Listener);

        if (option.Border)
        {
            var item=option.Border;
            if (IFrameSplitOperator.IsNumber(option.Border.Left)) chart.Frame.ChartBorder.Left=option.Border.Left;
            else option.Border.Left=chart.Frame.ChartBorder.Left;
            if (IFrameSplitOperator.IsNumber(option.Border.Right)) chart.Frame.ChartBorder.Right=option.Border.Right;
            else option.Border.Right=chart.Frame.ChartBorder.Right;
            if (IFrameSplitOperator.IsNumber(option.Border.Top)) chart.Frame.ChartBorder.Top=option.Border.Top;
            else option.Border.Top=chart.Frame.ChartBorder.Top;
            if (IFrameSplitOperator.IsNumber(option.Border.Bottom)) chart.Frame.ChartBorder.Bottom=option.Border.Bottom;
            else option.Border.Bottom=chart.Frame.ChartBorder.Bottom;

            if (item.AutoLeft) chart.Frame.AutoLeftBorder=item.AutoLeft;
            if (item.AutoRight) chart.Frame.AutoRightBorder=item.AutoRight;
        }

        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)
        {
            var item=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 (IFrameSplitOperator.IsNumber(option.CorssCursorInfo.HPenType)) chart.ChartCorssCursor.HPenType=option.CorssCursorInfo.HPenType;
            if (option.CorssCursorInfo.VPenType>0) chart.ChartCorssCursor.VPenType=option.CorssCursorInfo.VPenType;
            if (IFrameSplitOperator.IsNumber(item.VLineType)) chart.ChartCorssCursor.VLineType=item.VLineType;
            if (option.CorssCursorInfo.DateFormatType>0) chart.ChartCorssCursor.StringFormatX.DateFormatType=option.CorssCursorInfo.DateFormatType;
            if (IFrameSplitOperator.IsBool(item.IsDrawXRangeBG)) chart.ChartCorssCursor.IsDrawXRangeBG=item.IsDrawXRangeBG;
            if (IFrameSplitOperator.IsBool(option.CorssCursorInfo.IsFixXLastTime)) chart.ChartCorssCursor.IsFixXLastTime=option.CorssCursorInfo.IsFixXLastTime;
            if (item.RightButton)
            {
                if (IFrameSplitOperator.IsBool(item.RightButton.Enable)) chart.ChartCorssCursor.RightButton.Enable=item.RightButton.Enable;
            } 
        }

        //保存十字光标文字高度
        option.CorssCursor={};
        option.CorssCursor.TitleHeight=chart.ChartCorssCursor.TextHeight;

        

        if (option.Frame)
        {
            for(var i=0;i<option.Frame.length;++i)
            {
                var item=option.Frame[i];
                if (!chart.Frame.SubFrame[i]) continue;
                var subFrame=chart.Frame.SubFrame[i].Frame;

                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 (item.RightTextPosition>0) chart.Frame.SubFrame[i].Frame.YTextPosition[1]=item.RightTextPosition;
                if (item.LeftTextPosition>0) chart.Frame.SubFrame[i].Frame.YTextPosition[0]=item.LeftTextPosition;

                if (item.IsShowXLine==false) chart.Frame.SubFrame[i].Frame.IsShowXLine=item.IsShowXLine;
                if (item.IsShowYLine==false) chart.Frame.SubFrame[i].Frame.IsShowYLine=item.IsShowYLine;
                if (IFrameSplitOperator.IsNumber(item.YTextBaseline)) chart.Frame.SubFrame[i].Frame.YTextBaseline=item.YTextBaseline;
                
                if (item.YCoordinateType>0) chart.Frame.SubFrame[0].Frame.YSplitOperator.CoordinateType=item.YCoordinateType;
                if (item.IsYReverse==true) chart.Frame.SubFrame[0].Frame.CoordinateType=1;  //反转坐标
                if (IFrameSplitOperator.IsNumber(item.PercentageTextFormat)) subFrame.YSplitOperator.PercentageTextFormat=item.PercentageTextFormat;    //百分比坐标格式

                if (item.DefaultYMaxMin) chart.Frame.SubFrame[i].Frame.YSplitOperator.DefaultYMaxMin=item.DefaultYMaxMin;
                if (IFrameSplitOperator.IsBool(item.EnableRemoveZero)) chart.Frame.SubFrame[i].Frame.YSplitOperator.EnableRemoveZero=item.EnableRemoveZero;
                if (IFrameSplitOperator.IsPlusNumber(item.MinYDistance)) chart.Frame.SubFrame[i].Frame.MinYDistance=item.MinYDistance;
                if (IFrameSplitOperator.IsNumber(item.BorderLine)) chart.Frame.SubFrame[i].Frame.BorderLine=item.BorderLine;
                if (IFrameSplitOperator.IsBool(item.IsShowIndexTitle)) chart.Frame.SubFrame[i].Frame.IsShowIndexTitle=item.IsShowIndexTitle;
                if (IFrameSplitOperator.IsBool(item.IsDrawTitleBottomLine)) subFrame.IsDrawTitleBottomLine=item.IsDrawTitleBottomLine;
            }
        }

        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=0;i<option.Overlay.length;++i)
            {
                var item=option.Overlay[i];
                chart.OverlaySymbol(item.Symbol,item);
            }
        }

        if (option.ExtendChart)
        {
            for(var i=0;i<option.ExtendChart.length;++i)
            {
                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=0;i<option.Windows.length;++i)
        {
            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 (IFrameSplitOperator.IsNumber(item.TitleHeight)) chart.Frame.SubFrame[i].Frame.ChartBorder.TitleHeight=item.TitleHeight;
            else item.TitleHeight=chart.Frame.SubFrame[i].Frame.ChartBorder.TitleHeight;
            if (item.IsShowTitleArraw==false) chart.Frame.SubFrame[i].Frame.IsShowTitleArraw=false;
            if (item.IsShowIndexName==false) chart.Frame.SubFrame[i].Frame.IsShowIndexName=false;
            if (item.IsShowOverlayIndexName==false) chart.Frame.SubFrame[i].Frame.IsShowOverlayIndexName=false;
            if (IFrameSplitOperator.IsNumber(item.IndexParamSpace)) chart.Frame.SubFrame[i].Frame.IndexParamSpace=item.IndexParamSpace;
            if (IFrameSplitOperator.IsNumber(item.IndexTitleSpace)) chart.Frame.SubFrame[i].Frame.IndexTitleSpace=item.IndexTitleSpace;
            
            if (item.OverlayIndexType)
            {
                if (IFrameSplitOperator.IsNumber(item.OverlayIndexType.Position)) chart.Frame.SubFrame[i].Frame.OverlayIndexType.Position=item.OverlayIndexType.Position;
                if (IFrameSplitOperator.IsNumber(item.OverlayIndexType.LineSpace)) chart.Frame.SubFrame[i].Frame.OverlayIndexType.LineSpace=item.OverlayIndexType.LineSpace;
            }
        }
        
        //叠加指标宽度
        if (option.OverlayIndexFrameWidth>40) chart.OverlayIndexFrameWidth=option.OverlayIndexFrameWidth;

        //叠加指标
        if (IFrameSplitOperator.IsNonEmptyArray(option.OverlayIndex))
        {
            for(var i=0;i<option.OverlayIndex.length;++i)
            {
                var item=option.OverlayIndex[i];
                if (item.Windows>=chart.Frame.SubFrame.length) continue;
    
                var itemString = JSON.stringify(item);
                var obj = JSON.parse(itemString);
                if (item.Index) obj.IndexName=item.Index;
                if (item.Windows>=0) obj.WindowIndex=item.Windows;
                chart.CreateOverlayWindowsIndex(obj);
            }
    
        }
        
        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=0;i<option.Frame.length;++i)
            {
                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=0;i<option.Windows.length;++i)
        {
            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;

        chart.ModifyIndexDialog=this.ModifyIndexDialog;
        chart.ChangeIndexDialog=this.ChangeIndexDialog;

        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.ScriptError) chart.ScriptErrorCallback=option.ScriptError;       //指标执行错误回调
        if (IFrameSplitOperator.IsString(option.SplashTitle)) chart.LoadDataSplashTitle=option.SplashTitle;
        if (IFrameSplitOperator.IsBool(option.EnableSelectRect)) chart.EnableSelectRect=option.EnableSelectRect; //是否启用区间选择
        if (IFrameSplitOperator.IsBool(option.EnableZoomIndexWindow)) chart.EnableZoomIndexWindow=option.EnableZoomIndexWindow;
        if (IFrameSplitOperator.IsBool(option.IsDrawPictureXY)) chart.IsDrawPictureXY=option.IsDrawPictureXY;

        chart.SelectRectDialog=new MinuteSelectRectDialog(this.DivElement);
        

        if (option.Minute)   //分钟走势图属性设置
        {
            if (option.Minute.IsShowTooltip==false) chart.IsShowTooltip=false;
            if (option.Minute.DragMode>=0) chart.DragMode=option.Minute.DragMode;
        }

        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;
            else if(option.Language==='TC') chart.LanguageID=JSCHART_LANGUAGE_ID.LANGUAGE_TRADITIONAL_CHINESE_ID;
        }

        if (option.Info && option.Info.length>0) chart.SetMinuteInfo(option.Info,false);

        if (option.DrawTool)    //画图工具
        {
            if (option.DrawTool.StorageKey && chart.ChartDrawStorage) chart.ChartDrawStorage.Load(option.DrawTool.StorageKey);
        }

        if (option.BeforeOpen)  //集合竞价
        {
            var item=option.BeforeOpen;

            if (IFrameSplitOperator.IsBool(item.IsShow)) chart.IsShowBeforeData=item.IsShow;
            if (IFrameSplitOperator.IsNumber(item.Width)) chart.ExtendWidth.Left=item.Width;
        }

        if (option.AfterClose)  //收盘集合竞价
        {
            var item=option.AfterClose;
            if (IFrameSplitOperator.IsBool(item.IsShow)) chart.IsShowAfterData=item.IsShow;
            if (IFrameSplitOperator.IsNumber(item.Width)) chart.ExtendWidth.Right=item.Width;
        }

        chart.Create(windowsCount,option.Listener);                            //创建子窗口

        if (option.CorssCursorInfo)
        {
            var item=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.RightTextFormat>0) chart.ChartCorssCursor.TextFormat.Right=option.CorssCursorInfo.RightTextFormat;
            if (option.CorssCursorInfo.IsOnlyDrawMinute == true) chart.ChartCorssCursor.IsOnlyDrawMinute = option.CorssCursorInfo.IsOnlyDrawMinute;    //Y轴显示收盘价
            if (IFrameSplitOperator.IsBool(option.CorssCursorInfo.IsFixXLastTime)) chart.ChartCorssCursor.IsFixXLastTime=option.CorssCursorInfo.IsFixXLastTime;

            if (item.RightButton)
            {
                if (IFrameSplitOperator.IsBool(item.RightButton.Enable)) chart.ChartCorssCursor.RightButton.Enable=item.RightButton.Enable;
            } 
        }

        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)
        {
            var item=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 (item.AutoLeft) chart.Frame.AutoLeftBorder=item.AutoLeft;
            if (item.AutoRight) chart.Frame.AutoRightBorder=item.AutoRight;
        }

        if (option.SplashTitle) chart.ChartSplashPaint.SplashTitle=option.SplashTitle;

        if (IFrameSplitOperator.IsBool(option.EnableBorderDrag))
        {
            chart.EnableBorderDrag=option.EnableBorderDrag;
        }

        this.AdjustChartBorder(chart);

        if (option.Frame)
        {
            for(var i=0;i<option.Frame.length;++i)
            {
                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.IsShowYText[0]=item.IsShowLeftText;
                    chart.Frame.SubFrame[i].Frame.YSplitOperator.IsShowLeftText=item.IsShowLeftText;            //显示左边刻度
                }
                if (item.IsShowRightText==false) 
                {
                    chart.Frame.SubFrame[i].Frame.IsShowYText[1]=item.IsShowRightText;
                    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 (item.RightTextFormat>0) chart.Frame.SubFrame[i].Frame.YSplitOperator.RightTextFormat=item.RightTextFormat;
                if (IFrameSplitOperator.IsNumber(item.TitleHeight)) chart.Frame.SubFrame[i].Frame.ChartBorder.TitleHeight=item.TitleHeight;
                if (IFrameSplitOperator.IsNumber(item.BorderLine)) chart.Frame.SubFrame[i].Frame.BorderLine=item.BorderLine;
                if (IFrameSplitOperator.IsBool(item.EnableRemoveZero)) chart.Frame.SubFrame[i].Frame.YSplitOperator.EnableRemoveZero=item.EnableRemoveZero;
                if (IFrameSplitOperator.IsNumber(item.FloatPrecision)) chart.Frame.SubFrame[i].Frame.YSplitOperator.FloatPrecision=item.FloatPrecision;
                if (IFrameSplitOperator.IsNumber(item.YTextBaseline)) chart.Frame.SubFrame[i].Frame.YTextBaseline=item.YTextBaseline;
            }

            chart.UpdateXShowText();
        }

        if (option.ExtendChart)
        {
            for(var i=0;i<option.ExtendChart.length;++i)
            {
                var item=option.ExtendChart[i];
                chart.CreateExtendChart(item.Name, item);
            }
        }

        //叠加股票
        if (option.Overlay)
        {
            for(var i=0;i<option.Overlay.length;++i)
            {
                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;
                chart.TitlePaint[0].IsShowAveragePrice=false;   //标题栏均线也不显示
                for(var i=0;i<chart.ExtendChartPaint.length;++i)
                {
                    var item=chart.ExtendChartPaint[i];
                    if (item.ClassName=="MinuteTooltipPaint")
                        item.IsShowAveragePrice=false;
                }
            }
            if (option.MinuteLine.SplitType>0) chart.Frame.SubFrame[0].Frame.YSplitOperator.SplitType=option.MinuteLine.SplitType;
        }

        if(option.MinuteTitle)
        {
            var item=option.MinuteTitle;
            if(IFrameSplitOperator.IsBool(item.IsShowName)) chart.TitlePaint[0].IsShowName=item.IsShowName;
            if(IFrameSplitOperator.IsBool(item.IsShowDate)) chart.TitlePaint[0].IsShowDate=item.IsShowDate;
            if(IFrameSplitOperator.IsBool(item.IsShowTime)) chart.TitlePaint[0].IsShowTime=item.IsShowTime;
            if(IFrameSplitOperator.IsBool(item.IsTitleShowLatestData)) chart.IsTitleShowLatestData=item.IsTitleShowLatestData;
            if(IFrameSplitOperator.IsBool(item.IsAlwaysShowLastData)) chart.TitlePaint[0].IsAlwaysShowLastData=item.IsAlwaysShowLastData;
            //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个指标窗口设置
        if (IFrameSplitOperator.IsNonEmptyArray(option.Windows))
        {
            let scriptData = new JSIndexScript();
            for(var i=0;i<option.Windows.length;++i)
            {
                var index=2+i;
                var item=option.Windows[i];
                if (item.Script)
                {
                    chart.WindowIndex[index]=new ScriptIndex(item.Name,item.Script,item.Args,item);    //脚本执行
                }
                else if (item.API)  //使用API挂接指标数据 API:{ Name:指标名字, Script:指标脚本可以为空, Args:参数可以为空, Url:指标执行地址 }
                {
                    var apiItem=item.API;
                    chart.WindowIndex[index]=new APIScriptIndex(apiItem.Name,apiItem.Script,apiItem.Args,item);
                }
                else
                {
                    var indexItem=JSIndexMap.Get(item.Index);
                    if (indexItem)
                    {
                        chart.WindowIndex[index]=indexItem.Create();       //创建子窗口的指标
                        chart.CreateWindowIndex(index);
                    }
                    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[index] = new ScriptIndex(indexInfo.Name, indexInfo.Script, args,indexInfo);    //脚本执行
                        if (item.StringFormat>0) chart.WindowIndex[index].StringFormat=item.StringFormat;
                        if (item.FloatPrecision>=0) chart.WindowIndex[index].FloatPrecision=item.FloatPrecision;
                    }
                }

                if (item.Modify!=null) chart.Frame.SubFrame[index].Frame.ModifyIndex=item.Modify;
                if (item.Change!=null) chart.Frame.SubFrame[index].Frame.ChangeIndex=item.Change;
                if (item.Close!=null) chart.Frame.SubFrame[index].Frame.CloseIndex=item.Close;
                if (!isNaN(item.TitleHeight)) chart.Frame.SubFrame[index].Frame.ChartBorder.TitleHeight=item.TitleHeight;
            }
        }

        this.AdjustTitleHeight(chart);

        //叠加指标
        if (IFrameSplitOperator.IsNonEmptyArray(option.OverlayIndex))
        {
            for(var i=0;i<option.OverlayIndex.length;++i)
            {
                var item=option.OverlayIndex[i];
                if (item.Windows>=chart.Frame.SubFrame.length) continue;
    
                var itemString = JSON.stringify(item);
                var obj = JSON.parse(itemString);
                if (item.Index) obj.IndexName=item.Index;
                if (item.Windows>=0) obj.WindowIndex=item.Windows;
                chart.CreateOverlayWindowsIndex(obj);
            }
        }
        
        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();
        if (option.Windows)
        {
            for(var i=0;i<option.Windows.length;++i)
            {
                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.KLine.RightSpaceCount>0) chart.RightSpaceCount=option.KLine.RightSpaceCount;
        }

        if (option.Train)
        {
            if (option.Train.DataCount) chart.TrainDataCount=option.Train.DataCount;
            if (option.Train.Callback) chart.TrainCallback=option.Train.Callback;
            if (option.Train.StartDate) chart.TrainStartDate=option.Train.StartDate;
        }

        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.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;
        }

        //保存十字光标文字高度
        option.CorssCursor={};
        option.CorssCursor.TitleHeight=chart.ChartCorssCursor.TextHeight;

        if (option.Frame)
        {
            for(var i=0;i<option.Frame.length;++i)
            {
                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 (item.Height>0) chart.Frame.SubFrame[i].Height = item.Height;

                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.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.ExtendChart)
        {
            for(var i=0;i<option.ExtendChart.length;++i)
            {
                var item=option.ExtendChart[i];
                chart.CreateExtendChart(item.Name, item);
            }
        }

        if (IFrameSplitOperator.IsNonEmptyArray(option.Windows))
        {
            //创建子窗口的指标
            let scriptData = new JSIndexScript();
            for(var i=0;i<option.Windows.length;++i)
            {
                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;
    }

    //深度图
    this.CreateDepthChartContainer=function(option)
    {
        var chart=null;
        chart=new DepthChartContainer(this.CanvasElement);
        if (option.NetworkFilter) chart.NetworkFilter=option.NetworkFilter;

        if (option.EnableScrollUpDown==true) chart.EnableScrollUpDown=option.EnableScrollUpDown;
        if (IFrameSplitOperator.IsPlusNumber(option.MaxVolRate)) chart.MaxVolRate=option.MaxVolRate;
        if (option.ZoomStepPixel>0) chart.ZoomStepPixel=option.ZoomStepPixel;
        if (IFrameSplitOperator.IsString(option.SplashTitle)) chart.LoadDataSplashTitle=option.SplashTitle;

        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;
            else if(option.Language==='TC') chart.LanguageID=JSCHART_LANGUAGE_ID.LANGUAGE_TRADITIONAL_CHINESE_ID;
        }
        
        chart.Create(option.Listener);  

        if (option.Border)
        {
            if (IFrameSplitOperator.IsNumber(option.Border.Left)) chart.Frame.ChartBorder.Left=option.Border.Left;
            else option.Border.Left=chart.Frame.ChartBorder.Left;
            if (IFrameSplitOperator.IsNumber(option.Border.Right)) chart.Frame.ChartBorder.Right=option.Border.Right;
            else option.Border.Right=chart.Frame.ChartBorder.Right;
            if (IFrameSplitOperator.IsNumber(option.Border.Top)) chart.Frame.ChartBorder.Top=option.Border.Top;
            else option.Border.Top=chart.Frame.ChartBorder.Top;
            if (IFrameSplitOperator.IsNumber(option.Border.Bottom)) chart.Frame.ChartBorder.Bottom=option.Border.Bottom;
            else option.Border.Bottom=chart.Frame.ChartBorder.Bottom;
        }

        this.AdjustChartBorder(chart);

        if (option.CorssCursorTouchEnd===true) chart.CorssCursorTouchEnd = option.CorssCursorTouchEnd;

        if (option.CorssCursorInfo)
        {
            var item=option.CorssCursorInfo;
            if (IFrameSplitOperator.IsNumber(item.HPenType)) chart.ChartCorssCursor.HPenType=item.HPenType;
            if (IFrameSplitOperator.IsNumber(item.VPenType)) chart.ChartCorssCursor.VPenType=item.VPenType;
            if (IFrameSplitOperator.IsBool(item.IsShowTooltip)) chart.ChartCorssCursor.IsShowTooltip=item.IsShowTooltip;
        }
        
        if (option.Frame)
        {
            var item=option.Frame
            if (item.SplitCount) chart.Frame.YSplitOperator.SplitCount=item.SplitCount;
            if (IFrameSplitOperator.IsNumber(item.SplitType)) chart.Frame.YSplitOperator.SplitType=item.SplitType;
            if (IFrameSplitOperator.IsNumber(item.Height)) chart.Frame.Height = item.Height;
            if (IFrameSplitOperator.IsNumber(item.YLineType)) chart.Frame.YSplitOperator.LineType=item.YLineType;
            if (IFrameSplitOperator.IsNumber(item.XLineType)) chart.Frame.XSplitOperator.LineType=item.XLineType;
            if (Array.isArray(item.IgnoreYValue)) chart.Frame.YSplitOperator.IgnoreYValue=item.IgnoreYValue;
            if (item.IsShowLeftText===false || item.IsShowLeftText===true) 
            {
                chart.Frame.IsShowYText[0]=item.IsShowLeftText;
                chart.Frame.YSplitOperator.IsShowLeftText=item.IsShowLeftText;            //显示左边刻度
            }
            if (item.IsShowRightText===false || item.IsShowRightText===true) 
            {
                chart.Frame.IsShowYText[1]=item.IsShowRightText;
                chart.Frame.YSplitOperator.IsShowRightText=item.IsShowRightText;          //显示右边刻度
            }

            if (item.IsShowXLine==false) chart.Frame.IsShowXLine=item.IsShowXLine;
            if (item.IsShowYLine==false) chart.Frame.IsShowYLine=item.IsShowYLine;

            if (IFrameSplitOperator.IsNumber(item.XSplitCount)) chart.Frame.XSplitOperator.SplitCount=item.XSplitCount; //X轴刻度个数 半边的
        }

        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 "深度图":
                chart=this.CreateDepthChartContainer(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.OnCreatedCallback) option.OnCreatedCallback(chart);

        //是否自动更新
        if (option.IsAutoUpdate!=null) chart.IsAutoUpdate=option.IsAutoUpdate;
        if (option.AutoUpdateFrequency>0) chart.AutoUpdateFrequency=option.AutoUpdateFrequency;
        //注册事件
        if (option.EventCallback)
        {
            for(var i=0;i<option.EventCallback.length;++i)
            {
                var item=option.EventCallback[i];
                chart.AddEventCallback(item);
            }
        }
        

        //设置股票代码
        if (!option.Symbol) 
        {
            chart.DrawEmpty();
            this.JSChartContainer=chart;
            this.DivElement.JSChart=this;   //div中保存一份
        }
        else
        {
            chart.Draw();
            chart.ChangeSymbol(option.Symbol);
    
            this.JSChartContainer=chart;
            this.DivElement.JSChart=this;   //div中保存一份
            this.JSChartContainer.Draw();
        }

        if (IFrameSplitOperator.IsBool(option.CheckLatestVerion) && option.CheckLatestVerion==false)
        {

        }
        else if (JSChart.LastVersion==null)
        {
            if (chart && typeof(chart.GetLatestVersion)=='function') chart.GetLatestVersion();
        }
    }

    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, option)
    {
        if (this.JSChartContainer) this.JSChartContainer.ChangeSymbol(symbol,option);
    }

    //K线切换指标
    this.ChangeIndex=function(windowIndex,indexName,option)
    {
        if (this.JSChartContainer && typeof(this.JSChartContainer.ChangeIndex)=='function')
            this.JSChartContainer.ChangeIndex(windowIndex,indexName,option);
    }

    this.AddIndexWindow=function(indexName,option)
    {
        if (this.JSChartContainer && typeof(this.JSChartContainer.AddIndexWindow)=='function')
            this.JSChartContainer.AddIndexWindow(indexName,option);
    }

    this.AddScriptIndexWindow=function(indexInfo, option)
    {
        if (this.JSChartContainer && typeof(this.JSChartContainer.AddScriptIndexWindow)=='function')
            this.JSChartContainer.AddScriptIndexWindow(indexInfo,option);
    }

    this.RemoveIndexWindow=function(id)
    {
        if (this.JSChartContainer && typeof(this.JSChartContainer.RemoveIndexWindow)=='function')
            this.JSChartContainer.RemoveIndexWindow(id);
    }

    this.ChangeScriptIndex=function(windowIndex,indexData,option)
    {
        if (this.JSChartContainer && typeof(this.JSChartContainer.ChangeScriptIndex)=='function')
            this.JSChartContainer.ChangeScriptIndex(windowIndex,indexData,option);
    }

    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, option)
    {
        if (this.JSChartContainer && typeof(this.JSChartContainer.ChangePeriod)=='function')
            this.JSChartContainer.ChangePeriod(period, option);
    }

    //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:起始日期(必填), Time:起始时间(分钟K线必填) 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=面积图 5=订单流
    this.ChangeKLineDrawType=function(drawType, isDraw)
    {
        if (this.JSChartContainer && typeof(this.JSChartContainer.ChangeKLineDrawType)=='function')
            this.JSChartContainer.ChangeKLineDrawType(drawType,isDraw);
    }
	
	//指标窗口个数
    this.ChangeIndexWindowCount = function(count, option)
    {
        if(this.JSChartContainer && typeof(this.JSChartContainer.ChangeIndexWindowCount) == 'function')
        {
            this.JSChartContainer.ChangeIndexWindowCount(count,option);
        }
    }
	
	//取消叠加
    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(可选), API}
    {
        if (this.JSChartContainer && typeof(this.JSChartContainer.AddOverlayIndex)=='function') 
            this.JSChartContainer.AddOverlayIndex(obj);
    }

    this.MoveOverlayIndex=function(src, dest, option)
    {
        if (this.JSChartContainer && typeof(this.JSChartContainer.MoveOverlayIndex)=='function') 
            this.JSChartContainer.MoveOverlayIndex(src, dest, option);
    }

    this.MoveOverlayIndexToNewWindow=function(src, option)
    {
        if (this.JSChartContainer && typeof(this.JSChartContainer.MoveOverlayIndexToNewWindow)=='function') 
            this.JSChartContainer.MoveOverlayIndexToNewWindow(src, option);
    }

    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.ChartDestory=function()
    {
        if (this.JSChartContainer && typeof (this.JSChartContainer.ChartDestory) == 'function') 
        {
            this.JSChartContainer.ChartDestory();
        }
    }

    //设置深度图数据 depthData=[ {ID:深度图ID, Data:数据},]   bDraw=是否立即重绘
    this.SetDepthMapData=function(depthData, bDraw)
    {
        if (this.JSChartContainer && typeof(this.JSChartContainer.SetDepthMapData)=='function') 
            this.JSChartContainer.SetDepthMapData(depthData, bDraw);
    }

    //设置强制横屏
    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.ShowCallAuctionData=function(obj, option)
    {
        if(this.JSChartContainer && typeof(this.JSChartContainer.ShowCallAuctionData)=='function')
        {
            JSConsole.Chart.Log('[JSChart:ShowCallAuctionData] obj, option ', obj, option);
            this.JSChartContainer.ShowCallAuctionData(obj, option);
        }
    }

    //返回弹幕数据类
    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,option)
    {
        if(this.JSChartContainer && typeof(this.JSChartContainer.CreateChartDrawPicture)=='function')
        {
            JSConsole.Chart.Log('[JSChart:CreateChartDrawPicture] ', name);
            this.JSChartContainer.CreateChartDrawPicture(name,option);
        }
    }

    this.AddChartDrawPicture=function(obj)
    {
        if(this.JSChartContainer && typeof(this.JSChartContainer.AddChartDrawPicture)=='function')
        {
            JSConsole.Chart.Log('[JSChart:AddChartDrawPicture] ', obj);
            this.JSChartContainer.AddChartDrawPicture(obj);
        } 
    }

    //删除画图工具
    this.ClearChartDrawPicture=function(drawPicture)
    {
        if(this.JSChartContainer && typeof(this.JSChartContainer.ClearChartDrawPicture)=='function')
        {
            //JSConsole.Chart.Log('[JSChart:ClearChartDrawPicture] ', drawPicture);
            this.JSChartContainer.ClearChartDrawPicture(drawPicture);
        }
    }

    //重新加载配置
    this.ReloadResource=function(option)
    {
        if(this.JSChartContainer && typeof(this.JSChartContainer.ReloadResource)=='function')
        {
            JSConsole.Chart.Log('[JSChart:ReloadResource] ');
            this.JSChartContainer.ReloadResource(option);
        }
    }

    this.EnableSplashScreen=function(option)
    {
        if(this.JSChartContainer && typeof(this.JSChartContainer.EnableSplashScreen)=='function')
        {
            JSConsole.Chart.Log('[JSChart:EnableSplashScreen] ');
            this.JSChartContainer.EnableSplashScreen(option);
        }
    }
}

JSChart.LastVersion=null;   //最新的版本号

//初始化
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;
}

JSChart.GetDivTooltipDataFormat=function()  //div tooltip数据格式化
{
    return g_DivTooltipDataForamt;
}

JSChart.SetUSATimeType=function(type)    //设置 0=标准时间 1=夏令时间 3=美国时间
{
    g_NYMEXTimeData.TimeType=type;
    g_COMEXTimeData.TimeType=type;
    g_NYBOTTimeData.TimeType=type;
    g_CBOTTimeData.TimeType=type;
}

JSChart.GetChinaFuturesTimeData=function()  //获取国内期货交易时间配置
{
    return g_FuturesTimeData;
}

JSChart.AddPeriodCallback=function(obj)     //添加自定义周期方法 { Period:周期ID, Callback:回调 }
{
    g_DataPlus.AddPeriodCallback(obj);
}

JSChart.RemovePeriodCallback=function(obj) //添加自定义周期方法 { Period:周期ID, }
{
    g_DataPlus.RemovePeriodCallback(obj);
}

//注册一个新的画图工具 {Name:中文名字, ClassName:类名, Create:function()}
JSChart.RegisterDrawPicture=function(obj)  
{
    return IChartDrawPicture.RegisterDrawPicture(obj);
}

//注册一个新图标 {Name:, Text: , Color:, Family:}
JSChart.RegisterDrawPictureIonFont=function(obj)
{
    return IChartDrawPicture.RegisterIonFont(obj);
}

JSChart.GetInternalTimeData=function(name)  //内置品种交易时间
{
    switch(name)
    {
        case "NYMEXTimeData":
            return g_NYMEXTimeData;
        case "COMEXTimeData":
            return g_COMEXTimeData;
        case "NYBOTTimeData":
            return g_NYBOTTimeData;
        case "CBOTTimeData":
            return g_CBOTTimeData;
        case "LMETimeData":
            return g_LMETimeData;
        case "FuturesTimeData":
            return g_FuturesTimeData;
        case "TOCOMTimeData":   //东京商品交易所（TOCOM
            return g_TOCOMTimeData;
        case "IPETimeData":
            return g_IPETimeData;   //美国洲际交易所
        default:
            return null;
    }
}

JSChart.RegisterExtendChartClass=function(name, option)
{
    g_ExtendChartPaintFactory.Add(name,option);
}

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轴绘制事件
    RECV_KLINE_MANUAL_UPDATE_DATA:21,   //手动更新K线事件
    ON_ENABLE_SPLASH_DRAW:22,           //开启/关闭过场动画事件

    ON_CLICK_CHART_PAINT:23,            //点击图形

    ON_DRAW_MINUTE_LAST_POINT:24,        //分时图绘制回调事件, 返回最后一个点的坐标
    ON_DRAW_DEPTH_TOOLTIP:25,            //绘制深度图tooltip事件
    ON_CLICK:26,                         //点击事件
    ON_PHONE_TOUCH:27,                   //手势点击事件 包含 TouchStart 和 TouchEnd

    ON_CLICKUP_CHART_PAINT:28,           //点击图形鼠标抬起

    ON_SPLIT_YCOORDINATE:29,             //分割Y轴及格式化刻度文字
    ON_DBCLICK:30,
    ON_SPLIT_XCOORDINATE:31,             //分割X轴及格式化刻度文字

    ON_KEYDOWN_SELECT_RECT:32,           //键盘空格区间选择完成事件
    ON_DRAG_SELECT_RECT:33,              //区间选择区域变动
    ON_DRAG_SELECT_RECT_MOUSEUP:34,      //区间选择区域变动鼠标松开

    ON_DRAW_KLINE_LAST_POINT:35,          //K线图绘制回调事件,返回最后一个点的坐标
    ON_CLICK_CROSSCURSOR_RIGHT:36,        //十字光标右边按钮

    ON_PLAY_SOUND:37,                     //播放声音 { Name:, Data: }
}

var JSCHART_OPERATOR_ID=
{
    OP_SCROLL_LEFT:1,   //往左移动
    OP_SCROLL_RIGHT:2,  //往右移动
    OP_ZOOM_OUT:3,  //缩小
    OP_ZOOM_IN:4,   //放大
    OP_GOTO_HOME:5, //最新一天数据
    OP_GOTO_END:6,  //第1天的数据

    OP_LEFT_ZOOM_OUT:7,   //左边缩小
    OP_LEFT_ZOOM_IN:8,    //左右放大

    OP_RIGHT_ZOOM_OUT:9,  //右边缩小
    OP_RIGHT_ZOOM_IN:10,  //右边放大
}

var JSCHART_DRAG_ID=
{
    DISABLE_DRAG_ID:0,
    CLICK_TOUCH_MODE_ID:3   //长按十字光标显示保留/点击十字光标消失 (使用TouchStatus)
}

var JSCHART_BUTTON_ID=
{
    CLOSE_BEFOREOPEN_ID:1,  //关闭集合竞价
}


function PhoneDBClick()
{
    this.Start=[];

    this.Clear=function()
    {
        this.Start=[];
    }

    this.AddTouchStart=function(x, y, time)
    {
        if (this.Start.length>0)
        {
            var item=this.Start[this.Start.length-1];
            var spanTime=time-item.Time;
            if (spanTime>0 && spanTime<300)
            {
                this.Start.push({ X:x, Y:y, Time:time });
            }
            else
            {
                this.Start=[];
            }
        }
        else
        {
            this.Start.push({ X:x, Y:y, Time:time });
        }
    }

    this.IsVaildDBClick=function()
    {
        if (this.Start.length==2) return true;

        return false;
    }

    this.AddTouchEnd=function(time)
    {
        if (this.Start.length<=0) return;

        var item=this.Start[this.Start.length-1];
        var spanTime=time-item.Time;
        if (spanTime>=0 && spanTime<150)
        {
            
        }
        else
        {
            this.Start=[];
        }
    }
}

/*
    图形控件
*/
function JSChartContainer(uielement, OffscreenElement)
{
    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.MoveOnChartDrawPicture=null;               //鼠标在画图上
    this.IsDrawPictureXY=false;                     //选中的画图工具是否显示X,Y轴对应数值
    this.EnableShowCorssCursor={ DrawPicture:true };  //DrawPicture=画图是否显示十字光标
    this.ChartPictureMenu;                          //画图工具 单个图形设置菜单
    this.ChartCorssCursor;                          //十字光标
    this.IsClickShowCorssCursor=false;              //手势点击显示十字光标
    this.ChartSplashPaint=null;                     //等待提示
    this.LoadDataSplashTitle="数据加载中";           //下载数据提示信息
    if (OffscreenElement) 
    {
        this.Canvas=OffscreenElement.getContext("2d");
        this.OffscreenCanvasElement=OffscreenElement;

        this.ShowCanvas=uielement.getContext("2d");
    }
    else
    {
        this.Canvas=uielement.getContext("2d");         //画布
        this.ShowCanvas=null;
    }
    
    this.UIElement=uielement;
    this.MouseDrag;
    this.PhoneTouchInfo;    //手机手势信息
    this.DragMode=1;                                //拖拽模式 0 禁止拖拽 1 数据拖拽 2 区间选择 3(CLICK_TOUCH_MODE_ID)=长按十字光标显示保留/点击十字光标消失 (使用TouchStatus)
    this.EnableBorderDrag=true;                     //是否可以拖拽边框调整指标框高度
    this.BorderDrag;    //{ Index:, }
    this.YDrag;         //{Index: }                 //y轴拖拽放大缩小
    this.TouchStatus={ CorssCursorShow:false },     //十字光标是否显示
    this.DragTimer;
    this.EnableScrollUpDown=false;                  //是否可以上下滚动图形(手机端才有)
    this.ClickChartTimer=null;                      //点击图形定时器,解决双击和单击K线事件

    this.CursorIndex=0;             //十字光标X轴索引
    this.LastPoint=new Point();     //鼠标位置
    this.IsForceLandscape=false;    //是否强制横屏
    this.CorssCursorTouchEnd = false;   //手离开屏幕自动隐藏十字光标
    this.IsTitleShowLatestData=false;     //十字/手势不在K线图上,标题显示最新一个数据
    this.StepPixel=4;                   //移动一个数据需要的像素 0=自动模式(根据K线宽度+间距)
    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.style["pointer-events"]="none";
    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["pointer-events"]="none";
    //this.SelectRect.style.opacity=g_JSChartResource.SelectRectAlpha;
    this.SelectRect.id=Guid();
    this.SelectRect.oncontextmenu=function() { return false; }; //屏蔽选中区域系统右键菜单
    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);
    this.LastMouseStatus={ }
    this.ClickDownPoint;         //鼠标点击坐标 {X, Y}, 鼠标放开以后清空为null
    this.IsDestroy=false;        //是否已经销毁了

    this.EnableYDrag={ Left:false, Right:false };   //是否可以拖拽Y轴,放大缩小Y轴最大最小值
    this.EnableZoomIndexWindow=false;               //是否支持双击缩放附图窗口

    this.PhoneDBClick=new PhoneDBClick();

    this.ChartDestory=function()    //销毁
    {
        this.IsDestroy=true;
        this.StopAutoUpdate();

        if (this.GetLatestVersionTimer!=null) 
        {
            clearTimeout(this.GetLatestVersionTimer);
            this.GetLatestVersionTimer=null;
        }
    }


    this.GetLatestVersionTimer=null;    //获取最新版本
    this.GetLatestVersion=function()
    {
        if (this.GetLatestVersionTimer!=null)
        {
            clearTimeout(this.GetLatestVersionTimer);
            this.GetLatestVersionTimer=null;
        }

        var roundeTime=Math.floor(Math.random()*50); 
        var waittimer=1000*60*3+(roundeTime*1000);
        var value="aHR0cHM6Ly9ocWNoYXJ0LnplYWxpbmsuY29tL2FwaS9HZXRWZXJzaW9u";
        JSConsole.Chart.Log("[JSChartContainer::GetLatestVersion] wait for get hqchart latest version. ",waittimer);
        this.GetLatestVersionTimer = setTimeout(()=>
        {
            var width=0, height=0;
            if (this.Frame && this.Frame.ChartBorder)
            {
                width=this.Frame.ChartBorder.GetChartWidth();
                height=this.Frame.ChartBorder.GetChartHeight();
            }
            
            var url=`${atob(value)}?width=${width}&height=${height}&type=h5`;

            if (JSChart.LastVersion!=null) return;  //只请求一次

            JSNetwork.HttpRequest({
                url: url,
                type:"get",
                dataType: "json",
                async:true,
                success:function(data)
                {
                    JSConsole.Chart.Log("[JSChartContainer::GetLatestVersion] hqchart latest version. ",data);
                    JSChart.LastVersion=data;
                },
                error:function(request, textStatus, errorThrown)
                {
                    JSConsole.Chart.Log("[JSChartContainer::GetLatestVersion] Get HQChart latest version failed.", request);
                }
            });
        }, waittimer);
    }

    //设置事件回调
    //{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); }
    uielement.onmouseout=(e)=>{ this.UIOnMounseOut(e); }
    uielement.onmouseleave=(e)=>{ this.UIOnMouseleave(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;

        //加载数据中,禁用鼠标事件
        this.MoveOnChartDrawPicture=null;
        if (this.ChartSplashPaint && this.ChartSplashPaint.IsEnableSplash == true) return;
        if (this.DisableMouse==true) return;
        if (this.BorderDrag) return;
        if (this.YDrag) return;

        //保存最后一次鼠标移动信息
        var MoveStatus={ X:x, Y:y, IsInClient: this.IsMouseOnClient(x,y) };
        this.LastMouseStatus.OnMouseMove=MoveStatus;
        //JSConsole.Chart.Log("[JSChartContainer::UIOnMouseMove] MoveStatus", MoveStatus);

        this.OnMouseMove(x,y,e);
    }

    this.IsMouseOnClient=function(x,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);
        return isInClient;
    }

    this.UIOnContextMenu=function(e)
    {
        if (this.ChartSplashPaint && this.ChartSplashPaint.IsEnableSplash == true) return;

        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 pixelTatio = GetDevicePixelRatio();
        var x = (e.clientX-this.UIElement.getBoundingClientRect().left)*pixelTatio;
        var y = (e.clientY-this.UIElement.getBoundingClientRect().top)*pixelTatio;
        this.OnDoubleClick(x,y,e);
    }

    //是否在拖拽Y轴上
    this.TryYDrag=function(x,y)
    {
        if (!this.EnableYDrag) return null;
        if (!this.EnableYDrag.Left && !this.EnableYDrag.Right) return null;
        if (!this.Frame || !this.Frame.PtInFrameY) return null;

        var dragY=this.Frame.PtInFrameY(x,y);
        if (!dragY || dragY.Index<0) return null;

        if (dragY.Left && this.EnableYDrag.Left && this.Frame.IsEnableDragY(dragY.Index))
        {
            return dragY;
        }

        if (dragY.Right && this.EnableYDrag.Right && this.Frame.IsEnableDragY(dragY.Index))
        {
            return dragY;
        }

        return null;
    }

    //是否可以上下拖拽
    this.TryUpDownDrag=function(x,y)
    {
        var windowIndex=this.Frame.PtInFrame(x,y);
        if (windowIndex<0) return null;

        var item=this.Frame.SubFrame[windowIndex];
        if (!item || !item.Frame) return null;

        var frame=item.Frame;
        if (!frame.YSplitOperator || !frame.YSplitOperator.FixedYMaxMin) return null;

        return { Index:windowIndex, X:x, Y:y };
    }

    this.TryRectSelectDrag=function(x,y)
    {
        var paint=this.GetRectSelectPaint();
        if (!paint) return null;
        if (paint.GetPointCount()<=0) return null;

        var item=paint.PtInPaint(x,y);

        return { Item:item, X:x, Y:y };
    }

    this.TryClickCrossCursor=function(x,y,e)
    {
        if (!this.ChartCorssCursor) return;

        var button=this.ChartCorssCursor.PtInButton(x,y);
        if (!button) return false;

        var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_CLICK_CROSSCURSOR_RIGHT);
        if (event && event.Callback)
        {
            var sendData={ Button:button, e };
            event.Callback(event,sendData,this);
        }

        return true;
    }

    this.UIOnMouseDown=function(e)
    {
        this.MoveOnChartDrawPicture=null;

        if (this.ChartSplashPaint && this.ChartSplashPaint.IsEnableSplash == true) return;

        this.ClickDownPoint={ X:e.clientX, Y:e.clientY };
        this.IsOnTouch=true;
        this.BorderDrag=null;
        this.YDrag=null;
        this.UpDownDrag=null;
        this.RectSelectDrag=null;

        var pixelTatio = GetDevicePixelRatio();
        var x = (e.clientX-this.UIElement.getBoundingClientRect().left)*pixelTatio;
        var y = (e.clientY-this.UIElement.getBoundingClientRect().top)*pixelTatio;

        var button=this.Frame.PtInButtons(x,y);
        if (button && this.ClickFrameButton)
        {
            this.ClickFrameButton(button);
            return;
        }

        if (this.TryClickCrossCursor(x,y, e))
        {
            return;
        }

        if (this.TryClickLock)
        {
            //JSConsole.Chart.Log('[uielement.onmousedown] left, top ',e.clientX, e.clientY, this.getBoundingClientRect().left,this.getBoundingClientRect().top);
            if (this.TryClickLock(x,y)) return;
        }

        this.HideSelectRect();
        if (this.SelectRectRightMenu) this.SelectRectRightMenu.Hide();
        if (this.ChartPictureMenu) this.ChartPictureMenu.Hide();

        var paint=this.GetRectSelectPaint();
        if (paint && paint.GetPointCount()>0)
        {
            var item=paint.PtInPaint(x,y);
            if (item)
            {
                this.UIElement.style.cursor="ew-resize";
                this.RectSelectDrag={ Index:item.PointIndex };
                JSConsole.Chart.Log("[JSChartContainer::UIOnMouseDown] drag rect select ",item);
            }
        }
        
        if (!this.RectSelectDrag && this.ClearRectSelect(false)) this.Draw();

        if (this.EnableBorderDrag && this.Frame)
        {
            var dragBorder=this.Frame.PtInFrameBorder(x,y);
            if (dragBorder && dragBorder.Index>=0)
            {
                this.UIElement.style.cursor="n-resize";
                this.BorderDrag={ Index:dragBorder.Index };
                JSConsole.Chart.Log("[JSChartContainer::UIOnMouseDown] DragBorder ",dragBorder);
            }
        }

        //拖拽Y轴缩放
        if (!this.BorderDrag)
        {
            var dragY=this.TryYDrag(x,y);
            if (dragY)
            {
                this.UIElement.style.cursor=dragY.Position==0 ? "n-resize":"row-resize";
                this.YDrag=dragY;
                JSConsole.Chart.Log("[JSChartContainer::UIOnMouseDown] dragY ",dragY);
            }
            else
            {
                var dragUpDown=this.TryUpDownDrag(x,y);
                if (dragUpDown)
                {
                    this.UIElement.style.cursor="pointer";
                    this.UpDownDrag=dragUpDown;
                    JSConsole.Chart.Log("[JSChartContainer::UIOnMouseDown] dragUpDown ",dragUpDown);
                }
            }
        }

        if(this.DragMode==0) return;

        var drag=
        {
            "Click":{},
            "LastMove":{}  //最后移动的位置
        };

        drag.Click.X=e.clientX;
        drag.Click.Y=e.clientY;
        drag.Click.IsInFrameBottom=this.Frame.PtInFrameBottom(x,y);   //是否点击在X轴上
        drag.LastMove.X=e.clientX;
        drag.LastMove.Y=e.clientY;

        this.MouseDrag=drag;
        var drawPictureActive=this.GetActiveDrawPicture();
        this.SelectChartDrawPicture=null;

        if (this.BorderDrag)
        {

        }
        else if (this.YDrag || this.UpDownDrag || this.RectSelectDrag)
        {

        }
        else 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={};
            drawPictrueData.X=(e.clientX-this.UIElement.getBoundingClientRect().left)*pixelTatio;
            drawPictrueData.Y=(e.clientY-this.UIElement.getBoundingClientRect().top)*pixelTatio;
            if (this.GetChartDrawPictureByPoint(drawPictrueData))
            {
                if (drawPictrueData.ChartDrawPicture.EnableMove==true)
                {
                    drawPictrueData.ChartDrawPicture.Status=20;
                    drawPictrueData.ChartDrawPicture.ValueToPoint();
                    drawPictrueData.ChartDrawPicture.MovePointIndex=drawPictrueData.PointIndex;
                    this.CurrentChartDrawPicture=drawPictrueData.ChartDrawPicture;
                    this.SelectChartDrawPicture=drawPictrueData.ChartDrawPicture;
                }
                else
                {
                    this.CurrentChartDrawPicture=null;
                    this.SelectChartDrawPicture=null;
                }
               
                var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_CLICK_DRAWPICTURE); //选中画图工具事件
                if (event && event.Callback)
                {
                    var sendData={ DrawPicture: drawPictrueData.ChartDrawPicture };
                    event.Callback(event,sendData,this);
                }
                else
                {
                    this.OnSelectChartPicture(drawPictrueData.ChartDrawPicture);    //选中画图工具事件
                }
            }
            else
            {
                if (this.ClickChartTimer!=null)
                {
                    clearTimeout(this.ClickChartTimer);
                    this.ClickChartTimer=null;
                }
                
                var self=this;
                var ptClick={ X:this.ClickDownPoint.X, Y:this.ClickDownPoint.Y };
                this.ClickChartTimer = setTimeout(function() 
                {
                    self.TryClickPaintEvent(JSCHART_EVENT_ID.ON_CLICK_CHART_PAINT,ptClick,e);
                }, 250);

                if (drawPictureActive.Select.Guid!=null && this.SelectChartDrawPicture==null) 
                    this.DrawDynamicInfo();
            }
        }

        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);
        var moveSetpY=Math.abs(drag.LastMove.Y-e.clientY);
        var isDragSelectRect=(this.RectSelectDrag && this.RectSelectDrag.Index>=0);

        if (this.BorderDrag && this.BorderDrag.Index>=0)
        {
            if(Math.abs(drag.LastMove.Y-e.clientY)<5) return;

            var yMove=e.clientY-drag.LastMove.Y;

            this.OnMoveFromeBorder(this.BorderDrag.Index, yMove);

            drag.LastMove.X=e.clientX;
            drag.LastMove.Y=e.clientY;
        }
        else if (this.YDrag && this.YDrag.Index>=0)
        {
            if(moveSetpY<5) return;

            var yMove=e.clientY-drag.LastMove.Y;

            //this.UIElement.style.cursor="n-resize";

            JSConsole.Chart.Log("[JSChartContainer::DocOnMouseMove] YDrag ",this.YDrag,yMove);
            this.OnZoomUpDownFrameY(this.YDrag, yMove);

            drag.LastMove.X=e.clientX;
            drag.LastMove.Y=e.clientY;
        }
        else 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 || isDragSelectRect)  //数据上下左右拖拽
        {
            this.OnDragMode_One({X:moveSetp, Y:moveSetpY}, e);
        }
        else if (this.DragMode==2) //区间选择
        {
            var yMoveSetp=Math.abs(drag.LastMove.Y-e.clientY);

            if (moveSetp<5 && yMoveSetp<5) return;

            this.UIElement.style.cursor="default";

            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.OnDragMode_One=function(moveData, e)
    {
        var moveSetp=moveData.X;
        var moveSetpY=moveData.Y;
        var drag=this.MouseDrag;

        if (moveSetp<5 && moveSetpY<5) return;

        var bNeedDraw=false;
        var bUpDownY=false;
        if (moveSetpY>=5)
        {
            if (this.UpDownDrag && this.UpDownDrag.Index>=0)
            {
                var yMove=e.clientY-drag.LastMove.Y;
                JSConsole.Chart.Log("[JSChartContainer::OnDragMode_One] UpDownDrag ",this.UpDownDrag,yMove);
                this.UIElement.style.cursor="pointer";
                if (this.OnUpDonwFrameY(this.UpDownDrag, yMove)) 
                {
                    bNeedDraw=true;
                    bUpDownY=true;
                }
                drag.LastMove.Y=e.clientY;
            }
        }

        if (moveSetp>=5)
        {
            var isLeft=true;
            if (drag.LastMove.X<e.clientX) isLeft=false;//右移数据
            if (this.RectSelectDrag && this.RectSelectDrag.Index>=0)
            {
                var obj={ X:e.clientX, Y:e.clientY, PointIndex:this.RectSelectDrag.Index, Name:"MoveRectSelectLine" };
                if (this.MoveRectSelectPoint(obj)) bNeedDraw=true;
            }
            else
            {
                var cursorStatus="pointer";
                if (drag.Click.IsInFrameBottom)  cursorStatus="ew-resize";
                var oneStepWidth=this.GetMoveOneStepWidth();
                if (moveSetp<oneStepWidth)
                {
                    this.UIElement.style.cursor=cursorStatus;
                    if (bNeedDraw) this.Draw();
                    return;
                }
                else
                {
                    if (drag.Click && drag.Click.IsInFrameBottom)
                    {
                       
                        if (this.XCoordinateZoom(moveSetp,isLeft))
                        {
                            this.UpdataDataoffset();
                            this.UpdateFrameMaxMin();
                            this.ResetFrameXYSplit();
                            bNeedDraw=true;
                        }
                    }
                    else if(this.DataMove(moveSetp,isLeft))
                    {
                        this.UpdataDataoffset();
                        //this.UpdatePointByCursorIndex(); //推拽数据的时候不需要把鼠标位置更新到K线上
                        this.UpdateFrameMaxMin();
                        this.ResetFrameXYSplit();
                        bNeedDraw=true;
                    }
                    else if (!bUpDownY)
                    {
                        if (this.DragDownloadData) this.DragDownloadData();
                    }
                }
                this.UIElement.style.cursor=cursorStatus;
            }
            drag.LastMove.X=e.clientX;
        }

        if (bNeedDraw) 
        {
            this.Draw();
            this.OnKLinePageChange("datamove");
        }
    }

    this.DocOnMouseUp=function(e)
    {
        //清空事件
        document.onmousemove=null;
        document.onmouseup=null;
        var IsMinuteChart=(this.ClassName=="MinuteChartContainer" || this.ClassName=="MinuteChartHScreenContainer") ? true:false;
        var isDragSelectRect=(this.RectSelectDrag && this.RectSelectDrag.Index>=0);
        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 (isDragSelectRect)  //区间选择拖动范围
        {
            if (this.OnDragSelectRectMouseUp) this.OnDragSelectRectMouseUp(e);
        }
        else if (IsMinuteChart)
        {
            if (this.OnMinuteSelectRectMouseUp) this.OnMinuteSelectRectMouseUp(e);
        }
        else if (this.DragMode==2)  //区间选择
        {
            var drag=this.MouseDrag;
            drag.LastMove.X=e.clientX;
            drag.LastMove.Y=e.clientY;

            var selectData=new SelectRectData();
            var pixelTatio = GetDevicePixelRatio();
            //区间起始位置 结束位子
            selectData.XStart=(drag.Click.X-uielement.getBoundingClientRect().left)*pixelTatio;
            selectData.YStart=(drag.Click.Y-uielement.getBoundingClientRect().top)*pixelTatio;
            selectData.XEnd=(drag.LastMove.X-uielement.getBoundingClientRect().left)*pixelTatio;
            selectData.YEnd=(drag.LastMove.Y-uielement.getBoundingClientRect().top)*pixelTatio;
            selectData.JSChartContainer=this;
            selectData.Stock={Symbol:this.Symbol, Name:this.Name};

            if (!this.BorderDrag && this.GetSelectRectData(selectData))
            {
                var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_SELECT_RECT);
                var paint=this.GetRectSelectPaint();
                if (event && event.Callback)
                {
                    var data=
                    { 
                        X:drag.LastMove.X-uielement.getBoundingClientRect().left,
                        Y:drag.LastMove.Y-uielement.getBoundingClientRect().top,
                        SelectData:selectData,   //区间选择的数据
                        RectSelectPaint:paint    //区间选择背景
                    };
                    event.Callback(event,data,this);
                }

                if (IsMinuteChart)  //分时图直接显示显示区间选择
                {
                    this.HideSelectRect();
                    this.UpdateSelectRect(selectData.Start,selectData.End);
                }
                else
                {
                    if (this.SelectRectRightMenu)
                    {
                        e.data=
                        {
                            Chart:this,
                            X:drag.LastMove.X-uielement.getBoundingClientRect().left,
                            Y:drag.LastMove.Y-uielement.getBoundingClientRect().top,
                            SelectData:selectData,          //区间选择的数据
                            RectSelectPaint:paint           //区间选择背景
                        };
                        this.SelectRectRightMenu.DoModal(e);
                    }
                }
            }
            else
            {
                this.TryClickPaintEvent(JSCHART_EVENT_ID.ON_CLICKUP_CHART_PAINT,this.ClickDownPoint,e);
            }
        }
        else
        {
            this.TryClickPaintEvent(JSCHART_EVENT_ID.ON_CLICKUP_CHART_PAINT,this.ClickDownPoint,e);
            this.ClickEvent(e);
        }

        //清空数据
        JSConsole.Chart.Log('[KLineChartContainer::document.onmouseup]',e);
        this.UIElement.style.cursor="default";
        this.MouseDrag=null;
        this.ClickDownPoint=null;
        this.IsOnTouch=false;
        if (this.BorderDrag && this.BorderDrag.Index>=0) this.Frame.SaveSubFrameHeightRate();   //拖拽指标窗口高度以后保存
        this.BorderDrag=null;
        this.YDrag=null;
        this.UpDownDrag=null;
        this.RectSelectDrag=null;
        if (bClearDrawPicture===true) this.CurrentChartDrawPicture=null;
    }

    this.UIOnMounseOut=function(e)
    {
        JSConsole.Chart.Log('[KLineChartContainer::UIOnMounseOut]',e);
        this.UIOnMouseMove(e);
    }

    this.UIOnMouseleave=function(e)
    {
        JSConsole.Chart.Log('[KLineChartContainer::UIOnMouseleave]',e);
        //this.UIOnMouseMove(e);
    }

    //点击事件
    this.ClickEvent=function(e) 
    {
        var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_CLICK);
        if (!event || !event.Callback) return false;
        if (this.ClickDownPoint.X!=e.clientX || this.ClickDownPoint.Y!=e.clientY) return false;
        var pixelTatio = GetDevicePixelRatio();
        var x=(e.clientX-uielement.getBoundingClientRect().left)*pixelTatio;
        var y=(e.clientY-uielement.getBoundingClientRect().top)*pixelTatio;
        var data= { X:e.clientX, Y:e.clientY, FrameID:-1 };
    
        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)
        {
            var yValueExtend={};
            var yValue=this.Frame.GetYData(y,yValueExtend);

            if (IFrameSplitOperator.IsNumber(yValueExtend.FrameID) && yValueExtend.FrameID>=0)
            {
                var xValue=this.Frame.GetXData(x);
                data.FrameID=yValueExtend.FrameID;
                data.Data={ X:xValue, Y:yValue } ;
            }
        }
        
        event.Callback(event, data, this);
        return true;
    }

    this.PtInChartPaintTooltip=function(x,y, toolTip)
    {
        for(var i=0;i<this.ChartPaint.length;++i)
        {
            var item=this.ChartPaint[i];
            if (item.GetTooltipData(x,y,toolTip))
                return item;
        }

        return null;
    }

    this.PtInOverlayChartPaintTooltip=function(x,y,toolTip)
    {
        for(var i=0;i<this.OverlayChartPaint.length;++i)
        {
            var item=this.OverlayChartPaint[i];
            if (item.GetTooltipData(x,y,toolTip))
                return item;
        }

        return null;
    }

    this.TryClickPaintEvent=function(eventID, ptClick, e)
    {
        var event=this.GetEventCallback(eventID);
        if (event && event.Callback)
        {
            if (ptClick.X==e.clientX && ptClick.Y==e.clientY)
            {
                var pixelTatio = GetDevicePixelRatio();
                var x = (e.clientX-uielement.getBoundingClientRect().left)*pixelTatio;
                var y = (e.clientY-uielement.getBoundingClientRect().top)*pixelTatio;

                var toolTip=new TooltipData();
                var stock=null;
            
                //主数据
                var paint=this.PtInChartPaintTooltip(x,y, toolTip);
                if (paint) stock={ Symbol:this.Symbol, Name:this.Name };

                if (!paint)    //叠加数据
                {
                    paint=this.PtInOverlayChartPaintTooltip(x,y, toolTip);
                    if (paint) stock={ Symbol:toolTip.ChartPaint.Symbol, Name:toolTip.ChartPaint.Title };
                }

                if (toolTip.Data)
                {
                    var data= { X:e.clientX, Y:e.clientY, Stock: stock, Tooltip:toolTip };
                    event.Callback(event, data, this);
                    return true;
                }
            }
        }

        return false;
    }


    //判断是单个手指
    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.AddPhoneDBClickInfo=function(x,y,time)
    {
        var item={ X:x, Y:y, Time:time };
        this.PhoneDBClickInfo.Start.push(item);
    }

    this.ClearPhoneDBClickInfo=function()
    {
        this.PhoneDBClickInfo.Start=[];
    }

    this.IsShortPhoneClick=function(x,y,time)
    {

    }

    this.OnTouchStart=function(e)
    {
        if (this.ChartSplashPaint && this.ChartSplashPaint.IsEnableSplash == true) return;

        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 pt=this.PointAbsoluteToRelative(touches[0].clientX, touches[0].clientY, true);
                var x = pt.X;
                var y = pt.Y;
                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;
            this.PhoneTouchInfo={ Start:{X:touches[0].clientX, Y:touches[0].clientY }, End:{ X:touches[0].clientX, Y:touches[0].clientY } };
            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,true);
                else
                {
                    this.SetChartDrawPictureFirstPoint(drag.Click.X,drag.Click.Y,true);
                    //只有1个点 直接完成
                    if (this.FinishChartDrawPicturePoint()) this.DrawDynamicInfo({Corss:false, Tooltip:false});
                }

                if (e.cancelable) e.preventDefault();
                return;
            }
            else
            {
                var pt=this.PointAbsoluteToRelative(touches[0].clientX,touches[0].clientY, true);
                var drawPictrueData={ X:pt.X, Y:pt.Y };
                var pixelTatio = GetDevicePixelRatio(); //鼠标移动坐标是原始坐标 需要乘以放大倍速
                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.EnableZoomIndexWindow)
            {
                this.PhoneDBClick.AddTouchStart(touches[0].clientX, touches[0].clientY, Date.now());
                JSConsole.Chart.Log("[JSChartContainer::OnTouchStart] PhoneDBClick ", this.PhoneDBClick);
            }
            
            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);
            }
            
            this.TouchEvent({ EventID:JSCHART_EVENT_ID.ON_PHONE_TOUCH, FunctionName:"OnTouchStart"}, 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)
    {
        if (this.ChartSplashPaint && this.ChartSplashPaint.IsEnableSplash == true) return;

        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,true))
                        {
                            this.DrawDynamicInfo();
                        }
                    }
                    else if (drawPicture.Status==3)
                    {
                        if(this.SetChartDrawPictureThirdPoint(touches[0].clientX,touches[0].clientY,true))
                        {
                            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,true))
                        {
                            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;//右移数据

                    var oneStepWidth=this.GetMoveOneStepWidth();
                    if (moveSetp<oneStepWidth) return;

                    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;
                }
            }

            if (this.PhoneTouchInfo)
            {
                this.PhoneTouchInfo.End.X=touches[0].clientX;
                this.PhoneTouchInfo.End.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;

            if (this.EnableZoomUpDown && this.EnableZoomUpDown.Touch===false) 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);
        if (this.ChartSplashPaint && this.ChartSplashPaint.IsEnableSplash == true) return;

        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();
            }
        }

        if (this.EnableZoomIndexWindow)
        {
            var time=Date.now();
            this.PhoneDBClick.AddTouchEnd(time);
            if (this.PhoneDBClick.IsVaildDBClick())
            {
                this.OnTouchDBClick(this.PhoneDBClick.Start);
                this.PhoneDBClick.Clear();
            }
        }
        
        this.IsOnTouch = false;
        if (bClearDrawPicture===true) this.CurrentChartDrawPicture=null;
        this.StopDragTimer();
        this.TouchEvent({ EventID:JSCHART_EVENT_ID.ON_PHONE_TOUCH, FunctionName:"OnTouchEnd"}, e);
        this.OnTouchFinished();
        this.TouchDrawCount=0;
    }

    this.OnTouchDBClick=function(points)
    {
        var pt=this.PointAbsoluteToRelative(points[0].X, points[0].Y, true);
        var x=pt.X, y=pt.Y;
        JSConsole.Chart.Log(`[KLineChartContainer:OnTouchDBClick] Phone dbclick absolute [${x},${y}], soruce [${points[0].X},${points[0].Y}]`);

        var frameId=this.Frame.PtInFrame(x,y);
        JSConsole.Chart.Log("[KLineChartContainer::OnTouchDBClick] frameId",frameId);
        if (frameId>=this.Frame.ZoomStartWindowIndex)
        {
            if (this.ZoomIndexWindow(frameId, {X:x, Y:y}))
            {
                this.Frame.SetSizeChage(true);
                this.Draw();
                return true;
            }
        }
    }

    //手势事件
    this.TouchEvent=function(obj,e)
    {
        var eventID=obj.EventID;
        var event=this.GetEventCallback(eventID);
        if (!event || !event.Callback) return false;
        var drag=this.PhoneTouchInfo
        if (!drag || !drag.Start || !drag.End ) return false;
        var pixelTatio = GetDevicePixelRatio();
        var clientX=drag.End.X/pixelTatio;
        var clientY=drag.End.Y/pixelTatio;
        var x=drag.End.X-this.UIElement.getBoundingClientRect().left*pixelTatio;
        var y=drag.End.Y-this.UIElement.getBoundingClientRect().top*pixelTatio;
        var data= 
        { 
            X:clientX, Y:clientY, FrameID:-1, FunctionName:obj.FunctionName,
            Drag:
            { 
                Start:{ X:drag.Start.X/pixelTatio, Y:drag.Start.Y/pixelTatio }, 
                End:{ X:drag.End.X/pixelTatio, Y:drag.End.Y/pixelTatio } 
            } 
        };

        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)
        {
            var yValueExtend={};
            var yValue=this.Frame.GetYData(y,yValueExtend);

            if (IFrameSplitOperator.IsNumber(yValueExtend.FrameID) && yValueExtend.FrameID>=0)
            {
                var xValue=this.Frame.GetXData(x);
                data.FrameID=yValueExtend.FrameID;
                data.Data={ X:xValue, Y:yValue } ;
            }
        }

        event.Callback(event, data, this);
        return true;
    }

    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,true);
    }

    this.DrawEmpty=function()
    {
        if (this.UIElement.width<=0 || this.UIElement.height<=0) return; 
        this.Canvas.clearRect(0,0,this.UIElement.width,this.UIElement.height);
        if (this.Frame)
        {
            this.Frame.ScreenImageData=null;
            this.Frame.Draw();
        }
    }

    this.Draw=function()
    {
        if (this.ChartCorssCursor) this.ChartCorssCursor.Status=0;
        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.ClearCoordinateText();
            this.Frame.Draw( { IsEnableSplash:this.ChartSplashPaint.IsEnableSplash} );
            this.ChartSplashPaint.Draw();
            return;
        }

        //框架
        this.Frame.SetDrawDepthMap(()=>
        {
            for(var i=0;i<this.ExtendChartPaint.length;++i)
            {
                var item=this.ExtendChartPaint[i];
                if (item.IsCallbackDraw) item.Draw();
            }
        });

        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=0;i<this.ChartPaint.length;++i)
        {
            var item=this.ChartPaint[i];
            if (item.IsDrawFirst)
                item.Draw();
        }

        for(var i=0; i<this.ChartPaint.length; ++i)
        {
            var item=this.ChartPaint[i];
            if (!item.IsDrawFirst)
                item.Draw();
        }

        for(var i=0;i<this.ChartPaintEx.length;++i)
        {
            var item=this.ChartPaintEx[i];
            item.Draw();
        }

        //叠加股票
        for(var i=0;i<this.OverlayChartPaint.length;++i)
        {
            var item=this.OverlayChartPaint[i];
            item.Draw();
        }

        if (this.Frame.DrawOveraly)
            this.Frame.DrawOveraly();   //画叠加指标

        //固定扩展图形
        for(var i=0;i<this.ExtendChartPaint.length;++i)
        {
            var item=this.ExtendChartPaint[i];
            if (item.IsCallbackDraw) continue;
            if (!item.IsDynamic && item.IsAnimation==false) item.Draw();
        }

        if (this.Frame.DrawInsideHorizontal) this.Frame.DrawInsideHorizontal();
        if (this.Frame.DrawCustomHorizontal) this.Frame.DrawCustomHorizontal();
        if (this.Frame.DrawEx) this.Frame.DrawEx( {Symbol:this.Symbol} );
        if (this.ChartInfoPaint) this.ChartInfoPaint.Draw();
        this.Frame.DrawLock();
        this.Frame.Snapshot();

        for(var i=0;i<this.ExtendChartPaint.length;++i) //动态扩展图形
        {
            var item=this.ExtendChartPaint[i];
            if (item.IsCallbackDraw) continue;
            if (item.IsDynamic && item.DrawAfterTitle===false) item.Draw();
        }

        for(var i=0;i<this.ChartDrawPicture.length;++i)
        {
            var item=this.ChartDrawPicture[i];
            if (item.IsDrawFirst) item.Draw();
        }

        if (this.IsDrawPictureXY)
        {
            if (this.CurrentChartDrawPicture) this.Frame.DrawPictureCoordinate(this.CurrentChartDrawPicture, { Symbol:this.Symbol, Period:this.Period });
            else if (this.SelectChartDrawPicture) this.Frame.DrawPictureCoordinate(this.SelectChartDrawPicture, { Symbol:this.Symbol, Period:this.Period });
        }
        
        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 drawStatus=this.GetDrawStatus();
        drawStatus.DrawName="Draw";
        var eventTitleDraw=this.GetEventCallback(JSCHART_EVENT_ID.ON_TITLE_DRAW);
        var eventIndexTitleDraw=this.GetEventCallback(JSCHART_EVENT_ID.ON_INDEXTITLE_DRAW);
        for(var i=0;i<this.TitlePaint.length;++i)
        {
            var item=this.TitlePaint[i];
            if (!item.IsDynamic) continue;

            item.CursorIndex=this.CursorIndex;
            if (item.ClassName=='DynamicChartTitlePainting') item.OnDrawEvent=eventIndexTitleDraw
            else item.OnDrawEvent=eventTitleDraw;

            if (item.OnDrawEvent) 
            {
                item.OnDrawEvent.FunctionName='Draw';
                item.OnDrawEvent.PointPosition=null;
            }

            item.DrawStatus=drawStatus;
            item.Draw();
        }

        for(var i=0;i<this.ExtendChartPaint.length;++i) //动态扩展图形
        {
            var item=this.ExtendChartPaint[i];
            if (item.IsCallbackDraw) continue;
            if (item.IsDynamic && item.DrawAfterTitle===true && item.IsAnimation==false) item.Draw();
        }

        if (this.EnableAnimation)
        {
            for(var i=0;i<this.ExtendChartPaint.length;++i) //动画
            {
                var item=this.ExtendChartPaint[i];
                if (item.IsAnimation===true) item.Draw();
            }
        }

        for(var i=0;i<this.ChartDrawPicture.length;++i)
        {
            var item=this.ChartDrawPicture[i];
            if (!item.IsDrawFirst) item.Draw();
        }

        if (this.CurrentChartDrawPicture && this.CurrentChartDrawPicture.Status!=10)
        {
            this.CurrentChartDrawPicture.Draw();
        }

        this.OffscreenToShowCanvas();

        //发送图形状态给外部
        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.OffscreenToShowCanvas=function()
    {
        if (!this.ShowCanvas) return;

        this.ShowCanvas.clearRect(0,0,this.UIElement.width,this.UIElement.height);
        this.ShowCanvas.drawImage(this.OffscreenCanvasElement,0,0);
    }

    this.GetDrawStatus=function()
    {
        var status=
        {
            Point:{ X:this.LastPoint.X, Y:this.LastPoint.Y }, 
            IsOnTouch:this.IsOnTouch,
            CorssCursorTouchEnd:this.CorssCursorTouchEnd,
            IsTitleShowLatestData:this.IsTitleShowLatestData,
            IsMinuteChart:(this.ClassName=="MinuteChartContainer" || this.ClassName=="MinuteChartHScreenContainer") ? true:false
        };

        status.FrameID=this.Frame.PtInFrame(this.LastPoint.X, this.LastPoint.Y);

        return status;
    }
    //画动态信息
    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=0;i<this.ExtendChartPaint.length;++i)
            {
                var item=this.ExtendChartPaint[i];
                if (item.IsCallbackDraw) continue;
                if (item.IsDynamic && item.IsEraseBG) 
                {
                    isErase=true;
                    break;
                }
            }
        }

        if (isErase) this.Canvas.putImageData(this.Frame.ScreenImageData,0,0);


        for(var i=0;i<this.ExtendChartPaint.length;++i) //动态扩展图形
        {
            var item=this.ExtendChartPaint[i];
            if (item.IsCallbackDraw) continue;
            if (item.IsDynamic && item.DrawAfterTitle===false && item.IsAnimation==false) item.Draw();
        }

        for(var i=0;i<this.ChartDrawPicture.length;++i)
        {
            var item=this.ChartDrawPicture[i];
            if (item.IsDrawFirst) item.Draw();
        }

        if (this.IsDrawPictureXY)
        {
            if (this.CurrentChartDrawPicture) this.Frame.DrawPictureCoordinate(this.CurrentChartDrawPicture, { Symbol:this.Symbol, Period:this.Period });
            else if (this.SelectChartDrawPicture) this.Frame.DrawPictureCoordinate(this.SelectChartDrawPicture, { Symbol:this.Symbol, Period:this.Period });
        }
        
        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();
            }
            else if (this.IsOnTouch===true && (this.CurrentChartDrawPicture && this.EnableShowCorssCursor && this.EnableShowCorssCursor.DrawPicture==true))
            {
                this.ChartCorssCursor.Draw();
            }
        }

        var ptPosition=null;    //鼠标位置 null 无效 -1 在外面 >=0 对应的指标窗口中ID
        if (option && option.ParentFunction=='OnMouseMove' && option.Point)
        {
            ptPosition=this.Frame.PtInFrame(option.Point.X, option.Point.Y);
        }

        var drawStatus=this.GetDrawStatus();
        drawStatus.DrawName="DrawDynamicInfo";
        for(var i=0;i<this.TitlePaint.length;++i)
        {
            var item=this.TitlePaint[i];
            if (!item.IsDynamic) continue;

            item.CursorIndex=this.CursorIndex;
            if (item.OnDrawEvent) 
            {
                item.OnDrawEvent.FunctionName='DrawDynamicInfo';
                item.OnDrawEvent.PointPosition=ptPosition;
            }
            item.DrawStatus=drawStatus;

            if (item.ClassName=="DynamicMinuteTitlePainting")
            {
                if (option && IFrameSplitOperator.IsNumber(option.ClientPos) && option.Point)
                    item.PointInfo={ ClientPos:option.ClientPos, Point:{ X:option.Point.X, Y:option.Point.Y }};
                else 
                    item.PointInfo=null;
            }
            
            item.Draw();
        }

        for(var i=0;i<this.ExtendChartPaint.length;++i) //动态扩展图形   在动态标题以后画
        {
            var item=this.ExtendChartPaint[i];
            if (item.IsCallbackDraw) continue;
            if (item.ClassName=='KLineTooltipPaint' && option)
            {
                if (option.Tooltip==false) continue;
                if (option.Point) item.LatestPoint=option.Point;
            }
            else if (item.ClassName=="MinuteTooltipPaint" && option)
            {
                if (option.Point) item.LatestPoint=option.Point;
            }

            if (item.IsDynamic && item.DrawAfterTitle===true) item.Draw();
        }

        if (this.EnableAnimation)
        {
            for(var i=0;i<this.ExtendChartPaint.length;++i) //动画
            {
                var item=this.ExtendChartPaint[i];
                if (item.IsAnimation===true) item.Draw();
            }
        }

        for(var i=0;i<this.ChartDrawPicture.length;++i)
        {
            var item=this.ChartDrawPicture[i];
            if (!item.IsDrawFirst) item.Draw();
        }

        if (this.CurrentChartDrawPicture && this.CurrentChartDrawPicture.Status!=10)
        {
            this.CurrentChartDrawPicture.Draw();
        }

        

        this.OffscreenToShowCanvas();

        ++this.TouchDrawCount;
    }

    this.DrawAnimation=function()   //绘制动画 如弹幕
    {
        if (!this.EnableAnimation) return;

        if (this.Frame.ScreenImageData && !this.IsOnTouch)
        {
            for(var i=0;i<this.ExtendChartPaint.length;++i)
            {
                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=0;i<this.ExtendChartPaint.length;++i)
        {
            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.GetChartTooltipData=function(x,y,option)
    {
        var toolTip=new TooltipData();

        if (this.ChartInfoPaint)
        {
            if (this.ChartInfoPaint.GetTooltipData(x,y,toolTip)) 
                return toolTip;
        }

        if (this.PtInChartPaintTooltip(x,y, toolTip))
            return toolTip;

        if (IFrameSplitOperator.IsNonEmptyArray(this.Frame.SubFrame))
        {
            for(var i=0;i<this.Frame.SubFrame.length;++i)
            {
                var subFrame=this.Frame.SubFrame[i];
                for(var j=0;j<subFrame.OverlayIndex.length;++j)
                {
                    var overlayItem=subFrame.OverlayIndex[j];
                    for(var k=0;k<overlayItem.ChartPaint.length;++k)
                    {
                        var item=overlayItem.ChartPaint[k];
                        if (item.GetTooltipData(x,y,toolTip))
                            return toolTip;
                    }
                }
            }
        }

        if (this.PtInOverlayChartPaintTooltip(x,y,toolTip))
            return toolTip;
        
        return null;
    }

    this.OnMouseMove=function(x,y,e, isPhone)
    {
        this.LastPoint.X=x;
        this.LastPoint.Y=y;
        var mouseStatus=null;   //鼠标状态
        var frameID=this.Frame.PtInFrame(x,y);
        if (IFrameSplitOperator.IsNumber(frameID) && frameID>=0)    //在K线内部移动,调整K线索引
            this.CursorIndex=this.Frame.GetXData(x);

        var paint=this.GetRectSelectPaint();
        if (paint && paint.GetPointCount()>0)
        {
            var item=paint.PtInPaint(x,y);
            if (item)
            {
                mouseStatus={ Cursor:"ew-resize", Name:"DragRectSelect"};
                JSConsole.Chart.Log("[JSChartContainer::OnMouseMove] drag rect select ",item);
            }
        }

        if (this.EnableBorderDrag && this.Frame)
        {
            var dragBorder=this.Frame.PtInFrameBorder(x,y);
            if (dragBorder && dragBorder.Index>=0)
            {
                mouseStatus={ Cursor:"n-resize", Name:"DragBorder"};
                JSConsole.Chart.Log("[JSChartContainer::OnMouseMove] drag border ",dragBorder);
            }
        }

        if (this.EnableYDrag && this.Frame && !mouseStatus)
        {
            var dragY=this.TryYDrag(x,y);
            if (dragY)
            {
                mouseStatus={ Cursor:dragY.Position==0 ? "n-resize":"row-resize", Name:"DragY"};
                JSConsole.Chart.Log("[JSChartContainer::OnMouseMove] drag y ",dragY);
            }
        }

        var button=this.Frame.PtInButtons(x,y);
        if (button)
        {
            mouseStatus={ Cursor:"pointer", Name:"FrameButton"};
            JSConsole.Chart.Log("[JSChartContainer::OnMouseMove] frame button ", button);
        }

        if (this.ChartCorssCursor)
        {
            var crossButton=this.ChartCorssCursor.PtInButton(x,y);
            if (crossButton)
            {
                mouseStatus={ Cursor:"pointer", Name:"CorssCursorButton"};
                JSConsole.Chart.Log("[JSChartContainer::OnMouseMove] cross cursor button ", crossButton);
            }
        }

        if (this.ClassName=="KLineChartContainer"  && this.Frame.PtInFrameBottom(x,y))
        {
            mouseStatus={ Cursor:"ew-resize", Name:"FrameButtom"};
            JSConsole.Chart.Log("[JSChartContainer::OnMouseMove] frame bottom ");
        }
        

        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) && 
                drawPictrueData.ChartDrawPicture && drawPictrueData.ChartDrawPicture.EnableMove==true) 
            {
                
                if (drawPictrueData.PointIndex===100) this.UIElement.style.cursor="move";
                else this.UIElement.style.cursor="pointer";
                bDrawPicture=true;

                this.MoveOnChartDrawPicture=drawPictrueData.ChartDrawPicture;
            }
            else 
            {
                if (!this.MouseDrag) this.UIElement.style.cursor="default";
            }
        }

        var clientPos=this.PtInClient(x,y);
        var option={ ParentFunction:'OnMouseMove', Point:{X:x, Y:y}, IsPhone:isPhone===true, ClientPos:clientPos };
        if (e && (e.type=="mouseout" || e.type=="mouseleave")) option.Corss=false; //鼠标移开,不显示十字光标
        this.DrawDynamicInfo(option);
        if (mouseStatus) this.UIElement.style.cursor=mouseStatus.Cursor;

        if (this.IsShowTooltip && bDrawPicture==false)
        {
            var toolTip=this.GetChartTooltipData(x,y);

            if (toolTip && toolTip.Data)
            {
                if (isPhone===true)
                {
                    var touche=e.touches[0];
                    var xTooltip = touche.clientX-this.UIElement.getBoundingClientRect().left;
                    var yTooltip = touche.clientY-this.UIElement.getBoundingClientRect().top;
                }
                else
                {
                    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)
    {
        if (this.ChartSplashPaint && this.ChartSplashPaint.IsEnableSplash == true) return;
        
        var keyID = e.keyCode ? e.keyCode :e.which;
        switch(keyID)
        {
            case 37: //left
                if (this.CursorIndex<=0.99999)
                {
                    if (!this.DataMoveLeft()) 
                    {   //左移数据到头了 触发下载新数据
                        if (this.DragDownloadData) this.DragDownloadData();
                        break;
                    }
                    this.UpdataDataoffset();
                    this.UpdatePointByCursorIndex();
                    this.UpdateFrameMaxMin();
                    this.Draw();
                    this.ShowTooltipByKeyDown();
                    this.OnKLinePageChange("keydown");
                }
                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();
                    this.OnKLinePageChange("keydown");
                }
                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
                if (this.EnableZoomUpDown && this.EnableZoomUpDown.Keyboard===false) break;
                var cursorIndex={ ZoomType:this.ZoomType };
                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();
                this.OnKLinePageChange("keydown");
                break;
            case 40:    //down
                if (this.EnableZoomUpDown && this.EnableZoomUpDown.Keyboard===false) break;
                var cursorIndex={ ZoomType:this.ZoomType };
                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();
                this.OnKLinePageChange("keydown");
                break;
            case 46:    //del
                if (!this.SelectChartDrawPicture) break;
                var drawPicture=this.SelectChartDrawPicture;
                JSConsole.Chart.Log(drawPicture,"drawPicturedrawPicturedrawPicture")
                this.SelectChartDrawPicture=null;
                this.ClearChartDrawPicture(drawPicture);    //删除选中的画图工具
                break;
            case 32:    //space
                this.OnMarkRectSelect(e);
                break;
            default:
                return;
        }

        //不让滚动条滚动
        if(e.preventDefault) e.preventDefault();
        else e.returnValue = false;
    }

    this.OnDoubleClick=function(x,y,e)
    {
        //JSConsole.Chart.Log(e);
    }

    this.ZoomIndexWindow=function(frameID, option)   //最大化/最小化指标窗口 
    {
        if (frameID<0 || frameID>=this.Frame.SubFrame.length) return false;

        return this.Frame.ZoomIndexWindow(frameID, option);
    }

    this.RemoveMinSizeWindows=function()    //清空最小化窗口
    {
        if (!this.Frame.ZoomWindowsInfo) return;

        var aryDeleteIndex=[], aryIndex=[]; //删除的索引， 保留的索引
        for(var i=0;i<this.Frame.SubFrame.length;++i)
        {
            var item=this.Frame.SubFrame[i];
            item.Frame.ClearToolbar();
            if (item.Frame.IsMinSize) 
                aryDeleteIndex.push(i);
            else 
                aryIndex.push(i);
        }
        this.Frame.ZoomWindowsInfo=null;
        if (aryDeleteIndex.length<=0) return;

        for(var i=0;i<aryDeleteIndex.length;++i)
        {
            this.DeleteIndexPaint(aryDeleteIndex[i]);
        }

        var newSubFrame=[];
        var newWindowIndex=[];
        var newTitlePaint=[this.TitlePaint[0]];
        for(var i=0;i<aryIndex.length;++i)
        {
            var id=aryIndex[i];
            newSubFrame[i]=this.Frame.SubFrame[id];
            newWindowIndex[i]=this.WindowIndex[id];
            newTitlePaint[i+1]=this.TitlePaint[id+1];
        }
        this.Frame.SubFrame=newSubFrame;
        this.WindowIndex=newWindowIndex;
        this.TitlePaint=newTitlePaint;

        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 (IFrameSplitOperator.IsNonEmptyArray(this.ChartDrawPicture))
        {
            var aryDrawPicture=[];
            for(var i=0; i<this.ChartDrawPicture.length; ++i)
            {
                var item=this.ChartDrawPicture[i];
                for(var j=0; j<this.Frame.SubFrame.length; ++j)
                {
                    if (item.Frame==this.Frame.SubFrame[j].Frame)
                    {
                        aryDrawPicture.push(item);
                        break;
                    }
                }
            }
            this.ChartDrawPicture=aryDrawPicture;
        }

    }

    this.PtInClient=function(x,y)
    {
        this.Canvas.beginPath();
        if (this.Frame.IsHScreen===true)
        {
            var border=this.Frame.ChartBorder.GetHScreenBorder();
            this.Canvas.rect(border.Left,border.TopEx,border.Right-border.Left,border.BottomEx-border.TopEx);
        }
        else
        {
            var border=this.Frame.ChartBorder.GetBorder();
            if (border.DayBorder)   //多日分时+多日集合竞价
            {
                for(var i=0;i<border.DayBorder.length;++i)
                {
                    var client=border.DayBorder[i];
                    this.Canvas.beginPath();
                    this.Canvas.rect(client.LeftEx,border.TopEx,client.RightEx-client.LeftEx,border.BottomEx-border.TopEx);
                    if (this.Canvas.isPointInPath(x,y)) return 1;

                    //盘前
                    this.Canvas.beginPath();
                    this.Canvas.rect(client.Left,border.TopEx,client.LeftEx-client.Left,border.BottomEx-border.TopEx);
                    if (this.Canvas.isPointInPath(x,y)) 
                        return 200+parseInt(i);

                    //盘后
                    this.Canvas.beginPath();
                    this.Canvas.rect(client.RightEx,border.TopEx,client.Right-client.RightEx,border.BottomEx-border.TopEx);
                    if (this.Canvas.isPointInPath(x,y)) 
                        return 300+parseInt(i);
                }

                return -1;
            }

            this.Canvas.rect(border.LeftEx,border.Top,border.RightEx-border.LeftEx,border.Bottom-border.Top);
        }

        if (this.Canvas.isPointInPath(x,y)) return 1;

        if (this.Frame.ChartBorder.LeftExtendWidth>10)
        {
            this.Canvas.beginPath();
            if (this.Frame.IsHScreen===true)
            {
                this.Canvas.rect(border.Left,border.Top,border.Right-border.Left,border.TopEx-border.Top);
            }
            else
            {
                this.Canvas.rect(border.Left,border.Top,border.LeftEx-border.Left,border.Bottom-border.Top);
            }
    
            if (this.Canvas.isPointInPath(x,y)) return 2;
        }

        if (this.Frame.ChartBorder.RightExtendWidth>10)
        {
            this.Canvas.beginPath();
            if (this.Frame.IsHScreen===true)
            {
                this.Canvas.rect(border.Left,border.BottomEx,border.Right-border.Left,border.Bottom-border.BottomEx);
            }
            else
            {
                this.Canvas.rect(border.RightEx,border.Top,border.Right-border.RightEx,border.Bottom-border.Top);
            }
    
            if (this.Canvas.isPointInPath(x,y)) return 3;
        }

        return -1;
    }

    this.OnMoveFromeBorder=function(index, yMove)
    {
        if (!this.Frame) return;

        if (!this.Frame.OnMoveFromeBorder(index,yMove)) return ;

        //this.Frame.SetSizeChage(true);
        this.Frame.SetFrameBorderSizeChange();
        this.Frame.ReDrawToolbar();
        this.Draw();
    }

    this.OnZoomUpDownFrameY=function(obj, yMove)
    {
        if (!this.Frame) return;

        if (!this.Frame.OnZoomUpDownFrameY(obj,yMove)) return ;

        this.Frame.SetSizeChage(true);
        this.Draw();
    }

    this.OnUpDonwFrameY=function(obj, yMove)
    {
        if (!this.Frame) return false;

        if (!this.Frame.OnUpDonwFrameY(obj,yMove)) return false;

        this.Frame.SetSizeChage(true);

        return true;
    }

    this.CancelZoomUpDownFrameY=function(obj)
    {
        if (!this.Frame) return;

        if (!this.Frame.CancelZoomUpDownFrameY(obj)) return ;

        this.UpdateFrameMaxMin();
        this.Frame.SetSizeChage(true);
        this.Draw();
    }

    this.IsKLineContainer=function()
    {
        if (this.ClassName=='KLineChartContainer' || this.ClassName=='KLineChartHScreenContainer' ||
            this.ClassName=="KLineTrainChartContainer" || this.ClassName=="CustomKLineChartContainer" ) return true;

        return false;
    }

    this.UpdatePointByCursorIndex=function(type)    //type 1=根据十字光标更新 2=强制取消十字光标
    {
        var pt={X:null, Y:null};
        pt.X=this.Frame.GetXFromIndex(this.CursorIndex);
        var index=Math.abs(this.CursorIndex-0.5);
        if (this.IsKLineContainer()) index=this.CursorIndex;

        var data=this.Frame.Data;
        if (data.DataOffset+index<data.Data.length)
        {
            var close=data.Data[data.DataOffset+index].Close;
            pt.Y=this.Frame.GetYFromData(close);
        }
       
        if (type==1 && this.ChartCorssCursor)
        {
            if (this.ChartCorssCursor.Status==1)    //十字光标显示中, 不调整位置
            {

            }
            else
            {
                this.LastPoint.X=this.Frame.GetXFromIndex(this.CursorIndex);
                var index=Math.abs(this.CursorIndex-0.5);
                index=parseInt(index.toFixed(0));
                if (this.IsKLineContainer()) index=this.CursorIndex;
                this.LastPoint.Y=null;
            }
        }
        else if (type==2 && this.ChartCorssCursor)  //取消鼠标位置，十字光标就不显示了
        {
            this.LastPoint.Y=null;
            this.LastPoint.X=null;
        }
        else
        {
            this.LastPoint.X=pt.X;
            this.LastPoint.Y=pt.Y;
        }
    }

    this.ShowTooltipByKeyDown=function()
    {
        var index=Math.abs(this.CursorIndex-0.5);
        index=parseInt(index.toFixed(0));
        if (this.ClassName=='KLineChartContainer' || this.ClassName=='KLineTrainChartContainer') 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 scrollPos=GetScrollPosition();
            var left = x;
            var top = y;

            var format=g_DivTooltipDataForamt.Create('HistoryDataStringFormat');
            format.Value=toolTip;
            format.Symbol=this.Symbol;
            format.LanguageID=this.LanguageID;
            if (!format.Operator()) return;
            var textHeight=format.LineCount*25; //每行的行高25
            if (format.Height>0) textHeight=format.Height;  //新版本高度有格式化类计算完成
            var width=format.Width;

            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";
            
            if (top+xMove+textHeight>this.UIElement.getBoundingClientRect().height-5)
                this.Tooltip.style.top = (top-textHeight)+ "px";
            else 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 format=g_DivTooltipDataForamt.Create('KLineInfoDataStringFormat');
            format.Value=toolTip;
            format.Symbol=this.Symbol;
            format.LanguageID=this.LanguageID;
            if (!format.Operator()) return;
            var width=format.Width;

            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";
        }
        else if (toolTip.Type==2)   //指标信息
        {
            var left = x;
            var top = y;
            
            var format=g_DivTooltipDataForamt.Create('KLineTradeDataStringFormat');
            format.Value=toolTip;
            format.Symbol=this.Symbol;
            format.LanguageID=this.LanguageID;
            if (!format.Operator()) return;
            var width=format.Width;

            this.Tooltip.className='jchart-klinetrade-tooltip';
            this.Tooltip.style.position = "absolute";
            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";
        }
        else if (toolTip.Type==3)   //分时图异动信息
        {
            var left = x;
            var top = y;

            var format=g_DivTooltipDataForamt.Create('MinuteInfoDataStringFormat');
            format.Value=toolTip;
            format.Symbol=this.Symbol;
            format.LanguageID=this.LanguageID;
            if (!format.Operator()) return;
            var width=format.Width;

            this.Tooltip.className='jchart-minuteinfo-tooltip'; //分时图异动
            this.Tooltip.style.position = "absolute";
            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";
        }
        else if (toolTip.Type==4)   //icon图标信息
        {
            var left = x;
            var top = y;

            var format=g_DivTooltipDataForamt.Create('IconDataStringFormat');
            format.Value=toolTip;
            format.Symbol=this.Symbol;
            format.LanguageID=this.LanguageID;
            if (!format.Operator()) return;
            var width=format.Width;

            this.Tooltip.className='jchart-iconinfo-tooltip'; //图标信息
            this.Tooltip.style.position = "absolute";
            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()
    {
        if (this.Tooltip.style.display!="none") this.Tooltip.style.display = "none";
    }

    this.ShowSelectRect=function(x,y,x2,y2)
    {
        var left = x;
        var top = y;

        var border=this.Frame.ChartBorder.GetBorder();

        var borderRight=border.Right;
        var borderLeft=border.Left;

        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 paint=this.GetRectSelectPaint();
        if (!paint) return;

        var data=this.ChartPaint[0].Data;
        var startItem=data.Data[start];
        var endItem=data.Data[end];

        JSConsole.Chart.Log('[JSChartContainer::UpdateSelectRect]',startItem,endItem);
        paint.SetPoint(startItem, { Index:0 });
        paint.SetPoint(endItem, { Index:1 });

        this.Draw();
    }

    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=0;i<this.ChartPaint.length;++i)
        {
            var item=this.ChartPaint[i];
            if (item.IsShow==false) continue;   //隐藏的图形不计算
            chartPaint.push(this.ChartPaint[i]);
        }

        for(var i=0;i<this.OverlayChartPaint.length;++i)
        {
            chartPaint.push(this.OverlayChartPaint[i]);
        }

        for(var i=0;i<chartPaint.length;++i)
        {
            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={ OverlayFrame:[] };
                frameItem.Frame=paint.ChartFrame;
                frameItem.Range=range;
                frameMaxMinData.push(frameItem);
            }
        }

        var mapFrame=new Map();
        for(var i=0;i<frameMaxMinData.length;++i)
        {
            var item=frameMaxMinData[i];
            mapFrame.set(item.Frame.Identify,item);
        }

        //叠加坐标Y轴使用主图指标， 最大最小值
        for(var i=0;i<this.Frame.SubFrame.length;++i)
        {
            var subFrame=this.Frame.SubFrame[i];
            for(var j=0;j<subFrame.OverlayIndex.length;++j)
            {
                var overlayItem=subFrame.OverlayIndex[j];
                var overlayFrame=overlayItem.Frame;
                if (overlayFrame.IsShareY!=true) continue;
                if (!overlayFrame.MainFrame) continue;
                if (!mapFrame.has(overlayFrame.MainFrame.Identify)) continue;

                var frameItem=mapFrame.get(overlayFrame.MainFrame.Identify);
                if (!frameItem) continue;
                frameItem.OverlayFrame.push(overlayFrame);
                if (overlayFrame.IsCalculateYMaxMin===false) continue;  //叠加坐标Y轴不调整

                for(var k=0; k<overlayItem.ChartPaint.length; ++k)
                {
                    var paint=overlayItem.ChartPaint[k];
                    var range=paint.GetMaxMin();
                    if (range==null || range.Max==null || range.Min==null) continue;

                    if (frameItem.Range.Max<range.Max) frameItem.Range.Max=range.Max;
                    if (frameItem.Range.Min>range.Min) frameItem.Range.Min=range.Min;
                }
            }
        }

        for(var i=0;i<frameMaxMinData.length;++i)
        {
            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 j in item.OverlayFrame)
            {
                item.OverlayFrame[j].XYSplit=true;
            }
        }

        

        //更新独立子坐标
        for(var i=0;i<this.Frame.SubFrame.length;++i)
        {
            var subFrame=this.Frame.SubFrame[i];
            for(var j=0;j<subFrame.OverlayIndex.length;++j)
            {
                var overlayItem=subFrame.OverlayIndex[j];
                if (overlayItem.Frame.IsShareY===true) continue;
                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.GetMoveOneStepWidth=function()
    {
        if (IFrameSplitOperator.IsPlusNumber(this.StepPixel)) return this.StepPixel;
        
        var pixelRatio=GetDevicePixelRatio();
        var mainFrame=this.Frame.SubFrame[0].Frame;
        var dataWidth=mainFrame.DataWidth;
        var distanceWidth=mainFrame.DistanceWidth;
        var oneStepWidth=this.StepPixel;
        var oneStepWidth=(dataWidth+distanceWidth)/pixelRatio;
        if (oneStepWidth<1) oneStepWidth=1;

        return oneStepWidth;
    }

    this.DataMove=function(step,isLeft)
    {
        var oneStepWidth=this.GetMoveOneStepWidth();
        var moveStep=step;
        step=parseInt(step/oneStepWidth);  //除以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 (this.Frame.SubFrame && this.Frame.SubFrame.length>0 && this.Frame.SubFrame[0].Frame)
        {
            var fristFrame=this.Frame.SubFrame[0].Frame;
            if (fristFrame.DataWidth<=1 || fristFrame.DistanceWidth<=1) //K线在缩放很小的时候 移动加速
            {
                if (IFrameSplitOperator.IsPlusNumber(this.StepPixel))
                    step=moveStep*this.StepPixel;
            }
               
        }

        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;
        }
    }

    this.XCoordinateZoom=function(step, isMoveLeft)
    {
        var oneStepWidth=this.GetMoveOneStepWidth();
        var moveStep=step;
        step=parseInt(step/oneStepWidth);  //除以4个像素
        if (step<=0) return false;

        return this.Frame.XCoordinateZoom(isMoveLeft);
    }

    //获取鼠标在当前子窗口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 startClientPos=this.PtInClient(selectData.XStart, selectData.YStart);
        var endClientPos=this.PtInClient(selectData.XEnd, selectData.YEnd);
        
        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;
            case "TC":
                languageID=JSCHART_LANGUAGE_ID.LANGUAGE_TRADITIONAL_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();
    }

    this.ReloadTiltePaintResource=function(resource)  //重新加载配置
    {
        for(var i in this.TitlePaint)
        {
            var item=this.TitlePaint[i];
            if (item.ReloadResource) item.ReloadResource(resource);
        }
    }

    this.ReloadExtendChartPaintResource=function(resource)  //扩展画法重新加载配置
    {
        for(var i in this.ExtendChartPaint)
        {
            var item=this.ExtendChartPaint[i];
            if (item.ReloadResource) item.ReloadResource(resource);
        }
    }

    this.ReloadResource=function(option)
    {
        this.ReloadBorder(option);
        this.ReloadTiltePaintResource(option.Resource);
        this.ReloadChartPaint(option.Resource);
        this.ReloadFrame(option.Resource);
        this.ReloadExtendChartPaintResource(option.Resource);
        this.ReloadChartCorssCursor(option,option.Resource);

        if (option.Update && this.Update) this.Update( {UpdateCursorIndexType:2} );       //是否立即更新并重绘
        else if (option.Draw==true) this.Draw(); //是否立即重绘
    }

    this.ReloadBorder=function(option)  //根据页面缩放调整对应边框的尺长
    {
        if (!option) return;

        var pixelTatio = GetDevicePixelRatio(); //获取设备的分辨率
        if (option.Border)
        {
            var item=option.Border;
            if (IFrameSplitOperator.IsNumber(item.Left)) this.Frame.ChartBorder.Left=item.Left*pixelTatio;
            if (IFrameSplitOperator.IsNumber(item.Right)) this.Frame.ChartBorder.Right=item.Right*pixelTatio;
            if (IFrameSplitOperator.IsNumber(item.Top)) this.Frame.ChartBorder.Top=item.Top*pixelTatio;
            if (IFrameSplitOperator.IsNumber(item.Bottom)) this.Frame.ChartBorder.Bottom=item.Bottom*pixelTatio;
        }

        for(var i in option.Windows)
        {
            var item=option.Windows[i];
            if (i>=this.Frame.SubFrame.length) continue;
            var subFrame=this.Frame.SubFrame[i];
            var border=subFrame.Frame.ChartBorder;
            if (IFrameSplitOperator.IsNumber(item.TitleHeight)) border.TitleHeight=item.TitleHeight*pixelTatio;
        }

        for(var i in option.Frame)
        {
            var item=option.Frame[i];
            if (i>=this.Frame.SubFrame.length) continue;

            var subFrame=this.Frame.SubFrame[i];
            var border=subFrame.Frame.ChartBorder;
            if (item.TopSpace>=0) border.TopSpace=item.TopSpace*pixelTatio;
            if (item.BottomSpace>=0) border.BottomSpace=item.BottomSpace*pixelTatio;
        }
    }

    this.ReloadFrame=function(resource)
    {
        for(var i in this.Frame.SubFrame)
        {
            var item=this.Frame.SubFrame[i];
            var subFrame=item.Frame;
            if (subFrame && subFrame.ReloadResource) subFrame.ReloadResource(resource);
        }
    }

    this.ReloadChartPaint=function(resource)
    {
        for(var i in this.ChartPaint)
        {
            var item=this.ChartPaint[i];
            if (item && item.ReloadResource) item.ReloadResource(resource);
        }
    }

    this.ReloadChartCorssCursor=function(option, resource)
    {
        var pixelTatio = GetDevicePixelRatio(); //获取设备的分辨率
        if (option && option.CorssCursor)
        {
            var item=option.CorssCursor;
            if (IFrameSplitOperator.IsNumber(item.TitleHeight)) this.ChartCorssCursor.TextHeight=item.TitleHeight*pixelTatio;  //十字光标文本信息高度
        }

        if (this.ChartCorssCursor.ReloadResource) this.ChartCorssCursor.ReloadResource(resource);
    }

    this.SetDepthMapData=function(depthData, bDraw)
    {
        for(var i in depthData)
        {
            var item=depthData[i];
            for(var j in this.ExtendChartPaint)
            {
                var chart=this.ExtendChartPaint[j];
                if (chart.ID==item.ID)
                {
                    chart.Data=item.Data;
                    break;
                }
            }
        }

        if (bDraw) this.Draw();
    }

    //画图工具
    //把X, Y绝对位置转成的相对位置的点
    this.PointAbsoluteToRelative=function(x, y, isPhone)
    {
        var pt={ X:x, Y:y };
        var pixelTatio = GetDevicePixelRatio();             //x,y是原始坐标 需要乘以放大倍速
        var uiRect=this.UIElement.getBoundingClientRect();  //dom返回的是没有放大倍数的值

        if (isPhone)
        {
            pt.X=x-uiRect.left*pixelTatio;      //手机端 dom返回的是没有放大倍数的值
            pt.Y=y-uiRect.top*pixelTatio;
        }
        else
        {
            pt.X=(x-uiRect.left)*pixelTatio;
            pt.Y=(y-uiRect.top)*pixelTatio;
        }

        return pt;
    }

    this.SetChartDrawPictureFirstPoint=function(x,y, isPhone)
    {
        var drawPicture=this.CurrentChartDrawPicture;
        if (!drawPicture) return false;
        if (!this.Frame.SubFrame || this.Frame.SubFrame.length<=0) return false;

        //相对坐标
        var pt=this.PointAbsoluteToRelative(x, y, isPhone);
        var xFixed=pt.X;
        var yFixed=pt.Y;

        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=xFixed;
        drawPicture.Point[0].Y=yFixed;
        drawPicture.Status=1;   //第1个点完成
        return true;
    }

    this.SetChartDrawPictureSecondPoint=function(x,y,isPhone)
    {
        var drawPicture=this.CurrentChartDrawPicture;
        if (!drawPicture) return false;

        //相对坐标
        var pt=this.PointAbsoluteToRelative(x, y, isPhone);

        drawPicture.Point[1]=new Point();
        drawPicture.Point[1].X=pt.X;
        drawPicture.Point[1].Y=pt.Y;

        drawPicture.Status=2;   //设置第2个点
        return true;
    }

    //设置第3个点
    this.SetChartDrawPictureThirdPoint=function(x,y,isPhone)
    {
        var drawPicture=this.CurrentChartDrawPicture;
        if (!drawPicture) return false;

        //相对坐标
        var pt=this.PointAbsoluteToRelative(x, y, isPhone);

        drawPicture.Point[2]=new Point();
        drawPicture.Point[2].X=pt.X;
        drawPicture.Point[2].Y=pt.Y;

        drawPicture.Status=3;   //设置第3个点
        return true;
    }

    //xStep,yStep 移动的偏移量
    this.MoveChartDrawPicture=function(x,y,isPhone)
    {
        var drawPicture=this.CurrentChartDrawPicture;
        if (!drawPicture) return false;

        var pixelTatio = GetDevicePixelRatio(); //x,y 需要乘以放大倍速
        if (isPhone) pixelTatio=1;
        var xStep=x*pixelTatio;
        var yStep=y*pixelTatio;
        //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;
        if (drawPicture.ClassName=="ChartDrawRuler")    //尺子不用保存的
        {
            this.CurrentChartDrawPicture=null;
            return true;
        }

        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.OnSelectChartPicture=function(chart)
    {   
        JSConsole.Chart.Log('[JSChartContainer::OnSelectChartPicture',chart);
        if (!this.ChartPictureMenu) this.ChartPictureMenu=new ChartPictureSettingMenu(this.UIElement.parentNode);

        var event={ data: { ChartPicture:chart, HQChart:this}};
        this.ChartPictureMenu.DoModal(event);
    }

    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();
                }
            }
        }
    }

    //获取画图工具当前选中图形的Guid
    this.GetActiveDrawPicture=function()
    {
        var result={ Move: { Guid:null }, Select:{ Guid:null }, MoveOn: {Guid:null} };
        if (this.CurrentChartDrawPicture) 
            result.Move={ Guid: this.CurrentChartDrawPicture.Guid };
        if (this.SelectChartDrawPicture) 
            result.Select={ Guid:this.SelectChartDrawPicture.Guid };
        if (this.MoveOnChartDrawPicture)
            result.MoveOn={ Guid:this.MoveOnChartDrawPicture.Guid };

        return result;
    }

    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.EnableShowCorssCursorLine=function(bShow)
    {
        if (!this.ChartCorssCursor) return;

        this.ChartCorssCursor.IsShowCorss=bShow;
    }

    //获取扩展画法
    this.GetExtendChartByClassName=function(name)
    {
        for(var i=0; i<this.ExtendChartPaint.length; ++i)
        {
            var item=this.ExtendChartPaint[i];
            if (item.ClassName==name) return { Index:i, Chart:item };
        }

        return null
    }

    this.GetExtendChartRightWidth=function()  //扩展画法右边宽度
    {
        var width=0;
        for(var i=0; i<this.ExtendChartPaint.length; ++i)
        {
            var item=this.ExtendChartPaint[i];
            if (!item) continue;
            if (item.ClassName=="StockChip" || item.ClassName=="DrawToolsButton")
            {
                if (IFrameSplitOperator.IsNumber(item.Width)) 
                    width+=item.Width;
            }
        }

        return width;
    }

    //删除扩展画法
    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);
    }

    //全屏提示信息 { Title:提示信息, Draw:false/true 是否立即重绘, }
    this.EnableSplashScreen=function(option)
    {
        if (!this.ChartSplashPaint) return;
        if (!option) return;

        if (IFrameSplitOperator.IsString(option.Title)) this.ChartSplashPaint.SetTitle(option.Title);
        this.ChartSplashPaint.EnableSplash(true);

        if (option.Draw===false) return;
        this.Draw();
    }

    this.SetSubFrameOption=function(subFrame, option)
    {
        if (!option) return;

        if (option.Window)
        {
            var item=option.Window;
            if (item.Modify!=null) subFrame.Frame.ModifyIndex=item.Modify;
            if (item.Change!=null) subFrame.Frame.ChangeIndex=item.Change;
            if (item.Close!=null) subFrame.Frame.CloseIndex=item.Close;
            if (item.Overlay!=null) subFrame.Frame.OverlayIndex=item.Overlay;
            if (item.IsDrawTitleBG==true)  subFrame.Frame.IsDrawTitleBG=item.IsDrawTitleBG;

            if (item.OverlayIndexType)
            {
                if (IFrameSplitOperator.IsNumber(item.OverlayIndexType.Position)) subFrame.Frame.OverlayIndexType.Position=item.OverlayIndexType.Position;
                if (IFrameSplitOperator.IsNumber(item.OverlayIndexType.LineSpace)) subFrame.Frame.OverlayIndexType.LineSpace=item.OverlayIndexType.LineSpace;
            }
        }

        if (IFrameSplitOperator.IsNumber(option.SplitCount)) subFrame.Frame.YSplitOperator.SplitCount=option.SplitCount;
        if (IFrameSplitOperator.IsNumber(option.TitleHeight)) subFrame.Frame.ChartBorder.TitleHeight=option.TitleHeight;
        if (IFrameSplitOperator.IsBool(option.IsShowTitleArraw)) subFrame.Frame.IsShowTitleArraw=option.IsShowTitleArraw;
        if (IFrameSplitOperator.IsBool(option.IsShowIndexName)) subFrame.Frame.IsShowIndexName=option.IsShowIndexName;
        if (IFrameSplitOperator.IsBool(option.IsShowOverlayIndexName)) subFrame.Frame.IsShowOverlayIndexName=option.IsShowOverlayIndexName;
        if (IFrameSplitOperator.IsNumber(option.IndexParamSpace)) subFrame.Frame.IndexParamSpace=option.IndexParamSpace;
        if (IFrameSplitOperator.IsBool(option.IsShowXLine)) subFrame.Frame.IsShowXLine=option.IsShowXLine;
        if (IFrameSplitOperator.IsBool(option.IsShowYLine)) subFrame.Frame.IsShowYLine=option.IsShowYLine;
        if (IFrameSplitOperator.IsBool(option.IsShowIndexTitle)) subFrame.Frame.IsShowIndexTitle=option.IsShowIndexTitle;

        if (IFrameSplitOperator.IsBool(option.IsShowLeftText)) 
        {
            subFrame.Frame.IsShowYText[0]=option.IsShowLeftText;
            subFrame.Frame.YSplitOperator.IsShowLeftText=option.IsShowLeftText;            //显示左边刻度
        }
        if (IFrameSplitOperator.IsBool(option.IsShowRightText)) 
        {
            subFrame.Frame.IsShowYText[1]=option.IsShowRightText;
            subFrame.Frame.YSplitOperator.IsShowRightText=option.IsShowRightText;         //显示右边刻度
        }

    }

    this.AddNewSubFrame=function(option)
    {
        var index=this.Frame.SubFrame.length;
        var subFrame=this.CreateSubFrameItem(index);
        var pixelRatio=GetDevicePixelRatio();
        subFrame.Frame.ChartBorder.TitleHeight*=pixelRatio;
        this.Frame.SubFrame[index]=subFrame;
        var titlePaint=new DynamicChartTitlePainting();
        titlePaint.Frame=this.Frame.SubFrame[index].Frame;
        titlePaint.Canvas=this.Canvas;
        titlePaint.LanguageID=this.LanguageID;
        titlePaint.GetEventCallback=(id)=> { return this.GetEventCallback(id); }
        this.TitlePaint[index+1]=titlePaint;

        this.SetSubFrameOption(subFrame,option);

        //最后一个显示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);
        if (this.UpdateXShowText) this.UpdateXShowText();
        this.ResetFrameXYSplit();
        this.UpdateFrameMaxMin();          //调整坐标最大 最小值
        this.Draw();

        return index;
    }

    //增加一个指标窗口
    this.AddIndexWindow=function(indexName,option)
    {
        //查找系统指标
        let scriptData = new JSIndexScript();
        let indexInfo = scriptData.Get(indexName);
        if (!indexInfo) return;

        this.RemoveMinSizeWindows();    //清空隐藏的指标
        var index=this.AddNewSubFrame(option);

        var 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,
            OutName:indexInfo.OutName
        };

        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;
        }

        this.WindowIndex[index] = new ScriptIndex(indexData.Name, indexData.Script, indexData.Args,indexData);    //脚本执行
        if (this.ClassName=="MinuteChartContainer" || this.ClassName=="MinuteChartHScreenContainer")
            var bindData=this.SourceData;
        else 
            var bindData=this.ChartPaint[0].Data;

        this.BindIndexData(index,bindData);     //执行脚本
    }

    //增加一个自定义指标窗口
    this.AddScriptIndexWindow=function(indexInfo, option)
    {
        if (!indexInfo || !indexInfo.Script || !indexInfo.Name) return;

        this.RemoveMinSizeWindows();    //清空隐藏的指标
        var index=this.AddNewSubFrame(option);

        var indexData = 
        { 
            Name:indexInfo.Name, Script:indexInfo.Script, Args: indexInfo.Args, ID:indexInfo.Name ,
            //扩展属性 可以是空
            KLineType:indexInfo.KLineType,  YSpecificMaxMin:indexInfo.YSpecificMaxMin,  YSplitScale:indexInfo.YSplitScale,
            FloatPrecision:indexInfo.FloatPrecision, Condition:indexInfo.Condition,StringFormat:indexInfo.StringFormat,
            OutName:indexInfo.OutName
        };

        if (indexInfo.ID) indexData.ID=indexInfo.ID;

        this.WindowIndex[index] = new ScriptIndex(indexData.Name, indexData.Script, indexData.Args,indexData);    //脚本执行
        if (this.ClassName=="MinuteChartContainer" || this.ClassName=="MinuteChartHScreenContainer")
            var bindData=this.SourceData;
        else 
            var bindData=this.ChartPaint[0].Data;

        this.BindIndexData(index,bindData);     //执行脚本
    }

    //区间选择
    this.GetRectSelectPaint=function()
    {
        for(var i=0;i<this.ExtendChartPaint.length;++i)
        {
            var item=this.ExtendChartPaint[i];
            if (item.ClassName=="RectSelectPaint")
                return item;
        }

        return null;
    }

    this.SetRectSelectData=function(kItem)
    {
        var paint=this.GetRectSelectPaint();
        if (!paint) return false;

        if (paint.GetPointCount()==2) return false;

        return paint.SetPoint(kItem);
    }

    this.MoveRectSelectPoint=function(obj)
    {
        var paint=this.GetRectSelectPaint();
        if (!paint) return false;

        if (!this.ChartPaint[0] || !this.ChartPaint[0].Data) return false;
        var kData=this.ChartPaint[0].Data;

        if (!this.Frame.SubFrame[0]) return false;
        var subFrame=this.Frame.SubFrame[0].Frame;
        if (!subFrame) false;

        var pixelTatio = GetDevicePixelRatio();
        var x=(obj.X-uielement.getBoundingClientRect().left)*pixelTatio;
        var index=subFrame.GetXData(x);
        index=parseInt(index.toFixed(0));
        var dataIndex=index+kData.DataOffset;
        if (dataIndex>=kData.Data.length) dataIndex=kData.Data.length-1;

        var item = kData.Data[dataIndex];
        JSConsole.Chart.Log("[KLineChartContainer::MoveRectSelectPoint] point, item", obj.PointIndex, item);

        if (!paint.SetPoint(item,{ Index: obj.PointIndex })) return false;

        var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_DRAG_SELECT_RECT);
        if (event)
        {
            var selectData=paint.GetSelectRectData();
            var data={ X:obj.X, Y:obj.Y, SelectData:selectData, RectSelectPaint:paint };
            event.Callback(event,data,this);
        }

        return true;
    }

    this.ClearRectSelect=function(bEnforce)
    {
        var paint=this.GetRectSelectPaint();
        if (!paint) return false;
        if (bEnforce) paint.PreventClose=false;
        return paint.ClearPoint();
    }

    //删除叠加指标, 没有重回
    this.DeleteOverlayIndex=function(identify, windowIndex)
    {
        var findIndex=null;
        if (IFrameSplitOperator.IsNumber(windowIndex))
        {
            if (windowIndex>=0 && windowIndex<this.Frame.SubFrame.length)
            {
                var item=this.Frame.SubFrame[windowIndex];
                for(var j=0; j<item.OverlayIndex.length; ++j)
                {
                    var overlayItem=item.OverlayIndex[j];
                    if (overlayItem.Identify===identify)
                    {
                        item.OverlayIndex.splice(j, 1);
                        findIndex=windowIndex
                        break;
                    }
                }
            }
        }
        else
        {
            for(var i=0; i<this.Frame.SubFrame.length; ++i)
            {
                var item=this.Frame.SubFrame[i];
                for(var j=0; j<item.OverlayIndex.length; ++j)
                {
                    var overlayItem=item.OverlayIndex[j];
                    if (overlayItem.Identify===identify)
                    {
                        item.OverlayIndex.splice(j, 1);
                        findIndex=i;
                        break;
                    }
                }
            }
        }

        if (findIndex==null) 
        {
            console.warn(`[JSChartContainer::DeleteOverlayIndex] can't find overlay index. [identify=${identify}]`);
            return false;
        }

        var windowsIndex=findIndex+1;
        var titlePaint=this.TitlePaint[windowsIndex];
        if (titlePaint.OverlayIndex.has(identify))
            titlePaint.OverlayIndex.delete(identify);

        if (titlePaint.OverlayDynamicTitle.has(identify))
            titlePaint.OverlayDynamicTitle.delete(identify);

        return true;
    }

    //移动叠加指标  src={ WindowIndex:指标窗口索引，IndexID:指标ID } dest={ WindowIndex:指标窗口索引 } , option={ Operator: 0=移动, 1=复制 }
    this.MoveOverlayIndex=function(src, dest, option)
    {
        if (!src || !dest || !option) return false;
        if ( !IFrameSplitOperator.IsNumber(src.WindowIndex) || src.WindowIndex<0 || src.WindowIndex>=this.Frame.SubFrame.length ) return false;
        if ( !IFrameSplitOperator.IsNumber(dest.WindowIndex) || dest.WindowIndex<0 || dest.WindowIndex>=this.Frame.SubFrame.length ) return false;
            
        var item=this.Frame.SubFrame[src.WindowIndex];
        var findOverlayItem=null;
        for(var i=0; i<item.OverlayIndex.length; ++i)
        {
            var overlayItem=item.OverlayIndex[i];
            if (overlayItem.Identify===src.IndexID)
            {
                findOverlayItem=overlayItem;
                break;
            }
        }

        if (!findOverlayItem) return false;

        var subFrame=this.Frame.SubFrame[dest.WindowIndex];
        subFrame.Interval=this.OverlayIndexFrameWidth;
        var overlayFrame=new OverlayIndexItem();
        var frame=this.CreateOverlayFrame();
        frame.Canvas=this.Canvas;
        frame.MainFrame=subFrame.Frame;
        frame.ChartBorder=subFrame.Frame.ChartBorder;
        frame.IsShow=findOverlayItem.Frame.IsShow;
        //if (obj.IsShareY===true) frame.IsShareY=true;   
        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;
        var scriptIndex=this.CloneOverlayScript(findOverlayItem.Script);
        scriptIndex.OverlayIndex={ IsOverlay:true, Identify:overlayFrame.Identify, WindowIndex:dest.WindowIndex, Frame:overlayFrame };    //叠加指标信息
        overlayFrame.Script=scriptIndex;
        subFrame.OverlayIndex.push(overlayFrame);

        if (option.Operator==0) //移动模式, 删除原来的
        {
            this.DeleteOverlayIndex(findOverlayItem.Identify, src.WindowIndex);
        }

        var bindData=this.GetMainData();
        this.BindOverlayIndexData(overlayFrame,dest.WindowIndex,bindData);
        this.UpdataDataoffset();           //更新数据偏移
        this.UpdateFrameMaxMin();          //调整坐标最大 最小值
        this.Draw();
    }

    //移动叠加指标到新的指标窗口 src={ WindowIndex:指标窗口索引，IndexID:指标ID } , option={ Operator: 0=移动, 1=复制 }
    this.MoveOverlayIndexToNewWindow=function(src, option)
    {
        if (!src || !option) return false;
        if ( !IFrameSplitOperator.IsNumber(src.WindowIndex) || src.WindowIndex<0 || src.WindowIndex>=this.Frame.SubFrame.length ) return false;

        var item=this.Frame.SubFrame[src.WindowIndex];
        var findOverlayItem=null;
        for(var i=0; i<item.OverlayIndex.length; ++i)
        {
            var overlayItem=item.OverlayIndex[i];
            if (overlayItem.Identify===src.IndexID)
            {
                findOverlayItem=overlayItem;
                break;
            }
        }

        if (!findOverlayItem) return false;

        this.RemoveMinSizeWindows();    //清空隐藏的指标

        var index=this.Frame.SubFrame.length;
        var subFrame=this.CreateSubFrameItem(index);
        var pixelRatio=GetDevicePixelRatio();
        subFrame.Frame.ChartBorder.TitleHeight*=pixelRatio;
        this.Frame.SubFrame[index]=subFrame;
        var titlePaint=new DynamicChartTitlePainting();
        titlePaint.Frame=this.Frame.SubFrame[index].Frame;
        titlePaint.Canvas=this.Canvas;
        titlePaint.LanguageID=this.LanguageID;
        titlePaint.GetEventCallback=(id)=> { return this.GetEventCallback(id); }
        this.TitlePaint[index+1]=titlePaint;

        this.SetSubFrameOption(subFrame, option);

        //最后一个显示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;
        }

        if (option.Operator==0) //移动模式, 删除原来的
        {
            this.DeleteOverlayIndex(findOverlayItem.Identify, src.WindowIndex);
        }

        this.UpdataDataoffset();        //更新数据偏移  
        this.Frame.SetSizeChage(true);
        if (this.UpdateXShowText) this.UpdateXShowText();
        this.ResetFrameXYSplit();
        this.UpdateFrameMaxMin();          //调整坐标最大 最小值
        this.Draw();

        this.WindowIndex[index] = this.CloneScript(findOverlayItem.Script);    
        var bindData=this.GetMainData();

        this.BindIndexData(index,bindData);     //执行脚本
    }

    this.GetMainData=function()
    {
        switch(this.ClassName)
        {
            case "MinuteChartContainer":
            case "MinuteChartHScreenContainer":
                return this.SourceData;
            case "KLineChartContainer":
            case "KLineChartHScreenContainer":
                return this.ChartPaint[0].Data;
        }
    }

    this.CreateOverlayFrame=function()
    {
        switch(this.ClassName)
        {
            case "KLineChartContainer":
                return new OverlayKLineFrame();
            case "KLineChartHScreenContainer":
                return new OverlayKLineHScreenFrame();
            case "MinuteChartContainer":
                return new OverlayMinuteFrame();
            case "MinuteChartHScreenContainer":
                return new OverlayMinuteHScreenFrame();
        }
    }

    this.CloneScript=function(src)
    {
        var scriptIndex=null;
        switch(src.ClassName)
        {
            case "ScriptIndex":
            case "OverlayScriptIndex":
                scriptIndex=new ScriptIndex();
                break;
            case "APIScriptIndex":
                scriptIndex=new APIScriptIndex();
                break;
        }

        src.CopyTo(scriptIndex);

        return scriptIndex;
    }

    this.CloneOverlayScript=function(src)
    {
        var scriptIndex=null;
        switch(src.ClassName)
        {
            case "ScriptIndex":
                scriptIndex=new ScriptIndex();
                break;
            case "APIScriptIndex":
                scriptIndex=new APIScriptIndex();
                break;
            case "OverlayScriptIndex":
                scriptIndex=new OverlayScriptIndex();
                break;
        }

        src.CopyTo(scriptIndex);

        return scriptIndex;
    }
}

function GetDevicePixelRatio()
{
    if (typeof(window) =='undefined') return 1;
    return window.devicePixelRatio || 1;
}

function GetFontHeight(context, font, word)
{
    if (!context) return null;

    if (font) context.font=font;

    var text='擎';
    if (IFrameSplitOperator.IsString(word)) text=word;

    var fontInfo=context.measureText(text);
    var textHeight=fontInfo.fontBoundingBoxAscent + fontInfo.fontBoundingBoxDescent;
    if (!IFrameSplitOperator.IsNumber(textHeight)) textHeight=fontInfo.width+2*GetDevicePixelRatio();

    return textHeight;
}

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 "guid" + (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 ToFixedPoint2(width, value)
{
    var fixValue=(width % 2)===0 ? Math.floor(value):Math.floor(value) + 0.5;    //毛边修正
    return fixValue;
}

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.
    //value*=GetDevicePixelRatio();
    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.YStart;
    this.XEnd;  //X位置结束为止
    this.YEnd;
}

//坐标信息
function CoordinateInfo()
{
    this.Value;                                                 //坐标数据
    this.Message=[];                                            //坐标输出文字信息 0=左 1=右 2=内左 3=内右
    this.TextColor=g_JSChartResource.FrameSplitTextColor        //文字颜色
    this.Font=g_JSChartResource.FrameSplitTextFont;             //字体
    this.LineColor=g_JSChartResource.FrameSplitPen;             //线段颜色
    this.LineType=1;                                            //线段类型 -1 不画线段 2 虚线 8,9=集合竞价坐标
    this.ExtendData;                                            //扩展属性
                                                                //百分比 { PriceColor:, PercentageColor:, SplitColor:, Font: }
}


//边框信息
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.LeftExtendWidth=0;      //左边扩展图形宽度
    this.RightExtendWidth=0;

    this.MultiDayMinute={ Count:1, Left:0, Right:0 }  // { Count:天数, Left:, Right: }

    this.GetBorder=function()
    {
        var data=
        { 
            Left:this.Left, 
            LeftEx:this.Left+this.LeftExtendWidth,
            Right:this.UIElement.width-this.Right,
            RightEx:this.UIElement.width-this.Right-this.RightExtendWidth,

            Top:this.Top,
            TopEx:this.Top+this.TitleHeight+this.TopSpace,
            TopTitle:this.Top+this.TitleHeight,
            Bottom:this.UIElement.height-this.Bottom,
            BottomEx:this.UIElement.height-this.Bottom-this.BottomSpace,

            ChartWidth:this.UIElement.width,
            ChartHeight:this.UIElement.height
        };

        if (this.MultiDayMinute && this.MultiDayMinute.Count>1 && ( this.MultiDayMinute.Left>0 || this.MultiDayMinute.Right>0 ))
        {
            var frameWidth=this.UIElement.width-this.Left-this.Right;   //坐标框子宽度
            var dayWidth=frameWidth/this.MultiDayMinute.Count;   // 每天的框子的宽度

            var dayBorder=[];
            for(var i=0;i<this.MultiDayMinute.Count;++i)
            {
                var item={ Left:this.Left+dayWidth*i, Right:this.Left+dayWidth*(i+1) };
                item.LeftEx=item.Left+this.MultiDayMinute.Left;
                item.RightEx=item.Right-this.MultiDayMinute.Right;
                dayBorder.push(item);
            }

            data.DayBorder=dayBorder;
        }

        return data;
    }

    this.GetHScreenBorder=function()
    {
        var data=
        {
            Left:this.Left,
            LeftEx:this.Left+this.BottomSpace,

            Right:this.UIElement.width-this.Right,
            RightEx:this.UIElement.width-this.Right-this.TitleHeight- this.TopSpace,
            RightTitle:this.UIElement.width-this.Right-this.TitleHeight,

            Top:this.Top,
            TopEx:this.Top+this.LeftExtendWidth,
            Bottom:this.UIElement.height-this.Bottom,
            BottomEx:this.UIElement.height-this.Bottom-this.RightExtendWidth,

            ChartWidth:this.UIElement.width,
            ChartHeight:this.UIElement.height
        };

        return data;
    }

    //1=在K线上 -1不在图上 [200-299]=集合竞价 [300-399]=集合竞价 2=左边集合竞价 3=右边集合竞价
    this.PtInClient=function(x, y, canvas, isHScreen)
    {
        if (isHScreen)
        {
            var border=this.GetHScreenBorder();
            canvas.rect(border.Left,border.TopEx,border.Right-border.Left,border.BottomEx-border.TopEx);
        }
        else
        {
            var border=this.GetBorder();
            if (border.DayBorder)   //多日分时+多日集合竞价
            {
                for(var i=0;i<border.DayBorder.length;++i)
                {
                    var client=border.DayBorder[i];
                    canvas.beginPath();
                    canvas.rect(client.LeftEx,border.TopEx,client.RightEx-client.LeftEx,border.BottomEx-border.TopEx);
                    if (canvas.isPointInPath(x,y)) return 1;

                    //盘前
                    canvas.beginPath();
                    canvas.rect(client.Left,border.TopEx,client.LeftEx-client.Left,border.BottomEx-border.TopEx);
                    if (canvas.isPointInPath(x,y)) 
                        return 200+parseInt(i);

                    //盘后
                    canvas.beginPath();
                    canvas.rect(client.RightEx,border.TopEx,client.Right-client.RightEx,border.BottomEx-border.TopEx);
                    if (canvas.isPointInPath(x,y)) 
                        return 300+parseInt(i);
                }

                return -1;
            }

            canvas.rect(border.LeftEx,border.Top,border.RightEx-border.LeftEx,border.Bottom-border.Top);
        }

        if (canvas.isPointInPath(x,y)) return 1;

        if (this.LeftExtendWidth>10)
        {
            canvas.beginPath();
            if (isHScreen===true)
            {
                canvas.rect(border.Left,border.Top,border.Right-border.Left,border.TopEx-border.Top);
            }
            else
            {
                canvas.rect(border.Left,border.Top,border.LeftEx-border.Left,border.Bottom-border.Top);
            }
    
            if (canvas.isPointInPath(x,y)) return 2;
        }

        if (this.RightExtendWidth>10)
        {
            canvas.beginPath();
            if (isHScreen===true)
            {
                canvas.rect(border.Left,border.BottomEx,border.Right-border.Left,border.Bottom-border.BottomEx);
            }
            else
            {
                canvas.rect(border.RightEx,border.Top,border.Right-border.RightEx,border.Bottom-border.Top);
            }
    
            if (canvas.isPointInPath(x,y)) return 3;
        }

        return -1;
    }

    this.GetChartWidth=function()
    {
        return this.UIElement.width;
    }

    this.GetChartHeight=function()
    {
        return this.UIElement.height;
    }

    this.GetLeft=function()
    {
        return this.Left+this.LeftExtendWidth;
    }

    this.GetRight=function()
    {
        return this.UIElement.width-this.Right-this.RightExtendWidth;
    }

    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.LeftExtendWidth-this.RightExtendWidth;
    }

    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.ClassName='IChartFramePainting';

    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.IsShowTitleArraw=true;        //是否显示指标信息上涨下跌箭头
    this.IsShowIndexName=true;         //是否显示指标名字
    this.IsShowOverlayIndexName=true;  //是否显示叠加指标名字
    this.OverlayIndexType= { Position:0, LineSpace:5 };
    this.IndexParamSpace=2;            //指标参数数值显示间距
    this.IndexTitleSpace=0;            //指标标题和参数值之间的间距
    this.IsShowIndexTitle=true;        //显示整个指标标题信息
    this.IsDrawTitleBottomLine=false;

    this.BorderLine=null;               //1=上 2=下 4=左 8=右
    this.Buttons=[];                    //按钮事件 

    this.IsMinSize=false;               //窗口是否最小化


    this.PtInButtons=function(x,y) //坐标是否在按钮上
    {
        for(var i=0;i<this.Buttons.length;++i)
        {
            var item=this.Buttons[i];
            if (!item.Rect) continue;

            var rect=item.Rect;
            this.Canvas.beginPath();
            this.Canvas.rect(rect.Left,rect.Top,rect.Width,rect.Height);
            if (this.Canvas.isPointInPath(x,y))
            {
                return { ID:item.ID, Rect:rect };
            }

        }

        return null;
    }

    this.GetBorder=function()
    {
        if (this.IsHScreen) return this.ChartBorder.GetHScreenBorder();
        else return this.ChartBorder.GetBorder();
    }

    this.Draw=function()
    {
        this.Buttons=[];
        this.DrawFrame();
        this.DrawBorder();

        this.SizeChange=false;
        this.XYSplit=false;
    }

    this.DrawFrame=function() { }

    this.ClearCoordinateText=function(option)
    {
        if (IFrameSplitOperator.IsNonEmptyArray(this.HorizontalInfo))
        {
            for(var i=0;i<this.HorizontalInfo.length;++i)
            {
                var item=this.HorizontalInfo[i];
                if (item && item.Message && Array.isArray(item.Message)) item.Message[0]=item.Message[1]=null;
            }
        }

        if (IFrameSplitOperator.IsNonEmptyArray(this.VerticalInfo))
        {
            for(var i=0;i<this.VerticalInfo.length;++i)
            {
                var item=this.VerticalInfo[i];
                if (item && item.Message && Array.isArray(item.Message)) item.Message[0]=item.Message[1]=null;
            }
        }
    }

    //画边框
    this.DrawBorder=function()
    {
        if (!this.IsShowBorder) return;
        if (this.IsMinSize) return;

        var border=this.IsHScreen==true?this.ChartBorder.GetHScreenBorder():this.ChartBorder.GetBorder();

        var left=ToFixedPoint(border.Left);
        var top=ToFixedPoint(border.Top);
        var right=ToFixedPoint(border.Right);
        var bottom=ToFixedPoint(border.Bottom);
        var width=right-left;
        var height=bottom-top;

        //JSConsole.Chart.Log('[IChartFramePainting.DrawBorder] bottom',bottom);
        if (this.BorderLine==null)
        {
            this.Canvas.strokeStyle=this.PenBorder;
            this.Canvas.strokeRect(left,top,width,height);
        }
        else if (IFrameSplitOperator.IsPlusNumber(this.BorderLine)) //单独绘制每个边框
        {
            this.Canvas.strokeStyle=this.PenBorder;
            this.Canvas.beginPath();

            if ((this.BorderLine&1)>0) //上
            {
                this.Canvas.moveTo(left,top);
                this.Canvas.lineTo(right,top);
            }

            if ((this.BorderLine&2)>0)  //下
            {
                this.Canvas.moveTo(left,bottom);
                this.Canvas.lineTo(right,bottom);
            }

            if ((this.BorderLine&4)>0)  //左
            {
                this.Canvas.moveTo(left,top);
                this.Canvas.lineTo(left,bottom);
            }

            if ((this.BorderLine&8)>0)    //右
            {
                this.Canvas.moveTo(right,top);
                this.Canvas.lineTo(right,bottom);
            }
              
            this.Canvas.stroke();
        }

        
    }

    //画标题背景色
    this.DrawTitleBG=function()
    {
        if (this.ChartBorder.TitleHeight<=0) return;

        var border=this.GetBorder();

        var left=ToFixedPoint(border.Left);
        var top=ToFixedPoint(border.Top);
        var right=ToFixedPoint(border.Right);
        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);

        if (this.IsDrawTitleBottomLine)
        {
            this.Canvas.strokeStyle=this.PenBorder;
            this.Canvas.beginPath();
            this.Canvas.moveTo(left,ToFixedPoint(border.TopTitle));
            this.Canvas.lineTo(right,ToFixedPoint(border.TopTitle));
            this.Canvas.stroke();
        }
    }

    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;
    }

    this.ReloadResource=function(resource)
    {
        if (!resource)
        {
            this.PenBorder=g_JSChartResource.FrameBorderPen;        //边框颜色
            this.TitleBGColor=g_JSChartResource.FrameTitleBGColor;  //标题背景色
        }

        for(var i in this.HorizontalInfo)
        {
            var item=this.HorizontalInfo[i];
            if (item.Font) item.Font=g_JSChartResource.FrameSplitTextFont;             //字体
            if (item.TextColor) item.TextColor=g_JSChartResource.FrameSplitTextColor        //文字颜色
            if (item.LineColor) item.LineColor=g_JSChartResource.FrameSplitPen;             //线段颜色
        }

        for(var i in this.VerticalInfo)
        {
            var item=this.VerticalInfo[i];
            if (item.Font) item.Font=g_JSChartResource.FrameSplitTextFont;             //字体
            if (item.TextColor) item.TextColor=g_JSChartResource.FrameSplitTextColor        //文字颜色
            if (item.LineColor) item.LineColor=g_JSChartResource.FrameSplitPen;             //线段颜色
        }
    }

    this.GetFontHeight=function(font)
    {
        return GetFontHeight(this.Canvas, font, "擎");
    }

    //左右刻度文字宽度
    this.GetScaleTextWidth=function()
    {

    }
}

//空框架只画边框
function NoneFrame()
{
    this.newMethod=IChartFramePainting;   //派生
    this.newMethod();
    delete this.newMethod;

    this.ClassName="NoneFrame";

    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.ClassName="AverageWidthFrame";
    this.DataWidth=50*GetDevicePixelRatio();
    this.DistanceWidth=10*GetDevicePixelRatio();
    this.MinXDistance = 30*GetDevicePixelRatio();       //X轴刻度最小间距
    this.MinYDistance=12*GetDevicePixelRatio();         //Y轴刻度最小间距
    this.CoordinateType=0;  //坐标类型 0=普通坐标 1=反转坐标
    this.IsShowYText=[true,true];       //是否显示Y轴坐标坐标 [0=左侧] [1=右侧]
    this.XBottomOffset=g_JSChartResource.Frame.XBottomOffset;   //X轴文字显示向下偏移
    this.YTextTopOffset=g_JSChartResource.Frame.YTopOffset;         //Y轴顶部文字向下偏移
    this.YTextPosition=[0,0],       //是坐标否强制画在内部 [0=左侧] [1=右侧] 1=OUT" , 2=INSIDE
    this.YTextPadding=[g_JSChartResource.Frame.YTextPadding[0], g_JSChartResource.Frame.YTextPadding[1]],        //Y轴文字和边框间距 [0=左侧] [1=右侧]
    this.IsShowXLine=true;              //是否显示X轴刻度线
    this.IsShowYLine=true;
    this.YInsideOffset=0;
    this.YTextBaseline=0;       //0=居中 1=上部 (目前就支持内部刻度)
    this.MultiTextFormat=0;    //多行刻度信息显示模式 0=显示第1行 1=价格/百分比 2=显示2行
    this.RightTextMaxWidth=0;

    this.ShortYLineLength=5;
    this.ShortXLineLength=5;
    this.DrawDepthMapCallback;      //绘制深度图

    //画图工具刻度
    
    this.DrawPicture={ 
        BGColor:g_JSChartResource.DrawPicture.XYCoordinate.BGColor, 
        TextBGColor:g_JSChartResource.DrawPicture.XYCoordinate.TextBGColor, 
        TextColor:g_JSChartResource.DrawPicture.XYCoordinate.TextColor, Font:g_JSChartResource.DrawPicture.XYCoordinate.Font };

    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 (this.Logarithmic && this.GetYLogarithmicFromData)
        {
            return this.GetYLogarithmicFromData(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()
    {
        this.RightTextMaxWidth=0;
        if (!IFrameSplitOperator.IsNonEmptyArray(this.HorizontalInfo)) return;

        var border=this.ChartBorder.GetBorder();
        var left=border.Left;
        var right=border.Right
        var bottom = border.Bottom
        var top = this.ChartBorder.GetTopTitle();
        var borderRight=this.ChartBorder.Right;
        var borderLeft=this.ChartBorder.Left;

        var isDrawLeft=borderLeft>10 && this.IsShowYText[0]===true && this.YTextPosition[0]!=2;
        var isDrawRight=borderRight>10 && this.IsShowYText[1]===true && this.YTextPosition[1]!=2;

        var yPrev=null; //上一个坐标y的值
        var pixelRatio=GetDevicePixelRatio();
        var itemHeight=(border.BottomEx-border.TopEx)/this.HorizontalInfo.length;
        var aryMultiText=[];
        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;  //两个坐标在近了 就不画了
            
            var yFixed=ToFixedPoint(y);
            if (y!=bottom && this.IsShowYLine)
            {
                this.Canvas.strokeStyle=item.LineColor;
                if (item.LineType==2)
                {
                    this.Canvas.save();
                    this.Canvas.setLineDash([5*pixelRatio,5*pixelRatio]);   //虚线
                    this.Canvas.beginPath();
                    this.Canvas.moveTo(left,yFixed);
                    this.Canvas.lineTo(right,yFixed);
                    this.Canvas.stroke();
                    this.Canvas.restore();
                }
                else if (item.LineType==3)  //只在刻度边上画一个短横线
                {

                }
                else if (item.LineType==8 || item.LineType==9)  //集合竞价不画线
                {

                }
                else if (item.LineType>0)
                {
                    if (g_JSChartResource.FrameYLineDash)
                    {
                        this.Canvas.setLineDash(g_JSChartResource.FrameYLineDash);   //虚线
                        this.Canvas.beginPath();
                        this.Canvas.moveTo(left,yFixed);
                        this.Canvas.lineTo(right,yFixed);
                        this.Canvas.stroke();
                        this.Canvas.setLineDash([]);
                    }
                    else
                    {
                        this.Canvas.beginPath();
                        this.Canvas.moveTo(left,yFixed);
                        this.Canvas.lineTo(right,yFixed);
                        this.Canvas.stroke();
                    }
                }
            }
            
            var yText=y;
            if (y >= bottom - 2) 
            {
                this.Canvas.textBaseline = 'bottom';
            }
            else if (y <= top + 2) 
            {
                this.Canvas.textBaseline = 'top';
                yText+=this.YTextTopOffset;
            }
            else 
            {
                this.Canvas.textBaseline = "middle";
            }

            //坐标信息 左边 间距小于10 不画坐标
            this.Canvas.strokeStyle=item.TextColor;
            this.Canvas.fillStyle=item.TextColor;

            if (item.Message[0]!=null && isDrawLeft)
            {
                if (item.Font!=null) this.Canvas.font=item.Font;

                this.Canvas.textAlign="right";
                this.Canvas.fillText(item.Message[0],left-this.YTextPadding[0],yText);
            }

            //坐标信息 右边 间距小于10 不画坐标
            if (item.Message[1]!=null && isDrawRight)
            {
                if (item.Font!=null) this.Canvas.font=item.Font;

                var xText=right;
                if (item.LineType==3)
                {
                    var lineLength=this.ShortYLineLength*GetDevicePixelRatio();
                    this.Canvas.beginPath();
                    this.Canvas.moveTo(xText,yFixed);
                    this.Canvas.lineTo(xText+lineLength,yFixed);
                    this.Canvas.stroke();

                    xText+=lineLength;
                }

                this.Canvas.textAlign="left";
                if (Array.isArray(item.Message[1]))
                {
                    if (this.MultiTextFormat==1)    //显示1行 格式:价格/百分比
                    {
                        if (item.ExtendData)
                        {
                            if (item.ExtendData.Font) this.Canvas.font=item.ExtendData.Font;
                        }
                            
                        var textData=
                        { 
                            Text:
                            [ 
                                {Text:item.Message[1][0], Width:this.Canvas.measureText(item.Message[1][0]).width },
                                {Text:item.Message[1][1], Width:this.Canvas.measureText(item.Message[1][1]).width } 
                            ],
                            X:xText+2,
                            Y:yText,
                            TextBaseline:this.Canvas.textBaseline,
                            Item:item
                        }
                        aryMultiText.push(textData);
                    }
                    else if (this.MultiTextFormat==2)   //显示2行
                    {
                        this.Canvas.fillText(item.Message[1][0],xText+this.YTextPadding[1],yText);
                        var lineHeight=this.Canvas.measureText('M').width;
                        if (itemHeight>lineHeight*2) this.Canvas.fillText(item.Message[1][1],xText+this.YTextPadding[1],yText+lineHeight);
                    }
                    else    //显示第1行
                    {
                        this.Canvas.fillText(item.Message[1][0],xText+this.YTextPadding[1],yText);
                    }
                }
                else
                {
                    this.Canvas.fillText(item.Message[1],xText+this.YTextPadding[1],yText);
                }
                
            }

            yPrev=y;
        }

        if (IFrameSplitOperator.IsNonEmptyArray(aryMultiText) && this.MultiTextFormat==1) this.DrawHorizontalMuText(aryMultiText)
    }

    this.DrawHorizontalMuText=function(aryText)
    {
        var maxWidth=[null,null];
        for(var i=0;i<aryText.length;++i)
        {
            var item=aryText[i];
            var width=item.Text[0].Width;
            if (!IFrameSplitOperator.IsNumber(maxWidth[0])) maxWidth[0]=width;
            else if (maxWidth[0]<width) maxWidth[0]=width;

            width=item.Text[1].Width;
            if (!IFrameSplitOperator.IsNumber(maxWidth[1])) maxWidth[1]=width;
            else if (maxWidth[1]<width) maxWidth[1]=width;
        }

        for(var i=0;i<aryText.length;++i)
        {
            var item=aryText[i];
            var message=item.Item;

            this.Canvas.textBaseline=message.TextBaseline;
            if (message.ExtendData && message.ExtendData.Font) this.Canvas.font=message.ExtendData.Font;
            else if (message.Font) this.Canvas.font=message.Font;

            if (message.ExtendData && message.ExtendData.PriceColor) this.Canvas.fillStyle=message.ExtendData.PriceColor;
            else this.Canvas.fillStyle=message.TextColor;

            this.Canvas.textAlign="right";
            var x=item.X+maxWidth[1];
            this.Canvas.fillText(item.Text[1].Text,x,item.Y);

            if (message.ExtendData && message.ExtendData.SplitColor) this.Canvas.fillStyle=message.ExtendData.SplitColor;
            else this.Canvas.fillStyle=message.TextColor;

            this.Canvas.textAlign="left";
            var splitWidth=this.Canvas.measureText('/').width;
            this.Canvas.fillText('/',x,item.Y);
            
            if (message.ExtendData && message.ExtendData.PercentageColor) this.Canvas.fillStyle=message.ExtendData.PercentageColor;
            else this.Canvas.fillStyle=message.TextColor;

            this.Canvas.textAlign="right";
            var x=item.X+maxWidth[1]+maxWidth[0]+splitWidth;
            this.Canvas.fillText(item.Text[0].Text,x,item.Y);

            var textWidth=maxWidth[1]+maxWidth[0]+splitWidth*4;
            if (this.RightTextMaxWidth<textWidth) this.RightTextMaxWidth=textWidth;
        }
    }

    //画Y轴Message[2,3]两个内部刻度
    this.DrawInsideClientHorizontal=function()
    {
        var border=this.GetBorder();
        if (border.DayBorder && IFrameSplitOperator.IsNonEmptyArray(border.DayBorder))
        {
            var item=border.DayBorder[0];
            var left=item.LeftEx;
            var item=border.DayBorder[border.DayBorder.length-1];
            var right=item.RightEx;
            var bottom=border.Bottom;
            var top=border.TopTitle;
        }
        else
        {
            var left=border.LeftEx;
            var right=border.RightEx;
            var bottom=border.Bottom;
            var top=border.TopTitle;
        }
       

        var pixelTatio = GetDevicePixelRatio();
        var yPrev = null; //上一个坐标y的值
        var yInsideText=null;
        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;  //两个坐标在近了 就不画了

            if (item.Message[2]) 
            {
                if (item.Font != null) this.Canvas.font = item.Font;
                this.Canvas.fillStyle = item.TextColor;
                this.Canvas.textAlign = "left";
                var yText=y;
                if (y >= bottom - 2) 
                {
                    this.Canvas.textBaseline = 'bottom';
                }
                else if (y <= top + 2) 
                {
                    this.Canvas.textBaseline = 'top';
                    yText+=this.YTextTopOffset;
                }
                else 
                {
                    this.Canvas.textBaseline = "middle";
                }

                var textObj={ X:left, Y:yText, 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[2], left + 1*pixelTatio, yText);
                    if (yInsideText==null || yInsideText>yText)
                    {
                        this.YInsideOffset=this.Canvas.measureText(item.Message[2]).width+4*GetDevicePixelRatio();
                        yInsideText=yText;
                    }
                        
                }
            }

            if (item.Message[3])
            {
                if (item.Font != null) this.Canvas.font = item.Font;
                this.Canvas.fillStyle = item.TextColor;
                this.Canvas.textAlign = "right";
                var yText=y;
                if (y >= bottom - 2) 
                {
                    this.Canvas.textBaseline = 'bottom';
                }
                else if (y <= top + 2) 
                {
                    this.Canvas.textBaseline = 'top';
                    yText+=this.YTextTopOffset;
                }
                else 
                {
                    this.Canvas.textBaseline = "middle";
                }
                var textWidth = this.Canvas.measureText(item.Message[3]).width;
                var textObj={ X:right-textWidth, Y:yText, 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[3], right - 1*pixelTatio, yText);
            }
            yPrev = y;
        }
    }

    //Y刻度画在左边内部
    this.DrawInsideHorizontal = function () 
    {
        if (this.IsHScreen===true) return;  //横屏不画
        if (this.IsMinSize) return;
        if (this.IsShowYText[0]===false && this.IsShowYText[1]===false) return;

        this.DrawInsideClientHorizontal();

        var border=this.ChartBorder.GetBorder();

        var left = border.Left
        var right = border.Right;
        var bottom = border.Bottom;
        var top = border.TopTitle;
        var borderRight = this.ChartBorder.Right;
        var borderLeft = this.ChartBorder.Left;
        var titleHeight = this.ChartBorder.TitleHeight;

        var isDrawLeft= (borderLeft<10 || this.YTextPosition[0]==2) && this.IsShowYText[0]===true;
        var isDrawRight= (borderRight<10 || this.YTextPosition[1]==2) && this.IsShowYText[1]===true;

        if ( isDrawLeft || isDrawRight )
        {
            var pixelTatio = GetDevicePixelRatio();
            var yPrev = null; //上一个坐标y的值
            var yInsideText=null;
            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 && isDrawLeft) 
                {
                    if (item.Font != null) this.Canvas.font = item.Font;
                    this.Canvas.fillStyle = item.TextColor;
                    this.Canvas.textAlign = "left";
                    var yText=y;
                    if (y >= bottom - 2) 
                    {
                        this.Canvas.textBaseline = 'bottom';
                    }
                    else if (y <= top + 2) 
                    {
                        this.Canvas.textBaseline = 'top';
                        yText+=this.YTextTopOffset;
                    }
                    else 
                    {
                        if (this.YTextBaseline==1) this.Canvas.textBaseline = "bottom";
                        else this.Canvas.textBaseline = "middle";
                    }

                    var textObj={ X:left, Y:yText, 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, yText);
                        if (yInsideText==null || yInsideText>yText)
                        {
                            this.YInsideOffset=this.Canvas.measureText(item.Message[0]).width+4*GetDevicePixelRatio();
                            yInsideText=yText;
                        }
                            
                    }
                }

                if (item.Message[1] != null && isDrawRight)
                {
                    if (item.Font != null) this.Canvas.font = item.Font;
                    this.Canvas.fillStyle = item.TextColor;
                    this.Canvas.textAlign = "right";
                    var yText=y;
                    if (y >= bottom - 2) 
                    {
                        this.Canvas.textBaseline = 'bottom';
                    }
                    else if (y <= top + 2) 
                    {
                        this.Canvas.textBaseline = 'top';
                        yText+=this.YTextTopOffset;
                    }
                    else 
                    {
                        if (this.YTextBaseline==1) this.Canvas.textBaseline = "bottom";
                        else this.Canvas.textBaseline = "middle";
                    }
                    
                    if (Array.isArray(item.Message[1])) var text=item.Message[1][0];
                    else var text=item.Message[1];

                    var textWidth = this.Canvas.measureText(text).width;
                    var textObj={ X:right-textWidth, Y:yText, 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(text, right - 1*pixelTatio, yText);
                }
                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 border=this.GetBorder();
        var top=border.TopTitle;
        var bottom=border.Bottom;
        var right=border.RightEx;
        var pixelRatio = GetDevicePixelRatio(); //获取设备的分辨率
        //JSConsole.Chart.Log('[AverageWidthFrame.DrawVertical] bottom',bottom);
        if (this.ChartBorder.Bottom<=5*GetDevicePixelRatio()) return;   //高度不够 不显示

        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;
            
            var item=this.VerticalInfo[i];
            var xFixed=ToFixedPoint(x);
            if (this.IsShowXLine)
            {
                if (item.LineType==2)   //虚线
                {
                    this.Canvas.strokeStyle=this.VerticalInfo[i].LineColor;
                    this.Canvas.setLineDash([5*pixelRatio,5*pixelRatio]);   
                    this.Canvas.beginPath();
                    this.Canvas.moveTo(xFixed,top);
                    this.Canvas.lineTo(xFixed,bottom);
                    this.Canvas.stroke();
                    this.Canvas.setLineDash([]);
                }
                else if (item.LineType==3)
                {

                }
                else if (item.LineType>0)   //实线
                {
                    if (g_JSChartResource.FrameXLineDash)
                    {
                        this.Canvas.strokeStyle=this.VerticalInfo[i].LineColor;
                        this.Canvas.setLineDash(g_JSChartResource.FrameXLineDash);   //虚线
                        this.Canvas.beginPath();
                        this.Canvas.moveTo(xFixed,top);
                        this.Canvas.lineTo(xFixed,bottom);
                        this.Canvas.stroke();
                        this.Canvas.setLineDash([]);
                    }
                    else
                    {
                        this.Canvas.strokeStyle=this.VerticalInfo[i].LineColor;
                        this.Canvas.beginPath();
                        this.Canvas.moveTo(xFixed,top);
                        this.Canvas.lineTo(xFixed,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=item.TextColor;
                this.Canvas.strokeStyle=item.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)
                {
                    var yText=bottom;
                    if (item.LineType==3)
                    {
                        var lineLength=this.ShortXLineLength*pixelRatio;
                        this.Canvas.beginPath();
                        this.Canvas.moveTo(xFixed,yText);
                        this.Canvas.lineTo(xFixed,yText+lineLength);
                        this.Canvas.stroke();

                        yText+=lineLength+2*pixelRatio;
                    }

                    this.Canvas.fillText(this.VerticalInfo[i].Message[0],x,yText+this.XBottomOffset);
                    textRightPrev=textLeft+testWidth;
                }
            }

            xPrev=x;
        }
    }

    //Y坐标转y轴数值
    this.GetYData=function(y,isLimit)
    {
        if (this.Logarithmic && this.GetYLogarithmicFromData)
        {
            return this.GetYLogarithmicData(y);
        }

        if (this.CoordinateType==1) //反转坐标
        {
            if (isLimit==false)
            {
                return (y-this.ChartBorder.GetTopEx())/this.ChartBorder.GetHeightEx()*(this.HorizontalMax-this.HorizontalMin)+this.HorizontalMin;
            }
            else
            {
                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 (isLimit==false)
            {
                return (this.ChartBorder.GetBottomEx()-y)/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());
    }

    //选中的画图工具X,Y轴坐标信息
    this.DrawPictureXCoordinate=function(drawPicture, range, option)
    {
        if (this.IsHScreen) return;
        if (!range) return;
        if (!IFrameSplitOperator.IsNonEmptyArray(range.Points)) return;

        var border=this.GetBorder();
        var left=border.Left;
        var right=border.Right;

        this.Canvas.font=this.DrawPicture.Font;
        var fontHeight=this.GetFontHeight();

        if (range.X)
        {
            var xRange=range.X;
            var xLeft=xRange.Min.X;
            var xRight=xRange.Max.X;
            if (xLeft<left) xLeft=left;
            if (xRight>right) xRight=right;

            this.Canvas.fillStyle=this.DrawPicture.BGColor;
            this.Canvas.fillRect(xLeft, border.Bottom, xRight-xLeft, fontHeight);
        }

        for(var i=0;i<range.Points.length;++i)
        {
            var item=range.Points[i];
            if (item.X<left || item.X>right) continue;

            var index=this.GetXData(item.X, false);
            var index=Math.round(index);
            var kItem=this.GetKItem(index);
            if (kItem)
            {
                var text=IFrameSplitOperator.FormatDateString(kItem.Date,null);
                if (ChartData.IsMinutePeriod(option.Period)) text+=" " + IFrameSplitOperator.FormatTimeString(kItem.Time, "HH:MM");
                var textWidth=this.Canvas.measureText(text).width+2;

                var textLeft=item.X-textWidth/2;
                if (textLeft<left) textLeft=left;
                this.Canvas.fillStyle=this.DrawPicture.TextBGColor;
                this.Canvas.fillRect(textLeft, border.Bottom, textWidth, fontHeight);

                this.Canvas.fillStyle=this.DrawPicture.TextColor;
                var yCenter=border.Bottom+fontHeight;
                this.Canvas.fillText(text,textLeft+1,yCenter);
            }
        }
    }

    this.GetKItem=function(currentIndex)
    {
        if (!this.Data) return null;
        if (!IFrameSplitOperator.IsNonEmptyArray(this.Data.Data)) return null;
        var index=this.Data.DataOffset+currentIndex;
        return this.Data.Data[index];
    }

    this.DrawPictureYCoordinate=function(drawPicture, range, option)
    {
        if (this.IsHScreen) return;
        if (!range) return;
        if (!IFrameSplitOperator.IsNonEmptyArray(range.Points)) return;

        var border=this.GetBorder();
        var top=border.TopEx;
        var bottom=border.BottomEx;
        var right=border.Right;

        this.Canvas.font=this.DrawPicture.Font;
        var fontHeight=this.GetFontHeight();
        this.Canvas.textAlign="left";
        this.Canvas.textBaseline = "bottom";

        var defaultfloatPrecision=2;
        if (option && option.Symbol) defaultfloatPrecision=GetfloatPrecision(option.Symbol);

        var textWidth=0;
        for(var i=0;i<range.Points.length; ++i)
        {
            var item=range.Points[i];
            var Value=this.GetYData(item.Y);
            var text=Value.toFixed(defaultfloatPrecision);
            var value=this.Canvas.measureText(text).width;
            if (textWidth<value) textWidth=value;

            range.Points[i].Text=text;
        }

        textWidth+=this.YTextPadding[1]+2;
        if (range.Y) 
        {
            var yRange=range.Y;
            var yTop=yRange.Min.Y;
            var yBottom=yRange.Max.Y;

            if (yRange.Min.Y<top) yTop=top;
            if (yRange.Max.Y>bottom) yBottom=bottom;

            this.Canvas.fillStyle=this.DrawPicture.BGColor;
            this.Canvas.fillRect(right, yTop, textWidth+5, yBottom-yTop);
        }

        
        for(var i=0;i<range.Points.length; ++i)
        {
            var item=range.Points[i];
            if (item.Y<top || item.Y>bottom) continue;

            this.Canvas.fillStyle=this.DrawPicture.TextBGColor;
            this.Canvas.fillRect(right, item.Y-fontHeight/2, textWidth, fontHeight);

            this.Canvas.fillStyle=this.DrawPicture.TextColor;
            var yText=item.Y+fontHeight/2;
            this.Canvas.fillText(item.Text,right+this.YTextPadding[1],yText);
        }

    }

    //字体外部设置好
    this.GetCustomItemTextInfo=function(item, bLeft,pixelTatio)
    {
        var text=bLeft?item.Message[0]:item.Message[1];
        var aryText=[];
        var width=0;
        if (Array.isArray(text))
        {
            for(var i=0;i<text.length;++i)
            {
                var value=this.Canvas.measureText(text[i].Text).width;
                if (value>width) width=value;
                aryText.push({Text:text[i].Text, Width:value+2*pixelTatio});
            }

            if (width>0) width+=2*pixelTatio;
        }
        else
        {
            width=this.Canvas.measureText(text).width+2*pixelTatio;
            aryText.push( {Text:text, Width:width} );
        }
        
        return  { MaxWidth:width, Text:aryText };
    }

    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 defaultTextHeight=18*pixelTatio;
        var textHeight=defaultTextHeight;
        
        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 textInfo=this.GetCustomItemTextInfo(item,true,pixelTatio);
                var textWidth=textInfo.MaxWidth;
                var fontHeight=this.GetFontHeight();
                textHeight=fontHeight>defaultTextHeight? fontHeight:defaultTextHeight;
                var bgColor=item.LineColor;
                var rgb=this.RGBToStruct(item.LineColor);
                if (rgb) bgColor=`rgba(${rgb.R}, ${rgb.G}, ${rgb.B}, ${g_JSChartResource.FrameLatestPrice.BGAlpha})`;   //内部刻度 背景增加透明度
                
                var yText=y;
                for(var i=0;i<textInfo.Text.length;++i)
                {
                    var itemText=textInfo.Text[i];
                    if (this.IsHScreen)
                    {
                        var bgTop=top;
                        var textLeft=yText-textHeight/2-1*pixelTatio;
                        this.Canvas.fillStyle=bgColor;
                        this.Canvas.fillRect(textLeft,bgTop,textHeight,itemText.Width);
                        this.DrawHScreenText({X:yText, Y:bgTop}, {Text:itemText.Text, Color:item.TextColor, XOffset:1*pixelTatio, YOffset:2*pixelTatio});
                        if (i==0) this.DrawLine(bgTop+itemText.Width,bottom,yText,item.LineColor,item.LineType);

                        yText-=textHeight+1*pixelTatio;
                    }
                    else
                    {
                        var bgTop=yText-textHeight/2-1*pixelTatio;
                        var textLeft=left + 1*pixelTatio
                        this.Canvas.fillStyle=bgColor;
                        this.Canvas.fillRect(textLeft,bgTop,itemText.Width,textHeight);
                        this.Canvas.fillStyle = item.TextColor;
                        this.Canvas.fillText(itemText.Text, textLeft + 1*pixelTatio, yText);
                        if (i==0) this.DrawLine(textLeft+itemText.Width,right,yText,item.LineColor,item.LineType);

                        yText+=textHeight+1*pixelTatio;
                    }
                }
            }
            else
            {
                if (item.Font != null) this.Canvas.font = item.Font;
                this.Canvas.textAlign = "right";
                this.Canvas.textBaseline = "middle";
                var textInfo=this.GetCustomItemTextInfo(item,true,pixelTatio);
                var textWidth=textInfo.MaxWidth;
                var fontHeight=this.GetFontHeight();
                textHeight=fontHeight>defaultTextHeight? fontHeight:defaultTextHeight;
                
                var yText=y;
                for(var i=0;i<textInfo.Text.length;++i)
                {
                    var itemText=textInfo.Text[i];
                    if (this.IsHScreen)
                    {
                        if (i==0) var bgTop=top-itemText.Width;
                        else var bgTop=top-textWidth;

                        var textLeft=yText-textHeight/2-1*pixelTatio;
                        this.Canvas.fillStyle=item.LineColor;
                        this.Canvas.fillRect(textLeft,bgTop,textHeight,itemText.Width);
                        this.DrawHScreenText({X:yText, Y:bgTop}, {Text:itemText.Text, Color:item.TextColor, XOffset:1*pixelTatio, YOffset:2*pixelTatio});
                        if (i==0) this.DrawLine(bgTop+itemText.Width,bottom,yText,item.LineColor,item.LineType);

                        yText-=textHeight+1*pixelTatio;
                    }
                    else
                    {
                        var bgTop=yText-textHeight/2-1*pixelTatio;
                        if (i==0)
                        {
                            var rectLeft=left-itemText.Width;
                            var textLeft=left;
                        }
                        else
                        {
                            var rectLeft=left-textWidth;
                            var textLeft=left-(textWidth-itemText.Width);
                        }
                        
                        this.Canvas.fillStyle=item.LineColor;
                        this.Canvas.fillRect(rectLeft,bgTop,itemText.Width,textHeight);
                        this.Canvas.fillStyle = item.TextColor;
                        this.Canvas.fillText(itemText.Text, textLeft - 1*pixelTatio, yText);
                        if (i==0) this.DrawLine(left,right,yText,item.LineColor,item.LineType);
                        
                        yText+=textHeight+1*pixelTatio;
                    }
                }
            }
        }
        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 textInfo=this.GetCustomItemTextInfo(item,false,pixelTatio);
                var textWidth=textInfo.MaxWidth;
                var fontHeight=this.GetFontHeight();
                textHeight=fontHeight>defaultTextHeight? fontHeight:defaultTextHeight;
                var bgColor=item.LineColor;
                var rgb=this.RGBToStruct(item.LineColor);
                if (rgb) bgColor=`rgba(${rgb.R}, ${rgb.G}, ${rgb.B}, ${g_JSChartResource.FrameLatestPrice.BGAlpha})`;   //内部刻度 背景增加透明度
                
                var yText=y;
                for(var i=0;i<textInfo.Text.length;++i)
                {
                    var itemText=textInfo.Text[i];
                    if (this.IsHScreen)
                    {
                        var bgTop=bottom-itemText.Width;
                        var textLeft=yText-textHeight/2-1*pixelTatio;
                        this.Canvas.fillStyle=bgColor;
                        this.Canvas.fillRect(textLeft,bgTop,textHeight,textWidth);
                        this.DrawHScreenText({X:yText, Y:bgTop}, {Text:itemText.Text, Color:item.TextColor, XOffset:1*pixelTatio, YOffset:2*pixelTatio});
                        if (i==0) this.DrawLine(top,bgTop,yText,item.LineColor,item.LineType);
                        yText-=textHeight+1*pixelTatio;
                    }
                    else
                    {
                        var bgTop=yText-textHeight/2-1*pixelTatio;
                        var textLeft=right-itemText.Width;
                        this.Canvas.fillStyle=bgColor;
                        this.Canvas.fillRect(textLeft,bgTop,textWidth,textHeight);  //文本背景区域
                        this.Canvas.fillStyle = item.TextColor;
                        this.Canvas.fillText(itemText.Text, textLeft + 1*pixelTatio, yText);
                        if (i==0) this.DrawLine(left,textLeft,yText,item.LineColor,item.LineType);
                        yText+=textHeight+1*pixelTatio;
                    }
                }
            }
            else
            {
                if (item.Font != null) this.Canvas.font = item.Font;
                this.Canvas.textAlign = "left";
                this.Canvas.textBaseline = "middle";
                var textInfo=this.GetCustomItemTextInfo(item,false,pixelTatio);
                var textWidth=textInfo.MaxWidth;
                var fontHeight=this.GetFontHeight();
                textHeight=fontHeight>defaultTextHeight? fontHeight:defaultTextHeight;
                
                var yText=y;
                for(var i=0;i<textInfo.Text.length;++i)
                {
                    var itemText=textInfo.Text[i];
                    if (this.IsHScreen)
                    {
                        var bgTop=bottom;
                        //bgTop+=(textWidth-itemText.Width);
                        var textLeft=yText-textHeight/2-1*pixelTatio;
                        this.Canvas.fillStyle=item.LineColor;
                        this.Canvas.fillRect(textLeft,bgTop,textHeight,itemText.Width);
                        this.DrawHScreenText({X:yText, Y:bgTop}, {Text:itemText.Text, Color:item.TextColor, XOffset:1*pixelTatio, YOffset:2*pixelTatio});
                        if (i==0)  this.DrawLine(top,bgTop,yText,item.LineColor,item.LineType);

                        yText-=textHeight+1*pixelTatio;
                    }
                    else
                    {
                        var bgTop=yText-textHeight/2-1*pixelTatio;
                        if (i==0)
                        {
                            var textLeft=right;
                        }
                        else
                        {
                            var textLeft=right+textWidth-itemText.Width;
                        }

                        this.Canvas.fillStyle=item.LineColor;
                        this.Canvas.fillRect(textLeft,bgTop,itemText.Width,textHeight);
                        this.Canvas.fillStyle = item.TextColor;
                        this.Canvas.fillText(itemText.Text, textLeft + 1*pixelTatio, yText);
                        if (i==0) this.DrawLine(left,right,yText,item.LineColor,item.LineType);

                        yText+=textHeight+1*pixelTatio;
                    }
                }
            }
        }
    }

    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.DrawLine=function(left,right,y, color,lineType)
    {
        if (lineType==-1) return;

        if (lineType==0)
        {
            this.Canvas.strokeStyle=color;
            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();
        }
        else
        {
            this.DrawDotLine(left,right,y, color);
        }
    }

    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;
    }

    this.GetScaleTextWidth=function()
    {
        var border=this.ChartBorder.GetBorder();
        var pixelTatio = GetDevicePixelRatio(); //获取设备的分辨率
        if (this.IsHScreen)
        {
            var borderTop=this.ChartBorder.Top;
            var borderBottom=this.ChartBorder.Bottom;
            var isDrawLeft=borderTop>10*pixelTatio && this.IsShowYText[0]===true && this.YTextPosition[0]!=2;
            var isDrawRight=borderBottom>10*pixelTatio && this.IsShowYText[1]===true && this.YTextPosition[1]!=2;
        }
        else
        {
            var borderRight=this.ChartBorder.Right;
            var borderLeft=this.ChartBorder.Left;
            var isDrawLeft=borderLeft>10 && this.IsShowYText[0]===true && this.YTextPosition[0]!=2;
            var isDrawRight=borderRight>10 && this.IsShowYText[1]===true && this.YTextPosition[1]!=2;
        }
       
        if (!isDrawRight && !isDrawLeft) return null;

        var width={ Left:null, Right:null };
        var rightExtendWidth=0;
        for(var i=0;i<this.HorizontalInfo.length;++i)
        {
            var textWidth=null;
            var item=this.HorizontalInfo[i];
            if (!item) continue;
            if (item.Font!=null) this.Canvas.font=item.Font;

            if (item.Message[0]!=null && isDrawLeft)
            {
                textWidth=this.Canvas.measureText(item.Message[0]).width;
                if (width.Left==null || width.Left<textWidth)
                    width.Left=textWidth;

                //JSConsole.Chart.Log(`[ChartData::GetScaleTextWidth] ${item.Message[0]} ${textWidth}`);
            }

            if (item.Message[1]!=null && isDrawRight)
            {
                if (item.Font!=null) this.Canvas.font=item.Font;

                if (Array.isArray(item.Message[1]))
                {
                    if (this.MultiTextFormat==1)    //显示1行 格式:价格/百分比
                    {
                        if (item.ExtendData)
                        {
                            if (item.ExtendData.Font) this.Canvas.font=item.ExtendData.Font;
                            var width1=this.Canvas.measureText(item.Message[1][0]).width;
                            var width2=this.Canvas.measureText(item.Message[1][1]).width;
                            var width3=this.Canvas.measureText('/').width;
                            textWidth=width1+width3;

                            if (rightExtendWidth<width2) rightExtendWidth=width2;

                            //JSConsole.Chart.Log(`[ChartData::GetScaleTextWidth] ${item.Message[1][1]}/${item.Message[1][0]} ${textWidth}, ${rightExtendWidth}`);
                        }
                    }
                    else if (this.MultiTextFormat==2)   //显示2行
                    {
                        textWidth=this.Canvas.measureText(item.Message[1][0]).width;
                        var textWidth2=this.Canvas.measureText(item.Message[1][1]).width;
                        if (textWidth<textWidth2) textWidth=textWidth2;
                    }
                    else    //显示第1行
                    {
                        textWidth=this.Canvas.measureText(item.Message[1][0]).width;
                    }
                }
                else
                {
                    textWidth=this.Canvas.measureText(item.Message[1]).width;
                }
                
                if (width.Right==null || width.Right<textWidth)
                    width.Right=textWidth;
            }
        }

        if (IFrameSplitOperator.IsNumber(width.Right)) width.Right+=rightExtendWidth;

        if (IFrameSplitOperator.IsNumber(width.Left)) width.Left+=this.YTextPadding[0];
        if (IFrameSplitOperator.IsNumber(width.Right)) width.Right+=this.YTextPadding[1];
        
        return { TextWidth:width };
    }

    this.ClearToolbar=function()
    {
        if (!this.ToolbarID) return;

        var divToolbar=document.getElementById(this.ToolbarID);
        if (!divToolbar) return;
        this.ChartBorder.UIElement.parentNode.removeChild(divToolbar);
        this.ToolbarRect=null;
    }

    this.HideToolbar=function()
    {
        if (!this.ToolbarID) return;

        this.ToolbarRect=null;
        var divToolbar=document.getElementById(this.ToolbarID);
        if (!divToolbar) return;

        if (divToolbar.style.display!='none') divToolbar.style.display='none';
    }
}

function MinuteFrame()
{
    this.newMethod=AverageWidthFrame;   //派生
    this.newMethod();
    delete this.newMethod;

    this.ClassName="MinuteFrame";
    this.DataWidth=1*GetDevicePixelRatio();
    this.DistanceWidth=1*GetDevicePixelRatio();
    this.MinuteCount=243;   //每天的分钟个数
    this.BeforeBGColor=g_JSChartResource.Minute.Before.BGColor;  //集合竞价背景
    this.MultiDayBorderPen=g_JSChartResource.FrameBorderPen;
    this.CustomHorizontalInfo=[];
    this.RightFrame=null;   //右侧多重坐标
    this.ToolbarID=Guid();  //工具条Div id
    this.ReDrawToolbar=false;
    this.DayCount=1;        //显示天数

    this.ModifyIndex=true;      //是否显示'改参数'菜单
    this.ChangeIndex=true;      //是否显示'换指标'菜单
    this.CloseIndex=true;       //是否显示'关闭指标窗口'菜单

    this.ModifyIndexEvent;   //改参数 点击事件
    this.ChangeIndexEvent;   //换指标 点击事件
    this.ToolbarRect=null;   //保存工具条的位置
    this.IsShowPositionTitle=false; //是否显示持仓标题

    this.LastCalculateStatus={ Width:0, XPointCount:0 };    //最后一次计算宽度的状态
    this.BeforeCloseIcon=
    {
        Family:g_JSChartResource.Minute.Before.CloseIcon.Family,
        Text:g_JSChartResource.Minute.Before.CloseIcon.Text,
        Color:g_JSChartResource.Minute.Before.CloseIcon.Color,
        Size:g_JSChartResource.Minute.Before.CloseIcon.Size
    };

    this.BeforeOpenVerticalInfo=[];      //盘前集合竞价X轴
    this.AfterCloseVerticalInfo=[];      //收盘集合竞价X轴

    this.DrawFrame=function()
    {
        if (!this.IsMinSize)
        {
            this.SplitXYCoordinate();
            this.DrawBeforeDataBG();
    
            this.YInsideOffset=0;
            this.DrawTitleBG();
            this.DrawHorizontal();
            this.DrawVertical();
        }
        
        if (this.SizeChange==true || this.ReDrawToolbar==true) 
        {
            this.DrawToolbar();  //大小变动才画工具条
            this.ReDrawToolbar=false;
        }
    }

    //画边框
    this.SuperDrawBorder=this.DrawBorder;
    this.DrawBorder=function()
    {
        if (!this.IsShowBorder) return;
        if (this.IsMinSize) return;
        this.SuperDrawBorder();

        if (this.Identify==1)   //走势图和成交量中间用粗线分割开
        {
            var border=this.ChartBorder.GetBorder();
            var left=ToFixedPoint(border.Left);
            var top=ToFixedPoint(border.Top);
            var right=ToFixedPoint(border.Right);
    
            this.Canvas.strokeStyle=this.PenBorder;
            this.Canvas.beginPath();
            this.Canvas.moveTo(left,top);
            this.Canvas.lineTo(right,top);
            this.Canvas.save();
            this.Canvas.lineWidth=2 * GetDevicePixelRatio();
            this.Canvas.stroke();
            this.Canvas.restore();
        }
    }

    this.DrawVolTitle=function(symbol)
    {
        if (!MARKET_SUFFIX_NAME.IsShowMinuteVolTitle(symbol)) return;

        if (this.Identify==1)   //显示"成交量"
        {
            var pixelRatio=GetDevicePixelRatio();
            var left=this.ChartBorder.GetLeft()+2*pixelRatio+this.YInsideOffset;

            var top=this.ChartBorder.GetTopEx()+2*pixelRatio;

            this.Canvas.textAlign='left';
            this.Canvas.textBaseline='top';
            if (g_JSChartResource.Minute.VolBarColor || g_JSChartResource.Minute.VolTitleColor)
            {
                if (g_JSChartResource.Minute.VolBarColor) this.Canvas.fillStyle=g_JSChartResource.Minute.VolBarColor
                else this.Canvas.fillStyle=g_JSChartResource.Minute.VolTitleColor;
                var languageID=this.YSplitOperator.LanguageID;
                var text=g_JSChartLocalization.GetText('MVol-Vol',languageID);
                this.Canvas.fillText(text,left,top);
                left+=this.Canvas.measureText(text).width;
                left+=6*GetDevicePixelRatio();
            }
            
            if (this.IsShowPositionTitle)
            {
                text=g_JSChartLocalization.GetText('MVol-Position',languageID);
                this.Canvas.fillStyle=g_JSChartResource.Minute.PositionColor;
                this.Canvas.fillText(text,left,top);
            }
        }
    }

    this.DrawToolbar=function()
    {
        if (typeof($)=="undefined") return;

        if (this.Identify<2) return;
        if (!this.ChartBorder.UIElement) return;

        var divToolbar=document.getElementById(this.ToolbarID);
        if (divToolbar && this.SizeChange==false && this.ReDrawToolbar==false) return;

        if (!divToolbar)
        {
            divToolbar=document.createElement("div");
            divToolbar.className='klineframe-toolbar';
            divToolbar.id=this.ToolbarID;
            divToolbar.oncontextmenu = function() { return false;}; //屏蔽右键系统菜单
            //为divToolbar添加属性identify
            divToolbar.setAttribute("identify",this.Identify.toString());
            this.ChartBorder.UIElement.parentNode.appendChild(divToolbar);
        }

        if (!this.ModifyIndex && !this.ChangeIndex && !this.OverlayIndex)
        {
            if (divToolbar.style.display!='none')
                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;

        if (this.ToolbarRect)
        {
            //尺寸变动移动才重新设置DOM
            if (this.ToolbarRect.Left==left && this.ToolbarRect.Top==top && 
                this.ToolbarRect.Width==toolbarWidth && this.ToolbarRect.Height==toolbarHeight/pixelTatio)
            {
                return;
            }
        }

        this.ToolbarRect={ Left:left, Top:top, Width:toolbarWidth, Height:toolbarHeight/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 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;
        if (this.CloseIndex)
        {
            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);
        }

        $("#"+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.DrawMultiDayBeforeDataBG=function(border)
    {
        var dayBorder=border.DayBorder;
        var top=ToFixedPoint(border.Top);
        var bottom=ToFixedPoint(border.Bottom);
        var height=bottom-top;
        this.Canvas.fillStyle=this.BeforeBGColor;
        this.Canvas.strokeStyle=this.MultiDayBorderPen;
        for(var i in dayBorder)
        {
            var drawCount=0;
            var item=dayBorder[i];
            var left=ToFixedPoint(item.Left);
            var right=ToFixedPoint(item.LeftEx);
            var width=right-left;
            if (width>3) 
            {
                this.Canvas.fillRect(left,top,width,height);
                ++drawCount;
            }

            var left=ToFixedPoint(item.RightEx);
            var right=ToFixedPoint(item.Right);
            var width=right-left;
            if (width>3) 
            {
                this.Canvas.fillRect(left,top,width,height);
                ++drawCount;
            }

            if (drawCount==2 && i!=dayBorder.length-1)
            {
                this.Canvas.beginPath();
                this.Canvas.moveTo(right,top);
                this.Canvas.lineTo(right,bottom);
                this.Canvas.stroke();
            }
        }
    }

    this.DrawCallAuctionVertical=function(verticalInfo, callAuctionData, border, isBeforeClose)
    {
        if (!callAuctionData) return;

        var top=border.TopTitle;
        var bottom=border.Bottom;
        var left=border.Left;
        var right=border.LeftEx;
        var pixelRatio = GetDevicePixelRatio(); //获取设备的分辨率

        var xPrev=null;         //上一个坐标x的值
        var textRightPrev=null; //上一次刻度输出右边x坐标

        for(var i in verticalInfo)
        {
            var item=verticalInfo[i];
            var x=this.GetLeftExtendXFromIndex(item.Value,callAuctionData);
            if (x>right) break;
            if (xPrev!=null && Math.abs(x-xPrev)<this.MinXDistance) continue;
            
            var xFixed=ToFixedPoint(x);
            if (this.IsShowXLine)
            {
                if (item.LineType==2)   //虚线
                {
                    this.Canvas.strokeStyle=item.LineColor;
                    this.Canvas.setLineDash([5*pixelRatio,5*pixelRatio]);   
                    this.Canvas.beginPath();
                    this.Canvas.moveTo(xFixed,top);
                    this.Canvas.lineTo(xFixed,bottom);
                    this.Canvas.stroke();
                    this.Canvas.setLineDash([]);
                }
                else if (item.LineType==3)
                {

                }
                else if (item.LineType>0)   //实线
                {
                    if (g_JSChartResource.FrameXLineDash)
                    {
                        this.Canvas.strokeStyle=item.LineColor;
                        this.Canvas.setLineDash(g_JSChartResource.FrameXLineDash);   //虚线
                        this.Canvas.beginPath();
                        this.Canvas.moveTo(xFixed,top);
                        this.Canvas.lineTo(xFixed,bottom);
                        this.Canvas.stroke();
                        this.Canvas.setLineDash([]);
                    }
                    else
                    {
                        this.Canvas.strokeStyle=item.LineColor;
                        this.Canvas.beginPath();
                        this.Canvas.moveTo(xFixed,top);
                        this.Canvas.lineTo(xFixed,bottom);
                        this.Canvas.stroke();
                    }
                }
            }
            

            if (item.Message[0]!=null && this.ChartBorder.Bottom>5*pixelRatio)
            {
                if (item.Font!=null) this.Canvas.font=item.Font;
                
                var textLeft=0;
                this.Canvas.fillStyle=item.TextColor;
                this.Canvas.strokeStyle=item.TextColor;
                var testWidth=this.Canvas.measureText(item.Message[0]).width;
                if (x<testWidth/2)
                {
                    this.Canvas.textAlign="left";
                    this.Canvas.textBaseline="top";
                    textLeft=x;
                }
                else if ((x + testWidth / 2) >= border.ChartWidth)
                {
                    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)
                {
                    var yText=bottom;
                    if (item.LineType==3)
                    {
                        var lineLength=this.ShortXLineLength*pixelRatio;
                        this.Canvas.beginPath();
                        this.Canvas.moveTo(xFixed,yText);
                        this.Canvas.lineTo(xFixed,yText+lineLength);
                        this.Canvas.stroke();

                        yText+=lineLength+2*pixelRatio;
                    }

                    this.Canvas.fillText(item.Message[0],x,yText+this.XBottomOffset);
                    textRightPrev=textLeft+testWidth;
                }
            }

            xPrev=x;
        }
    }

    //画集合竞价背景
    this.DrawBeforeDataBG=function()
    {
        var border=this.ChartBorder.GetBorder();
        if (border.DayBorder)
        {
            this.DrawMultiDayBeforeDataBG(border);
            return;
        }

        if (this.ChartBorder.LeftExtendWidth<10 && this.ChartBorder.RightExtendWidth<10) return;
        //if (this.Identify>=2) return;

        var top=ToFixedPoint(border.Top);
        var bottom=ToFixedPoint(border.Bottom);
        this.Canvas.fillStyle=this.BeforeBGColor;

        if (this.ChartBorder.LeftExtendWidth>10)
        {
            var left=ToFixedPoint(border.Left);
            var right=ToFixedPoint(this.ChartBorder.GetLeft());
            var width=right-left;
            var height=bottom-top;
            
            this.Canvas.fillRect(left,top,width,height);

            //绘制关闭图标
            if (this.Identify==0)
            {
                this.Canvas.font=this.BeforeCloseIcon.Size+'px '+this.BeforeCloseIcon.Family;
                this.Canvas.fillStyle=this.BeforeCloseIcon.Color;
                this.Canvas.textAlign = 'left';
                this.Canvas.textBaseline='top';
                this.Canvas.fillText(this.BeforeCloseIcon.Text,border.Left,border.TopEx);

                var rect={ Left:border.Left, Top:border.TopEx, Width:this.BeforeCloseIcon.Size, Height:this.BeforeCloseIcon.Size };
                this.Buttons.push( { Rect:rect, Name:"集合竞价关闭按钮" , ID:JSCHART_BUTTON_ID.CLOSE_BEFOREOPEN_ID });
            }

            this.DrawCallAuctionVertical(this.BeforeOpenVerticalInfo, this.YSplitOperator.BeforeOpenData, border, true);
        }

        if (this.ChartBorder.RightExtendWidth>10)
        {
            this.Canvas.fillStyle=this.BeforeBGColor;
            var left=ToFixedPoint(this.ChartBorder.GetRight());
            var right=ToFixedPoint(border.Right);
            var width=right-left;
            var height=bottom-top;

            this.Canvas.fillRect(left,top,width,height);
        }
    }

    //选中的画图工具X轴坐标信息
    this.DrawPictureXCoordinate=function(drawPicture, range, option)
    {
        if (this.IsHScreen) return;
        if (!range) return;
        if (!IFrameSplitOperator.IsNonEmptyArray(range.Points)) return;

        var border=this.GetBorder();
        var left=border.Left;
        var right=border.Right;

        this.Canvas.font=this.DrawPicture.Font;
        var fontHeight=this.GetFontHeight();

        if (range.X)
        {
            var xRange=range.X;
            var xLeft=xRange.Min.X;
            var xRight=xRange.Max.X;
            if (xLeft<left) xLeft=left;
            if (xRight>right) xRight=right;

            this.Canvas.fillStyle=this.DrawPicture.BGColor;
            this.Canvas.fillRect(xLeft, border.Bottom, xRight-xLeft, fontHeight);
        }

        for(var i=0;i<range.Points.length;++i)
        {
            var item=range.Points[i];
            if (item.X<left || item.X>right) continue;

            var index=parseInt(this.GetXData(item.X));
            var kItem=this.GetKItem(index,option);
            if (kItem)
            {
                //var text=IFrameSplitOperator.FormatDateString(kItem.Date,null);
                var text=IFrameSplitOperator.FormatTimeString(kItem.Time, "HH:MM");
                var textWidth=this.Canvas.measureText(text).width+2;

                var textLeft=item.X-textWidth/2;
                if (textLeft<left) textLeft=left;
                this.Canvas.fillStyle=this.DrawPicture.TextBGColor;
                this.Canvas.fillRect(textLeft, border.Bottom, textWidth, fontHeight);

                this.Canvas.fillStyle=this.DrawPicture.TextColor;
                var yCenter=border.Bottom+fontHeight;
                this.Canvas.fillText(text,textLeft+1,yCenter);
            }
        }
    }

    this.GetKItem=function(currentIndex,option)
    {
        if (!this.Data) return null;
        if (!IFrameSplitOperator.IsNonEmptyArray(this.Data.Data)) return null;
        if (currentIndex<this.Data.Data.length)
        {
            return this.Data.Data[currentIndex];
        }
        else
        {
            var kItem=this.Data.Data[this.Data.Data.length-1];
            var xDatetime=g_MinuteTimeStringData.GetTimeData(option.Symbol);
            var index=currentIndex%xDatetime.length;
            var timeItem=xDatetime[index];
            
            return { Date:kItem.Date, Time:timeItem };
        }
    }

    //分割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.GetMultiDayXFromIndex=function(index, border)
    {
        var dayBorder=border.DayBorder;
        var minuteIndex=index%this.MinuteCount;
        var dayIndex=parseInt(index/this.MinuteCount);
        if (dayIndex>=dayBorder.length) dayIndex=dayBorder.length-1;

        var client=dayBorder[dayIndex];
        var count=this.MinuteCount-1;

        if (minuteIndex>=count) 
        {
            return client.RightEx;
        }
        else
        {
            var width=(client.RightEx-client.LeftEx);
            var offset=client.LeftEx+width*minuteIndex/count;
            return offset;
        }
    }

    this.GetXFromIndex=function(index)
    {
        var count=this.XPointCount-1;
        var border=this.ChartBorder.GetBorder();
        if (border.DayBorder) return this.GetMultiDayXFromIndex(index, border);

        if (count==1)
        {
            if (index==0) return border.LeftEx;
            else return border.RightEx;
        }
        else if (count<=0)
        {
            return border.LeftEx;
        }
        else if (index>=count)
        {
            return border.RightEx;
        }
        else
        {
            var width=(border.RightEx-border.LeftEx);
            var offset=border.LeftEx+width*index/count;
            return offset;
        }
    }

    this.GetMultiDayXData=function(x,border)
    {
        var dayBorder=border.DayBorder;
        for(var i=0;i<dayBorder.length;++i)
        {
            var client=dayBorder[i];
            if (x>=client.Left && x<=client.Right)
            {
                var count=this.MinuteCount-1;
                var dayMinuteCount=this.MinuteCount*i;
                if (x<=client.LeftEx) return 0+dayMinuteCount;
                if (x>=client.RightEx) return count+dayMinuteCount;

                var width=client.RightEx-client.LeftEx;
                return (x-client.LeftEx)*(count*1.0/width)+dayMinuteCount;
            }
        }
    }

    //X坐标转x轴数值
    this.GetXData=function(x)
    {
        var count=this.XPointCount-1;
        if (count<0) count=0;

        var border=this.ChartBorder.GetBorder();
        if (border.DayBorder) return this.GetMultiDayXData(x, border);

        if (x<=border.LeftEx) return 0;
        if (x>=border.RightEx) return count;

        var width=border.RightEx-border.LeftEx;
        return (x-border.LeftEx)*(count*1.0/width);
    }

    this.DrawCustomHorizontal=function()    //Y轴刻度定制显示
    {
        if (this.IsMinSize) return;
        for(var i in this.CustomHorizontalInfo)
        {
            var item=this.CustomHorizontalInfo[i];
            switch(item.Type)
            {
                case 0:
                case 1:
                    this.DrawCustomItem(item);  //自定义刻度
                    break;
            }
        }
    }

    this.GetLeftExtendXFromIndex=function(index, obj)
    {
        var count=obj.TotalCount-1;

        var border=this.ChartBorder.GetBorder();
        if (border.DayBorder) return this.GetLeftExtendMultiDayXFromIndex(index, obj, border);

        var left=border.Left;
        var width=this.ChartBorder.LeftExtendWidth;

        var offset=left+width*index/count;
        return offset;
    }

    this.GetLeftExtendMultiDayXFromIndex=function(index, obj, border)
    {
        var dayBorder=border.DayBorder;
        var client=dayBorder[obj.Index];
        var count=obj.TotalCount-1;

        var left=client.Left;
        var right=client.LeftEx;
        var width=right-left;

        var offset=left+width*index/count;
        return offset;
    }

    this.GetLeftExtendMultiDayXData=function(x, obj, border)
    {
        var dayBorder=border.DayBorder;
        for(var i in dayBorder)
        {
            var client=dayBorder[i];
            if (x>=client.Left && x<=client.LeftEx)
            {
                var count=obj[i].TotalCount-1;
                var left=client.Left;
                var right=client.LeftEx;

                var width=right-left;
                var index=(x-left)*(count*1.0/width);

                return { DayIndex:parseInt(i), DataIndex:index };
            }
        }
    }

    this.GetLeftExtendXData=function(x, obj)
    {
        var border=this.ChartBorder.GetBorder();
        if (border.DayBorder) return this.GetLeftExtendMultiDayXData(x, obj, border);

        var count=obj.TotalCount-1;
        if (count<0) count=0;

        var left=border.Left;
        var right=border.LeftEx;

        if (x<=left) return 0;
        if (x>=right) return count;

        var width=right-left;
        return (x-left)*(count*1.0/width);
    }

    this.GetLeftExtendYFromData=function(value,isLimit,obj)
    {
        if (!obj || !obj.Range) return this.GetYFromData(value,isLimit);

        var range=obj.Range;
        var border=this.ChartBorder.GetBorder();
        var height=border.BottomEx-border.TopEx;
        var offset=height*(value-range.Min)/(range.Max-range.Min);
        return border.BottomEx-offset;
    }

    this.GetLeftExtendYData=function(y, isLimit, obj)
    {
        if (!obj || !obj.Range) return this.GetYData(y,isLimit);

        var range=obj.Range;
        var border=this.ChartBorder.GetBorder();
        var height=border.BottomEx-border.TopEx;
        return (border.BottomEx-y)/height*(range.Max-range.Min)+range.Min;
    }

    this.GetRightExtendMultiDayXFromIndex=function(index, obj, border)
    {
        var dayBorder=border.DayBorder;
        var client=dayBorder[obj.Index];
        var count=obj.TotalCount-1;

        var left=client.RightEx;
        var right=client.Right;
        var width=right-left;

        var offset=left+width*index/count;
        return offset;
    }

    this.GetRightExtendXFromIndex=function(index, obj)
    {
        var count=obj.TotalCount-1;

        var border=this.ChartBorder.GetBorder();
        if (border.DayBorder) return this.GetRightExtendMultiDayXFromIndex(index, obj, border);

        var left=border.RightEx;
        var width=this.ChartBorder.RightExtendWidth;

        var offset=left+width*index/count;
        return offset;
    }

    this.GetRightExtendYFromData=function(value,isLimit,obj)
    {
        return this.GetLeftExtendYFromData(value,isLimit,obj)
    }

    this.GetRightExtendYData=function(y, isLimit, obj)
    {
        if (!obj || !obj.Range) return this.GetYData(y,isLimit);

        return this.GetLeftExtendYData(y, isLimit, obj);
    }

    this.GetRightExtendMultiDayXData=function(x, obj, border)
    {
        var dayBorder=border.DayBorder;
        for(var i in dayBorder)
        {
            var client=dayBorder[i];
            if (x>=client.RightEx && x<=client.Right)
            {
                var count=obj[i].TotalCount-1;
                var left=client.RightEx;
                var right=client.Right;

                var width=right-left;
                var index=(x-left)*(count*1.0/width);

                return { DayIndex:parseInt(i), DataIndex:index };
            }
        }
    }

    this.GetRightExtendXData=function(x, obj)
    {
        var border=this.ChartBorder.GetBorder();
        if (border.DayBorder) return this.GetRightExtendMultiDayXData(x, obj, border);

        var count=obj.TotalCount-1;
        if (count<0) count=0;

        var left=border.RightEx;
        var right=border.Right;

        if (x<=left) return 0;
        if (x>=right) return count;

        var width=right-left;
        return (x-left)*(count*1.0/width);
    }
}

//走势图 横屏框架
function MinuteHScreenFrame()
{
    this.newMethod=MinuteFrame;   //派生
    this.newMethod();
    delete this.newMethod;

    this.ClassName="MinuteHScreenFrame";
    this.IsHScreen=true;        //是否是横屏

    //画标题背景色
    this.DrawTitleBG=function()
    {
        if (this.ChartBorder.TitleHeight<=0) return;

        var border=this.ChartBorder.GetHScreenBorder();
        var left=ToFixedPoint(border.RightEx);
        var top=ToFixedPoint(border.Top);
        var bottom=ToFixedPoint(border.Bottom);
        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.DrawBeforeDataBG=function()
    {
        if (this.ChartBorder.LeftExtendWidth<10 && this.ChartBorder.RightExtendWidth<10) return;
        var border=this.ChartBorder.GetHScreenBorder();

        var left=ToFixedPoint(border.Left);
        var right=ToFixedPoint(border.Right);
        this.Canvas.fillStyle=this.BeforeBGColor;
        
        if (this.ChartBorder.LeftExtendWidth>10)
        {
            var top=ToFixedPoint(border.Top);
            var bottom=ToFixedPoint(border.TopEx);
            var width=right-left;
            var height=bottom-top;
            
            this.Canvas.fillRect(left,top,width,height);
        }

        if (this.ChartBorder.RightExtendWidth>10)
        {
            var top=border.BottomEx;
            var bottom=border.Bottom;
            var width=right-left;
            var height=bottom-top;

            this.Canvas.fillRect(left,top,width,height);
        }
    }

    //Y坐标转y轴数值
    this.GetYData=function(x)
    {
        var border=this.ChartBorder.GetHScreenBorder();
        if (x<border.LeftEx) return this.HorizontalMin;
		if (x>border.RightEx) return this.HorizontalMax;

        var width=border.RightEx-border.LeftEx;
		return (x-border.LeftEx)/width*(this.HorizontalMax-this.HorizontalMin)+this.HorizontalMin;
    }

    //X坐标转x轴数值
    this.GetXData=function(y)
    {
        var border=this.ChartBorder.GetHScreenBorder();
        var count=this.XPointCount-1;
        if (count<0) count=0;

        if (y<=border.TopEx) return 0;
		if (y>=border.BottomEx) return count;

        var height=(border.BottomEx-border.TopEx);
		return (y-border.TopEx)*(count*1.0/height);
    }

    this.GetXFromIndex=function(index)
    {
        var count=this.XPointCount-1;
        var border=this.ChartBorder.GetHScreenBorder();
        if (count==1)
        {
            if (index==0) return border.TopEx;
            else return border.BottomEx;
        }
        else if (count<=0)
        {
            return border.TopEx;
        }
        else if (index>=count)
        {
            return border.BottomEx;
        }
        else
        {
            var height=border.BottomEx-border.TopEx;
            var offset=border.TopEx+height*index/count;
            return offset;
        }
    }

    
    this.GetYFromData=function(value)
    {
        var border=this.ChartBorder.GetHScreenBorder();
        if(value<=this.HorizontalMin) return border.LeftEx;
        if(value>=this.HorizontalMax) return border.RightEx;

        var width=(border.RightEx-border.LeftEx)*(value-this.HorizontalMin)/(this.HorizontalMax-this.HorizontalMin);
        return border.LeftEx+width;
    }

    this.DrawVolTitle=function(symbol)
    {
        if (!MARKET_SUFFIX_NAME.IsShowMinuteVolTitle(symbol)) return;

        if (this.Identify==1)   //显示"成交量"
        {
            var pixelRatio=GetDevicePixelRatio();
            var left=this.ChartBorder.GetRight()-2*pixelRatio;
            var top=this.ChartBorder.GetTopEx()+2*pixelRatio;

            var xText=left,yText=top;
            this.Canvas.save();
            this.Canvas.translate(xText, yText);
            this.Canvas.rotate(90 * Math.PI / 180);

            var x=this.YInsideOffset,y=0;
            this.Canvas.textAlign='left';
            this.Canvas.textBaseline='top';
            if (g_JSChartResource.Minute.VolBarColor || g_JSChartResource.Minute.VolTitleColor)
            {
                if (g_JSChartResource.Minute.VolBarColor) this.Canvas.fillStyle=g_JSChartResource.Minute.VolBarColor
                else this.Canvas.fillStyle=g_JSChartResource.Minute.VolTitleColor;
                var languageID=this.YSplitOperator.LanguageID;
                var text=g_JSChartLocalization.GetText('MVol-Vol',languageID);
                this.Canvas.fillText(text,x,y);
                x+=this.Canvas.measureText(text).width;
                x+=6*GetDevicePixelRatio();
            }
            
            if (this.IsShowPositionTitle)
            {
                text=g_JSChartLocalization.GetText('MVol-Position',languageID);
                this.Canvas.fillStyle=g_JSChartResource.Minute.PositionColor;
                this.Canvas.fillText(text,x,y);
            }

            this.Canvas.restore();
        }
    }

    //画Y轴
    this.DrawHorizontal=function()
    {
        var border=this.ChartBorder.GetHScreenBorder();

        var top=border.Top;
        var bottom=border.Bottom;
        var left=border.Left;
        var right=border.Right;
        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;
        }
    }

    this.DrawInsideClientHorizontal=function()
    {
        var border=this.GetBorder();
        var left=border.Left;
        var right=border.Right;
        var bottom=border.BottomEx;
        var top=border.TopEx;

        var pixelTatio = GetDevicePixelRatio();
        var yPrev = null; //上一个坐标y的值
        var yInsideText=null;
        for (var i = this.HorizontalInfo.length - 1; i >= 0; --i)  //从上往下画分割线
        {
            var item = this.HorizontalInfo[i];
            if (!item || !item.Message[2] || !item.Message[3]) continue;
            var y = this.GetYFromData(item.Value);
            if (y != null && yPrev!=null && Math.abs(y - yPrev) < this.MinYDistance) continue;  //两个坐标在近了 就不画了

            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";
            }

            if (item.Message[2]) 
            {
                if (item.Font != null) this.Canvas.font = item.Font;
                this.Canvas.fillStyle = item.TextColor;
                this.Canvas.textAlign = "left";

                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[2], 2, 0);
                this.Canvas.restore();
            }

            if (item.Message[3])
            {
                if (item.Font != null) this.Canvas.font = item.Font;
                this.Canvas.fillStyle = item.TextColor;
                this.Canvas.textAlign = "right";

                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[3], -2, 0);
                this.Canvas.restore();
                
            }
            yPrev = y;
        }
    }

    //画X轴
    this.DrawVertical=function()
    {
        var border=this.ChartBorder.GetHScreenBorder();
        var left=border.Left;
        var right=border.Right;
        var bottom=border.Bottom;

        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.IsMinSize) return;
        if (this.IsShowYText[0]===false && this.IsShowYText[1]===false) return;

        this.DrawInsideClientHorizontal();

        var border=this.ChartBorder.GetHScreenBorder();
        var left = border.Left;
        var right = border.RightEx;
        var top=border.Top;
        var bottom=border.Bottom;
        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的值
            var yInsideText=null;
            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*pixelTatio, 0);
                    this.Canvas.restore();

                    if (yInsideText==null || yInsideText<xText)
                    {
                        this.YInsideOffset=this.Canvas.measureText(item.Message[0]).width+4*GetDevicePixelRatio();
                        yInsideText=xText;
                    }
                }

                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*pixelTatio, 0);
                    this.Canvas.restore();
                }
                yPrev = y;
            }
        }
    }

    this.GetLeftExtendXFromIndex=function(index, obj)
    {
        var count=obj.TotalCount-1;

        var border=this.ChartBorder.GetHScreenBorder();
        var left=border.Top;
        var width=this.ChartBorder.LeftExtendWidth;

        var offset=left+width*index/count;
        return offset;
    }

    this.GetLeftExtendXData=function(y, obj)
    {
        var count=obj.TotalCount-1;
        if (count<0) count=0;

        var border=this.ChartBorder.GetHScreenBorder();
        var left=border.Top;
        var right=border.TopEx;

        if (y<=left) return 0;
        if (y>=right) return count;

        var width=right-left;
        return (y-left)*(count*1.0/width);
    }

    this.GetLeftExtendYFromData=function(value,isLimit,obj)
    {
        if (!obj || !obj.Range) return this.GetYFromData(value,isLimit);

        var range=obj.Range;
        var border=this.ChartBorder.GetHScreenBorder();
        var width=border.RightEx-border.LeftEx;
        var offset=width*(value-range.Min)/(range.Max-range.Min);
        return border.LeftEx+offset;
    }

    this.GetLeftExtendYData=function(x, isLimit, obj)
    {
        if (!obj || !obj.Range) return this.GetYData(y,isLimit);

        var range=obj.Range;
        var border=this.ChartBorder.GetHScreenBorder();
        var width=border.RightEx-border.LeftEx;
        return (x-border.LeftEx)/width*(range.Max-range.Min)+range.Min;
    }

    this.GetRightExtendXFromIndex=function(index, obj)
    {
        var count=obj.TotalCount-1;

        var border=this.ChartBorder.GetHScreenBorder();
        var left=border.BottomEx;
        var width=this.ChartBorder.RightExtendWidth;

        var offset=left+width*index/count;
        return offset;
    }

    this.GetRightExtendXData=function(y, obj)
    {
        var count=obj.TotalCount-1;
        if (count<0) count=0;

        var border=this.ChartBorder.GetHScreenBorder();
        var left=border.BottomEx;
        var right=border.Bottom;

        if (y<=left) return 0;
        if (y>=right) return count;

        var width=right-left;
        return (y-left)*(count*1.0/width);
    }

    this.GetRightExtendYFromData=function(value,isLimit,obj)
    {
        if (!obj || !obj.Range) return this.GetYFromData(value,isLimit);

        return this.GetLeftExtendYFromData(value,isLimit,obj);
    }


}

function OverlayMinuteFrame()
{
    this.newMethod=MinuteFrame;     //派生
    this.newMethod();
    delete this.newMethod;

    this.ClassName="OverlayMinuteFrame";
    this.IsShow=true;               //坐标是否显示
    this.IsShareY=false;            //使用和主框架公用Y轴
    this.IsCalculateYMaxMin=true;   //是否计算Y最大最小值

    this.Draw=function()
    {
        this.SplitXYCoordinate();
        if (this.IsShow)
        {

        }

        this.SizeChange=false;
        this.XYSplit=false;
    }

    this.GetScaleTextWidth=function()
    {
        return { TextWidth:0 };
    }

    //分割x,y轴坐标信息
    this.SplitXYCoordinate=function()
    {
        if (this.XYSplit==false) return;

        if (this.IsShareY)  //和主图指标共享Y轴坐标
        {
            this.HorizontalMax=this.MainFrame.HorizontalMax;
            this.HorizontalMin=this.MainFrame.HorizontalMin;
            this.HorizontalInfo=[];
            for(var i in this.MainFrame.HorizontalInfo)
            {
                var item=this.MainFrame.HorizontalInfo[i];
                this.HorizontalInfo.push(item);
            }
        }
        else    //独立Y轴坐标
        {
            if (this.YSplitOperator!=null) this.YSplitOperator.Operator();
        }
        
        // if (this.XSplitOperator!=null) this.XSplitOperator.Operator(); 子坐标和主坐标X轴一致 所以不用计算
    }
}

function OverlayMinuteHScreenFrame()
{
    this.newMethod=MinuteHScreenFrame;     //派生
    this.newMethod();
    delete this.newMethod;

    this.ClassName="OverlayMinuteHScreenFrame";
    this.IsShow=true;                   //坐标是否显示

    this.Draw=function()
    {
        this.SplitXYCoordinate();
        if (this.IsShow)
        {

        }

        this.SizeChange=false;
        this.XYSplit=false;
    }

    //分割x,y轴坐标信息
    this.SplitXYCoordinate=function()
    {
        if (this.XYSplit==false) return;

        if (this.IsShareY)  //和主图指标共享Y轴坐标
        {
            this.HorizontalMax=this.MainFrame.HorizontalMax;
            this.HorizontalMin=this.MainFrame.HorizontalMin;
            this.HorizontalInfo=[];
            for(var i in this.MainFrame.HorizontalInfo)
            {
                var item=this.MainFrame.HorizontalInfo[i];
                this.HorizontalInfo.push(item);
            }
        }
        else    //独立Y轴坐标
        {
            if (this.YSplitOperator!=null) this.YSplitOperator.Operator();
        }
        
        // if (this.XSplitOperator!=null) this.XSplitOperator.Operator(); 子坐标和主坐标X轴一致 所以不用计算
    }
}

//K线框架
function KLineFrame()
{
    this.newMethod=AverageWidthFrame;   //派生
    this.newMethod();
    delete this.newMethod;

    this.ClassName='KLineFrame';
    this.ToolbarID=Guid();  //工具条Div id

    this.ModifyIndex=true;      //是否显示'改参数'菜单
    this.ChangeIndex=true;      //是否显示'换指标'菜单
    this.CloseIndex=true;       //是否显示'关闭指标窗口'菜单
    this.OverlayIndex=false;    //是否显示叠加指标

    this.ModifyIndexEvent;   //改参数 点击事件
    this.ChangeIndexEvent;   //换指标 点击事件
    this.ToolbarRect=null;   //保存工具条的位置
    this.ReDrawToolbar=false;

    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.RightSpaceCount=0;

    this.Logarithmic=null; //{Up:上部 , Donw:下部 , OpenPrice:第一个开盘价}

    this.DrawToolbar=function()
    {
        if (typeof($)=="undefined") return;
        
        if (!this.ChartBorder.UIElement || !this.ChartBorder.UIElement.parentNode) return;

        var divToolbar=document.getElementById(this.ToolbarID);
        if (divToolbar && this.SizeChange==false && this.ReDrawToolbar==false)  return;

        if (!divToolbar)
        {
            
            divToolbar=document.createElement("div");
            divToolbar.className='klineframe-toolbar';
            divToolbar.id=this.ToolbarID;
            divToolbar.oncontextmenu = function() { return false;}; //屏蔽右键系统菜单
            //为divToolbar添加属性identify
            divToolbar.setAttribute("identify",this.Identify.toString());
            this.ChartBorder.UIElement.parentNode.appendChild(divToolbar);
        }

        if ((!this.ModifyIndex && !this.ChangeIndex && !this.OverlayIndex && !this.CloseIndex))
        {
            if (divToolbar.style.display!='none')
                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;

        if (this.ToolbarRect)
        {
            //尺寸变动移动才重新设置DOM
            if (this.ToolbarRect.Left==left && this.ToolbarRect.Top==top && 
                this.ToolbarRect.Width==toolbarWidth && this.ToolbarRect.Height==toolbarHeight/pixelTatio)
            {
                return;
            }
        }

        this.ToolbarRect={ Left:left, Top:top, Width:toolbarWidth, Height:toolbarHeight/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.DrawFrame=function()
    {
        if (!this.IsMinSize)
        {
            this.SplitXYCoordinate();

            if (this.SizeChange==true) 
            {
                this.CalculateDataWidth();
                if (this.Logarithmic) this.SplitLogarithmicXYCoordinate();
            }
    
            if (this.DrawDepthMapCallback) this.DrawDepthMapCallback();
    
            this.DrawTitleBG();
            this.DrawHorizontal();
            this.DrawVertical();
        }
        
        if (this.SizeChange==true || this.ReDrawToolbar==true) 
        {
            this.DrawToolbar();  //大小变动才画工具条
            this.ReDrawToolbar=false;
        }
    }

    //isLimit 是否限制在当前屏坐标下
    this.GetXFromIndex=function(index,isLimit)
    {
        if (isLimit===false)
        {
            if (index>=0)
            {
                var offset=this.ChartBorder.GetLeft()+g_JSChartResource.FrameLeftMargin+this.DistanceWidth/2+this.DataWidth/2;
                for(var i=1;i<=index;++i)
                {
                    offset+=this.DistanceWidth+this.DataWidth;
                }
            }
            else
            {
                var offset=this.ChartBorder.GetLeft()-(this.DistanceWidth/2+this.DataWidth+this.DistanceWidth);
                var absIndex=Math.abs(index);
                for(var i=1;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()+g_JSChartResource.FrameLeftMargin+this.DistanceWidth/2+this.DataWidth/2;
            for(var i=1;i<=index;++i)
            {
                offset+=this.DistanceWidth+this.DataWidth;
            }
        }

        return offset;
    }

    //X坐标转x轴数值 isLimit=是否限制在当前屏坐标下
    this.GetXData=function(x,isLimit)
    {
        var distanceWidth=this.DistanceWidth;
        var dataWidth=this.DataWidth;
        var left=this.ChartBorder.GetLeft()+g_JSChartResource.FrameLeftMargin;

        if (isLimit==false)
        {
            if (x<this.ChartBorder.GetLeft())
            {
                var index=-1;
                var xPoint=this.ChartBorder.GetLeft()-(distanceWidth/2+dataWidth+distanceWidth);
                while(index>-10000)
                {
                    if (xPoint<=x) 
                        break;
                    xPoint-=(dataWidth+distanceWidth);
                    --index;
                }
    
                return index;
            }
            else
            {
                var index=0;
                var xPoint=left+distanceWidth/2+dataWidth+distanceWidth;
                while(index<10000)  //自己算x的数值
                {
                    if (xPoint>=x) break;
                    xPoint+=(dataWidth+distanceWidth);
                    ++index;
                }

                return index;
            }
        }
        else
        {
            if (x<=this.ChartBorder.GetLeft()) return 0;
            if (x>=this.ChartBorder.GetRight()) return this.XPointCount-1;
            
            var right=this.ChartBorder.GetRight()-g_JSChartResource.FrameRightMargin;
            var index=0;
            var xPoint=left+distanceWidth/2+dataWidth+distanceWidth;
            while(xPoint<right && index<10000 && index+1<this.XPointCount)  //自己算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.GetFrameWidth()-g_JSChartResource.FrameMargin;

        if (this.ZoomIndex>=0 && this.LastCalculateStatus.Width==width && this.LastCalculateStatus.XPointCount==this.XPointCount) //宽度没变 尝试使用原来的柱子宽度
        {
            var caclWidth=(this.DistanceWidth/2+g_JSChartResource.FrameLeftMargin)+(this.DataWidth + this.DistanceWidth)*(this.XPointCount-1);
            var caclWidth2=(this.DataWidth + this.DistanceWidth) * this.XPointCount;
            if (caclWidth<= 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.OnSize=function(obj)
    {
        var width=this.GetFrameWidth()-g_JSChartResource.FrameMargin;
        var xPointCount=0;
        var y=this.DistanceWidth/2+g_JSChartResource.FrameLeftMargin+(this.DataWidth+this.DistanceWidth);
        for(;y<width; y+=(this.DataWidth+this.DistanceWidth), ++xPointCount)
        {
            
        }

        obj.CurCount=this.XPointCount;
        obj.CalcCount=xPointCount;
        obj.DataWidth=this.DataWidth;
        obj.DistanceWidth=this.DistanceWidth;
        obj.Changed=false;

        this.LastCalculateStatus.Width=width;
        if (obj.CurCount==obj.CalcCount) return obj;

        this.XPointCount=xPointCount;
        this.LastCalculateStatus.XPointCount=this.XPointCount;
        if (this.Data)
        {
            this.Data.DataOffset+=(obj.CurCount-obj.CalcCount);
            if (this.Data.DataOffset<0) this.Data.DataOffset=0;
            obj.Changed=true;
        }
        return obj;
    }

    this.SetDataWidth=function(dataWidth)
    {
        var zoomIndex=ZOOM_SEED.length-1;
        for(var i in ZOOM_SEED)
        {
            var item=ZOOM_SEED[i];
            if (item[0]<=dataWidth) 
            {
                zoomIndex=parseInt(i)-1;
                break;
            }
        }

        this.ZoomIndex=zoomIndex;
        this.DataWidth=ZOOM_SEED[this.ZoomIndex][0];
        this.DistanceWidth=ZOOM_SEED[this.ZoomIndex][1];
        var width=this.GetFrameWidth()-g_JSChartResource.FrameMargin;
        var xPointCount=0;
        var y=this.DistanceWidth/2+g_JSChartResource.FrameLeftMargin+(this.DataWidth+this.DistanceWidth);
        for(;y<=width; y+=(this.DataWidth+this.DistanceWidth), ++xPointCount) { }

        this.XPointCount=xPointCount;
        this.LastCalculateStatus.XPointCount=this.XPointCount;
        this.LastCalculateStatus.Width=width;

        var obj={ XPointCount:this.XPointCount, DataWidth:this.DataWidth, DistanceWidth:this.DistanceWidth };
        return obj;
    }

    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();
        if (this.Logarithmic) this.SplitLogarithmicXYCoordinate();
    }

    this.SplitLogarithmicXYCoordinate=function()
    {
        var up=this.Logarithmic.Up;
        var down=this.Logarithmic.Down;
        var logHeight=0;    //对数额外高度
        var count=0;
        var maxCount=Math.max(up.length, down.length);

        var aryLogHeight=[];
        for(var i=0;i<maxCount;++i)
        {
            aryLogHeight[i]=i*2;
        }

        for(var i=0, j=aryLogHeight.length-1; i<up.length; ++i,--j)
        {
            var item=up[i];
            item.LogHeight=aryLogHeight[j];
            logHeight+=item.LogHeight;
            ++count;
        }

        for(var i=0, j=aryLogHeight.length-1;i<down.length; ++i,--j)
        {
            var item=down[i];
            item.LogHeight=aryLogHeight[j];
            logHeight+=item.LogHeight;
            ++count;
        }

        var heightRate=2*GetDevicePixelRatio(); 
        var top=this.ChartBorder.GetTopEx();
        var bottom=this.ChartBorder.GetBottomEx();
        var height=(bottom-top);
        var perHeight=(height-logHeight*heightRate)/count;
        if (perHeight<0) 
        {
            perHeight=0;
            heightRate=height/logHeight;
        }

        if (this.CoordinateType==1) //反转坐标
        {
            var itemTop=top;
            for(var i=down.length-1;i>=0;--i)   //上部
            {
                var item=down[i];
                item.Height=perHeight+(heightRate*item.LogHeight);
                item.Top=itemTop;
                item.Bottom=item.Top+item.Height;
                itemTop=item.Bottom;
            }

            var itemBottom=bottom;
            for(var i=up.length-1;i>=0;--i) //下部
            {   
                var item=up[i];
                item.Height=perHeight+(heightRate*item.LogHeight)
                item.Bottom=itemBottom;
                item.Top=itemBottom-item.Height;
                itemBottom=item.Top;
            }
        }
        else
        {
            var itemTop=top;
            for(var i=up.length-1;i>=0;--i)
            {
                var item=up[i];
                item.Height=perHeight+(heightRate*item.LogHeight);
                item.Top=itemTop;
                item.Bottom=item.Top+item.Height;
                itemTop=item.Bottom;
            }
    
            var itemBottom=bottom;
            for(var i=down.length-1;i>=0;--i)
            {
                var item=down[i];
                item.Height=perHeight+(heightRate*item.LogHeight)
                item.Bottom=itemBottom;
                item.Top=itemBottom-item.Height;
                itemBottom=item.Top;
            }
        }
        JSConsole.Chart.Log("[KLineFrame::SplitLogarithmicXYCoordinate]", this.Logarithmic);
    }

    this.GetYLogarithmicFromData=function(value, isLimit)
    {
        if (this.CoordinateType==1)
        {
            if(value<=this.HorizontalMin) return this.ChartBorder.GetTopEx();
            if(value>=this.HorizontalMax) return this.ChartBorder.GetBottomEx();

            if (value>this.Logarithmic.OpenPrice)
            {
                var up=this.Logarithmic.Up;
                for(var i in up)
                {
                    var item=up[i];
                    if (value>=item.Start && value<=item.End)
                    {
                        var itemHeight=item.Bottom-item.Top;
                        var height=itemHeight*(value-item.Start)/(item.End-item.Start);
                        return item.Top+height;
                    }
                }
            }
            else
            {
                var down=this.Logarithmic.Down;
                for(var i in down)
                {
                    var item=down[i];
                    if (value>=item.Start && value<=item.End)
                    {
                        var itemHeight=item.Bottom-item.Top;
                        var height=itemHeight*(value-item.Start)/(item.End-item.Start);
                        return item.Top+height;
                    }
                }
            }
        }
        else
        {
            if(value<=this.HorizontalMin) return this.ChartBorder.GetBottomEx();
            if(value>=this.HorizontalMax) return this.ChartBorder.GetTopEx();

            if (value>this.Logarithmic.OpenPrice)
            {
                var up=this.Logarithmic.Up;
                for(var i in up)
                {
                    var item=up[i];
                    if (value>=item.Start && value<=item.End)
                    {
                        var itemHeight=item.Bottom-item.Top;
                        var height=itemHeight*(value-item.Start)/(item.End-item.Start);
                        return item.Bottom-height;
                    }
                }
            }
            else
            {
                var down=this.Logarithmic.Down;
                for(var i in down)
                {
                    var item=down[i];
                    if (value>=item.Start && value<=item.End)
                    {
                        var itemHeight=item.Bottom-item.Top;
                        var height=itemHeight*(value-item.Start)/(item.End-item.Start);
                        return item.Bottom-height;
                    }
                }
            }
        }
    }

    this.GetYLogarithmicData=function(y)
    {
        if (this.CoordinateType==1) //反转坐标
        {
            if (y<this.ChartBorder.GetTopEx()) return this.HorizontalMin;
            if (y>this.ChartBorder.GetBottomEx()) return this.HorizontalMax;

            var up=this.Logarithmic.Up;
            for(var i in up)
            {
                var item=up[i];
                if (y>=item.Top && y<=item.Bottom)
                {
                    return (y-item.Top)/item.Height*(item.End-item.Start)+item.Start;
                }
            }

            var down=this.Logarithmic.Down;
            for(var i in down)
            {
                var item=down[i];
                if (y>=item.Top && y<=item.Bottom)
                {
                    return (y-item.Top)/item.Height*(item.End-item.Start)+item.Start;
                }
            }
        }
        else
        {
            if (y<this.ChartBorder.GetTopEx()) return this.HorizontalMax;
            if (y>this.ChartBorder.GetBottomEx()) return this.HorizontalMin;

            var up=this.Logarithmic.Up;
            for(var i in up)
            {
                var item=up[i];
                if (y>=item.Top && y<=item.Bottom)
                {
                    return (item.Bottom-y)/item.Height*(item.End-item.Start)+item.Start;
                }
            }

            var down=this.Logarithmic.Down;
            for(var i in down)
            {
                var item=down[i];
                if (y>=item.Top && y<=item.Bottom)
                {
                    return (item.Bottom-y)/item.Height*(item.End-item.Start)+item.Start;
                }
            }
        }
    }

    this.CalculateCount=function(zoomIndex)
    {
        var width=this.GetFrameWidth()-g_JSChartResource.FrameMargin;
        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 dataCount=this.Data.Data.length;
        var maxDataCount=dataCount+this.RightSpaceCount;

        var rightSpaceCount=0;
        var lastDataIndex = this.Data.DataOffset + this.XPointCount - 1;    //最右边的数据索引
        var lastCursorIndex=this.Data.DataOffset + cursorIndex.Index;
        if (lastDataIndex>=dataCount) 
        {
            rightSpaceCount=lastDataIndex-(this.Data.Data.length-1);    //计算右边预留空间
            lastDataIndex=this.Data.Data.length-1;
            if (rightSpaceCount>this.RightSpaceCount) rightSpaceCount=this.RightSpaceCount;
        }

        var xPointCount=this.CalculateCount(this.ZoomIndex-1);
        JSConsole.Chart.Log(`[KLineFrame::ZoomUp] old status. XPointCount=${xPointCount} ZoomIndex=${this.ZoomIndex} DataCount= ${this.Data.Data.length} rightSpaceCount=${rightSpaceCount}`);

        var isShowAll=false;
        --this.ZoomIndex;
        if (cursorIndex.IsLockRight==true) //固定右边
        {
            var rightDataIndex=this.Data.DataOffset + this.XPointCount;    //最右边的数据索引
            if (xPointCount>rightDataIndex)
            {
                xPointCount=rightDataIndex;
                this.XPointCount=xPointCount;
                this.Data.DataOffset=0;
            }
            else
            {
                var dataOffset=lastDataIndex - (xPointCount-rightSpaceCount)+1;
                this.XPointCount=xPointCount;
                this.Data.DataOffset=dataOffset;
                if (this.Data.DataOffset<0) this.Data.DataOffset=0;
            }
        }
        else if (xPointCount>=maxDataCount) 
        {
            //xPointCount=maxDataCount;
            //this.XPointCount=xPointCount;
            this.Data.DataOffset=0;
            this.XPointCount=xPointCount;
            isShowAll=true;
            JSConsole.Chart.Log(`[KLineFrame::ZoomUp] Show all data. XPointCount=${xPointCount} ZoomIndex=${this.ZoomIndex} DataCount= ${dataCount}`);
        }
        else
        {
            var dataOffset=lastDataIndex - (xPointCount-rightSpaceCount)+1;
            if (cursorIndex.ZoomType==1)    //以十字光标为中心左右放大
            {
                var moveOffset=(this.XPointCount-xPointCount)+1;
                var leftOffset=parseInt(cursorIndex.Index/this.XPointCount*moveOffset);
                var rightOffset=moveOffset-leftOffset;
                var offset=this.Data.DataOffset+leftOffset;
                if (offset<dataCount) dataOffset=this.Data.DataOffset+leftOffset;
            }

            this.XPointCount=xPointCount;
            this.Data.DataOffset=dataOffset;
            if (this.Data.DataOffset<0) this.Data.DataOffset=0;

            JSConsole.Chart.Log(`[KLineFrame::ZoomUp] calculate. XPointCount=${xPointCount} ZoomIndex=${this.ZoomIndex} DataCount= ${dataCount} DataOffset=${this.Data.DataOffset}`);
        }
       
        this.DataWidth = ZOOM_SEED[this.ZoomIndex][0];
        this.DistanceWidth = ZOOM_SEED[this.ZoomIndex][1];
        if (!isShowAll)
        {
            var width=this.GetFrameWidth()-g_JSChartResource.FrameMargin;
            this.TrimKLineDataWidth(width);
        }
        this.LastCalculateStatus.XPointCount=this.XPointCount;
        cursorIndex.Index=lastCursorIndex-this.Data.DataOffset;

        return true;
    }

    this.XCoordinateZoom=function(isMoveLeft)
    {
        var oldXPointCount=this.XPointCount;
        if (isMoveLeft) //放大  右边固定
        {
            if (this.ZoomIndex<=0) return false;
            if (this.Data.DataOffset<0) return false;
            var zoomIndex=this.ZoomIndex-1;
            var xPointCount=this.CalculateCount(zoomIndex);
            var dataCount=this.Data.Data.length;
            var moveOffset=oldXPointCount-xPointCount;
            if (moveOffset<=0) return false;
            this.Data.DataOffset+=moveOffset;
            if (this.Data.DataOffset>dataCount) this.Data.DataOffset=0;
        }
        else    //缩小
        {
            if (this.ZoomIndex+1>=ZOOM_SEED.length) return false;
            if (this.Data.DataOffset<0) return false;
            var zoomIndex=this.ZoomIndex+1;
            var xPointCount=this.CalculateCount(zoomIndex);

            var moveOffset=xPointCount-oldXPointCount;
            this.Data.DataOffset-=moveOffset;
            if (this.Data.DataOffset<0) this.Data.DataOffset=0;
        }
        
        
        //JSConsole.Chart.Log(`[KLineFrame::XCoordinateZoom] old (XPointCount=${oldXPointCount} ZoomIndex=${this.ZoomIndex})  DataCount= ${this.Data.Data.length} `);

        this.XPointCount=xPointCount;
        this.ZoomIndex=zoomIndex;
        this.DataWidth = ZOOM_SEED[this.ZoomIndex][0];
        this.DistanceWidth = ZOOM_SEED[this.ZoomIndex][1];
        var width=this.GetFrameWidth()-g_JSChartResource.FrameMargin;
        this.TrimKLineDataWidth(width);
        
        this.LastCalculateStatus.XPointCount=this.XPointCount;

        return true;
        //var lastCursorIndex=this.Data.DataOffset + cursorIndex.Index;

        
    }

    this.ZoomDown=function(cursorIndex) //缩小
    {
        if (this.ZoomIndex+1>=ZOOM_SEED.length) return false;
        if (this.Data.DataOffset<0) return false;
        var dataCount=this.Data.Data.length;
        var maxDataCount=dataCount+this.RightSpaceCount;
        //if (this.XPointCount>=maxDataCount) return false;

        var rightSpaceCount=0;
        var lastDataIndex = this.Data.DataOffset + this.XPointCount - 1;    //最右边的数据索引
        if (lastDataIndex>=this.Data.Data.length) 
        {
            rightSpaceCount=lastDataIndex-(this.Data.Data.length-1);    //计算右边预留空间
            lastDataIndex=this.Data.Data.length-1;
            if (rightSpaceCount>this.RightSpaceCount) rightSpaceCount=this.RightSpaceCount;
        }

        var xPointCount=this.CalculateCount(this.ZoomIndex+1);
        var lastCursorIndex=this.Data.DataOffset + cursorIndex.Index;

        JSConsole.Chart.Log(`[KLineFrame::ZoomDown] old status. XPointCount=${xPointCount} ZoomIndex=${this.ZoomIndex} DataCount= ${this.Data.Data.length} lastCursorIndex=${lastCursorIndex} rightSpaceCount=${rightSpaceCount}`);

        var isShowAll=false;
        ++this.ZoomIndex;
        if (cursorIndex.IsLockRight==true) //固定右边
        {
            var rightDataIndex=this.Data.DataOffset + this.XPointCount;    //最右边的数据索引
            if (xPointCount>rightDataIndex)
            {
                xPointCount=rightDataIndex;
                this.XPointCount=xPointCount;
                this.Data.DataOffset=0;
            }
            else
            {
                var dataOffset=lastDataIndex - (xPointCount-rightSpaceCount)+1;
                this.XPointCount=xPointCount;
                this.Data.DataOffset=dataOffset;
                if (this.Data.DataOffset<0) this.Data.DataOffset=0;
            }
        }
        else if (xPointCount>=maxDataCount)     //所有数据无法显示完一屏
        {
            //xPointCount=maxDataCount;
            this.XPointCount=xPointCount;
            this.Data.DataOffset=0;
            isShowAll=true; //数据铺满全屏, 不需要调整宽度
            JSConsole.Chart.Log(`[KLineFrame::ZoomDown] Show all data. XPointCount=${xPointCount} ZoomIndex=${this.ZoomIndex} DataCount= ${dataCount}`);
        }
        else
        {
            var dataOffset=lastDataIndex - (xPointCount-rightSpaceCount)+1;
            if (cursorIndex.ZoomType==1)    //当前十字光标位置左右同时缩小
            {
                var moveOffset=(xPointCount-this.XPointCount)+1;
                var leftOffset=parseInt(cursorIndex.Index/this.XPointCount*moveOffset);
                var rightOffset=moveOffset-leftOffset;
                var dataOffset=this.Data.DataOffset-leftOffset;
                if (dataOffset+(xPointCount-this.RightSpaceCount)>=dataCount) dataOffset=this.Data.DataOffset-moveOffset;
            }

            this.XPointCount=xPointCount;
            this.Data.DataOffset=dataOffset;
            if (this.Data.DataOffset<0) this.Data.DataOffset=0;

            JSConsole.Chart.Log(`[KLineFrame::ZoomDown] calculate. XPointCount=${xPointCount} ZoomIndex=${this.ZoomIndex} DataCount= ${dataCount} DataOffset=${this.Data.DataOffset}`);
        }

        this.DataWidth = ZOOM_SEED[this.ZoomIndex][0];
        this.DistanceWidth = ZOOM_SEED[this.ZoomIndex][1];
        if (!isShowAll) 
        {
            var width=this.GetFrameWidth()-g_JSChartResource.FrameMargin;
            this.TrimKLineDataWidth(width);
        }
        this.LastCalculateStatus.XPointCount=this.XPointCount;
        cursorIndex.Index=lastCursorIndex-this.Data.DataOffset;

        return true;
    }

    this.GetFrameWidth=function()
    {
        if (this.IsHScreen) 
        {
            var border=this.ChartBorder.GetHScreenBorder();
            return border.BottomEx-border.TopEx;
            //return this.ChartBorder.GetHeight();
        }
        else
        {
            var border=this.ChartBorder.GetBorder();
            return border.RightEx-border.LeftEx;
            //return this.ChartBorder.GetWidth();
        }
    }

    this.DrawCustomHorizontal=function()    //Y轴刻度定制显示
    {
        if (this.IsMinSize) return;
        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.ClassName='OverlayKLineFrame';

    this.MainFrame=null;    //主框架
    this.IsShareY=false;    //使用和主框架公用Y轴
    this.IsCalculateYMaxMin=true;   //是否计算Y最大最小值
    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 border=this.ChartBorder.GetBorder();
        var top = this.ChartBorder.GetTopTitle();
        var bottom = border.Bottom;
        var right=border.Right;
        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();
    }

    this.GetScaleTextWidth=function()
    {
        if (!this.IsShow) return null;

        var border=this.ChartBorder.GetBorder();
        var pixelTatio = GetDevicePixelRatio(); //获取设备的分辨率
        if (this.IsHScreen)
        {
            var borderBottom=this.ChartBorder.Bottom;
            var isDrawRight=borderBottom>10*pixelTatio && this.IsShowYText[1]===true && this.YTextPosition[1]!=2;
        }
        else
        {
            var borderRight=this.ChartBorder.Right;
            var isDrawRight=borderRight>10 && this.IsShowYText[1]===true && this.YTextPosition[1]!=2;
        }
        
        if (!isDrawRight) return null;

        var width={ Left:null, Right:0 };
        for(var i=0;i<this.HorizontalInfo.length;++i)
        {
            var textWidth=null;
            var item=this.HorizontalInfo[i];
            if (!item) continue;

            if (item.Message[1]!=null && isDrawRight)
            {
                if (item.Font!=null) this.Canvas.font=item.Font;

                textWidth=this.Canvas.measureText(item.Message[1]).width;
                if (width.Right<textWidth) width.Right=textWidth;
            }
        }

        return { TextWidth:width };
    }

    //分割x,y轴坐标信息
    this.SplitXYCoordinate=function()
    {
        if (this.XYSplit==false) return;

        if (this.IsShareY)  //和主图指标共享Y轴坐标
        {
            this.HorizontalMax=this.MainFrame.HorizontalMax;
            this.HorizontalMin=this.MainFrame.HorizontalMin;
            this.HorizontalInfo=[];
            for(var i in this.MainFrame.HorizontalInfo)
            {
                var item=this.MainFrame.HorizontalInfo[i];
                this.HorizontalInfo.push(item);
            }

            this.CoordinateType=this.MainFrame.CoordinateType;
        }
        else    //独立Y轴坐标
        {
            if (this.YSplitOperator!=null) this.YSplitOperator.Operator();
        }
        
        // if (this.XSplitOperator!=null) this.XSplitOperator.Operator(); 子坐标和主坐标X轴一致 所以不用计算
    }

    //画Y轴
    this.DrawHorizontal=function()
    {
        var border=this.ChartBorder.GetBorder();
        var left=border.Left;
        var right=border.Right;
        var bottom = border.Bottom;
        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;

                var text=item.Message[1];
                if (Array.isArray(item.Message[1])) text=item.Message[1][0];
               
                this.Canvas.fillStyle=item.TextColor;
                this.Canvas.textAlign="left";
                this.Canvas.fillText(text,right+2,y);
            }

            yPrev=y;
        }
    }

    //画X轴
    this.DrawVertical=function()
    {
        var border=this.ChartBorder.GetBorder();
        var top=border.TopEx;
        //var left=this.ChartBorder.GetLeft();
        var right=border.Right;
        var bottom=border.BottomEx;
        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.ClassName='KLineHScreenFrame';
    this.IsHScreen=true;        //是否是横屏

    //画标题背景色
    this.DrawTitleBG=function()
    {
        if (this.ChartBorder.TitleHeight<=0) return;

        var border=this.ChartBorder.GetHScreenBorder();
        var left=ToFixedPoint(border.RightTitle);
        var top=ToFixedPoint(border.Top);
        var bottom=ToFixedPoint(border.Bottom);
        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,isLimit)
    {
        var border=this.ChartBorder.GetHScreenBorder();
        if (isLimit===false)
        {
            var width=(border.RightEx-border.LeftEx)*(value-this.HorizontalMin)/(this.HorizontalMax-this.HorizontalMin);
            return border.LeftEx+width;
        }
        else
        {
            if(value<=this.HorizontalMin) return border.LeftEx;
            if(value>=this.HorizontalMax) return border.RightEx;
    
            var width=(border.RightEx-border.LeftEx)*(value-this.HorizontalMin)/(this.HorizontalMax-this.HorizontalMin);
            return border.LeftEx+width;
        }
    }

    //画Y轴
    this.DrawHorizontal=function()
    {
        var border=this.ChartBorder.GetHScreenBorder();
        var top=border.Top;
        var bottom=border.Bottom;
        var borderTop=this.ChartBorder.Top;
        var borderBottom=this.ChartBorder.Bottom;
        var left=border.Left;
        var right=border.Right;

        var yPrev=null; //上一个坐标y的值
        var pixelTatio = GetDevicePixelRatio(); //获取设备的分辨率

        var isDrawLeft=borderTop>10*pixelTatio && this.IsShowYText[0]===true && this.YTextPosition[0]!=2;
        var isDrawRight=borderBottom>10*pixelTatio && this.IsShowYText[1]===true && this.YTextPosition[1]!=2;

        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!=left)
            {
                if (item.LineType==2)
                {
                    this.Canvas.strokeStyle=item.LineColor;
                    this.Canvas.setLineDash([5*pixelTatio,5*pixelTatio]);   //虚线
                    this.Canvas.beginPath();
                    this.Canvas.moveTo(ToFixedPoint(y),top);
                    this.Canvas.lineTo(ToFixedPoint(y),bottom);
                    this.Canvas.stroke();
                    this.Canvas.setLineDash([]);
                }
                else if (item.LineType>0)
                {
                    this.Canvas.strokeStyle=item.LineColor;
                    if (g_JSChartResource.FrameYLineDash)
                    {
                        this.Canvas.setLineDash(g_JSChartResource.FrameYLineDash);   //虚线
                        this.Canvas.beginPath();
                        this.Canvas.moveTo(ToFixedPoint(y),top);
                        this.Canvas.lineTo(ToFixedPoint(y),bottom);
                        this.Canvas.stroke();
                        this.Canvas.setLineDash([]);
                    }
                    else
                    {
                        this.Canvas.beginPath();
                        this.Canvas.moveTo(ToFixedPoint(y),top);
                        this.Canvas.lineTo(ToFixedPoint(y),bottom);
                        this.Canvas.stroke();
                    }
                }
            }
            
            //坐标信息 左边 间距小于10 不画坐标
            if (item.Message[0]!=null && isDrawLeft)
            {
                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 && isDrawRight)
            {
                if (item.Font!=null) this.Canvas.font=item.Font;

                this.Canvas.fillStyle=item.TextColor;
                this.Canvas.textAlign="left";
                this.Canvas.textBaseline="middle";
                var text;
                if (Array.isArray(item.Message[1])) //横屏只支持单行
                {
                    text=item.Message[1][0];
                }
                else
                {
                    text=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(text, 2, 0);
                this.Canvas.restore();
            }

            yPrev=y;
        }
    }

    //Y刻度画在左边内部
    this.DrawInsideHorizontal = function () 
    {
        if (this.IsMinSize) return;
        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();
        
        var isDrawLeft= (borderTop<10*pixelTatio || this.YTextPosition[0]==2) && this.IsShowYText[0]===true;
        var isDrawRight= (borderBottom<10*pixelTatio || this.YTextPosition[1]==2) && this.IsShowYText[1]===true;

        if ( isDrawLeft || isDrawRight )
        {
            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 && isDrawLeft) 
                {
                    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 && isDrawRight)
                {
                    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 border=this.ChartBorder.GetHScreenBorder();
        var offset=border.TopEx+ g_JSChartResource.FrameLeftMargin + 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 border=this.ChartBorder.GetHScreenBorder();
        var left=border.Left;
        var right=border.RightTitle;
        var bottom=border.Bottom;
        var pixelRatio = GetDevicePixelRatio(); //获取设备的分辨率
        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;

            var item=this.VerticalInfo[i];
            if (item.LineType==2)
            {
                this.Canvas.strokeStyle=this.VerticalInfo[i].LineColor;
                this.Canvas.setLineDash([5*pixelRatio,5*pixelRatio]);   //虚线
                this.Canvas.beginPath();
                this.Canvas.moveTo(left,ToFixedPoint(x));
                this.Canvas.lineTo(right,ToFixedPoint(x));
                this.Canvas.stroke();
                this.Canvas.setLineDash([]);
            }
            else if (item.LineType>0)
            {
                this.Canvas.strokeStyle=this.VerticalInfo[i].LineColor;
                if (g_JSChartResource.FrameXLineDash)
                {
                    this.Canvas.setLineDash(g_JSChartResource.FrameXLineDash);   //虚线
                    this.Canvas.beginPath();
                    this.Canvas.moveTo(left,ToFixedPoint(x));
                    this.Canvas.lineTo(right,ToFixedPoint(x));
                    this.Canvas.stroke();
                    this.Canvas.setLineDash([]);
                }
                else    //实线
                {
                    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, this.XBottomOffset);
                this.Canvas.restore();
            }

            xPrev=x;
        }
    }

    //Y坐标转y轴数值
    this.GetYData=function(x)
    {
        var border=this.ChartBorder.GetHScreenBorder();
        if (x<border.LeftEx) return this.HorizontalMin;
		if (x>border.RightEx) return this.HorizontalMax;

        var width=border.RightEx-border.LeftEx;
		return (x-border.LeftEx)/width*(this.HorizontalMax-this.HorizontalMin)+this.HorizontalMin;
    }

    //X坐标转x轴数值
    this.GetXData=function(y)
    {
        var border=this.ChartBorder.GetHScreenBorder();
        if (y<=border.TopEx) return 0;
		if (y>=border.BottomEx) return this.XPointCount-1;

        var left=border.TopEx;
        var right=border.BottomEx;
        var distanceWidth=this.DistanceWidth;
        var dataWidth=this.DataWidth;

        var index=0;
        var xPoint=left+distanceWidth/2+ dataWidth+distanceWidth;
        while(xPoint<right && index<10000 && index+1<this.XPointCount)  //自己算x的数值
        {
            if (xPoint>y) break;
            xPoint+=(dataWidth+distanceWidth);
            ++index;
        }
        return index;

		//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()-g_JSChartResource.FrameMargin;

        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.ZoomUp=function(cursorIndex)
    {
        if (this.ZoomIndex<=0) return false;
        if (this.Data.DataOffset<0) return false;
        var dataCount=this.Data.Data.length;
        var maxDataCount=dataCount+this.RightSpaceCount;
        if (this.XPointCount>=dataCount) return false;

        var rightSpaceCount=0;
        var lastDataIndex = this.Data.DataOffset + this.XPointCount - 1;    //最右边的数据索引
        var lastCursorIndex=this.Data.DataOffset + cursorIndex.Index;
        if (lastDataIndex>=dataCount) 
        {
            rightSpaceCount=lastDataIndex-(dataCount-1);    //计算右边预留空间
            lastDataIndex=dataCount-1;
            if (rightSpaceCount>this.RightSpaceCount) rightSpaceCount=this.RightSpaceCount;
        }
        
        var xPointCount=this.CalculateCount(this.ZoomIndex-1);
        JSConsole.Chart.Log(`[KLineHScreenFrame::ZoomUp] old status. XPointCount=${xPointCount} ZoomIndex=${this.ZoomIndex} DataCount= ${this.Data.Data.length} rightSpaceCount=${rightSpaceCount}`);
        
        --this.ZoomIndex;
        if (xPointCount>=maxDataCount) 
        {
            xPointCount=maxDataCount;
            this.XPointCount=xPointCount;
            this.Data.DataOffset=0;

            JSConsole.Chart.Log(`[KLineHScreenFrame::ZoomUp] Show all data. XPointCount=${xPointCount} ZoomIndex=${this.ZoomIndex} DataCount= ${dataCount}`);
        }
        else
        {
            this.XPointCount=xPointCount;
            this.Data.DataOffset = lastDataIndex - (this.XPointCount-rightSpaceCount)+1;

            JSConsole.Chart.Log(`[KLineHScreenFrame::ZoomUp] calculate. XPointCount=${xPointCount} ZoomIndex=${this.ZoomIndex} DataCount= ${dataCount} DataOffset=${this.Data.DataOffset}`);
        }

        this.DataWidth = ZOOM_SEED[this.ZoomIndex][0];
	    this.DistanceWidth = ZOOM_SEED[this.ZoomIndex][1];
        var width=this.ChartBorder.GetHeight()-g_JSChartResource.FrameMargin;
        this.TrimKLineDataWidth(width);
        this.LastCalculateStatus.XPointCount=this.XPointCount;
        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 dataCount=this.Data.Data.length;
        var maxDataCount=dataCount+this.RightSpaceCount;
        if (this.XPointCount>=dataCount) return false;

        var rightSpaceCount=0;
        var lastDataIndex = this.Data.DataOffset + this.XPointCount - 1;    //最右边的数据索引
        if (lastDataIndex>=this.Data.Data.length) 
        {
            rightSpaceCount=lastDataIndex-(this.Data.Data.length-1);    //计算右边预留空间
            lastDataIndex=this.Data.Data.length-1;
            if (rightSpaceCount>this.RightSpaceCount) rightSpaceCount=this.RightSpaceCount;
        }

        var xPointCount=this.CalculateCount(this.ZoomIndex+1);
        var lastCursorIndex=this.Data.DataOffset + cursorIndex.Index;
        JSConsole.Chart.Log(`[KLineHScreenFrame::ZoomDown] old status. XPointCount=${xPointCount} ZoomIndex=${this.ZoomIndex} DataCount= ${this.Data.Data.length} lastCursorIndex=${lastCursorIndex} rightSpaceCount=${rightSpaceCount}`);

        ++this.ZoomIndex;
        if (xPointCount>=maxDataCount) 
        {
            xPointCount=maxDataCount;
            this.XPointCount=xPointCount;
            this.Data.DataOffset=0;
            
            JSConsole.Chart.Log(`[KLineHScreenFrame::ZoomDown] Show all data. XPointCount=${xPointCount} ZoomIndex=${this.ZoomIndex} DataCount= ${dataCount}`);
        }
        else
        {
            this.XPointCount=xPointCount;
            this.Data.DataOffset = lastDataIndex - (this.XPointCount-rightSpaceCount)+1;

            JSConsole.Chart.Log(`[KLineHScreenFrame::ZoomDown] calculate. XPointCount=${xPointCount} ZoomIndex=${this.ZoomIndex} DataCount= ${dataCount} DataOffset=${this.Data.DataOffset}`);
        }

        this.DataWidth = ZOOM_SEED[this.ZoomIndex][0];
	    this.DistanceWidth = ZOOM_SEED[this.ZoomIndex][1];
        var width=this.ChartBorder.GetHeight()-g_JSChartResource.FrameMargin;
        this.TrimKLineDataWidth(width);
        this.LastCalculateStatus.XPointCount=this.XPointCount;
        cursorIndex.Index=lastCursorIndex-this.Data.DataOffset;

        return true;
    }
    */
}


function OverlayKLineHScreenFrame()
{
    this.newMethod=KLineHScreenFrame;   //派生
    this.newMethod();
    delete this.newMethod;

    this.ClassName='OverlayKLineHScreenFrame';
    this.MainFrame=null;    //主框架
    this.IsShareY=false;    //使用和主框架公用Y轴
    this.IsCalculateYMaxMin=true;   //是否计算Y最大最小值
    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.IsShareY)  //和主图指标共享Y轴坐标
        {
            this.HorizontalMax=this.MainFrame.HorizontalMax;
            this.HorizontalMin=this.MainFrame.HorizontalMin;
            this.HorizontalInfo=[];
            for(var i in this.MainFrame.HorizontalInfo)
            {
                var item=this.MainFrame.HorizontalInfo[i];
                this.HorizontalInfo.push(item);
            }
        }
        else
        {
            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();
        */
    }

    this.GetScaleTextWidth=function()
    {
        return { TextWidth:0 };
    }
}

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.IsShareY)    //共享Y轴坐标
        {
            this.Frame.XYSplit=true;
            return;
        }

        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 (IFrameSplitOperator.IsNumber(range.Max))
                {
                    if (value.Max==null || value.Max<range.Max) value.Max=range.Max;
                }

                if (IFrameSplitOperator.IsNumber(range.Min))
                {
                    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.MinSubFrameHeight=g_JSChartResource.DragSubFrameBorder.MinFrameHeight;
    this.DragBorderHeight=g_JSChartResource.DragSubFrameBorder.TopBorderHeight; //拖拽边框高度

    this.AutoLeftBorder=null;       //{ Blank:10 留白宽度, MinWidth:最小宽度 }
    this.AutoRightBorder=null;      //{ Blank:10 留白宽度, MinWidth:最小宽度 } 
    this.OverlayBlankWidth=40;
    this.AuotRightWidth;            //右边主坐标刻度宽度

    this.ZoomWindowsInfo=null;      //附图指标缩放,备份信息
    this.ZoomStartWindowIndex=1;    //允许缩放窗口起始位置

    this.OnMoveFromeBorder=function(index, yMove)
    {
        if (this.SubFrame.length<=0) return false;

        var topFrame=this.SubFrame[index];
        var bottomFrame=null;
        for(var i=index+1;i<this.SubFrame.length;++i)
        {
            var item=this.SubFrame[i];
            if (item.Height>0)
            {
                bottomFrame=item;
                break;
            }
        }

        if (!topFrame || !bottomFrame) return false;

        var bottomBackup=topFrame.Frame.ChartBorder.Bottom;
        var topBackup=bottomFrame.Frame.ChartBorder.Top;

        topFrame.Frame.ChartBorder.Bottom-=yMove;
        bottomFrame.Frame.ChartBorder.Top+=yMove;

        var height=topFrame.Frame.ChartBorder.GetHeightEx();
        var height2=bottomFrame.Frame.ChartBorder.GetHeightEx();
        
        //缩小的时候 小于最小高度 不处理
        if ((height<this.MinSubFrameHeight && yMove<0) || (height2<this.MinSubFrameHeight && yMove>0)) 
        {
            topFrame.Frame.ChartBorder.Bottom=bottomBackup;
            bottomFrame.Frame.ChartBorder.Top=topBackup;
            return false;
        }
        
        return true;
    }

    this.ReDrawToolbar=function()
    {
        for(var i in this.SubFrame)
        {
            this.SubFrame[i].Frame.ReDrawToolbar=true;
        }
    }

    this.SetFrameBorderSizeChange=function()
    {
        var firstFrame=this.SubFrame[0];
        if (!firstFrame || !firstFrame.Frame) return;

        var splitOper=firstFrame.Frame.YSplitOperator;  
        if (!splitOper) return;
        if (splitOper.CoordinateType==2) //对数坐标 需要重新计算Y轴分割
        {
            firstFrame.Frame.XYSplit=true;
        }
    }

    this.CancelZoomUpDownFrameY=function(obj)
    {
        var index=obj.Index;
        if (this.SubFrame.length<=0) return false;
        if (!this.SubFrame[index]) return false;

        var subFrame=this.SubFrame[index];
        var frame=subFrame.Frame;
        var splitOper=frame.YSplitOperator;

        if (splitOper.FixedYMaxMin)
        {
            splitOper.FixedYMaxMin=null;
            splitOper.EnableZoomUpDown=false;
            frame.XYSplit=true;
            for(var i in subFrame.OverlayIndex)
            {
                var item=subFrame.OverlayIndex[i];
                if (item.Frame.IsShareY) item.Frame.XYSplit=true;
            }
            
            JSConsole.Chart.Log(`[HQTradeFrame::CancelZoomUpDownFrameY]`);
            return true;
        }

        return false;
    }

    this.OnZoomUpDownFrameY=function(obj, yMove)
    {
        var index=obj.Index;
        if (this.SubFrame.length<=0) return false;
        if (!this.SubFrame[index]) return false;

        var subFrame=this.SubFrame[index];
        var frame=subFrame.Frame;
        var top=frame.ChartBorder.GetTopEx();
        var bottom=frame.ChartBorder.GetBottomEx();

        var maxValue=frame.HorizontalMax;
        var minValue=frame.HorizontalMin;

        var moveStep=(maxValue-minValue)*Math.abs(yMove)/(bottom-top);

        var splitOper=frame.YSplitOperator;

        var newFixedYMaxMin={ Max:maxValue, Min:minValue };
        if (obj.Position==1)
        {
            var step=yMove>0 ? -moveStep:moveStep;
            newFixedYMaxMin.Max+=step;
        }
        else if (obj.Position==2)
        {
            var step=yMove>0 ? -moveStep:moveStep;
            newFixedYMaxMin.Min+=step;
        }
        else if (obj.Position==0)
        {
            var step=yMove>0 ? moveStep:-moveStep;
            newFixedYMaxMin.Max+=step;
            newFixedYMaxMin.Min-=step;
        }
        else
        {
            return false;
        }

        if (newFixedYMaxMin.Max>newFixedYMaxMin.Min) 
        {
            splitOper.FixedYMaxMin=newFixedYMaxMin;
            splitOper.EnableZoomUpDown=true;
            frame.XYSplit=true;

            for(var i in subFrame.OverlayIndex)
            {
                var item=subFrame.OverlayIndex[i];
                if (item.Frame.IsShareY) item.Frame.XYSplit=true;
            }
            
            JSConsole.Chart.Log(`[HQTradeFrame::OnZoomUpDownFrameY] Max=${newFixedYMaxMin.Max}, Min=${newFixedYMaxMin.Min}`);
            return true;
        }

        return false;
    }

    this.OnUpDonwFrameY=function(obj, yMove)
    {
        var index=obj.Index;
        if (this.SubFrame.length<=0) return false;
        if (!this.SubFrame[index]) return false;

        var subFrame=this.SubFrame[index];
        var frame=subFrame.Frame;
        var top=frame.ChartBorder.GetTopEx();
        var bottom=frame.ChartBorder.GetBottomEx();
        var splitOper=frame.YSplitOperator;
        if (!splitOper) return false;

        var maxValue=frame.HorizontalMax;
        var minValue=frame.HorizontalMin;

        var moveStep=(maxValue-minValue)*Math.abs(yMove)/(bottom-top);
        var step=yMove>0 ? -moveStep:moveStep;
        var newFixedYMaxMin={ Max:maxValue, Min:minValue };
        newFixedYMaxMin.Max-=step;
        newFixedYMaxMin.Min-=step;

        splitOper.FixedYMaxMin=newFixedYMaxMin;
        splitOper.EnableZoomUpDown=true;
        frame.XYSplit=true;

        for(var i in subFrame.OverlayIndex)
        {
            var item=subFrame.OverlayIndex[i];
            if (item.Frame.IsShareY) item.Frame.XYSplit=true;
        }
        
        JSConsole.Chart.Log(`[HQTradeFrame::OnUpDonwFrameY] Max=${newFixedYMaxMin.Max}, Min=${newFixedYMaxMin.Min}, yMove=${yMove}, moveStep=${moveStep}`);
        return true;
    }

    this.ClearUpDonwFrameYData=function(option)   //清空上下拖拽的数据
    {
        if (this.SubFrame.length<=0) return;

        if (option)
        {
            var index=option.Index;
            if (index<0 || index>=this.SubFrame.length) return;

            var item=this.SubFrame[index];
            if (!item || !item.Frame || !item.Frame.YSplitOperator) return;

            var splitOper=item.Frame.YSplitOperator;
            if (splitOper.EnableZoomUpDown==true) splitOper.FixedYMaxMin=null;
        }
        else
        {
            for(var i=0;i<this.SubFrame.length;++i)
            {
                var item=this.SubFrame[i];
                if (!item || !item.Frame || !item.Frame.YSplitOperator) continue;
    
                var splitOper=item.Frame.YSplitOperator;
                if (splitOper.EnableZoomUpDown==true) splitOper.FixedYMaxMin=null;
            }
        }
    }

    this.ClearCoordinateText=function(option) //清空X，Y轴刻度文字， 线段保留
    {
        for(var i=0;i<this.SubFrame.length;++i)
        {
            var item=this.SubFrame[i];
            if (!item.Frame) continue;

            item.Frame.ClearCoordinateText(option);
        }
    }

    

    this.RestoreIndexWindows=function()
    {
        if (!this.ZoomWindowsInfo) return false;

        var subFrame=this.SubFrame[this.ZoomWindowsInfo.FrameID];

        for(var i=this.ZoomStartWindowIndex;i<this.ZoomWindowsInfo.Data.length; ++i)
        {
            var restoreItem=this.ZoomWindowsInfo.Data[i];
            var frameItem=this.SubFrame[i];
            frameItem.Height=restoreItem.Height;
            frameItem.Frame.IsMinSize=false;
            frameItem.Frame.ReDrawToolbar=true;
            frameItem.Frame.XSplitOperator.ShowText=restoreItem.ShowXText;
            frameItem.Frame.XYSplit=true;

            for(var j=0; j<frameItem.OverlayIndex.length; ++j)
            {
                var overlayItem=frameItem.OverlayIndex[j];
                overlayItem.Frame.IsMinSize=false;
            }
        }

        this.ZoomWindowsInfo=null;

        return true;
    }

    this.ZoomIndexWindow=function(frameID, option)
    {
        var subFrame=this.SubFrame[frameID];
        if (!subFrame) return false;
        if (this.ZoomWindowsInfo)   //还原
        {
            return this.RestoreIndexWindows();
        }
        else    //放大
        {
            var zoomInfo={ FrameID:frameID, Data:[] };    //备份下放大前各个窗口的高度
            for(var i=0; i<this.SubFrame.length; ++i)
            {
                var item=this.SubFrame[i];
                zoomInfo.Data[i]={ Height:item.Height, ShowXText:item.Frame.XSplitOperator.ShowText };
            }
            this.ZoomWindowsInfo=zoomInfo;

            var totalHeight=0;
            for(var i=this.ZoomStartWindowIndex;i<this.SubFrame.length;++i)
            {
                var item=this.SubFrame[i];
                var frame=item.Frame;
                frame.XYSplit=true;
                
                totalHeight+=item.Height;
                
                if (i!=frameID)
                {
                    item.Height=0;
                    frame.IsMinSize=true;  //最小化
                    frame.HideToolbar();
                    frame.XSplitOperator.ShowText=false;

                    for(var j=0; j<item.OverlayIndex.length; ++j)
                    {
                        var overlayItem=item.OverlayIndex[j];
                        overlayItem.Frame.IsMinSize=true;
                    }
                }
            }
            subFrame.Height=totalHeight;
            subFrame.Frame.XSplitOperator.ShowText=true;

            return true;
        }
    }

    //保存高度比例
    this.SaveSubFrameHeightRate=function()
    {
        var height=this.ChartBorder.GetHeight();

        for(var i=0; i<this.SubFrame.length; ++i)
        {
            var item=this.SubFrame[i];
            var subHeight=item.Frame.ChartBorder.GetHeight();
            var rate=(subHeight/height)*100;
            item.Height=rate;
        }
    }

    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=0; i<this.SubFrame.length; ++i)
        {
            var item=this.SubFrame[i];
            totalHeight+=item.Height;
        }

        for(var i=0; i<this.SubFrame.length; ++i)
        {
            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.LeftExtendWidth=this.ChartBorder.LeftExtendWidth;
            item.Frame.ChartBorder.RightExtendWidth=this.ChartBorder.RightExtendWidth;
            var frameHeight=height*(item.Height/totalHeight)+top;
            item.Frame.ChartBorder.Bottom=this.ChartBorder.GetChartHeight()-frameHeight;
            top=frameHeight;
        }
    }

    this.SetExtendWidth=function(obj)
    {
        if (!obj) return;
        var leftWidth=null, rightWidth=null;
        if (IFrameSplitOperator.IsNumber(obj.Left)) 
        {
            leftWidth=obj.Left;
            this.ChartBorder.LeftExtendWidth=leftWidth;
        }

        if (IFrameSplitOperator.IsNumber(obj.Right)) 
        {
            rightWidth=obj.Right;
            this.ChartBorder.RightExtendWidth=rightWidth;
        }

        for(var i in this.SubFrame)
        {
            var item=this.SubFrame[i];
            if (leftWidth!=null) item.Frame.ChartBorder.LeftExtendWidth=leftWidth;
            if (rightWidth!=null) item.Frame.ChartBorder.RightExtendWidth=rightWidth;
        }
    }

    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.GetScaleTextWidth=function()
    {
        var width={ Left:null, Right:null, OverlayRight:0 };
        var aryOverlayWidth=[];// 叠加坐标
        for(var i=0; i<this.SubFrame.length; ++i)
        {
            var item=this.SubFrame[i];
            if (item.Height<=0) continue;
            var frame=item.Frame;
            if (!frame) continue;
            if (!frame.XSplitOperator) continue; 
            
            var maxValue=frame.HorizontalMax;   //最大最小要还原
            var minValue=frame.HorizontalMin;

            frame.YSplitOperator.Operator();
            var value=frame.GetScaleTextWidth();

            frame.HorizontalMax=maxValue;
            frame.HorizontalMin=minValue;

            if (value && value.TextWidth)
            {
                var widthItem=value.TextWidth;
                if (IFrameSplitOperator.IsNumber(widthItem.Left))
                {
                    if (width.Left==null || width.Left<widthItem.Left) width.Left=widthItem.Left;
                }

                if (IFrameSplitOperator.IsNumber(widthItem.Right))
                {
                    if (width.Right==null || width.Right<widthItem.Right) width.Right=widthItem.Right;
                }
            }

            //右侧叠加指标
            if (IFrameSplitOperator.IsNonEmptyArray(item.OverlayIndex))
            {
                for(var j=0, k=0; j<item.OverlayIndex.length; ++j)
                {
                    var overlayItem=item.OverlayIndex[j];
                    if (!overlayItem.Frame) continue;

                    var maxValue=overlayItem.Frame.HorizontalMax;   //最大最小要还原
                    var minValue=overlayItem.Frame.HorizontalMin;

                    overlayItem.Frame.YSplitOperator.Operator();
                    var value=overlayItem.Frame.GetScaleTextWidth();

                    overlayItem.Frame.HorizontalMax=maxValue;
                    overlayItem.Frame.HorizontalMin=minValue;

                    overlayItem.RightWidth={ Index:-1, Width:0 }; 
                    if (!value || !value.TextWidth) continue;
                    var widthItem=value.TextWidth;
                    if (!IFrameSplitOperator.IsNumber(widthItem.Right)) continue;

                    overlayItem.RightWidth.Index=k;
                    overlayItem.RightWidth.Width=widthItem.Right;
                    
                    if (aryOverlayWidth[k])
                    {
                        aryOverlayWidth[k][i]=overlayItem.RightWidth;
                    }
                    else
                    {
                        aryOverlayWidth[k]=[];
                        aryOverlayWidth[k][i]=overlayItem.RightWidth;
                    }

                    ++k;
                }
            }
        }

        var overlayWidth=[];
        for(var i=0; i<aryOverlayWidth.length; ++i)
        {
            var colItem=aryOverlayWidth[i];
            var max=0;
            for(var j=0; j<colItem.length; ++j)
            {
                if (!colItem[j]) continue;
                var item=colItem[j].Width;
                if (max<item) max=item;
            }

            if (max>0) max+=this.OverlayBlankWidth

            for(var j=0; j<colItem.length; ++j)
            {
                if (!colItem[j]) continue;
                colItem[j].Width=max;
            }

            overlayWidth[i]=max;
        }

        for(var i=0;i<overlayWidth.length;++i)
        {
            var value=overlayWidth[i];
            if (!IFrameSplitOperator.IsNumber(value)) continue;
            width.OverlayRight+=value;
        }

        return width;
    }

    this.IsFrameXYSplit=function()
    {
        for(var i in this.SubFrame)
        {
            var item=this.SubFrame[i];
            if (item.Frame.XYSplit) return true;

            for(var j=0; j<item.OverlayIndex.length; ++j)
            {
                var overlayItem=item.OverlayIndex[j];
                if (overlayItem.Frame.XYSplit) return true;
            }

        }
        return false;
    }

    this.Draw=function(option)
    {
        if (this.SizeChange===true) 
        {
            this.CalculateChartBorder();
        }

        var isSplash=false; //是否过场动画
        if (option && option.IsEnableSplash===true) isSplash=true;
        if (isSplash==false && (this.AutoLeftBorder || this.AutoRightBorder) && this.IsFrameXYSplit())
        {
            this.AutoRightOverlayWidth=[];
            var textWidth=this.GetScaleTextWidth();
            var bSizeChange=false;
            if (IFrameSplitOperator.IsNumber(textWidth.Left) && this.AutoLeftBorder)
            {
                var blank=0;
                if (IFrameSplitOperator.IsNumber(this.AutoLeftBorder.Blank)) blank=this.AutoLeftBorder.Blank;
                var value=textWidth.Left+blank;
                if (IFrameSplitOperator.IsNumber(this.AutoLeftBorder.MinWidth))
                {
                    if (this.AutoLeftBorder.MinWidth>value) value=this.AutoLeftBorder.MinWidth;
                }
                if (this.IsHScreen) this.ChartBorder.Top=value;
                else this.ChartBorder.Left=value;

                for(var i=0; i<this.SubFrame.length; ++i)
                {
                    var item=this.SubFrame[i];
                    if (this.IsHScreen) item.Frame.ChartBorder.Top=value;
                    else item.Frame.ChartBorder.Left=value;
                }
            }

            if (IFrameSplitOperator.IsNumber(textWidth.Right) && this.AutoRightBorder)
            {
                var blank=0;
                if (IFrameSplitOperator.IsNumber(this.AutoRightBorder.Blank)) blank=this.AutoRightBorder.Blank;
                var value=textWidth.Right+blank;
                if (IFrameSplitOperator.IsNumber(this.AutoRightBorder.MinWidth))
                {
                    if (this.AutoRightBorder.MinWidth>value) value=this.AutoRightBorder.MinWidth;
                }

                this.AuotRightWidth=value;
                if (IFrameSplitOperator.IsPlusNumber(textWidth.OverlayRight))
                {
                    value+=this.OverlayBlankWidth;
                    this.AuotRightWidth=value;
                    value+=textWidth.OverlayRight;
                }

                if (this.GetExtendChartRightWidth)
                {
                    var extendWidth=this.GetExtendChartRightWidth();
                    value+=extendWidth;
                }

                if (this.IsHScreen) 
                {
                    if (this.ChartBorder.Bottom!=value) bSizeChange=true;
                    this.ChartBorder.Bottom=value;
                }
                else  
                {
                    if (this.ChartBorder.Right!=value) bSizeChange=true;
                    this.ChartBorder.Right=value;
                }
                for(var i=0; i<this.SubFrame.length; ++i)
                {
                    var item=this.SubFrame[i];
                    if (this.IsHScreen) item.Frame.ChartBorder.Bottom=value;
                    else item.Frame.ChartBorder.Right=value;

                    item.Frame.ReDrawToolbar=true;
                }
            }

            this.SetSizeChage(true);
        }

        for(var i in this.SubFrame)
        {
            var item=this.SubFrame[i];
            if (item.Height<=0) continue;

            item.Frame.Draw();

            if (this.AutoRightBorder)
            {
                var rightOffset=this.AuotRightWidth;

                for(var j=0; j<item.OverlayIndex.length; ++j)
                {
                    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) 
                    {
                        overlayItem.Frame.RightOffset=rightOffset;
                        overlayItem.Frame.Draw();
                        rightOffset+=overlayItem.RightWidth.Width;
                    }
                }

            }
            else
            {
                var rightOffset=item.Interval;
                if (item.Frame.RightTextMaxWidth>rightOffset) rightOffset=item.Frame.RightTextMaxWidth;
                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) 
                    {
                        overlayItem.Frame.RightOffset=rightOffset;
                        overlayItem.Frame.Draw();
                        if (overlayItem.Frame.IsShow) 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.DrawPictureCoordinate=function(drawPicture, option)
    {
        if (!drawPicture || !drawPicture.Frame) return;
        if (!IFrameSplitOperator.IsNonEmptyArray(drawPicture.Point)) return;
        if (!drawPicture.GetXYCoordinate) return;

        var range=drawPicture.GetXYCoordinate();
        drawPicture.Frame.DrawPictureYCoordinate(drawPicture, range, option);

        for(var i=0;i<this.SubFrame.length;++i)
        {
            var item=this.SubFrame[i];
            if (!item || !item.Frame) continue;
            if (!item.Frame.XSplitOperator.ShowText) continue;

            item.Frame.DrawPictureXCoordinate(drawPicture, range, option);
            break;
        }
    }

    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.DrawEx=function(option)
    {
        for(var i in this.SubFrame)
        {
            var item = this.SubFrame[i];
            if ((item.Frame.ClassName=="MinuteFrame"||item.Frame.ClassName=="MinuteHScreenFrame")  && i==1)
            {
                item.Frame.DrawVolTitle(option.Symbol);
            }
        }
    }

    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.SetDrawDepthMap=function(callback)
    {
        for(var i in this.SubFrame)
        {
            var item=this.SubFrame[i];
            item.Frame.DrawDepthMapCallback=callback;
        }
    }

    //图形快照
    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=0; i<this.SubFrame.length; ++i)
        {
            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 i;   //转成整形
            }
        }

        return -1;
    }

    this.PtInButtons=function(x,y)
    {
        for(var i in this.SubFrame)
        {
            var item=this.SubFrame[i];
            var button=item.Frame.PtInButtons(x,y);
            if (button) return button;
        }

        return null
    }

    //是否在X轴坐标上
    this.PtInFrameBottom=function(x,y)
    {
        var left=this.ChartBorder.GetLeft();
        var top=this.ChartBorder.GetBottom();
        var width=this.ChartBorder.GetWidth();
        var height=this.ChartBorder.Bottom;
        
        this.Canvas.beginPath();
        this.Canvas.rect(left,top,width,height);
        if (this.Canvas.isPointInPath(x,y)) return true;
        return false;
    }

    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);
        this.UpdateAllFrame();
        return result;
    }

    this.ZoomDown=function(cursorIndex)
    {
        var result=this.SubFrame[0].Frame.ZoomDown(cursorIndex);
        this.UpdateAllFrame();
        return result;
    }

    this.XCoordinateZoom=function(step, isMoveLeft)
    {
        var result=this.SubFrame[0].Frame.XCoordinateZoom(step, isMoveLeft);
        this.UpdateAllFrame();
        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;
            }
        }
    }

    this.GetCurrentPageSize=function()  //获取当前页显示的数据个数
    {
        if (this.SubFrame.length<=0) return null;
        var item=this.SubFrame[0];
        if (!item || !item.Frame) return null;

        return item.Frame.XPointCount;
    }

    this.OnSize=function()
    {
        var obj={};
        this.SubFrame[0].Frame.OnSize(obj);
        this.UpdateAllFrame();
        return obj;
    }

    this.SetDataWidth=function(dataWidth)
    {
        var obj=this.SubFrame[0].Frame.SetDataWidth(dataWidth);
        this.UpdateAllFrame();
        return obj;
    }

    this.UpdateAllFrame=function()
    {
        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;
            }
        }
    }

    //鼠标是否在边框上
    this.PtInFrameBorder=function(x,y)
    {
        var height=this.DragBorderHeight;
        for(var i=0;i<this.SubFrame.length-1;++i)
        {
            var item=this.SubFrame[i];
            if (item.Frame.Heigh<=0) continue;
            var bottom=item.Frame.ChartBorder.GetBottom();
            var left=item.Frame.ChartBorder.GetLeft();
            var right=item.Frame.ChartBorder.GetRight();

            item.Frame.Canvas.beginPath();
            item.Frame.Canvas.rect(left,bottom-height/2,(right-left),height);
            if (item.Frame.Canvas.isPointInPath(x,y))
            {
                return { Index:i, Bottom:true };
            }
        }
        return null;
    }

    this.IsEnableDragY=function(index)
    {
        if (!this.SubFrame) return false;
        var item=this.SubFrame[index];
        if (!item || !item.Frame || !item.Frame.YSplitOperator) return false;
        var split=item.Frame.YSplitOperator;
        if (typeof(split.IsEnableDragY)!='function') return false;

        return split.IsEnableDragY();
    }

    this.PtInFrameY=function(x,y)
    {
        for(var i=0;i<this.SubFrame.length;++i)
        {
            var item=this.SubFrame[i];
            if (item.Frame.Heigh<=0) continue;
            var rightWidth=item.Frame.ChartBorder.Right;

            var border=item.Frame.ChartBorder.GetBorder();
            var bottom=border.Bottom;
            var top=border.TopTitle;
            var left=border.Left;
            var right=border.Right;

            var maxTopHegith=30;
            var barHegith=(bottom-top);
            if (barHegith/3>maxTopHegith)
            {
                var barTop=top+maxTopHegith;
                var barBottom=bottom-maxTopHegith;
            }
            else
            {
                var internal=barHegith/3;
                var barTop=top+internal;
                var barBottom=bottom-internal;
            }

            var position=0;
            if (y<barTop) position=1;
            else if (y>barBottom) position=2;

            if (rightWidth>=10)
            {
                item.Frame.Canvas.beginPath();
                item.Frame.Canvas.rect(right,top,rightWidth,(bottom-top));
                if (item.Frame.Canvas.isPointInPath(x,y))
                {
                    return { Index:i, Right:true, Left:false , Position:position };    //Position 1=上面 2 下面 0=中间(TODO)
                }
            }

            var leftWidth=item.Frame.ChartBorder.Left;
            if (leftWidth>=10)
            {
                item.Frame.Canvas.beginPath();
                item.Frame.Canvas.rect(0,top,leftWidth,(bottom-top));
                if (item.Frame.Canvas.isPointInPath(x,y))
                {
                    return { Index:i, Right:false, Left:true, Position:position };
                }
            }
 
        }
        return null;
    }

    this.SetDayCount=function(dayCount)
    {
        this.ChartBorder.MultiDayMinute.Count=dayCount;
        for(var i=0;i<this.SubFrame.length;++i)
        {
            var item=this.SubFrame[i];
            if (!item.Frame) continue;

            item.Frame.DayCount=dayCount;
            item.Frame.ChartBorder.MultiDayMinute.Count=dayCount;
        }
    }

    //设置多日分时宽度
    this.SetMultiDayMinuteWidth=function(obj)
    {
        if (!obj) return;
        if (IFrameSplitOperator.IsNumber(obj.Left)) this.ChartBorder.MultiDayMinute.Left=obj.Left;
        if (IFrameSplitOperator.IsNumber(obj.Right)) this.ChartBorder.MultiDayMinute.Right=obj.Right;

        for(var i=0;i<this.SubFrame.length;++i)
        {
            var item=this.SubFrame[i];
            if (!item.Frame) continue;

            if (IFrameSplitOperator.IsNumber(obj.Left)) item.Frame.ChartBorder.MultiDayMinute.Left=obj.Left;
            if (IFrameSplitOperator.IsNumber(obj.Right)) item.Frame.ChartBorder.MultiDayMinute.Right=obj.Right;
        }
    }
}

//行情框架横屏
function HQTradeHScreenFrame()
{
    this.newMethod=HQTradeFrame;   //派生
    this.newMethod();
    delete this.newMethod;

    this.IsHScreen=true;        //是否是横屏

    this.CalculateChartBorder=function()    //计算每个子框架的边框信息
    {
        if (this.SubFrame.length<=0) return;
        var border=this.ChartBorder.GetHScreenBorder();
        var right=this.ChartBorder.Right;
        var left=border.Right;
        var width=border.Right-border.Left;
        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 DepthChartFrame()
{
    this.newMethod=AverageWidthFrame;   //派生
    this.newMethod();
    delete this.newMethod;

    this.ScreenImageData;                   //截图
    this.Position;                          //画布的位置
    this.ClassName="DepthChartFrame";

    //X轴价格 最大,最小
    this.VerticalRange={ Max:88, Min:8, Center:null, MaxDiffer:null, Differ:null, Step:0.05 };
    this.AskPrice;
    this.BidPrice;
    this.MinZoom=0.05;  //最小缩放

    this.SetPriceList=function(aryAskPrice, aryBidPrice)
    {
        this.AskPrice=aryAskPrice;
        this.BidPrice=aryBidPrice;
    }

    this.DrawFrame=function()
    {
        this.SplitXYCoordinate();
        this.DrawHorizontal();
        this.DrawVertical();
    }

    this.GetXFromIndex=function(value)
    {
        var left=this.ChartBorder.GetLeft();
        var right=this.ChartBorder.GetRight();
        var width=this.ChartBorder.GetWidth();
        var offset=width*(value-this.VerticalRange.Min)/(this.VerticalRange.Max-this.VerticalRange.Min);
        return left+offset;
    }

    this.GetXData=function(x)
    {
        var left=this.ChartBorder.GetLeft();
        var right=this.ChartBorder.GetRight();
        var width=this.ChartBorder.GetWidth();

        return (x-left)/width*(this.VerticalRange.Max-this.VerticalRange.Min)+this.VerticalRange.Min;
    }

    this.GetXFromPrice=function(price)
    {
        var isAskPrice=false;
        var find=this.GetPrice(this.BidPrice, price);
        if (find==null) 
        {
            find=this.GetPrice(this.AskPrice, price);
            isAskPrice=true;
        }

        if (find==null) 
        {
            if (this.BidPrice && Array.isArray(this.BidPrice) && this.BidPrice.length>0)
            {
                var minPrice=this.BidPrice[0];
                if (price<minPrice) 
                {
                    isAskPrice=false;
                    find= minPrice;
                }
            }
        }

        if (find==null)   
        {      
            if (this.AskPrice && Array.isArray(this.AskPrice) && this.AskPrice.length>0)
            {
                var maxPrice=this.AskPrice[this.AskPrice.length-1];
                if (price>maxPrice) 
                {
                    isAskPrice=true;
                    find=maxPrice;
                }
            }
        }

        if (find==null) return null;

        var x=this.GetXFromIndex(find);

        return { X:x, Price:find, IsAsk:isAskPrice };
    }

    this.GetPrice=function(aryPrice, price)
    {
        if (!aryPrice || !Array.isArray(aryPrice) || aryPrice.length<=0) return null;

        if (price<aryPrice[0] || price>aryPrice[aryPrice.length-1]) return null;

        var lastPrice=null;
        for(var i in aryPrice)
        {
            var item=aryPrice[i];
            if (price==item)
            {
                return item;
            }

            if (price<item)
                return lastPrice;

            lastPrice=item;
        }
    }

    //分割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
        };
    }

    this.SetDrawDepthMap=function(callback)
    {
        
    }

    this.PtInFrame=function(x,y)    //鼠标哪个指标窗口
    {
        var left=this.ChartBorder.GetLeft();
        var top=this.ChartBorder.GetTop();
        var width=this.ChartBorder.GetWidth();
        var height=this.ChartBorder.GetHeight();

        this.Canvas.beginPath();
        this.Canvas.rect(left,top,width,height);
        if (this.Canvas.isPointInPath(x,y))
            return 0;

        return -1;
    }

    this.PtInFrameBorder=function(x,y)
    {
        return null;
    }

    this.ZoomUp=function()  //放大
    {
        var xRange=this.VerticalRange;
        var differ=xRange.Differ;
        var minDiffer=xRange.MaxDiffer*this.MinZoom;
        if (differ<minDiffer) return false;

        var offsetDiffer=xRange.Differ*xRange.Step;
        differ-=offsetDiffer;
        xRange.Differ=differ;
        xRange.Min=xRange.Center-xRange.Differ;
        xRange.Max=xRange.Center+xRange.Differ;

        return true;
    }

    this.ZoomDown=function() //缩小
    {
        var xRange=this.VerticalRange;
        var differ=xRange.Differ;
        if (differ==xRange.MaxDiffer) return false;

        var offsetDiffer=xRange.Differ*xRange.Step;
        differ+=offsetDiffer;
        if (differ>xRange.MaxDiffer) differ=xRange.MaxDiffer;

        xRange.Differ=differ;
        xRange.Min=xRange.Center-xRange.Differ;
        xRange.Max=xRange.Center+xRange.Differ;

        return true;
    }
}


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
        };
    }

    this.SetDrawDepthMap=function(callback)
    {
        
    }

    this.PtInFrame=function(x,y)    //鼠标哪个指标窗口
    {
        var left=this.ChartBorder.GetLeft();
        var top=this.ChartBorder.GetTop();
        var width=this.ChartBorder.GetWidth();
        var height=this.ChartBorder.GetHeight();

        this.Canvas.beginPath();
        this.Canvas.rect(left,top,width,height);
        if (this.Canvas.isPointInPath(x,y))
            return 0;

        return -1;
    }

    this.PtInFrameBorder=function(x,y)
    {
        return null;
    }
}


//历史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.YFClose=null;   //前结算价
    this.FClose=null;    //结算价

    //指数才有的数据
    this.Stop;  //停牌家数
    this.Up;    //上涨
    this.Down;  //下跌
    this.Unchanged; //平盘

    this.ExtendData;    //扩展数据

    this.BFactor;   //前复权
    this.AFactor;   //后复权

    /*
    { 
        PriceOffset: ,  
        High: [ { Price:, Value:, Text: Color ,Font:{ Weight:}}, ..... ], 
        Low:[ { Price:, Value:, Text: Color , Font:{ Weight:}}, ..... ] , 
        Order:  //订单信息
        [ 
            { 
                Price:,  
                Ask:{ Color:, Value: , Text:, BG:, Font:{ Weight:} } 
                Bid:{ Color:, Value:,  Text:, BG:, Font:{ Weight:} }, 
                HBar:{ Color:, Width }  //横线柱子 Width K线宽度比值
            }, 
            ........
        ] 
    }
    */
    this.OrderFlow; //订单流 
}

//数据复制
HistoryData.Copy=function(data)
{
    var newData=new HistoryData();

    newData.Date=data.Date;
    if (IFrameSplitOperator.IsNumber(data.Time)) newData.Time=data.Time;

    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;
    
    if (IFrameSplitOperator.IsNumber(data.FlowCapital)) newData.FlowCapital=data.FlowCapital;
    if (IFrameSplitOperator.IsNumber(data.Position)) newData.Position=data.Position;
    if (IFrameSplitOperator.IsNumber(data.YFClose)) newData.YFClose=data.YFClose;
    if (IFrameSplitOperator.IsNumber(data.FClose)) newData.FClose=data.FClose;

    //指数涨停家数
    if (IFrameSplitOperator.IsNumber(data.Stop)) newData.Stop=data.Stop;
    if (IFrameSplitOperator.IsNumber(data.Up)) newData.Up=data.Up;
    if (IFrameSplitOperator.IsNumber(data.Down)) newData.Down=data.Down;
    if (IFrameSplitOperator.IsNumber(data.Unchanged)) newData.Unchanged=data.Unchanged;

    //复权因子
    if (IFrameSplitOperator.IsNumber(data.BFactor)) newData.BFactor=data.BFactor;
    if (IFrameSplitOperator.IsNumber(data.AFactor)) newData.AFactor=data.AFactor;

    if (data.OrderFlow) newData.OrderFlow=data.OrderFlow;

    return newData;
}

//把数据 src 复制到 dest中
HistoryData.CopyTo=function(dest,src)
{
    dest.Date=src.Date;
    if (IFrameSplitOperator.IsNumber(src.Time)) dest.Time=src.Time;

    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;
    
    if (IFrameSplitOperator.IsNumber(src.FlowCapital)) dest.FlowCapital=src.FlowCapital;
    if (IFrameSplitOperator.IsNumber(src.Position)) dest.Position=src.Position;
    if (IFrameSplitOperator.IsNumber(src.YFClose)) dest.YFClose=src.YFClose;
    if (IFrameSplitOperator.IsNumber(src.FClose)) dest.FClose=src.FClose;

    if (IFrameSplitOperator.IsNumber(src.Stop)) dest.Stop=src.Stop;
    if (IFrameSplitOperator.IsNumber(src.Up)) dest.Up=src.Up;
    if (IFrameSplitOperator.IsNumber(src.Down)) dest.Down=src.Down;
    if (IFrameSplitOperator.IsNumber(src.Unchanged)) dest.Unchanged=src.Unchanged;

    if (IFrameSplitOperator.IsNumber(src.BFactor)) dest.BFactor=src.BFactor;
    if (IFrameSplitOperator.IsNumber(src.AFactor)) dest.AFactor=src.AFactor;
}

//数据复权拷贝
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;
    newData.Position=data.Position;
    newData.YFClose=data.YFClose;
    newData.FClose=data.FClose;

    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;     //持仓量
    this.YClearing;         //昨结算价
}

//盘前集合竞价
function BeforeOpenData()
{
    this.Time;
    this.Date;
    this.Price;     //匹配的价格
    this.AvPrice;   //均价
    this.Vol=[];    //[0]=匹配量 [1]=未匹配量
    this.ColorID;   //0=平盘 1=红 2=绿  3 ...自定义颜色     
}

//收盘集合竞价
function AfterCloseData()
{
    this.Time;
    this.Date;
    this.Price;     //匹配的价格
    this.AvPrice;   //均价
    this.Vol=[];    //[0]=匹配量 [1]=未匹配量
    this.ColorID;   //0=平盘 1=红 2=绿  3 ...自定义颜色     
}

//单指标数据
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,              //龙虎榜

    //公告预留类型
    ANNOUNCEMENT_EX_START:100,
    ANNOUNCEMENT_EX_END:200,
}

function KLineInfoData()
{
    this.ID;
    this.Date;
    this.Title;
    this.InfoType;
    this.ExtendData;    //扩展数据
}

//外部数据计算方法接口
function DataPlus () 
{ 
    this.PeriodCallback=new Map();

    this.GetPeriodCallback=function(period)
    {
        if (!this.PeriodCallback.has(period)) return null;
        
        return this.PeriodCallback.get(period);
    }

    this.AddPeriodCallback=function(obj)
    {
        if (!IFrameSplitOperator.IsNumber(obj.Period) || !obj.Callback) return;

        var item={ Period:obj.Period, Callback:obj.Callback };
        this.PeriodCallback.set(obj.Period, item);
    }

    this.RemovePeriodCallback=function(obj)
    {
        if (!this.PeriodCallback.has(obj.ID)) return;
        this.PeriodCallback.delete(obj.ID);
    }
}; 

DataPlus.GetMinutePeriodData=null;

var g_DataPlus=new DataPlus();

/*
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(unit)
    {
        var value=1;
        if (IFrameSplitOperator.IsNumber(unit)>0) value=unit;
        var result=new Array();
        for(var i in this.Data)
        {
            result[i]=this.Data[i].Vol/value;
        }

        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.GetSettlementPrice=function()  //结算价
    {
        var result=new Array();
        for(var i in this.Data)
        {
            result[i]=this.Data[i].FClose;
        }

        return result;
    }

    this.GetIsEqual=function()
    {
        var result=[];
        for(var i in this.Data)
        {
            var item=this.Data[i];
            result[i]=(item.Close==item.Open? 1:0);
        }

        return result;
    }

    this.GetIsUp=function()
    {
        var result=[];
        for(var i in this.Data)
        {
            var item=this.Data[i];
            result[i]=(item.Close>item.Open? 1:0);
        }

        return result;
    }

    this.GetIsDown=function()
    {
        var result=[];
        for(var i in this.Data)
        {
            var item=this.Data[i];
            result[i]=(item.Close<item.Open? 1:0);
        }

        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.GetAvPrice=function()
    {
        var result=new Array();
        for(var i in this.Data)
        {
            var value=this.Data[i].AvPrice;
            if (IFrameSplitOperator.IsNumber(value))
                result[i]=value;
            else 
                result[i]=0;
        }

        return result;
    }

    //获取数据日期和时间范围
    this.GetDateRange=function()
    {
        if (!this.Data || this.Data.length<=0) return null;

        var start=this.Data[0];
        var end=this.Data[this.Data.length-1];
        var range={ Start:{Date:start.Date}, End:{Date:end.Date} };
        if (IFrameSplitOperator.IsNumber(start.Time)) range.Start.Time=start.Time;
        if (IFrameSplitOperator.IsNumber(end.Time)) range.End.Time=end.Time;

        return range;
    }

    this.GetDateList=function()
    {
        if (!this.Data || this.Data.length<=0) return null;
        var aryDate=[];
        var setDate=new Set();
        for(var i=0;i<this.Data.length; ++i)
        {
            var item=this.Data[i];
            if (!IFrameSplitOperator.IsNumber(item.Date)) continue;

            if (setDate.has(item.Date)) continue;

            setDate.add(item.Date);
            aryDate.push(item.Date);
        }

        return aryDate;
    }

    //计算分钟
    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;  
                    newData.Position=minData.Position;
                    newData.YFClose=minData.YFClose;
                    newData.FClose=minData.FClose;
                }
                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.Position=minData.Position;
                    newData.FlowCapital=minData.FlowCapital;  
                    newData.FClose=minData.FClose;
                }

                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; 
                    newData.Position=minData.Position; 
                    newData.YFClose=minData.YFClose; 
                    newData.FClose=minData.FClose; 
                }
                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.Position=minData.Position;
                    newData.FlowCapital=minData.FlowCapital;  
                    newData.FClose=minData.FClose; 
                }
            }
        }
        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 22://半年:
                    var halfYear=ChartData.GetHalfYear(dayData.Date);
                    if (halfYear!=startDate)
                    {
                        isNewData=true;
                        startDate=halfYear;
                    }
                    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;
                newData.Position=dayData.Position; 
                newData.YFClose=dayData.YFClose; 
                newData.FClose=dayData.FClose; 
            }
            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;
                    newData.Position=dayData.Position; 
                    newData.YFClose=dayData.YFClose; 
                    newData.FClose=dayData.FClose; 
                }
                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.Position=dayData.Position;
                    newData.FlowCapital=dayData.FlowCapital;
                    newData.Date=dayData.Date;
                    newData.FClose=dayData.FClose; 
                }
            }
        }

        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;  
                    newData.Position=dayData.Position;  
                    newData.YFClose=dayData.YFClose; 
                    newData.FClose=dayData.FClose; 
                }
                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.Position=dayData.Position;
                    newData.FlowCapital=dayData.FlowCapital;
                    newData.FClose=dayData.FClose;  
                }
            }
        }
        return result;
    }

    //周期数据 1=周 2=月 3=年
    this.GetPeriodData=function(period)
    {
        //外部自定义周期计算函数
        var itemCallback=g_DataPlus.GetPeriodCallback(period);
        if (itemCallback) return itemCallback.Callback(period,this.Data,this);

        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==22 || (period>CUSTOM_DAY_PERIOD_START && period<=CUSTOM_DAY_PERIOD_END)) 
        if (ChartData.IsDayPeriod(period,false)) 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);
        if (ChartData.IsMinutePeriod(period,false)) return this.GetMinutePeriodData(period);
    }

    //复权  0 不复权 1 前复权 2 后复权
    this.GetRightData=function(right, option)
    {
        var result=[];
        if (this.Data.length<=0) return result;

        if (option && option.AlgorithmType==1)  //使用复权因子计算
        {
            for(var i=0;i<this.Data.length;++i)
            {
                var item=this.Data[i];
                var seed=(right==1?item.BFactor:item.AFactor);
                result[i]=HistoryData.CopyRight(item,seed);
            }

            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)
            {
                var value=this.Data[index].Close;
                if(yClose!=value && value!=0)
                    seed *= yClose/value;

                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.GetRightDate=this.GetRightData;

    //叠加数据和主数据拟合,去掉主数据没有日期的数据
    this.GetOverlayData=function(overlayData, bApiPeriod)
    {
        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, bApiPeriod)
    {
        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<financeData.length)
            {
                var fDate=financeData[j].Date;
                if (date<fDate)
                {
                    ++i;
                    continue;
                }
            }
            
            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=[];
        if (!Array.isArray(financeData) || financeData.length<=0) return result;

        var i=0;
        var firstItem=financeData[0];
        for(i=0;i<this.Data.length;++i)
        {
            var date=this.Data[i].Date;
            var time=this.Data[i].Time;
            if (date>firstItem.Date || (date==firstItem.Date && time>=firstItem.Time))
            {
                break;
            }    
        }

        for(var 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) ||
                    (financeData[j].Date==date && financeData[j].Time<time && financeData[j+1].Time<=time) )
                {
                    ++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;   //财务日期 调试用
                item.FinanceTime=financeData[j].Time;   //财务日期 调试用
            }
            else
            {
                item.Value=null;
                item.FinanceDate=null;
                item.FinanceTime=null;
            }
            result[i]=item;

            ++i;
        }

        return result;
    }

    //日线拟合交易数据, 不做平滑处理
    this.GetFittingTradeData=function(tradeData, nullValue, bExactMatch)
    {
        var result=[];
        var bMatch=false;

        for(var i=0,j=0;i<this.Data.length;)
        {
            var date=this.Data[i].Date;

            if (j<tradeData.length)
            {
                if (tradeData[j].Date>date)
                {
                    var item=new SingleData();
                    item.Date=date;
                    item.Value=nullValue;
                    result[i]=item;
                    ++i;
                    continue;
                }
            }

            if (j+1<tradeData.length)
            {
                if (tradeData[j].Date<date && tradeData[j+1].Date<=date)
                {
                    ++j;
                    bMatch=false;
                    continue;
                }
            }

            var item=new SingleData();
            item.Date=date;
            item.Value=nullValue;
            item.FinanceDate=null;
            if (j<tradeData.length)
            {
                var tradeItem=tradeData[j];
                if (this.Period==0 && bExactMatch===true) //日线完全匹配
                {
                    if (tradeItem.Date==item.Date)
                    {
                        item.Value=tradeItem.Value;
                        item.FinanceDate=tradeItem.Date;   //财务日期 调试用
                        bMatch=true;
                    }
                }
                else    //其他日线周期
                {
                    if (bMatch==false)
                    {
                        item.Value=tradeItem.Value;
                        item.FinanceDate=tradeItem.Date;   //财务日期 调试用
                        bMatch=true;
                    }
                }
            }
           
            result[i]=item;
            ++i;
        }

        return result;
    }

    this.GetMinuteFittingTradeData=function(tradeData, nullValue,bExactMatch)
    {
        var result=[];
        var bMatch=false;

        for(var i=0,j=0;i<this.Data.length;)
        {
            var date=this.Data[i].Date;
            var time=this.Data[i].Time;

            if (j<tradeData.length)
            {
                if (tradeData[j].Date>date || (tradeData[j].Date==date && tradeData[j].Time>time))
                {
                    var item=new SingleData();
                    item.Date=date;
                    item.Time=time;
                    item.Value=nullValue;
                    result[i]=item;
                    ++i;
                    continue;
                }
            }

            if (j+1<tradeData.length)
            {
                if ( (tradeData[j].Date<date && tradeData[j+1].Date<=date) || 
                    (tradeData[j].Date==date && tradeData[j].Time<time && tradeData[j+1].Time<=time) )
                {
                    ++j;
                    bMatch=false;
                    continue;
                }
            }

            var item=new SingleData();
            item.Date=date;
            item.FinanceDate=null;
            item.Time=time;
            item.Value=nullValue;
            if (j<tradeData.length)
            {
                var tradeItem=tradeData[j];
                if (this.Period==4 && bExactMatch===true) //1分钟线完全匹配
                {
                    if (tradeItem.Date==item.Date && tradeItem.Time==item.Time)  //完全匹配
                    {
                        item.Value=tradeItem.Value;
                        item.FinanceDate=tradeItem.Date;   //财务日期 调试用
                        item.FinanceTime=tradeItem.Time;
                        bMatch=true;
                    }
                }
                else    //其他日线周期
                {
                    if (bMatch==false)
                    {
                        item.Value=tradeItem.Value;
                        item.FinanceDate=tradeItem.Date;   //财务日期 调试用
                        item.FinanceTime=tradeItem.Time;
                        bMatch=true;
                    }
                }
            }

            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 weekCount=2;
        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 21: //双周
                    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 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) //合并数据
    {
        if (!this.Data || this.Data.length<=0)
        {
            this.Data=data;
            return true;
        }

        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)
            {
                firstItemID=i;
                firstItem=item;
                break;
            }

            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.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.ConverPeriod=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.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::ConverPeriod] 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;
    }

    //拟合其他K线数据指标   
    this.FitKLineIndex=function(kLineData, outVar, peirod, indexPeriod)
    {
        var count=this.Data.length;         //原始K线数据
        var indexCount=kLineData.length;    //拟合K线数据
        var isMinutePeriod=[ChartData.IsMinutePeriod(peirod,true), ChartData.IsMinutePeriod(indexPeriod,true) ]; //0=原始K线 1=需要拟合的K线
        var isDayPeriod=[ChartData.IsDayPeriod(peirod,true), ChartData.IsDayPeriod(indexPeriod,true)  ];   //0=原始K线 1=需要拟合的K线
        var firstItem=ChartData.GetKLineDataTime(this.Data[0]);

        //计算拟合以后的数据索引
        var aryFixDataID=[];
        var indexStart=indexCount;
        for(var i=0;i<indexCount;++i)
        {
            var item=ChartData.GetKLineDataTime(kLineData[i]);

            if ( (isDayPeriod[0] && isDayPeriod[1]) || (isMinutePeriod[0] && isDayPeriod[1]) )   //日线(拟合) => 日线(原始)    日线(拟合 => 分钟(原始)
            {
                if (item.Date>=firstItem.Date)
                {
                    indexStart = i;
                    break;
                }
            }
            else if (isMinutePeriod[0] && isMinutePeriod[1]) //分钟(拟合 => 分钟(原始)
            {
                if (item.Date>firstItem.Date)
                {
                    indexStart = i;
                    break;
                }

                if (item.Date == firstItem.Date && item.Time >= firstItem.Time )
                {
                    indexStart = i;
                    break;
                }
            }
        }

        for(var i=0, j=indexStart; i<count; )
        {
            var item=ChartData.GetKLineDataTime(this.Data[i]);
            if (j>=indexCount)
            {
                var fitItem={ Date:item.Date, Time:item.Time, Index:-1 };
                aryFixDataID[i]=fitItem;
                ++i;
                continue;
            }

            var destItem=ChartData.GetKLineDataTime(kLineData[j]);
            if ( (isDayPeriod[0] && isDayPeriod[1]) || (isMinutePeriod[0] && isDayPeriod[1]) )  //日线(拟合) => 日线(原始)    日线(拟合 => 分钟(原始)
            {
                if (destItem.Date == item.Date)
                {
                    var fitItem={ Date:item.Date, Time:item.Time, Index:j, Data2:destItem.Date, Time2:destItem.Time };
                    aryFixDataID[i]=fitItem;
                    ++i;
                }
                else 
                {
                    if (j+1<indexCount)
                    {
                        var nextDestItem=ChartData.GetKLineDataTime(kLineData[j+1]);
                        if ( destItem.Date<=item.Date && nextDestItem.Date>item.Date )
                        {
                            var fitItem={ Date:item.Date, Time:item.Time, Index:j+1, Data2:nextDestItem.Date, Time2:nextDestItem.Time };
                            aryFixDataID[i]=fitItem;
                            ++i;
                        }
                        else if (nextDestItem.Date <= item.Date )
                        {
                            ++j;
                        }
                        else
                        {
                            var fitItem={ Date:item.Date, Time:item.Time, Index:-1 };
                            aryFixDataID[i]=fitItem;
                            ++i;
                        }
                    }
                    else
                    {
                        ++j;
                    }
                }
            }
            else if (isMinutePeriod[0] && isMinutePeriod[1])    //分钟(拟合 => 分钟(原始)
            {
                if (destItem.Date == item.Date && destItem.Time == item.Time)
                {
                    var fitItem={ Date:item.Date, Time:item.Time, Index:j, Data2:destItem.Date, Time2:destItem.Time };
                    aryFixDataID[i]=fitItem;
                    ++i;
                }
                else
                {
                    if (j+1<indexCount)
                    {
                        var nextDestItem=ChartData.GetKLineDataTime(kLineData[j+1]);
                        if ( (destItem.Date<item.Date && nextDestItem.Date>item.Date) || 
                            (destItem.Date == item.Date && destItem.Time < item.Time && nextDestItem.Date == item.Date && nextDestItem.Time > item.Time) ||
                            (destItem.Date == item.Date && destItem.Time < item.Time && nextDestItem.Date > item.Date) ||
                            (destItem.Date < item.Date && nextDestItem.Date == item.Date && nextDestItem.Time > item.Time) )
                        {
                            var fitItem={ Date:item.Date, Time:item.Time, Index:j+1, Data2:nextDestItem.Date, Time2:nextDestItem.Time };
                            aryFixDataID[i]=fitItem;
                            ++i;
                        }
                        else if (nextDestItem.Date < item.Date || (nextDestItem.Date == item.Date && nextDestItem.Time <= item.Time) )
                        {
                            ++j;
                        }
                        else
                        {
                            var fitItem={ Date:item.Date, Time:item.Time, Index:-1 };
                            aryFixDataID[i]=fitItem;
                            ++i;
                        }
                    }
                    else
                    {
                        ++j;
                    }
                }
            }
        }

        //拟合数据
        var result=[];
        for(var i in outVar)
        {
            var item=outVar[i];
            if (Array.isArray(item.Data)) 
            {
                var data=[];
                result[i]={ Data:data, Name:item.Name } ;
                for(var j=0;j<aryFixDataID.length;++j)
                {
                    var dataItem=aryFixDataID[j];
                    data[j]=null;
                    if ( dataItem && dataItem.Index>=0 && dataItem.Index<item.Data.length )
                        data[j]=item.Data[dataItem.Index];
                }
            }
            else 
            {
                result[i]={ Data:item.Data, Name:item.Name} ;
            }
        }

        return result;
    }

    //获取数据索引
    this.FindDataIndexByDateTime=function(aryDateTime) //aryDateTime=[ { Date:, Time:, Index:-1 }, ......]
    {
        var findCount=0;
        for(var i in aryDateTime)
        {
            aryDateTime[i].Index=-1;
        }

        for(var i in this.Data)
        {
            var item=this.Data[i];
            for(var j in aryDateTime)
            {
                var findItem=aryDateTime[j];
                if (findItem.Index>=0) continue;

                if (IFrameSplitOperator.IsNumber(findItem.Time))
                {
                    if (findItem.Date==item.Date && findItem.Time==item.Time)
                    {
                        findItem.Index=parseInt(i);
                        ++findCount;
                        break;
                    }
                }
                else
                {
                    if (findItem.Date==item.Date)
                    {
                        findItem.Index=parseInt(i);
                        ++findCount;
                        break;
                    }
                }

                if (findCount>=aryDateTime.length) break;
            }
        }
    }

    //深拷贝数据
    this.CloneData=function(className)
    {
        var result=[];
        if (className=="HistoryData")
        {
            for(var i in this.Data)
            {
                var item=this.Data[i];
                var newItem=HistoryData.Copy(item);
                result.push(newItem);
            }
        }
        return result;
    }

    this.GetAPIDataIndex=function(date,time)
    {
        var result=[];
        if (date && time)
        {
            var count=this.Data.length;         //原始K线数据
            var indexCount=date.length;         //拟合数据
            var firstItem=ChartData.GetKLineDataTime(this.Data[0]);
            var indexStart=indexCount;  //拟合数据的起始位置

            var indexStart=indexCount;  //拟合数据的起始位置
            for(var i=0;i<indexCount;++i)
            {
                var itemDate=date[i];
                var itemTime=time[i];
    
               if (itemDate>firstItem.Date || (itemDate == firstItem.Date && itemTime >= firstItem.Time))
                {
                    indexStart = i;
                    break;
                }
            }

            for(var i=0, j=indexStart; i<count; )
            {
                var item=this.Data[i];
                if (j>=indexCount)
                {
                    var fitItem={ KDate:item.Date, KTime:item.Time, KIndex:i, Index:-1 };
                    result[i]=fitItem;
                    ++i;
                    continue;
                }

                var itemDate=date[j];
                var itemTime=time[j];
                if (itemDate == item.Date && itemTime == item.Time)
                {
                    var fitItem={ KDate:item.Date, KTime:item.Time, KIndex:i, Index:j, Data:itemDate, Time:itemTime };
                    result[i]=fitItem;
                    ++i;
                }
                else
                {
                    if (j+1<indexCount)
                    {
                        var nextItemDate=date[j+1];
                        var nextItemTime=time[j+1];

                        if ( (itemDate<item.Date && nextItemDate>item.Date) || 
                            (itemDate == item.Date && itemTime < item.Time && nextItemDate == item.Date && nextItemTime > item.Time) ||
                            (itemDate == item.Date && itemTime < item.Time && nextItemDate > item.Date) ||
                            (itemDate < item.Date && nextItemDate == item.Date && nextItemTime > item.Time) )
                        {
                            var fitItem={ KDate:item.Date, KTime:item.Time, KIndex:i, Index:j, Data:itemDate, Time:itemTime };
                            result[i]=fitItem;
                            ++i;
                        }
                        else if (nextItemDate < item.Date || (nextItemDate == item.Date && nextItemTime <= item.Time) )
                        {
                            ++j;
                        }
                        else
                        {
                            var fitItem={ KDate:item.Date, KTime:item.Time, KIndex:i, Index:-1 };
                            result[i]=fitItem;
                            ++i;
                        }
                    }
                    else
                    {
                        ++j;
                    }
                }
            }
        }
        else if (date)
        {
            var count=this.Data.length;         //原始K线数据
            var indexCount=date.length;         //拟合数据
            var firstItem=ChartData.GetKLineDataTime(this.Data[0]);

            var indexStart=indexCount;  //拟合数据的起始位置
            for(var i=0;i<indexCount;++i)
            {
                var item=date[i];
    
                if (item>=firstItem.Date)
                {
                    indexStart = i;
                    break;
                }
            }

            for(var i=0, j=indexStart; i<count; )
            {
                var item=this.Data[i];
                if (j>=indexCount)
                {
                    var fitItem={ KDate:item.Date, KIndex:i, Index:-1 };
                    result[i]=fitItem;
                    ++i;
                    continue;
                }

                var destDate=date[j];
                if (destDate == item.Date)
                {
                    var fitItem={ KDate:item.Date, KIndex:i, Index:j, Data:destDate };
                    result[i]=fitItem;
                    ++i;
                }
                else 
                {
                    if (j+1<indexCount)
                    {
                        var nextDestDate=date[j+1];
                        if ( destDate<=item.Date && nextDestDate>item.Date )
                        {
                            var fitItem={ KDate:item.Date, KIndex:i, Index:j, Data:destDate };
                            result[i]=fitItem;
                            ++i;
                        }
                        else if (nextDestDate <= item.Date )
                        {
                            ++j;
                        }
                        else
                        {
                            var fitItem={ KDate:item.Date, KIndex:i, Index:-1 };
                            result[i]=fitItem;
                            ++i;
                        }
                    }
                    else
                    {
                        ++j;
                    }
                }
            }
        }
        return result;
    }

    //K线数据拟合
    this.FixKData=function(aryKData, period)
    {
        if (ChartData.IsDayPeriod(period,true))
        {
            return this.FixKData_Day(aryKData);
        }
        else if (ChartData.IsMinutePeriod(period,true))
        {
            return this.FixKData_Minute(aryKData);
        }
        
        return null;
    }

    this.FixKData_Day=function(aryKData)
    {
        var result=[];
        var nOverlayDataCount=aryKData.length;
        for(var i=0,j=0; i<this.Data.length;)
        {
            var kItem=this.Data[i];
            if (j<nOverlayDataCount)
            {
                var fItem=aryKData[j];
                if (fItem.Date>kItem.Date)
                {
                    ++i;
                    continue;
                }
            }

            if (j+1<nOverlayDataCount)
            {
                var fItem = aryKData[j];
                var fItem2 = aryKData[j + 1];

                if (fItem.Date < kItem.Date && fItem2.Date <= kItem.Date)
                {
                    ++j;
                    continue;
                }
            }

            var item=new HistoryData();
            item.Date=kItem.Date;
            var index=j<nOverlayDataCount ? j : nOverlayDataCount-1;
            var fItem=aryKData[index];

            item.Close = fItem.Close;
			item.High = fItem.High;
			item.Low = fItem.Low;
			item.Open = fItem.Open;
			item.YClose = fItem.YClose;
			item.Amount = fItem.Amount;
            item.Vol = fItem.Vol;
            item.ExDate = fItem.Date;   //对应叠加数据的日期 调试用

            result[i]=item;
            ++i;
        }

        return result;
    }

    this.FixKData_Minute=function(aryKData)
    {
        var result=[];
        var nOverlayDataCount=aryKData.length;
        for(var i=0,j=0; i<this.Data.length;)
        {
            var kItem=this.Data[i];
            var kDateTime=ChartData.DateTimeToNumber(kItem);

            if (j<nOverlayDataCount)
            {
                var fItem=aryKData[j];
                var fDateTime=ChartData.DateTimeToNumber(fItem);
                if (fDateTime>kDateTime)
                {
                    ++i;
                    continue;
                }
            }

            if (j+1<nOverlayDataCount)
            {
                var fItem = aryKData[j];
                var fItem2 = aryKData[j + 1];
                var fDateTime=ChartData.DateTimeToNumber(fItem);
                var fDateTime2=ChartData.DateTimeToNumber(fItem2);

                if (fDateTime < kDateTime && fDateTime2 <= kDateTime)
                {
                    ++j;
                    continue;
                }
            }

            var item=new HistoryData();
            item.Date=kItem.Date;
            item.Time=kItem.Time;
            var index=j<nOverlayDataCount ? j : nOverlayDataCount-1;
            var fItem=aryKData[index];

            item.Close = fItem.Close;
			item.High = fItem.High;
			item.Low = fItem.Low;
			item.Open = fItem.Open;
			item.YClose = fItem.YClose;
			item.Amount = fItem.Amount;
            item.Vol = fItem.Vol;
            item.ExDate = fItem.Date;   //对应叠加数据的日期 调试用
            item.ExTime=fItem.Time;     //对应叠加数据的日期 调试用

            result[i]=item;
            ++i;
        }

        return result;
    }
}

ChartData.DateTimeToNumber=function(kItem)
{
    return kItem.Date*10000+kItem.Time;
}

ChartData.GetKLineDataTime=function(kLineItem)   //获取K线的 日期和时间 如果时间没有就用0
{
    var result={ Date:kLineItem.Date, Time:0 };
    if (IFrameSplitOperator.IsNumber(kLineItem.Time)) result.Time=kLineItem.Time;

    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;
}

ChartData.GetHalfYear=function(value)
{
    var year=parseInt(value/10000);
    var day=value%10000;
    if (day<=630) return year*10000+630;
    return year*10000+1231;
}

//是否是日线周期  0=日线 1=周线 2=月线 3=年线 9=季线 21=双周 22=半年 [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 || period==22) 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,'双周'],[22,"半年"],
        [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.GetEventCallback;

    this.Draw=function()
    {

    }

    this.GetBorder=function()
    {
        if (this.ChartFrame.IsHScreen) return this.ChartBorder.GetHScreenBorder();
        return this.ChartBorder.GetBorder();
    }

    this.ClipClient=function(isHScreen)          //裁剪客户端
    {
        if (isHScreen==true)
        {
            var left=this.ChartBorder.GetLeftEx();
            var right=this.ChartBorder.GetRightEx();
            var top=this.ChartBorder.GetTop();
            var bottom=this.ChartBorder.GetBottom();
        }
        else
        {
            var left=this.ChartBorder.GetLeft();
            var right=this.ChartBorder.GetRight();
            var top=this.ChartBorder.GetTopEx();
            var bottom=this.ChartBorder.GetBottomEx();
        }

        this.Canvas.beginPath();
        this.Canvas.rect(left,top,(right-left),(bottom-top));
        //this.Canvas.stroke(); //调试用
        this.Canvas.clip();
    }

    this.GetYFromData=function(value,isLimit)
    {
        return this.ChartFrame.GetYFromData(value,isLimit);
    }

    this.IsMinuteFrame=function()
    {
        var isMinute=(this.ChartFrame.ClassName=="MinuteFrame" || this.ChartFrame.ClassName=="MinuteHScreenFrame" ||
            this.ChartFrame.ClassName=="OverlayMinuteFrame" || this.ChartFrame.ClassName=="OverlayMinuteHScreenFrame" );

        return isMinute
    }

    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, distanceWidth,  maxSize, minSize, zoom, fontname)    //根据宽度自动获取对应字体
    {
        var pixelTatio = GetDevicePixelRatio();
        maxSize*=pixelTatio;
        minSize*=pixelTatio;

        if (maxSize==minSize)   //固定大小
        {
            var font=`${maxSize.toFixed(0)}px ${fontname}` ;
            return font;
        }

        var fontSize=(dataWidth+distanceWidth);
        if (zoom)
        {
            if (zoom.Type==0) 
            {
                if (zoom.Value>0) fontSize=(dataWidth*zoom.Value);
            }
            else if (zoom.Type==1)
            {
                if (zoom.Value>0) fontSize=(dataWidth+distanceWidth)*zoom.Value;
            }
            else if (zoom.Type==2)
            {
                if (IFrameSplitOperator.IsNumber(zoom.Value)) 
                    fontSize=(dataWidth+distanceWidth) + (2*zoom.Value)*pixelTatio;
            }
        }

        if (fontSize<minSize) fontSize=minSize;
        else if (fontSize>maxSize) fontSize=maxSize;

        var font=`${fontSize.toFixed(0)}px ${fontname}` ;

        /*
        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();
    }

    this.SetFillStyle=function(color, x0, y0, x1, y1)
    {
        if (Array.isArray(color))
        {
            let gradient = this.Canvas.createLinearGradient(x0, y0, x1, y1);
            var offset=1/(color.length);
            for(var i in color)
            {
                gradient.addColorStop(i*offset, color[i]);
            }
            this.Canvas.fillStyle=gradient;
        }
        else
        {
            this.Canvas.fillStyle=color;
        }
    }

    this.GetDynamicIconSize=function(dataWidth, distanceWidth, maxSize, minSize, zoom)
    {
        var pixelTatio = GetDevicePixelRatio();
        maxSize*=pixelTatio;
        minSize*=pixelTatio;

        if (maxSize==minSize) return maxSize;

        var iconSize=(dataWidth+distanceWidth)-2*pixelTatio;

        if (zoom)
        {
            if (zoom.Type==0) 
            {
                if (zoom.Value>0) iconSize=(dataWidth*zoom.Value);
            }
            else if (zoom.Type==1)
            {
                if (zoom.Value>0) iconSize=(dataWidth+distanceWidth)*zoom.Value;
            }
            else if (zoom.Type==2)
            {
                if (IFrameSplitOperator.IsNumber(zoom.Value)) 
                    iconSize=(dataWidth+distanceWidth) + (2*zoom.Value)*pixelTatio;
            }
        }

        if (iconSize<minSize) iconSize=minSize;
        else if (iconSize>maxSize) iconSize=maxSize;

        return iconSize;
    }

}


//缩放因子
/*
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],
    [15,5],     [13,5],
    [9,4], [7,4], [5,4], 

    [3,3],
    [3,1], [2,1], [1,1], [1,0],

    //[0.5,0],[0.4,0],[0.3,0],[0.2,0],[0.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=收盘价面积图 5=订单流
    this.CloseLineColor=g_JSChartResource.CloseLineColor;
    this.CloseLineAreaColor=g_JSChartResource.CloseLineAreaColor;
    this.CloseLineWidth=g_JSChartResource.CloseLineWidth;
    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:, Name:指标名称 }
    this.TradeIcon=g_JSChartResource.KLine.TradeIcon;
    this.TooltipRect=[];                    //2位数组 0 数据序号 1 区域
    this.InfoTooltipRect=[];                //2维数组 0 数据,  1 区域
    this.TradeIconTooltipRect=[];           //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.ShowRange={ };     //K线显示范围 { Start:, End:,  DataCount:, ShowCount: }
    this.CustomKLine;       //自定义K线, key=date*1000000+time,  key={ Color:, DrawType: }

    this.DrawKRange={ Start:null, End:null };   //当前屏K线的索引{ Start: , End:}
    
    /*
    this.CustomKLine=new Map([
        [20210415*1000000, { Color:'rgb(255,0,255)', DrawType:3, BGColor:"rgba(135,206,250,0.5)" }],
        [20210412*1000000, { DrawType:3 }],
        [20210108*1000000, { DrawType:3,BGColor:"rgba(135,206,250,0.5)"  }],
        [20210122*1000000, {Color:'rgb(122,135,155)'}]
    ]);
    */

    //订单流配置
    this.OrderFlow=
    { 
        UpColor:{BG:g_JSChartResource.OrderFlow.UpColor.BG, Border:g_JSChartResource.OrderFlow.UpColor.Border },
        DownColor:{ BG:g_JSChartResource.OrderFlow.DownColor.BG, Border:g_JSChartResource.OrderFlow.DownColor.Border },
        UnchagneColor: { BG:g_JSChartResource.OrderFlow.UnchagneColor.BG, Border:g_JSChartResource.OrderFlow.UnchagneColor.Border },
        Text:{ Color: g_JSChartResource.OrderFlow.Text.Color , Family:g_JSChartResource.OrderFlow.Text.Family, FontMaxSize:g_JSChartResource.OrderFlow.Text.FontMaxSize, MaxValue:g_JSChartResource.OrderFlow.Text.MaxValue },
        Line:{ UpDownColor: g_JSChartResource.OrderFlow.Line.UpDownColor, MiddleColor:g_JSChartResource.OrderFlow.Line.MiddleColor },

        ShowType:0  //显示类型 0, 1
    }

    this.IsShowOrderText=false;
    
    this.ReloadResource=function(resource)
    {
        this.TextFont=g_JSChartResource.KLine.MaxMin.Font;
        this.TextColor=g_JSChartResource.KLine.MaxMin.Color;

        this.CloseLineColor=g_JSChartResource.CloseLineColor;
        this.CloseLineAreaColor=g_JSChartResource.CloseLineAreaColor;
        this.CloseLineWidth=g_JSChartResource.CloseLineWidth;

        this.UpColor=g_JSChartResource.UpBarColor;
        this.DownColor=g_JSChartResource.DownBarColor;
        this.UnchagneColor=g_JSChartResource.UnchagneBarColor;          //平盘

        this.OrderFlow.UpColor={BG:g_JSChartResource.OrderFlow.UpColor.BG, Border:g_JSChartResource.OrderFlow.UpColor.Border };
        this.OrderFlow.DownColor={ BG:g_JSChartResource.OrderFlow.DownColor.BG, Border:g_JSChartResource.OrderFlow.DownColor.Border };
        this.OrderFlow.UnchagneColor= { BG:g_JSChartResource.OrderFlow.UnchagneColor.BG, Border:g_JSChartResource.OrderFlow.UnchagneColor.Border };
        this.OrderFlow.Text={ Color: g_JSChartResource.OrderFlow.Text.Color , Family:g_JSChartResource.OrderFlow.Text.Family, FontMaxSize:g_JSChartResource.OrderFlow.Text.FontMaxSize, MaxValue:g_JSChartResource.OrderFlow.Text.MaxValue };
        this.OrderFlow.Line={ UpDownColor: g_JSChartResource.OrderFlow.Line.UpDownColor, MiddleColor:g_JSChartResource.OrderFlow.Line.MiddleColor };
    }

    this.ClearCustomKLine=function()
    {
        this.CustomKLine=null;
    }

    this.GetCustomKLine=function(kItem)
    {
        if (!this.CustomKLine) return null;
        if (!kItem) return null;

        var key=kItem.Date*1000000;
        if (IFrameSplitOperator.IsNumber(kItem.Time)) key+=kItem.Time;
        if (!this.CustomKLine.has(key)) return null;

        var value=this.CustomKLine.get(key);
        return value;
    }

    this.DrawAKLine=function()  //美国线
    {
        var isHScreen=(this.ChartFrame.IsHScreen===true);
        var dataWidth=this.ChartFrame.DataWidth;
        var distanceWidth=this.ChartFrame.DistanceWidth;
        var xPointCount=this.ChartFrame.XPointCount;

        if (isHScreen)
        {
            var border=this.ChartBorder.GetHScreenBorder();
            var xOffset=border.TopEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
            var chartright=border.BottomEx;
        }
        else
        {
            var border=this.ChartBorder.GetBorder();
            var xOffset=border.LeftEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
            var chartright=border.RightEx;
        }

        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.GetYFromData(data.Low,false);
            var yHigh=this.GetYFromData(data.High,false);
            var yOpen=this.GetYFromData(data.Open,false);
            var yClose=this.GetYFromData(data.Close,false);

            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 xPointCount=this.ChartFrame.XPointCount;

        if (isHScreen)
        {
            var border=this.ChartBorder.GetHScreenBorder();
            var xOffset=border.TopEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
            var chartright=border.BottomEx;
        }
        else
        {
            var border=this.ChartBorder.GetBorder();
            var xOffset=border.LeftEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
            var chartright=border.RightEx;
        }
        

        var bFirstPoint=true;
        var firstPoint=null;
       
        this.Canvas.beginPath();
        this.Canvas.strokeStyle=this.CloseLineColor;
        if (IFrameSplitOperator.IsNumber(this.CloseLineWidth)) this.Canvas.lineWidth=this.CloseLineWidth;
        var ptLast=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.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.GetYFromData(data.Close,false);

            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 (i==this.Data.Data.length-1)
            {
                ptLast={ X:x, Y:yClose, XLeft:left, XRight:right, KItem:data, ChartRight:chartright };
            }
        }

        this.DrawLastPointEvent(ptLast);  //通知外部绘制最后一个点

        if (bFirstPoint) return;

        this.Canvas.stroke();
        if (isHScreen)
        {
            this.Canvas.lineTo(border.Left,x);
            this.Canvas.lineTo(border.Left,firstPoint.Y);
        }
        else
        {
            this.Canvas.lineTo(x,border.Bottom);
            this.Canvas.lineTo(firstPoint.X,border.Bottom);
        }
        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 xPointCount=this.ChartFrame.XPointCount;

        if (isHScreen)
        {
            var border=this.ChartBorder.GetHScreenBorder();
            var xOffset=border.TopEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
            var chartright=border.BottomEx;
        }
        else
        {
            var border=this.ChartBorder.GetBorder();
            var xOffset=border.LeftEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
            var chartright=border.RightEx;
        }
        
        var bFirstPoint=true;
        this.Canvas.beginPath();
        this.Canvas.strokeStyle=this.CloseLineColor;
        if (IFrameSplitOperator.IsNumber(this.CloseLineWidth)) this.Canvas.lineWidth=this.CloseLineWidth;
        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.GetYFromData(data.Close,false);

            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 border=this.ChartBorder.GetBorder();
        var xOffset=border.LeftEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
        var chartright=border.RightEx;
        var xPointCount=this.ChartFrame.XPointCount;

        if (isHScreen) 
        {
            var border=this.ChartBorder.GetHScreenBorder();
            xOffset=border.TopEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
            chartright=border.BottomEx;
        }

        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; 

        this.ShowRange.Start=this.Data.DataOffset;
        this.ShowRange.End=this.ShowRange.Start;
        this.ShowRange.DataCount=0;
        this.ShowRange.ShowCount=xPointCount;
        var ptLast=null;
        this.DrawKRange.Start=this.Data.DataOffset;
        for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth),++this.ShowRange.DataCount)
        {
            var data=this.Data.Data[i];
            this.ShowRange.End=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.GetYFromData(data.Low, false);
            var yHigh=this.GetYFromData(data.High, false);
            var yOpen=this.GetYFromData(data.Open, false);
            var yClose=this.GetYFromData(data.Close, false);
            var y=yHigh;

            this.DrawKRange.End=i;
            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;
            }

            var kLineOption=this.GetCustomKLine(data);

            if (kLineOption)
            {
                var barColor=kLineOption.Color;
                if (!barColor)
                {
                    if (data.Open<data.Close) barColor=upColor;
                    else if (data.Open>data.Close) barColor=downColor;
                    else barColor=unchagneColor;
                }

                var drawType=this.DrawType;
                if (IFrameSplitOperator.IsNumber(kLineOption.DrawType)) drawType=kLineOption.DrawType;

                this.DrawKBar_Custom(data, dataWidth, barColor, drawType, kLineOption, x, y, left, right, yLow, yHigh, yOpen, yClose, border, isHScreen);
            }
            else if (data.Open<data.Close)       //阳线
            {
                this.DrawKBar_Up(data, dataWidth, upColor, this.DrawType, x, y, left, right, yLow, yHigh, yOpen, yClose, isHScreen);
            }
            else if (data.Open>data.Close)  //阴线
            {
                this.DrawKBar_Down(data, dataWidth, downColor, this.DrawType, x, y, left, right, yLow, yHigh, yOpen, yClose, isHScreen);
            }
            else // 平线
            {
                this.DrawKBar_Unchagne(data, dataWidth, unchagneColor, this.DrawType, x, y, left, right, yLow, yHigh, yOpen, yClose, isHScreen);
            }
            
            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);
            }

            if (i==this.Data.Data.length-1)
            {
                ptLast={ X:x, Y:yClose, XLeft:left, XRight:right, KItem:data, ChartRight:chartright };
            }
        }

        this.DrawLastPointEvent(ptLast);  //通知外部绘制最后一个点

        this.PtMax=ptMax;
        this.PtMin=ptMin;
    }

    this.DrawKBar_Up=function(data, dataWidth, upColor, drawType, x, y, left, right, yLow, yHigh, yOpen, yClose, isHScreen) //阳线
    {
        if (dataWidth>=4)
        {
            if (drawType==3)
            {
                if ((dataWidth%2)!=0) dataWidth-=1;
            }

            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(drawType==3?Math.max(yClose,yOpen):yClose),ToFixedPoint(x));
                }
                else
                {
                    if (drawType==3)
                    {
                        var xFixed=left+dataWidth/2;
                        this.Canvas.moveTo(ToFixedPoint(xFixed),ToFixedPoint(y));
                        this.Canvas.lineTo(ToFixedPoint(xFixed),ToFixedPoint(Math.min(yClose,yOpen)));
                    }
                    else
                    {
                        this.Canvas.moveTo(ToFixedPoint(x),ToFixedPoint(y));
                        this.Canvas.lineTo(ToFixedPoint(x),ToFixedPoint(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 (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 (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(drawType==3?Math.min(yClose,yOpen):y),ToFixedPoint(x));
                    this.Canvas.lineTo(ToFixedPoint(yLow),ToFixedPoint(x));
                }
                else
                {
                    if (drawType==3)
                    {
                        var xFixed=left+dataWidth/2;
                        this.Canvas.moveTo(ToFixedPoint(xFixed),ToFixedPoint(Math.max(yClose,yOpen)));
                        this.Canvas.lineTo(ToFixedPoint(xFixed),ToFixedPoint(yLow));
                    }
                    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=upColor;
            this.Canvas.stroke();
        }
    }

    this.DrawKBar_Down=function(data, dataWidth, downColor, drawType, x, y, left, right, yLow, yHigh, yOpen, yClose, isHScreen) //阴线
    {
        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();
        }
    }

    this.DrawKBar_Unchagne=function(data, dataWidth, unchagneColor, drawType, x, y, left, right, yLow, yHigh, yOpen, yClose, isHScreen) //平线
    {
        if (dataWidth>=4)
        {
            if ((dataWidth%2)!=0) dataWidth-=1;
            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
                {
                    var xFixed=ToFixedPoint(left+dataWidth/2);
                    this.Canvas.moveTo(xFixed,y);
                    this.Canvas.lineTo(xFixed,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(left+dataWidth),ToFixedPoint(y));
            }

            if (data.Open>data.Low) //下影线
            {
                if (isHScreen)
                {
                    this.Canvas.moveTo(ToFixedPoint(y),ToFixedPoint(x));
                    this.Canvas.lineTo(ToFixedPoint(yLow),ToFixedPoint(x));
                }
                else
                {
                    var xFixed=ToFixedPoint(left+dataWidth/2);
                    this.Canvas.moveTo(xFixed,ToFixedPoint(y));
                    this.Canvas.lineTo(xFixed,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();
        }
    }

    this.DrawKBar_Custom=function(data, dataWidth, barColor, drawType, option, x, y, left, right, yLow, yHigh, yOpen, yClose, border, isHScreen)
    {
        if (option.BGColor) //画背景色
        {
            this.Canvas.fillStyle=option.BGColor;
            var distanceWidth=this.ChartFrame.DistanceWidth;
            if (isHScreen)
            {
                var yLeft=left-(distanceWidth/2);
                var yRight=right+(distanceWidth/2);
                var xTop=border.RightEx;
                var xBottom=border.LeftEx;

                this.Canvas.fillRect(ToFixedRect(xBottom),ToFixedRect(yLeft),ToFixedRect(xTop-xBottom),ToFixedRect(yRight-yLeft));
            }
            else
            {
                var xLeft=left-(distanceWidth/2);
                var xRight=right+(distanceWidth/2);
                var yTop=border.TopEx;
                var yBottom=border.BottomEx;
                
                this.Canvas.fillRect(ToFixedRect(xLeft),ToFixedRect(yTop),ToFixedRect(xRight-xLeft),ToFixedRect(yBottom-yTop));
            }
        }

        if (dataWidth>=4)
        {
            this.Canvas.strokeStyle=barColor;
            if (data.High>data.Close)   //上影线
            {
                this.Canvas.beginPath();
                if (isHScreen)
                {
                    this.Canvas.moveTo(ToFixedPoint(y),ToFixedPoint(x));
                    this.Canvas.lineTo(ToFixedPoint(drawType==3?Math.max(yClose,yOpen):yClose),ToFixedPoint(x));
                }
                else
                {
                    this.Canvas.moveTo(ToFixedPoint(x),ToFixedPoint(y));
                    this.Canvas.lineTo(ToFixedPoint(x),ToFixedPoint(drawType==3?Math.min(yClose,yOpen):yClose));
                }
                this.Canvas.stroke();
                y=yClose;
            }
            else
            {
                y=yClose;
            }

            this.Canvas.fillStyle=barColor;
            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.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 (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(drawType==3?Math.min(yClose,yOpen):y),ToFixedPoint(x));
                    this.Canvas.lineTo(ToFixedPoint(yLow),ToFixedPoint(x));
                }
                else
                {
                    this.Canvas.moveTo(ToFixedPoint(x),ToFixedPoint(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=barColor;
            this.Canvas.stroke();
        }
    }

    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.GetYFromData(data.Low,false);
            var yHigh=this.GetYFromData(data.High,false);
            var yOpen=this.GetYFromData(data.Open,false);
            var yClose=this.GetYFromData(data.Close,false);
            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;
        var pixelRatio=GetDevicePixelRatio();
        var textSize=fontSize*pixelRatio;
        this.Canvas.beginPath();
        this.Canvas.font=fontSize*pixelRatio+'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,false);

            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);

            if (this.IsShowKTooltip && !isHScreen)    //添加tooltip区域
            {
                var rect=new Rect(x-textSize/2,yClose-textSize/2,textSize,textSize);
                //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]数据区域
            }
        }
    }

    this.ClipTickClient=function(isHScreen)
    {
        var border=this.GetBorder();
        if (isHScreen==true)
        {
            var left=this.ChartBorder.GetLeftEx();
            var right=this.ChartBorder.GetRightEx();
            var top=this.ChartBorder.GetTop();
            var bottom=this.ChartBorder.GetBottom();
        }
        else
        {
            var left=border.Left;
            var right=border.Right;
            var top=border.TopTitle;
            var bottom=border.Bottom;
        }

        this.Canvas.beginPath();
        this.Canvas.rect(left,top,(right-left),(bottom-top));
        this.Canvas.clip();
    }

    this.Draw=function()
    {
        this.IsShowOrderText=false;
        this.TooltipRect=[];
        this.InfoTooltipRect=[];
        this.TradeIconTooltipRect=[];
        this.PtMax={X:null,Y:null,Value:null,Align:'left'}; //清空最大
        this.PtMin={X:null,Y:null,Value:null,Align:'left'}; //清空最小
        this.DrawKRange={ Start:null, End:null }; 

        this.ChartFrame.ChartKLine={Max:null, Min:null };   //保存K线上 显示最大最小值坐标

        if (!this.IsShow) return;

        if (ChartData.IsTickPeriod(this.Period))    //分笔图
        {
            this.Canvas.save();
            

            if (this.DrawType==1)
            {
                this.ClipClient(this.ChartFrame.IsHScreen);
                this.DrawCloseLine();
            }
            else
            {
                this.ClipTickClient(this.ChartFrame.IsHScreen);
                this.DrawTick();
            }
                

            this.Canvas.restore();
            return;
        }

        this.Canvas.save();
        this.ClipClient(this.ChartFrame.IsHScreen);

        if (this.DrawType==1) 
        {
            this.DrawCloseLine();
            this.Canvas.restore();
            return;
        }
        else if (this.DrawType==2)
        {
            this.DrawAKLine();
        }
        else if (this.DrawType==4)
        {
            this.DrawCloseArea();
        }
        else if (this.DrawType==5)
        {
            this.DrawOrderFlow();
        }
        else
        {
            this.DrawKBar();
        }

        if (this.TradeIcon) this.DrawTradeIcon()
        else this.DrawTrade();
        this.Canvas.restore();

        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 leftArrow=g_JSChartResource.KLine.MaxMin.LeftArrow;
        var rightArrow=g_JSChartResource.KLine.MaxMin.RightArrow;
        var highYOffset=g_JSChartResource.KLine.MaxMin.HighYOffset;
        var lowYOffset=g_JSChartResource.KLine.MaxMin.LowYOffset;

        var defaultfloatPrecision=GetfloatPrecision(this.Symbol);
        this.Canvas.font=this.TextFont;
        this.Canvas.fillStyle=this.TextColor;
        var top=this.ChartBorder.GetTopEx();
        var bottom=this.ChartBorder.GetBottomEx();

        var ptTop=ptMax;
        if (this.ChartFrame.CoordinateType==1)  //反转坐标
        {
            if (ptMax.Y<ptMin.Y) ptTop=ptMin;
            this.Canvas.textBaseline='top';
        }
        else
        {
            if (ptMax.Y>ptMin.Y) ptTop=ptMin;
            this.Canvas.textBaseline='bottom';
        }
        
        this.Canvas.textAlign=ptTop.Align;
        var left=ptTop.Align=='left'?ptTop.X:ptTop.X;
        if (IFrameSplitOperator.IsNumber(highYOffset)) ptTop.Y+=highYOffset;
        var text=ptTop.Value.toFixed(defaultfloatPrecision);
        if (ptTop.Align=='left') text=leftArrow+text;
        else text=text+rightArrow;
        if (ptTop.Y>(top-2))
        {
            this.Canvas.fillText(text,left,ptTop.Y);
            this.ChartFrame.ChartKLine.Max={X:left, Y:ptTop.Y, Text: { BaseLine:'bottom'}};
        }
        
        var ptBottom=ptMin;
        if (this.ChartFrame.CoordinateType==1)
        {
            if (ptMin.Y>ptMax.Y) ptBottom=ptMax;
            this.Canvas.textBaseline='bottom';
        }
        else
        {
            if (ptMax.Y>ptMin.Y) ptTop=ptMin;
            this.Canvas.textBaseline='top';
        }
        this.Canvas.textAlign=ptBottom.Align;
        
        var left=ptBottom.Align=='left'?ptBottom.X:ptBottom.X;
        if (IFrameSplitOperator.IsNumber(lowYOffset)) ptBottom.Y+=lowYOffset;
        var text=ptMin.Value.toFixed(defaultfloatPrecision);
        if (ptBottom.Align=='left') text=leftArrow+text;
        else  text=text+rightArrow;
        if (ptBottom.Y<(bottom+1))
        {
            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 leftArrow=g_JSChartResource.KLine.MaxMin.LeftArrow;
        var rightArrow=g_JSChartResource.KLine.MaxMin.RightArrow;
        var highYOffset=g_JSChartResource.KLine.MaxMin.HighYOffset;
        var lowYOffset=g_JSChartResource.KLine.MaxMin.LowYOffset;

        var defaultfloatPrecision=GetfloatPrecision(this.Symbol);
        var xText=ptMax.Y;
        var yText=ptMax.X;
        if (IFrameSplitOperator.IsNumber(highYOffset)) xText+=highYOffset;
        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=leftArrow+text;
        else  text=text+rightArrow;
        this.Canvas.fillText(text,0,0);
        this.Canvas.restore();

        
        var xText=ptMin.Y;
        var yText=ptMin.X;
        if (IFrameSplitOperator.IsNumber(lowYOffset)) xText+=lowYOffset;
        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=leftArrow+text;
        else text=text+rightArrow;
        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 top=this.ChartBorder.GetTop();

        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 iconBottom=item.YMin+1*pixelTatio+iconSize;
        var drawTop=true;
        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);
                    var 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
                    {
                        if (drawTop)
                        {
                            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;
                            if (iconTop-iconSize<top ) drawTop=false;
                        }
                        else    //上面显示不下,就显示在下面
                        {
                            this.Canvas.fillText(icon.Text,item.XCenter,iconBottom,iconSize);
                            var iconRect=new Rect(item.XCenter-iconSize/2,iconBottom-iconSize,iconSize,iconSize);
                            var infoCache={ Data:new Array(infoItem), Rect:iconRect, Type:infoItem.InfoType, TextRect:{X:item.XCenter, Y:iconBottom} };
                            mapImage.set(infoItem.InfoType,infoCache);
                            iconBottom+=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.GetYFromData(data.Low,false);
            var yHigh=this.GetYFromData(data.High,false);
            var yOpen=this.GetYFromData(data.Open,false);
            var yClose=this.GetYFromData(data.Close,false);
            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);

                    var iconRect=new Rect(x-iconSize/2,yLow,iconSize,iconSize);
                    var iconData={ Data:{ Type:1, KData:data, Name:this.TradeData.Name, Param:this.TradeData.Param }, Rect:iconRect, TextRect:{X:x, Y:yLow} };
                    this.TradeIconTooltipRect.push(iconData); 
                }
            }

            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);

                    var iconRect=new Rect(x-iconSize/2,yHigh-iconSize,iconSize,iconSize);
                    var iconData={ Data:{ Type:2, KData:data, Name:this.TradeData.Name,Param:this.TradeData.Param }, Rect:iconRect, TextRect:{X:x, Y:yHigh} };
                    this.TradeIconTooltipRect.push(iconData); 
                }
            }
        }
    }

    this.GetTooltipData=function(x,y,tooltip)
    {
        for(var i in this.TradeIconTooltipRect)
        {
            var item=this.TradeIconTooltipRect[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] trade icon ', item);
                tooltip.Data=item;
                tooltip.ChartPaint=this;
                tooltip.Type=2; //指标
                return true;
            }
        }

        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] info ', 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 (this.DrawType==5 && data.OrderFlow && IFrameSplitOperator.IsNumber(data.OrderFlow.PriceOffset))
                {
                    var high=data.High;
                    var low=data.Low;

                    if (IFrameSplitOperator.IsNonEmptyArray(data.OrderFlow.High))
                    {
                        for(var k=0;k<data.OrderFlow.High.length;++k)
                        {
                            var item=data.OrderFlow.High[k];
                            if (high<item.Price) high=item.Price;
                        }
                    }

                    if (IFrameSplitOperator.IsNonEmptyArray(data.OrderFlow.Low))
                    {
                        for(var k=0;k<data.OrderFlow.Low.length;++k)
                        {
                            var item=data.OrderFlow.Low[k];
                            if (low>item.Price) low=item.Price;
                        }
                    }

                    high+=data.OrderFlow.PriceOffset;
                    low-=data.OrderFlow.PriceOffset;

                    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;
                }
                else
                {
                    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;
    }

    this.DrawLastPointEvent=function(ptLast)
    {
        if (!this.GetEventCallback)  return;
        
        //通知外部绘制最后一个点
        var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_DRAW_KLINE_LAST_POINT);
        if (event)
        {
            var kWidth={ Data: this.ChartFrame.DataWidth, Distance:this.ChartFrame.DistanceWidth };
            if (ptLast) var data={ LastPoint:{ X:ptLast.X, Y:ptLast.Y, XLeft:ptLast.XLeft, XRight:ptLast.XRight }, KItem:ptLast.KItem, DrawType:this.DrawType, KWidth:kWidth, ChartRight:ptLast.ChartRight };
            else var data={ LastPoint:null, KItem:null, KWidth:kWidth };
            event.Callback(event,data,this);
        }
    }

    this.DrawOrderFlow=function()
    {
        var isHScreen=(this.ChartFrame.IsHScreen===true);
        var dataWidth=this.ChartFrame.DataWidth;
        var distanceWidth=this.ChartFrame.DistanceWidth;
        var border=this.ChartBorder.GetBorder();
        var xOffset=border.LeftEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
        var chartright=border.RightEx;
        var xPointCount=this.ChartFrame.XPointCount;

        if (isHScreen) 
        {
            var border=this.ChartBorder.GetHScreenBorder();
            xOffset=border.TopEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
            chartright=border.BottomEx;
        }
        
        var upColor=this.UpColor;
        var downColor=this.DownColor;
        var unchagneColor=this.UnchagneColor; 

        this.ShowRange.Start=this.Data.DataOffset;
        this.ShowRange.End=this.ShowRange.Start;
        this.ShowRange.DataCount=0;
        this.ShowRange.ShowCount=xPointCount;
        var ptLast=null;

        var horizontalMax=this.ChartFrame.HorizontalMax, horizontalMin=this.ChartFrame.HorizontalMin;
        var startOffset=this.Data.DataOffset, endOffset=this.Data.DataOffset+xPointCount
        for(var i=0; i<this.Data.Data.length;++i)   //绘制横线柱子
        {
            var kItem=this.Data.Data[i];
            if (!kItem || !kItem.OrderFlow) continue;
            if (!IFrameSplitOperator.IsNonEmptyArray(kItem.OrderFlow.Order)) continue;

            for(var j=0;j<kItem.OrderFlow.Order.length;++j)
            {
                var orderItem=kItem.OrderFlow.Order[j];
                if (!orderItem.HBar) continue;
                if (!IFrameSplitOperator.IsNumber(orderItem.HBar.Width)) continue;
                if (!IFrameSplitOperator.IsNumber(orderItem.Price)) continue;
                if (orderItem.Price>horizontalMax || orderItem.Price<horizontalMin) continue;
                var value=Math.ceil((i+orderItem.HBar.Width));
                var start=Math.min(i,value);
                var end=Math.max(i,value);
                if (end<startOffset || start>endOffset) continue;
                
                this.DrawOrderFlowHBar(i, kItem.OrderFlow, orderItem, dataWidth, distanceWidth);
            }

        }

        for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth),++this.ShowRange.DataCount)
        {
            var data=this.Data.Data[i];
            this.ShowRange.End=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.GetYFromData(data.Low, false);
            var yHigh=this.GetYFromData(data.High, false);
            var yOpen=this.GetYFromData(data.Open, false);
            var yClose=this.GetYFromData(data.Close, false);
            var y=yHigh;

            var yKline={ Low:yLow, High:yHigh, Open:yOpen, Close:yClose };
            var xKLine={ Left:left, Center:x, Right:right, DataWidth:dataWidth };

            this.DrawOrderFlowBar(data.OrderFlow, data, xKLine, yKline, isHScreen);
            
            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);
            }

            if (i==this.Data.Data.length-1)
            {
                ptLast={ X:x, Y:yClose, XLeft:left, XRight:right, KItem:data, ChartRight:chartright };
            }
        }
    }

    this.DrawOrderFlowBar=function(orderFlow, kItem, xKLine, yKline, isHScreen)
    {
        var top=Math.min(yKline.Open, yKline.Close)
        var bottom=Math.max(yKline.Open, yKline.Close);
        var barHeight=Math.abs(yKline.Open-yKline.Close);
        var cellHeight=0;
        if (orderFlow && IFrameSplitOperator.IsNumber(orderFlow.PriceOffset)) cellHeight=this.GetPriceYOffset(orderFlow.PriceOffset);
        var textFont=this.GetDynamicOrderFlowFont(cellHeight, xKLine.DataWidth/2);
        this.IsShowOrderText=(cellHeight>5 && xKLine.DataWidth>10);

        var kColor;
        if (kItem.Open<kItem.Close) kColor=this.OrderFlow.UpColor;
        else if (kItem.Open>kItem.Close) kColor=this.OrderFlow.DownColor;
        else kColor=this.OrderFlow.UnchagneColor;

        var isSmallKLine=(xKLine.DataWidth<4);

        if (isSmallKLine)
        {
            this.Canvas.strokeStyle=kColor.Border;
            this.Canvas.beginPath();
            this.Canvas.moveTo(ToFixedPoint(xKLine.Center),top-cellHeight/2);
            this.Canvas.lineTo(ToFixedPoint(xKLine.Center),bottom+cellHeight/2);
            this.Canvas.stroke();
        }
        else
        {
            this.Canvas.fillStyle=kColor.BG;
            this.Canvas.fillRect(ToFixedRect(xKLine.Left),ToFixedRect(top-cellHeight/2),ToFixedRect(xKLine.DataWidth),ToFixedRect(barHeight+cellHeight));
        }
        
        
        this.Canvas.textBaseline='middle';
        this.Canvas.textAlign='center';
        this.Canvas.font=textFont;
        var textWidth=xKLine.DataWidth/2;
        var textXOffset=textWidth/2;
        if (orderFlow && IFrameSplitOperator.IsNonEmptyArray(orderFlow.Order))
        {
            for(var i=0;i<orderFlow.Order.length;++i)
            {
                var item=orderFlow.Order[i];
                var yPrice=this.GetYFromData(item.Price, false);
    
                var rect={ Left:xKLine.Left, Right:xKLine.Center, Bottom:yPrice+cellHeight/2, Top:yPrice-cellHeight/2 };
                rect.Width=rect.Right-rect.Left;
                rect.Height=rect.Bottom-rect.Top;
    
                if (item.Ask.BG)
                {
                    this.Canvas.fillStyle=item.Ask.BG;
                    this.Canvas.fillRect(ToFixedRect(rect.Left),ToFixedRect(rect.Top),ToFixedRect(rect.Width),ToFixedRect(rect.Height));
                }
    
                var text=null;
                if (IFrameSplitOperator.IsString(item.Ask.Text)) text=item.Ask.Text;
                else if (IFrameSplitOperator.IsNumber(item.Ask.Value)) text=item.Ask.Value.toString();
                if (text && this.IsShowOrderText)
                {
                    if (item.Ask.Color) this.Canvas.fillStyle=item.Ask.Color;
                    else this.Canvas.fillStyle=this.OrderFlow.Text.Color;

                    if (item.Ask.Font)
                    {
                        var itemFont=this.GetDynamicOrderFlowFont(cellHeight, xKLine.DataWidth/2, item.Ask.Font);
                        this.Canvas.font=itemFont;
                        this.Canvas.fillText(text,xKLine.Left+textXOffset,yPrice);
                        this.Canvas.font=textFont;
                    }
                    else
                    {
                        this.Canvas.fillText(text,xKLine.Left+textXOffset,yPrice);
                    }
                }
    
                
                var rect={ Left:xKLine.Center, Right:xKLine.Right, Bottom:yPrice+cellHeight/2, Top:yPrice-cellHeight/2 };
                rect.Width=rect.Right-rect.Left;
                rect.Height=rect.Bottom-rect.Top;
    
                if (item.Bid.BG)
                {
                    this.Canvas.fillStyle=item.Bid.BG;
                    this.Canvas.fillRect(ToFixedRect(rect.Left),ToFixedRect(rect.Top),ToFixedRect(rect.Width),ToFixedRect(rect.Height));
                }
    
                var text=null;
                if (IFrameSplitOperator.IsString(item.Bid.Text)) text=item.Bid.Text;
                else if (IFrameSplitOperator.IsNumber(item.Bid.Value)) text=item.Bid.Value.toString();
                if (text && this.IsShowOrderText)
                {
                    if (item.Bid.Color) this.Canvas.fillStyle=item.Bid.Color;
                    else this.Canvas.fillStyle=this.OrderFlow.Text.Color;
    
                    if (item.Bid.Font)
                    {
                        var itemFont=this.GetDynamicOrderFlowFont(cellHeight, xKLine.DataWidth/2, item.Bid.Font);
                        this.Canvas.font=itemFont;
                        this.Canvas.fillText(text,xKLine.Center+textXOffset,yPrice);
                        this.Canvas.font=textFont;
                    }
                    else
                    {
                        this.Canvas.fillText(text,xKLine.Center+textXOffset,yPrice);
                    }
                    
                }
            }
        }
        
        if (yKline.High<top || yKline.Low>bottom)
        {
            this.Canvas.strokeStyle=this.OrderFlow.Line.UpDownColor;
            if (yKline.High<top)
            {
                this.Canvas.beginPath();
                this.Canvas.moveTo(ToFixedPoint(xKLine.Center),yKline.High-cellHeight/2);
                this.Canvas.lineTo(ToFixedPoint(xKLine.Center),top-cellHeight/2);
                this.Canvas.stroke();
            }

            if (yKline.Low>bottom)
            {
                this.Canvas.beginPath();
                this.Canvas.moveTo(ToFixedPoint(xKLine.Center),yKline.Low+cellHeight/2);
                this.Canvas.lineTo(ToFixedPoint(xKLine.Center),bottom+cellHeight/2);
                this.Canvas.stroke();
            }
        }

        if (!isSmallKLine && Math.abs(yKline.Open-yKline.Close)>1)  //K线中间竖线
        {
            this.Canvas.strokeStyle=this.OrderFlow.Line.MiddleColor;
            this.Canvas.beginPath();
            this.Canvas.moveTo(ToFixedPoint(xKLine.Center),top-cellHeight/2);
            this.Canvas.lineTo(ToFixedPoint(xKLine.Center),bottom+cellHeight/2);
            this.Canvas.stroke();
        }

        //K线边框
        if (!isSmallKLine)
        {
            this.Canvas.beginPath();
            this.Canvas.strokeStyle=kColor.Border;
            this.Canvas.rect(ToFixedPoint(xKLine.Left),ToFixedPoint(top-cellHeight/2),ToFixedRect(xKLine.DataWidth),ToFixedRect(barHeight+cellHeight));
            this.Canvas.stroke();
        }
        

        //var fontHeight=this.Canvas.measureText("擎").width+2;
        var textFont=this.GetDynamicOrderFlowFont(cellHeight, xKLine.DataWidth);
        //上下文字
        if (orderFlow && IFrameSplitOperator.IsNonEmptyArray(orderFlow.High) && this.IsShowOrderText)
        {
            for(var i=0;i<orderFlow.High.length;++i)
            {
                var item=orderFlow.High[i];
                var text;
                if (IFrameSplitOperator.IsString(item.Text)) text=item.Text;
                else if (IFrameSplitOperator.IsNumber(item.Value)) text=item.Value.toString();
                if (!text) continue;

                if (item.Color) this.Canvas.fillStyle=item.Color;
                else this.Canvas.fillStyle=this.OrderFlow.Text.Color;

                var yPrice=this.GetYFromData(item.Price, false);

                if (item.Font)
                {
                    var itemFont=this.GetDynamicOrderFlowFont(cellHeight, xKLine.DataWidth, item.Font);
                    this.Canvas.font=itemFont;
                    this.Canvas.fillText(text,xKLine.Center,yPrice);
                    this.Canvas.font=textFont;
                } 
                else
                {
                    this.Canvas.fillText(text,xKLine.Center,yPrice);
                }
                
            }
        }

        if (orderFlow && IFrameSplitOperator.IsNonEmptyArray(orderFlow.Low) && this.IsShowOrderText)
        {
            for(var i=0;i<orderFlow.Low.length;++i)
            {
                var item=orderFlow.Low[i];
                var text;
                if (IFrameSplitOperator.IsString(item.Text)) text=item.Text;
                else if (IFrameSplitOperator.IsNumber(item.Value)) text=item.Value.toString();
                if (!text) continue;

                if (item.Color) this.Canvas.fillStyle=item.Color;
                else this.Canvas.fillStyle=this.OrderFlow.Text.Color;

                var yPrice=this.GetYFromData(item.Price, false);

                if (item.Font)
                {
                    var itemFont=this.GetDynamicOrderFlowFont(cellHeight, xKLine.DataWidth, item.Font);
                    this.Canvas.font=itemFont;
                    this.Canvas.fillText(text,xKLine.Center,yPrice);
                    this.Canvas.font=textFont;
                } 
                else
                {
                    this.Canvas.fillText(text,xKLine.Center,yPrice);
                }
                
            }
        }
    }

    this.GetPriceYOffset=function(value)
    {
        var frame=this.ChartFrame;
        var y=frame.ChartBorder.GetHeightEx()*(value)/(frame.HorizontalMax-frame.HorizontalMin);
        return y;
    }

    this.GetDynamicOrderFlowFont=function(cellHeight, width, fontOption)
    {
        var fontSize=parseInt(cellHeight)-2;
        if (fontSize>this.OrderFlow.Text.FontMaxSize) fontSize=this.OrderFlow.Text.FontMaxSize;
        else if (fontSize<=0) fontSize=1;
        var font=this.FormatFontString(fontSize, this.OrderFlow.Text.Family, fontOption);

        for(var i=fontSize; i>0; i-=2)
        {
            var font=this.FormatFontString(i, this.OrderFlow.Text.Family, fontOption);
            this.Canvas.font=font;
            var textWidth=this.Canvas.measureText(this.OrderFlow.Text.MaxValue).width+2;
            if (textWidth<width) break;
        }

        return font;
    }

    this.FormatFontString=function(fontSize, family, option)
    {
        var font;
        if (!option) 
        {
            font=`${fontSize}px ${family}`;
        }
        else
        {
            if (option.Weight) font=`${option.Weight} ${fontSize}px ${family}`;
        }

        return font;
    }

    this.DrawOrderFlowHBar=function(index, orderFlow, orderItem, dataWidth, distanceWidth)
    {
        var offset=this.ShowRange.Start;
        var endOffset=this.ShowRange.Start+this.ShowRange.ShowCount;
        var yPrice=this.GetYFromData(orderItem.Price, false);
        var value=parseInt(index+orderItem.HBar.Width);
        var start=index-offset;
        var end=value-offset;
        if (start<0) start=0;
        if (end<0) end=0;

        if (start<=end)
        {
            var cellHeight=this.GetPriceYOffset(orderFlow.PriceOffset);

            var xStart=this.ChartFrame.GetXFromIndex(start)-dataWidth/2;
            var xEnd=this.ChartFrame.GetXFromIndex(end)+dataWidth/2;
            var yTop=yPrice-cellHeight/2;

            var fValue=orderItem.HBar.Width-parseInt(orderItem.HBar.Width);
            if (fValue>0.000001) xEnd+=(dataWidth+distanceWidth)*fValue;
    
            this.Canvas.fillStyle=orderItem.HBar.Color;
            this.Canvas.fillRect(ToFixedRect(xStart),ToFixedRect(yTop),ToFixedRect(xEnd-xStart),ToFixedRect(cellHeight+0.5)); //高度适当加上,否则行间有空隙
        }
        
    }
    
}

function ChartColorKline()
{
    this.newMethod=IChartPainting;   //派生
    this.newMethod();
    delete this.newMethod;

    this.ClassName='ChartColorKline';    //类名
    this.Symbol;        //股票代码
    this.Color='rgb(0,255,44)';
    this.IsEmptyBar=false;
    this.DrawType=0;    //0=实心K线柱子  3=空心K线柱子 
    this.KLineColor;    //Map key=K线索引 value=设置
    this.DrawName;

    this.Draw=function()
    {
        if (!this.IsShow) return;

        if (this.DrawName=="DRAWCOLORKLINE")
        {
            this.DrawColorBar();
        }
        else
        {
            if (!this.KLineColor) return;
            this.DrawBar();
        }
    }

    this.DrawUpBarItem=function(data, xOffset, dataWidth, option)
    {
        var isHScreen=(this.ChartFrame.IsHScreen===true);
        var left=xOffset;
        var right=xOffset+dataWidth;
        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 (dataWidth>=4)
        {
            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;
            }

            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.stroke();
        }
    }

    this.DrawDownBarItem=function(data, xOffset, dataWidth, option)
    {
        var isHScreen=(this.ChartFrame.IsHScreen===true);
        var left=xOffset;
        var right=xOffset+dataWidth;
        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 (dataWidth>=4)
        {
            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
            }

            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.stroke();
        }
    }

    this.DrawUnChangeBarItem=function(data, xOffset, dataWidth, option)
    {
        var isHScreen=(this.ChartFrame.IsHScreen===true);
        var left=xOffset;
        var right=xOffset+dataWidth;
        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 (dataWidth>=4)
        {
            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.stroke();
        }
    }

    this.DrawBar=function()
    {
        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 (this.IsHScreen) 
        {
            xOffset=this.ChartBorder.GetTop()+distanceWidth/2.0+2.0;
            chartright=this.ChartBorder.GetBottom();
        }

        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 (!this.KLineColor.has(i)) continue;
            var itemOption=this.KLineColor.get(i);

            var left=xOffset;
            var right=xOffset+dataWidth;
            if (right>chartright) break;

            if (itemOption.Color)
            {
                this.Canvas.strokeStyle=itemOption.Color;
                this.Canvas.fillStyle=itemOption.Color;
            }
            else
            {
                this.Canvas.strokeStyle=this.Color;
                this.Canvas.fillStyle=this.Color;
            }

            if (data.Open<data.Close)   //阳线
            {
                this.DrawUpBarItem(data,xOffset,dataWidth,itemOption);
            }
            else if (data.Open>data.Close)  //阴线
            {
                this.DrawDownBarItem(data,xOffset,dataWidth,itemOption);
            }
            else    //平线
            {
                this.DrawUnChangeBarItem(data,xOffset,dataWidth,itemOption);
            }
        }
    }

    this.DrawColorBar=function()
    {
        var isHScreen=(this.ChartFrame.IsHScreen===true);
        var dataWidth=this.ChartFrame.DataWidth;
        var distanceWidth=this.ChartFrame.DistanceWidth;
        var border=this.ChartBorder.GetBorder();
        var xOffset=border.LeftEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
        var chartright=border.RightEx;
        var xPointCount=this.ChartFrame.XPointCount;

        if (isHScreen) 
        {
            var border=this.ChartBorder.GetHScreenBorder();
            xOffset=border.TopEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
            chartright=border.BottomEx;
        }

        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) continue;
            if (!IFrameSplitOperator.IsNumber(data.Open) || !IFrameSplitOperator.IsNumber(data.High) || 
                !IFrameSplitOperator.IsNumber(data.Low) || !IFrameSplitOperator.IsNumber(data.Close)) continue;

            var left=xOffset;
            var right=xOffset+dataWidth;
            if (right>chartright) break;
            var x=left+(right-left)/2;
            var yLow=this.GetYFromData(data.Low, false);
            var yHigh=this.GetYFromData(data.High, false);
            var yOpen=this.GetYFromData(data.Open, false);
            var yClose=this.GetYFromData(data.Close, false);
            var y=yHigh;

            if (data.Open==data.Close) 
                this.DrawKBar_Unchagne(data, dataWidth, this.Color, this.IsEmptyBar, x, y, left, right, yLow, yHigh, yOpen, yClose, isHScreen);
            else 
                this.DrawKBar_Custom(data, dataWidth, this.Color, this.IsEmptyBar, x, y, left, right, yLow, yHigh, yOpen, yClose, isHScreen);
        }
    }

    this.DrawKBar_Unchagne=function(data, dataWidth, unchagneColor, drawType, x, y, left, right, yLow, yHigh, yOpen, yClose, isHScreen)
    {
        if (dataWidth>=4)
        {
            if ((dataWidth%2)!=0) dataWidth-=1;
            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
                {
                    var xFixed=ToFixedPoint(left+dataWidth/2);
                    this.Canvas.moveTo(xFixed,y);
                    this.Canvas.lineTo(xFixed,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(left+dataWidth),ToFixedPoint(y));
            }

            if (data.Open>data.Low) //下影线
            {
                if (isHScreen)
                {
                    this.Canvas.moveTo(ToFixedPoint(y),ToFixedPoint(x));
                    this.Canvas.lineTo(ToFixedPoint(yLow),ToFixedPoint(x));
                }
                else
                {
                    var xFixed=ToFixedPoint(left+dataWidth/2);
                    this.Canvas.moveTo(xFixed,ToFixedPoint(y));
                    this.Canvas.lineTo(xFixed,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();
        }
    }

    this.DrawKBar_Custom=function(data, dataWidth, barColor, isEmptyBar, x, y, left, right, yLow, yHigh, yOpen, yClose, isHScreen)
    {
        if (isEmptyBar)
        {
            if ((dataWidth%2)!=0) dataWidth-=1;
        }

        if (dataWidth>=4)
        {
            this.Canvas.strokeStyle=barColor;
            if (data.High>data.Close)   //上影线
            {
                this.Canvas.beginPath();
                if (isHScreen)
                {
                    this.Canvas.moveTo(ToFixedPoint(y),ToFixedPoint(x));
                    this.Canvas.lineTo(ToFixedPoint(isEmptyBar?Math.max(yClose,yOpen):yClose),ToFixedPoint(x));
                }
                else
                {
                    if (isEmptyBar)
                    {
                        var xFixed=left+dataWidth/2;
                        this.Canvas.moveTo(ToFixedPoint(xFixed),ToFixedPoint(y));
                        this.Canvas.lineTo(ToFixedPoint(xFixed),ToFixedPoint(Math.min(yClose,yOpen)));
                    }
                    else
                    {
                        this.Canvas.moveTo(ToFixedPoint(x),ToFixedPoint(y));
                        this.Canvas.lineTo(ToFixedPoint(x),ToFixedPoint(yClose));
                    }
                    
                }
                this.Canvas.stroke();
                y=yClose;
            }
            else
            {
                y=yClose;
            }

            
            this.Canvas.fillStyle=barColor;
            if (isHScreen)
            {
                if (Math.abs(yOpen-y)<1)  
                {
                    this.Canvas.fillRect(ToFixedRect(y),ToFixedRect(left),1,ToFixedRect(dataWidth));    //高度小于1,统一使用高度1
                }
                else 
                {
                    if (isEmptyBar) //空心柱
                    {
                        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 (isEmptyBar) //空心柱
                    {
                        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(isEmptyBar?Math.min(yClose,yOpen):y),ToFixedPoint(x));
                    this.Canvas.lineTo(ToFixedPoint(yLow),ToFixedPoint(x));
                }
                else
                {
                    if (isEmptyBar)
                    {
                        var xFixed=left+dataWidth/2;
                        this.Canvas.moveTo(ToFixedPoint(xFixed),ToFixedPoint(Math.max(yClose,yOpen)));
                        this.Canvas.lineTo(ToFixedPoint(xFixed),ToFixedPoint(yLow));
                    }
                    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=barColor;
            this.Canvas.stroke();
        }
    }

    this.GetMaxMin=function()
    {
        var range={Max:null,Min:null };

        if (this.DrawName=="DRAWCOLORKLINE")
        {
            var xPointCount=this.ChartFrame.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) continue;
                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;
    }
}

//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.CloseLineWidth=g_JSChartResource.CloseLineWidth;

    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.GetYFromData(data.Low/firstOverlayOpen*firstOpen,false);
            var yHigh=this.GetYFromData(data.High/firstOverlayOpen*firstOpen,false);
            var yOpen=this.GetYFromData(data.Open/firstOverlayOpen*firstOpen,false);
            var yClose=this.GetYFromData(data.Close/firstOverlayOpen*firstOpen,false);
            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.GetYFromData(data.Low/firstOverlayOpen*firstOpen,false);
            var yHigh=this.GetYFromData(data.High/firstOverlayOpen*firstOpen,false);
            var yOpen=this.GetYFromData(data.Open/firstOverlayOpen*firstOpen,false);
            var yClose=this.GetYFromData(data.Close/firstOverlayOpen*firstOpen,false);

            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;
        if (IFrameSplitOperator.IsNumber(this.CloseLineWidth)) this.Canvas.lineWidth=this.CloseLineWidth;
        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.GetYFromData(data.Close/firstOverlayOpen*firstOpen,false);

            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;

        this.Canvas.save();
        this.ClipClient(this.ChartFrame.IsHScreen);

        if (drawType==1) this.DrawCloseLine(firstOpen);
        else if (drawType==2) this.DrawAKLine(firstOpen);
        else this.DrawKBar(firstOpen);

        this.Canvas.restore();
    }

    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.UnchangeColor=g_JSChartResource.UnchagneBarColor;  //平盘

    this.CustomColor=g_JSChartResource.Minute.VolBarColor;   //自定义颜色

    this.YClose;    //前收盘
    this.Symbol;
    this.BeforeOpenData;    //盘前数据
    this.AfterCloseData;    //盘后数据  
    this.BeforeVolColor=g_JSChartResource.Minute.Before.VolColor;

    this.MultiDayBeforeOpenData;    //多日分时图 盘前数据 数组 1天一个
    this.MultiDayAfterCloseData;    //多日分时图 盘后数据 数组 1天一个

    this.Draw=function()
    {
        var isHScreen = (this.ChartFrame.IsHScreen === true);
        
        if (isHScreen) 
        {
            var border=this.ChartBorder.GetHScreenBorder();
            var chartright = border.BottomEx;
        }
        else
        {
            var border=this.ChartBorder.GetBorder();
            var chartright=border.RightEx;
        }

        this.DrawBeforeOpen();
        this.DrawMultiDayBeforeOpen();

        var xPointCount=this.ChartFrame.XPointCount;
        var yBottom=this.ChartFrame.GetYFromData(0);
        var yPrice=this.YClose; //上一分钟的价格
        var data=this.Data;
        var bShowColorBar=MARKET_SUFFIX_NAME.IsShowMinuteColorVolBar(this.Symbol);

        if (bShowColorBar) this.Canvas.strokeStyle=this.CustomColor;
        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;

            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;

            //价格>=上一分钟价格 红色 否则绿色
            if (!bShowColorBar) 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.DrawAfterClose();
        this.DrawMultiDayAfterClose();
    }

    this.DrawBeforeOpen=function()
    {
        if (this.ChartBorder.LeftExtendWidth<10) return;
        if (!this.BeforeOpenData) return;

        this.DrawCallAuction(-1,this.BeforeOpenData,true);
    }

    this.DrawAfterClose=function()
    {
        if (this.ChartBorder.RightExtendWidth<10) return;
        if (!this.AfterCloseData) return;

        this.DrawCallAuction(-1,this.AfterCloseData,false);
    }

    this.DrawMultiDayBeforeOpen=function()
    {
        if (this.ChartBorder.MultiDayMinute.Count<=1 || this.ChartBorder.MultiDayMinute.Left<=0) return;
        if (!this.MultiDayBeforeOpenData) return;

        for(var i in this.MultiDayBeforeOpenData)
        {
            var dayItem=this.MultiDayBeforeOpenData[i];
            this.DrawCallAuction(parseInt(i), dayItem, true);
        }
    }

    this.DrawMultiDayAfterClose=function()
    {
        if (this.ChartBorder.MultiDayMinute.Count<=1 || this.ChartBorder.MultiDayMinute.Right<=0) return;
        if (!this.MultiDayAfterCloseData) return;

        for(var i in this.MultiDayAfterCloseData)
        {
            var dayItem=this.MultiDayAfterCloseData[i];
            this.DrawCallAuction(parseInt(i), dayItem, false);
        }
    }

    this.DrawCallAuction=function(indexDay, callAutionData, isBeforeOpen)
    {
        if (!callAutionData) return;

        callAutionData.Index=indexDay;
        var border=this.GetBorder();
        var isHScreen=(this.ChartFrame.IsHScreen===true);
        var yPrice=this.YClose;             //上一分钟的价格
        var yBottom=this.ChartFrame.GetYFromData(0);
        if (callAutionData.Ver==1.0)
        {
            for(var i in callAutionData.Data)
            {
                var item=callAutionData.Data[i];
                if (!item || !IFrameSplitOperator.IsNumber(item.Vol[0])) continue;

                if (isBeforeOpen)
                {
                    var x=this.ChartFrame.GetLeftExtendXFromIndex(i,callAutionData);
                    var y=this.ChartFrame.GetLeftExtendYFromData(item.Vol[0]);
                }
                else
                {
                    var x=this.ChartFrame.GetRightExtendXFromIndex(i,callAutionData);
                    var y=this.ChartFrame.GetRightExtendYFromData(item.Vol[0]);
                }
                

                this.Canvas.strokeStyle = item.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 (item.Price) yPrice=item.Price;
            }
        }
        else if (callAutionData.Ver==2.0 || callAutionData.Ver==3.0)
        {
            var range={ Max: callAutionData.VolMax, Min:callAutionData.VolMin }
            
            for(var i in callAutionData.Data)
            {
                var item=callAutionData.Data[i];
                if (!item) continue;
                if (IFrameSplitOperator.IsPlusNumber(item.Vol[0])) 
                {
                    if (isBeforeOpen)
                    {
                        var x=this.ChartFrame.GetLeftExtendXFromIndex(i,callAutionData);
                        var y=this.ChartFrame.GetLeftExtendYFromData(item.Vol[0],false, { Range:range });
                    }
                    else
                    {
                        var x=this.ChartFrame.GetRightExtendXFromIndex(i,callAutionData);
                        var y=this.ChartFrame.GetRightExtendYFromData(item.Vol[0],false, { Range:range });
                    }
                    
                    this.Canvas.strokeStyle = this.GetBarColor(item.ColorID);

                    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 (IFrameSplitOperator.IsPlusNumber(item.Vol[1])) 
                {
                    if (isBeforeOpen)
                    {
                        var x=this.ChartFrame.GetLeftExtendXFromIndex(i,callAutionData);
                        var y=this.ChartFrame.GetLeftExtendYFromData(item.Vol[1],false, { Range:range });
                    }
                    else
                    {
                        var x=this.ChartFrame.GetRightExtendXFromIndex(i,callAutionData);
                        var y=this.ChartFrame.GetRightExtendYFromData(item.Vol[1],false, { Range:range });
                    }
                    
                    this.Canvas.strokeStyle = this.GetBarColor(item.ColorID);
                    this.Canvas.beginPath();
                    if (isHScreen)
                    {
                        y-=yBottom;
                        y=border.RightEx-y;
                        this.Canvas.moveTo(y,ToFixedPoint(x));
                        this.Canvas.lineTo(border.RightEx,ToFixedPoint(x));
                    }
                    else
                    {
                        y-=yBottom;
                        y=border.TopEx-y;
                        this.Canvas.moveTo(ToFixedPoint(x),y);
                        this.Canvas.lineTo(ToFixedPoint(x),border.TopEx);
                    }
                    this.Canvas.stroke();
                }
            }
        }
    }

    this.GetBarColor=function(id)
    {
        switch(id)
        {
            case 0:
                return this.UnchangeColor;
            case 1:
                return this.UpColor;
            case 2:
                return this.DownColor;
        }

        if (this.BeforeVolColor && Array.isArray(this.BeforeVolColor))
        {
            var index=id-3;
            if (index>=0 && index<this.BeforeVolColor.length)
                return this.BeforeVolColor[index];
        }

        return this.UnchangeColor;
    }

    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 || this.ChartFrame.IsMinSize) 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();
        if (this.IsDotLine) this.Canvas.setLineDash(g_JSChartResource.DOTLINE.LineDash); //画虚线
        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.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 isMinute=this.IsMinuteFrame();
        var dataWidth=this.ChartFrame.DataWidth;
        var distanceWidth=this.ChartFrame.DistanceWidth;
        var xPointCount=this.ChartFrame.XPointCount;

        if (bHScreen)
        {
            var border=this.ChartBorder.GetHScreenBorder();
            var chartright=border.BottomEx;
            var xOffset=border.TopEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
        }
        else
        {
            var border=this.ChartBorder.GetBorder();
            var xOffset=border.LeftEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
            var chartright=border.RightEx;
        }

        var lockRect=this.GetLockRect();
        if (lockRect)
        {
            if (bHScreen) chartright=lockRect.Top;
            else chartright=lockRect.Left;
        }

        this.Canvas.save();
        this.ClipClient(bHScreen);
        if (this.LineWidth>0) this.Canvas.lineWidth=this.LineWidth * GetDevicePixelRatio();
        this.Canvas.strokeStyle=this.Color;
        if (this.IsDotLine) this.Canvas.setLineDash(g_JSChartResource.DOTLINE.LineDash); //画虚线

        var bFirstPoint=true;
        var drawCount=0;
        for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
        //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;
            }

            if (isMinute)
            {
                var x=this.ChartFrame.GetXFromIndex(j);
            }
            else
            {
                var left=xOffset;
                var right=xOffset+dataWidth;
                if (right>chartright) break;
                var x=left+(right-left)/2;
            }
            
            var y=this.GetYFromData(value,false);

            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 ChartSubLine()
{
    this.newMethod=ChartLine;       //派生
    this.newMethod();
    delete this.newMethod;

    this.ClassName='ChartSubLine';     //类名
    this.Color="rgb(255,193,37)";   //线段颜色
    this.LineWidth;                 //线段宽度
    this.DrawType=0;                //画图方式  0=无效数平滑  1=无效数不画断开
    this.IsDotLine=false;           //虚线

    this.SubFrame={ Max:null,Min:null };

    this.Draw=function()
    {
        if (!this.IsShow) return;
        if (!this.Data || !this.Data.Data) return;

        this.CalculateDataMaxMin();

        switch(this.DrawType)
        {
            case 0:
                return this.DrawLine();
            case 1: 
                return this.DrawStraightLine();
        }
    }

    this.GetYFromData=function(value)
    {
        var bHScreen = (this.ChartFrame.IsHScreen === true);

        if (bHScreen)
        {
            if (value <= this.SubFrame.Min) return this.ChartBorder.GetLeftEx();
            if (value >= this.SubFrame.Max) return this.ChartBorder.GetRightEx();

            var width = this.ChartBorder.GetWidthEx() * (value - this.SubFrame.Min) / (this.SubFrame.Max - this.SubFrame.Min);
            return this.ChartBorder.GetLeftEx() + width;
        }
        else
        {
            if(value<=this.SubFrame.Min) return this.ChartBorder.GetBottomEx();
            if(value>=this.SubFrame.Max) return this.ChartBorder.GetTopEx();
    
            var height=this.ChartBorder.GetHeightEx()*(value-this.SubFrame.Min)/(this.SubFrame.Max-this.SubFrame.Min);
            return this.ChartBorder.GetBottomEx()-height;
        }
    }

    this.CalculateDataMaxMin=function()
    {
        this.SubFrame={ Max:null,Min:null };

        var bHScreen=(this.ChartFrame.IsHScreen===true);
        var chartright=this.ChartBorder.GetRight();
        if (bHScreen) chartright=this.ChartBorder.GetBottom();
        var xPointCount=this.ChartFrame.XPointCount;
        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);
            if (x>chartright) break;

            if (this.SubFrame.Min==null || this.SubFrame.Min>value) this.SubFrame.Min=value;
            if (this.SubFrame.Max==null || this.SubFrame.Max<value) this.SubFrame.Max=value;
        }
    }

    this.GetMaxMin=function()   //数据不参与坐标轴最大最小值计算
    {
        var range={Min:null, Max:null};
        return range;
    }
}

//叠加线段
function ChartOverlayLine()
{
    this.newMethod=ChartLine;   //派生
    this.newMethod();
    delete this.newMethod;

    this.MainData=new ChartData();  //主数据

    this.Draw=function()
    {
        if (!this.Data || !this.Data.Data) return;
        if (!this.MainData || !this.MainData.Data) return;

        switch(this.DrawType)
        {
            case 0:
                return this.DrawLine();
            case 1: 
                return this.DrawStraightLine();
        }
    }

    //获取第1个有效数据
    this.GetFirstVaildIndex=function()
    {
        var startIndex=this.Data.DataOffset;
        for(var i=startIndex, j=0 ; i<this.MainData.Data.length && i<this.Data.Data.length; ++i,++j )
        {
            var value=this.MainData.Data[i];
            var overlayValue=this.Data.Data[i];
            if (IFrameSplitOperator.IsNumber(value) && IFrameSplitOperator.IsNumber(overlayValue)) 
                return { Index:j, DataOffset:i, OverlayValue:overlayValue, MainValue:value };
        }

        return null;
    }

    //无效数不画
    this.DrawStraightLine=function()
    {
        var firstData=this.GetFirstVaildIndex();
        if (!firstData) return;

        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,rate=0;
        for(var i=firstData.DataOffset,j=firstData.Index;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 diff=value-firstData.OverlayValue;
            if (firstData.OverlayValue!=0) rate= 1+ diff/Math.abs(firstData.OverlayValue);
            else rate=1+diff;
            var fixedValue=firstData.MainValue*rate;
            //var fixedValue=value/firstData.OverlayValue*firstData.MainValue;
            var y=this.GetYFromData(fixedValue);

            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();
    }

    this.GetMaxMin=function()
    {
        var xPointCount=this.ChartFrame.XPointCount;
        var range={};
        range.Min=null;
        range.Max=null;

        var firstData=this.GetFirstVaildIndex();
        if (!firstData) return range;

        for(var i=firstData.DataOffset,j=firstData.Index; i<this.Data.Data.length && j<xPointCount; ++i,++j)
        {
            var overlayValue=this.Data.Data[i];
            if (!IFrameSplitOperator.IsNumber(overlayValue)) continue;

            var diff=overlayValue-firstData.OverlayValue;
            if (firstData.OverlayValue!=0) rate= 1+ diff/Math.abs(firstData.OverlayValue);
            else rate=1+diff;
            var value=firstData.MainValue*rate;
            //var value=overlayValue/firstData.OverlayValue*firstData.MainValue;

            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 ChartPartLine()
{
    this.newMethod=IChartPainting;   //派生
    this.newMethod();
    delete this.newMethod;

    this.ClassName='ChartPartLine';     //类名
    this.LineWidth;                     //线段宽度            

    this.Draw=function()
    {
        if (!this.IsShow || this.ChartFrame.IsMinSize) 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};
        var isPerNull=false;
        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 || item.Value==null) 
            {
                lastPoint.X=null;
                lastPoint.Y=null;
                isPerNull=true;
                continue;
            }

            var value=item.Value;
            var color=item.RGB;
            var x=this.ChartFrame.GetXFromIndex(j);
            var y=this.ChartFrame.GetYFromData(value);

            if (x>chartright) break;

            if (color!=lastColor || isPerNull==true)
            {
                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;
            isPerNull=false;
        }

        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;
    }
}

//斜率线 DRAWSL()
function ChartSlopeLine()
{
    this.newMethod=IChartPainting;   //派生
    this.newMethod();
    delete this.newMethod;

    this.ClassName='ChartSlopeLine';     //类名
    this.Color="rgb(255,193,37)";        //线段颜色
    this.IsDotLine=false;
    this.LineWidth;
    this.Option;    //[ { Slope:slope, Length:len, Direct:direct } ]

    this.Draw=function()
    {
        if (!this.IsShow || this.ChartFrame.IsMinSize) return;
        if (this.NotSupportMessage)
        {
            this.DrawNotSupportmessage();
            return;
        }

        if (!this.Data || !this.Data.Data) return;

        this.Canvas.save();
        this.Canvas.strokeStyle=this.Color;
        if (this.IsDotLine) this.Canvas.setLineDash(g_JSChartResource.DOTLINE.LineDash); //画虚线
        
        var left=this.ChartBorder.GetLeft();
        var top=this.ChartBorder.GetTopEx();
        var right=this.ChartBorder.GetRight();
        var bottom=this.ChartBorder.GetBottom();

        var chartright=this.ChartBorder.GetRight();
        var xPointCount=this.ChartFrame.XPointCount;

        this.Canvas.beginPath();
        this.Canvas.rect(left,top,(right-left),(bottom-top));
        this.Canvas.clip();

        for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j)
        {
            var value=this.Data.Data[i];
            if (!IFrameSplitOperator.IsNumber(value)) continue; 
            var option=this.Option[i];
            if (!option) continue;
           
            var x=this.ChartFrame.GetXFromIndex(j);
            var y=this.ChartFrame.GetYFromData(value);
            var z=option.Length*g_JSChartResource.DRAWSL.PixelWidth;
            if (x>chartright) break;

            var x2=Math.sqrt((z*z)/(1+option.Slope*option.Slope));
            var y2=x2*option.Slope;

            this.Canvas.beginPath();
            if (option.Direct==2)
            {
                this.Canvas.moveTo(x-x2,y+y2);
                this.Canvas.lineTo(x+x2,y-y2);
            }
            else if (option.Direct==1)
            {
                this.Canvas.moveTo(x,y);
                this.Canvas.lineTo(x-x2,y+y2);
            }
            else
            {
                this.Canvas.moveTo(x,y);
                this.Canvas.lineTo(x+x2,y-y2);
            }
            
            this.Canvas.stroke();
        }

        this.Canvas.restore();
    }
}


//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 || this.ChartFrame.IsMinSize) 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();
        var lineWidth=this.Canvas.lineWidth;
        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=ToFixedPoint2(lineWidth, x);
                this.Canvas.moveTo(xFix,y);  
                this.Canvas.lineTo(xFix,yBottom);
            }
            this.Canvas.stroke();
        }

        this.Canvas.restore();
    }

    this.Draw=function()
    {
        if (!this.IsShow || this.ChartFrame.IsMinSize) 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 || this.ChartFrame.IsMinSize) 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.IsShow || this.ChartFrame.IsMinSize) return;

        if (this.ChartFrame.IsHScreen===true) 
        {
            this.HScreenDraw();
            return;
        }

        var dataWidth=this.ChartFrame.DataWidth;
        var distanceWidth=this.ChartFrame.DistanceWidth;
        var border=this.ChartBorder.GetBorder();
        var xOffset=border.LeftEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
        var chartright=border.RightEx;
        var xPointCount=this.ChartFrame.XPointCount;
        var lockRect=this.GetLockRect();
        if (lockRect) chartright=lockRect.Left;
        var isMinute=this.IsMinuteFrame();

        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 barColor=this.GetBarColor(kItem);
                var bUp=barColor.IsUp;
                this.Canvas.fillStyle=barColor.Color;
                   
                var height=ToFixedRect(Math.abs(yBottom-y)>=1?yBottom-y:1);//高度调整为整数, 如果小于1, 统一使用1
                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);
                if (isMinute)
                {
                    var x=this.ChartFrame.GetXFromIndex(j);
                }
                else
                {
                    var left=xOffset;
                    var right=xOffset+dataWidth;
                    var x=left+(right-left)/2;
                }

                if (x>chartright) break;

                var barColor=this.GetBarColor(kItem);
                this.Canvas.strokeStyle=barColor.Color;
                
                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 border=this.ChartBorder.GetHScreenBorder();
        var xOffset=border.TopEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
        var chartBottom=border.BottomEx;
        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;
    }

    this.GetBarColor=function(kItem)
    {
        if (kItem.Close>=kItem.Open) return { Color:this.UpColor, IsUp:true };  //颜色, 是否是上涨
        else return { Color:this.DownColor, IsUp:false };
    }
}

// VERTLINE(HIGH>=HHV(HIGH,20),1)表示在创20天新高画垂直虚线。
// 支持横屏
function ChartVericaltLine()
{
    this.newMethod=IChartPainting;   //派生
    this.newMethod();
    delete this.newMethod;

    this.ClassName='ChartVericaltLine';    //类名
    this.LineWidth=2;
    this.LineCap;

    this.Draw=function()
    {
        if (this.ChartFrame.IsMinSize) return;

        var isHScreen=this.ChartFrame.IsHScreen==true;
        var dataWidth=this.ChartFrame.DataWidth;
        var distanceWidth=this.ChartFrame.DistanceWidth;
        var border=this.GetBorder();
        var xPointCount=this.ChartFrame.XPointCount;

        if (isHScreen)
        {
            var top=border.RightEx;
            var bottom=border.LeftEx;
            var xOffset=border.TopEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
        }
        else
        {
            var top=border.TopEx;
            var bottom=border.BottomEx;
            var xOffset=border.LeftEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
        }

        this.Canvas.save();
        this.Canvas.strokeStyle=this.Color;
        if (this.LineType) this.Canvas.setLineDash(this.LineType);
        if (this.LineCap) this.Canvas.lineCap = this.LineCap;
        
        this.Canvas.beginPath();
        var lineWidth=this.Canvas.lineWidth;
        if (this.LineWidth>0) 
        {
            lineWidth=this.LineWidth * GetDevicePixelRatio();
            this.Canvas.lineWidth=lineWidth;
        }
        var drawCount=0;
        for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
        {
            var item=this.Data.Data[i];
            if (!item) continue;

            var center=xOffset+dataWidth/2;
            center=ToFixedPoint2(lineWidth, center);
            if (isHScreen)
            {
                this.Canvas.moveTo(top,center);
                this.Canvas.lineTo(bottom,center);
            }
            else
            {
                this.Canvas.moveTo(center, top);
                this.Canvas.lineTo(center,bottom);
            }
            
            ++drawCount;
        }

        if (drawCount>0) this.Canvas.stroke();

        this.Canvas.restore();
    }

    this.GetMaxMin=function()
    {
        return { Min:null, Max:null };
    }
}

//HORLINE 支持横屏 
function ChartHorizontalLine()
{
    this.newMethod=IChartPainting;   //派生
    this.newMethod();
    delete this.newMethod;

    this.ClassName='ChartHorizontalLine';    //类名
    this.LineWidth=2;
    this.LineCap;
    this.ExtendType=0;   //1=表示向左延长，2=表示向右延长，3=表示左右延长

    this.Draw=function()
    {
        if (this.ChartFrame.IsMinSize) return;

        var isHScreen=this.ChartFrame.IsHScreen==true;
        var dataWidth=this.ChartFrame.DataWidth;
        var distanceWidth=this.ChartFrame.DistanceWidth;
        var border=this.GetBorder();
        
        var xPointCount=this.ChartFrame.XPointCount;
        if (isHScreen)
        {
            var left=border.TopEx;
            var right=border.BottomEx;
            var xOffset=border.TopEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
        }
        else
        {
            var left=border.LeftEx
            var right=border.RightEx;
            var xOffset=border.LeftEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
        }
        
        this.Canvas.save();
        this.Canvas.strokeStyle=this.Color;
        if (this.LineType) this.Canvas.setLineDash(this.LineType);
        if (this.LineCap) this.Canvas.lineCap = this.LineCap;
        
        this.Canvas.beginPath();
        var lineWidth=this.Canvas.lineWidth;
        if (this.LineWidth>0) 
        {
            lineWidth=this.LineWidth * GetDevicePixelRatio();
            this.Canvas.lineWidth=lineWidth;
        }
        var drawCount=0;
        for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
        {
            var item=this.Data.Data[i];
            if (!item) continue;
            if (!IFrameSplitOperator.IsNumber(item)) continue;

            var y=this.ChartFrame.GetYFromData(item);
            y=ToFixedPoint2(lineWidth, y);
            var center=xOffset+dataWidth/2;
            center=ToFixedPoint2(lineWidth, center);
            if (this.ExtendType==3) //左右延长
            {
                if (isHScreen)
                {
                    this.Canvas.moveTo(y, left);
                    this.Canvas.lineTo(y, right);
                }
                else
                {
                    this.Canvas.moveTo(left, y);
                    this.Canvas.lineTo(right, y);
                }
                
            }
            else if (this.ExtendType==1) //左延长
            {
                if (isHScreen)
                {
                    this.Canvas.moveTo(y, left);
                    this.Canvas.lineTo(y, center);
                }
                else
                {
                    this.Canvas.moveTo(left, y);
                    this.Canvas.lineTo(center, y);
                }
                
            }
            else    //右延长
            {
                if (isHScreen)
                {
                    this.Canvas.moveTo(y, center);
                    this.Canvas.lineTo(y, right);
                }
                else
                {
                    this.Canvas.moveTo(center, y);
                    this.Canvas.lineTo(right, y);
                }
                
            }

            ++drawCount;
        }

        if (drawCount>0) this.Canvas.stroke();

        this.Canvas.restore();
    }
}



//线段 多数据(一个X点有多条Y数据) 支持横屏
function ChartLineMultiData()
{
    this.newMethod=IChartPainting;   //派生
    this.newMethod();
    delete this.newMethod;

    this.ClassName='ChartLineMultiData';    //类名
    this.Color="rgb(255,193,37)";           //线段颜色
    
    this.PointColor;        //='rgb(255,193,80)';
    this.PointRadius;       //=2;
    this.LineWidth;

    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;

        this.Canvas.save();
        if (IFrameSplitOperator.IsPlusNumber(this.LineWidth)) this.Canvas.lineWidth=this.LineWidth * GetDevicePixelRatio();
        var bFirstPoint=true;
        var drawCount=0;
        var aryPoint=[];
        var aryValue;
        for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j)
        {
            var lineItem=this.Data.Data[i];
            if (!lineItem) continue;

            var x=this.ChartFrame.GetXFromIndex(j);
            if (x>chartright) break;

            if (Array.isArray(lineItem)) aryValue=lineItem;
            else aryValue=[lineItem];

            for(var index=0; index<aryValue.length; ++index)
            {
                var item=aryValue[index];
                if (!item) continue;

                var value =item.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;

                    if (item.Type===1) aryPoint.push({X:x, Y:y});
                }
                else
                {
                    if (isHScreen) this.Canvas.lineTo(y,x);
                    else this.Canvas.lineTo(x,y);

                    if (item.Type===1) aryPoint.push({X:x, Y:y});
                }

                ++drawCount;
            }
        }

        if (drawCount>0) this.Canvas.stroke();

        this.DrawPoint(aryPoint);

        this.Canvas.restore();
    }

    this.DrawPoint=function(aryPoint)
    {
        if (!this.PointColor) return;
        if (!IFrameSplitOperator.IsPlusNumber(this.PointRadius)) return;
        var radius=this.PointRadius*GetDevicePixelRatio();
        for(var i=0;i<aryPoint.length;++i)
        {
            var item=aryPoint[i];

            this.Canvas.beginPath();
            this.Canvas.arc(item.X,item.Y,radius,0,360,false);
            this.Canvas.fillStyle=this.PointColor;      //填充颜色
            this.Canvas.fill();                         //画实心圆
            this.Canvas.closePath();
        }
    }

    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 item=this.Data.Data[i];
            if (!item) continue;

            var aryValue;
            if (Array.isArray(item)) aryValue=item;
            else aryValue=[item];

            for(var j=0; j<aryValue.length; ++j)
            {
                var value=aryValue[j].Value;
                if (!IFrameSplitOperator.IsNumber(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;
    }
}

//柱子 支持横屏
function ChartStickLine()
{
    this.newMethod=IChartPainting;   //派生
    this.newMethod();
    delete this.newMethod;

    this.ClassName='ChartStickLine';    //类名
    this.Color="rgb(255,193,37)";               //线段颜色
    this.BarType=0;                     //柱子类型 0=实心 1=空心 -1=画虚线空心柱
    this.LineDotted=[3,3];              //虚线设置
    this.Width=0;                       //柱子宽度 0=1 3,50=k线宽度 101=K线宽度+间距宽度

    this.SetEmptyBar=function()         //设置空心柱子
    {
        if (this.BarType!=1 && this.BarType!=-1) return false;

        this.Canvas.lineWidth=GetDevicePixelRatio();
        this.Canvas.strokeStyle=this.Color;
        var emptyBGColor=g_JSChartResource.EmptyBarBGColor;
        if (emptyBGColor) this.Canvas.fillStyle=emptyBGColor;
        if (this.BarType==-1)   //虚线
        {
            this.Canvas.setLineDash(this.LineDotted);   //虚线
        }

        return true;
    }

    this.IsEmptyBar=function()
    {
        return (this.BarType==1 || this.BarType==-1);
    }

    this.Draw=function()
    {
        if (this.ChartFrame.IsMinSize) return;

        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();
        var zoomIndex=this.ChartFrame.ZoomIndex;
        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;

        var isMinute=this.IsMinuteFrame();
        
        this.Canvas.save();
        var bFillBar=false;
        var bFillKLine=false;
        var emptyBGColor=g_JSChartResource.EmptyBarBGColor;

        if (isMinute)
        {
            if (this.Width>1) this.Canvas.lineWidth=2*GetDevicePixelRatio();
            else this.Canvas.lineWidth=GetDevicePixelRatio();
            this.Canvas.strokeStyle=this.Color;
        }
        else if(this.Width==0)
        {
            this.SetEmptyBar();
        }
        else if (this.Width==3 || this.Width==50)   //3和50 K线宽度
        {
            if (dataWidth>=4)
            {
                bFillKLine=true; 
                this.SetEmptyBar();
                if (!this.IsEmptyBar()) this.Canvas.fillStyle=this.Color; 
                this.Canvas.strokeStyle=this.Color;
            }
            else    //太细了 画竖线
            {
                this.Canvas.lineWidth=GetDevicePixelRatio();
                this.Canvas.strokeStyle=this.Color;
            }  
        }
        else if (this.Width==101)
        {
            var lineWidth=dataWidth+distanceWidth+1*GetDevicePixelRatio();
            this.Canvas.lineWidth=lineWidth;
            this.Canvas.strokeStyle=this.Color;
        }
        else if (this.Width<=3)
        {
            var minWidth=2*GetDevicePixelRatio();
            var barWidth=dataWidth*(this.Width/3);
            if (barWidth<minWidth) barWidth=minWidth;
            this.SetEmptyBar();
            if (!this.IsEmptyBar()) this.Canvas.fillStyle=this.Color;
            bFillBar=true;
        }
        else
        {
            var barWidth=this.Width*GetDevicePixelRatio()+dataWidth;
            this.SetEmptyBar();
            if (!this.IsEmptyBar()) this.Canvas.fillStyle=this.Color;
            bFillBar=true;
        }

        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=x-barWidth/2;
                    var width=barWidth;
                    if (this.IsEmptyBar()) //空心
                    {
                        this.Canvas.beginPath();
                        this.Canvas.rect(ToFixedPoint(Math.min(y,y2)),ToFixedPoint(left),ToFixedRect(Math.abs(y-y2)),ToFixedRect(width));
                        this.Canvas.stroke();
                    }
                    else
                    {
                        this.Canvas.fillRect(ToFixedRect(Math.min(y,y2)),ToFixedRect(left),ToFixedRect(Math.abs(y-y2)),ToFixedRect(width));
                    }
                }
                else
                {
                    var left=x-barWidth/2;
                    var width=barWidth;
                    if (left+width>chartright) width=chartright-left; //不要超过右边框子
                    if (this.IsEmptyBar()) //空心
                    {
                        if (emptyBGColor)
                            this.Canvas.fillRect(ToFixedRect(left),ToFixedRect(Math.min(y,y2)),ToFixedRect(width),ToFixedRect(Math.abs(y-y2)));

                        this.Canvas.beginPath();
                        this.Canvas.rect(ToFixedPoint(left),ToFixedPoint(Math.min(y,y2)),ToFixedRect(width),ToFixedRect(Math.abs(y-y2)));
                        this.Canvas.stroke();
                    }
                    else
                    {
                        this.Canvas.fillRect(ToFixedRect(left),ToFixedRect(Math.min(y,y2)),ToFixedRect(width),ToFixedRect(Math.abs(y-y2)));
                    }
                }
            }
            else if (bFillKLine)
            {
                if (this.IsEmptyBar())    //空心
                {
                    if (isHScreen)
                    {
                        this.Canvas.beginPath();
                        this.Canvas.rect(ToFixedPoint(Math.min(y,y2)),ToFixedPoint(xOffset),ToFixedRect(Math.abs(y-y2)),ToFixedRect(dataWidth));
                        this.Canvas.stroke();
                    }
                    else
                    {
                        if (emptyBGColor)
                            this.Canvas.fillRect(ToFixedRect(xOffset),ToFixedRect(Math.min(y,y2)),ToFixedRect(dataWidth),ToFixedRect(Math.abs(y-y2)));

                        this.Canvas.beginPath();
                        this.Canvas.rect(ToFixedPoint(xOffset),ToFixedPoint(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;
    }
}

/*
    文字输出 支持横屏
    数组(Data)不为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.FixedFontSize=-1;  //固定字体大小
    this.YOffset=0;         //连线      
    this.Position;          //指定输出位置
    this.IconFont;          //Iconfont
    this.IconSize=
    { 
        Max: g_JSChartResource.DRAWICON.Icon.MaxSize, Min:g_JSChartResource.DRAWICON.Icon.MinSize, //图标的最大最小值
        Zoom:{ Type:g_JSChartResource.DRAWICON.Icon.Zoom.Type , Value:g_JSChartResource.DRAWICON.Icon.Zoom.Value }, //放大倍数
        YOffset:g_JSChartResource.DRAWICON.Icon.YOffset //Direction==2的向下偏移
    };  

    this.TextSize=
    {
        Max: g_JSChartResource.DRAWICON.Text.MaxSize, Min:g_JSChartResource.DRAWICON.Text.MinSize, //字体的最大最小值
        Zoom:{ Type:g_JSChartResource.DRAWICON.Text.Zoom.Type , Value:g_JSChartResource.DRAWICON.Text.Zoom.Value }, //放大倍数
        FontName:g_JSChartResource.DRAWICON.Text.FontName,
        YOffset:g_JSChartResource.DRAWICON.Text.YOffset
    }

    this.Font=
    {
        DRAWTEXT_FIX:g_JSChartResource.DRAWTEXT_FIX.Font,
        DRAWNUMBER_FIX: g_JSChartResource.DRAWNUMBER_FIX.Font
    }
    

    this.ReloadResource=function(resource)
    {
        if (this.Name=="DRAWTEXT")
        {
            this.TextSize=
            {
                Max: g_JSChartResource.DRAWTEXT.MaxSize, Min:g_JSChartResource.DRAWTEXT.MinSize, //字体的最大最小值
                Zoom:{ Type:g_JSChartResource.DRAWTEXT.Zoom.Type , Value:g_JSChartResource.DRAWTEXT.Zoom.Value }, //放大倍数
                FontName:g_JSChartResource.DRAWTEXT.FontName,
                YOffset:g_JSChartResource.DRAWTEXT.YOffset
            }
        }
        else if (this.Name=="DRAWNUMBER")
        {
            this.TextSize=
            {
                Max: g_JSChartResource.DRAWNUMBER.MaxSize, Min:g_JSChartResource.DRAWNUMBER.MinSize, //字体的最大最小值
                Zoom:{ Type:g_JSChartResource.DRAWNUMBER.Zoom.Type , Value:g_JSChartResource.DRAWNUMBER.Zoom.Value }, //放大倍数
                FontName:g_JSChartResource.DRAWNUMBER.FontName,
                YOffset:g_JSChartResource.DRAWNUMBER.YOffset
            }
        }
        else if (this.Name=="DRAWTEXT_FIX") 
        {
            this.Font.DRAWTEXT_FIX=g_JSChartResource.DRAWTEXT_FIX.Font;
        }
        else if (this.Name=="DRAWNUMBER_FIX") 
        {
            this.Font.DRAWNUMBER_FIX=g_JSChartResource.DRAWNUMBER_FIX.Font;
        }
    }

    this.SuperGetMaxMin=this.GetMaxMin;
    this.GetMaxMin=function()
    {
        if ( this.Name=="DRAWTEXT_FIX" || this.Name=='DRAWNUMBER_FIX')  //固定位置的 没有大小值
        {
            return { Min:null,Max:null };
        }
        else if (this.Name=="DRAWTEXTREL" || this.Name=="DRAWTEXTABS")
        {
            return { Min:null,Max:null };
        }
        else
        {
            return this.SuperGetMaxMin();
        }
    }

    this.DrawRectText=function()
    {
        if (!this.DrawData) return;
        var isHScreen=(this.ChartFrame.IsHScreen===true)
        var border=this.ChartFrame.GetBorder();
        

        if (this.Name=="DRAWTEXTREL")
        {
            if (isHScreen)
            {
                var height=border.RightTitle-border.LeftEx;
                var width=border.BottomEx-border.TopEx;
                var x=this.DrawData.Point.X/1000*width+border.TopEx;
                var y=border.RightTitle-this.DrawData.Point.Y/1000*width;
            }
            else
            {
                var width=border.RightEx-border.LeftEx;
                var height=border.BottomEx-border.TopTitle;
                var x=this.DrawData.Point.X/1000*width+border.LeftEx;
                var y=this.DrawData.Point.Y/1000*height+border.TopTitle;
            }
            
        }
        else if (this.Name=="DRAWTEXTABS")
        {
            if (isHScreen)
            {
                var x=this.DrawData.Point.X+border.TopEx;
                var y=border.RightTitle-this.DrawData.Point.Y;
            }
            else
            {
                var x=this.DrawData.Point.X+border.LeftEx;
                var y=this.DrawData.Point.Y+border.TopTitle;
            }
        }
        else
        {
            return;
        }

        if (this.Direction==1) this.Canvas.textBaseline='bottom';
        else if (this.Direction==2) this.Canvas.textBaseline='top';
        else this.Canvas.textBaseline='middle';
        this.Canvas.textAlign='left';
        this.Canvas.font=this.TextFont;
        this.Canvas.fillStyle=this.Color;
        this.DrawText(this.DrawData.Text,x,y,isHScreen);
    }

    this.Draw=function()
    {
        if (!this.IsShow || this.ChartFrame.IsMinSize) return;

        if (this.NotSupportMessage)
        {
            this.DrawNotSupportmessage();
            return;
        }

        if (this.Name=="DRAWTEXTREL" || this.Name=="DRAWTEXTABS")
        {
            this.DrawRectText();
            return;
        }

        if (this.Position) 
        {
            this.DrawPosition();
            return;
        }

        if (!this.Data || !this.Data.Data) return;

        var isHScreen=(this.ChartFrame.IsHScreen===true)
        var isMinute=this.IsMinuteFrame();
        var dataWidth=this.ChartFrame.DataWidth;
        var distanceWidth=this.ChartFrame.DistanceWidth;
        var xOffset=this.ChartBorder.GetLeft()+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
        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();
            xOffset=this.ChartBorder.GetTop()+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
        }
        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;

            if (this.FixedFontSize>0) var iconSize=this.FixedFontSize;
            else var iconSize=this.GetDynamicIconSize(dataWidth,distanceWidth,this.IconSize.Max,this.IconSize.Min,this.IconSize.Zoom);
            this.Canvas.font=iconSize+'px '+this.IconFont.Family;
        }
        else
        {
            if (this.FixedFontSize>0) 
                this.TextFont=`${this.FixedFontSize}px ${this.TextSize.FontName}`;
            else 
                this.TextFont=this.GetDynamicFont(dataWidth,distanceWidth,this.TextSize.Max,this.TextSize.Min,this.TextSize.Zoom,this.TextSize.FontName);
            this.Canvas.font=this.TextFont;
        }

        for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
        //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 (isMinute)
            {
                var x=this.ChartFrame.GetXFromIndex(j);
            }
            else
            {
                var left=xOffset;
                var right=xOffset+dataWidth;
                if (right>chartright) break;
                var x=left+(right-left)/2;
            }
            
            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.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.setLineDash([]);
            }

            if (isArrayText)
            {
                var text=this.Text[i];
                if (!text) continue;
                if (this.Name=='DRAWNUMBER')
                {
                    if (this.Direction==1) y-=g_JSChartResource.DRAWABOVE.YOffset*pixelTatio;
                    else if (this.Direction==2) y+=this.TextSize.YOffset*pixelTatio;
                }
                this.DrawText(text,x,y,isHScreen);
            }
            else
            {
                if (this.Name=='DRAWICON')
                {
                    if (this.Direction==1) y-=g_JSChartResource.DRAWABOVE.YOffset*pixelTatio;
                    else if (this.Direction==2) 
                    {
                        if (this.IconFont) y+=this.IconSize.YOffset*pixelTatio;
                        else y+=this.TextSize.YOffset*pixelTatio;
                    }
                }
                else if (this.Name=="DRAWTEXT")
                {
                    if (this.Direction==1) y-=g_JSChartResource.DRAWABOVE.YOffset*pixelTatio;
                    else if (this.Direction==2) y+=this.TextSize.YOffset*pixelTatio;
                }
                //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 y=this.ChartBorder.GetRightEx()-this.ChartBorder.GetWidthEx()*this.Position.Y;
            var x=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.GetHeightEx()*this.Position.Y;
        }

        this.Canvas.fillStyle=this.Color;

        if (this.Name=="DRAWTEXT_FIX") this.Canvas.font=this.Font.DRAWTEXT_FIX;
        else if (this.Name=="DRAWNUMBER_FIX") this.Canvas.font=this.Font.DRAWNUMBER_FIX;

        //TYPE:0为左对齐,1为右对齐.
        if (this.Position.Type==0) this.Canvas.textAlign='left';
        else if (this.Position.Type==1) this.Canvas.textAlign='right';
        else this.Canvas.textAlign='center';

        if (this.Direction==1) this.Canvas.textBaseline='bottom';
        else if (this.Direction==2) this.Canvas.textBaseline='top';
        else this.Canvas.textBaseline='middle';

        if (Array.isArray(this.Text))
        {
            if (!this.Data || !this.Data.Data) return;
            var xPointCount=this.ChartFrame.XPointCount;
            for(var i=this.Data.DataOffset,j=0; i<this.Data.Data.length && j<xPointCount; ++i,++j)
            {
                var text=this.Text[i];
                if (text)
                {
                    this.DrawText(text,x,y,isHScreen);
                    break;
                }
            }
        }
        else
        {
            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.ChartFrame.IsMinSize) return;

        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.IsShowLead=false;
    this.LeadData;
    this.UpColor=g_JSChartResource.UpBarColor;
    this.DownColor=g_JSChartResource.DownBarColor;

    this.BeforeOpenData;    //盘前数据 Data:[] 数据, TotalCount:一共的数据个数
    this.BeforeLineColor=g_JSChartResource.Minute.Before.LineColor;
    this.BeforeAvPriceColor=g_JSChartResource.Minute.Before.AvPriceColor;
    this.BeforePoint={ Color:g_JSChartResource.Minute.Before.Point.Color, Radius:g_JSChartResource.Minute.Before.Point.Radius };

    this.AfterCloseData;    //盘后数据

    this.MultiDayBeforeOpenData;    //多日分时图 盘前数据 数组 1天一个
    this.MultiDayAfterCloseData;    //多日分时图 盘后数据 数组 1天一个

    this.ColorLineData;     //自定义价格线分段颜色
    this.Source;            //原始分钟数据

    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;

        this.DrawBeforeOpen();   //盘前
        this.DrawMultiDayBeforeOpen();

        if (this.IsShowLead) this.DrawLead();   //领先指标

        if (!data) return;

        var bFirstPoint=true;
        var ptFirst={}; //第1个点
        var ptLast={};  //最后一个点
        var drawCount=0;
        var pointCount=0;
        for(var i=data.DataOffset,j=0;i<data.Data.length && j<xPointCount;++i,++j)
        {
            var value=null;
            value=data.Data[i];
            ++pointCount;
            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);
            }

            ptLast.X=x;
            ptLast.Y=y;
            ptLast.Price=value;

            ++drawCount;

            if (pointCount>=minuteCount) //上一天的数据和这天地数据线段要断开
            {
                bFirstPoint=true;
                this.Canvas.stroke();
                if (this.IsDrawArea)   //画面积
                {
                    if (isHScreen)
                    {
                        this.Canvas.lineTo(left,x);
                        this.Canvas.lineTo(left,ptFirst.X);
                        this.SetFillStyle(this.AreaColor,this.ChartBorder.GetRightEx(),bottom,this.ChartBorder.GetLeftEx(),bottom);
                    }
                    else
                    {
                        this.Canvas.lineTo(x,bottom);
                        this.Canvas.lineTo(ptFirst.X,bottom);
                        this.SetFillStyle(this.AreaColor, left,this.ChartBorder.GetTopEx(), left,bottom);
                    }
                    
                    this.Canvas.fill();
                }
                pointCount=0;
                drawCount=0;
            }
        }

        if (drawCount>0)
        {
            this.Canvas.stroke();
            if (this.IsDrawArea)   //画面积
            {
                if (isHScreen)
                {
                    this.Canvas.lineTo(left,x);
                    this.Canvas.lineTo(left,ptFirst.X);
                    this.SetFillStyle(this.AreaColor,this.ChartBorder.GetRightEx(),bottom,this.ChartBorder.GetLeftEx(),bottom);
                }
                else
                {
                    this.Canvas.lineTo(x,bottom);
                    this.Canvas.lineTo(ptFirst.X,bottom);
                    this.SetFillStyle(this.AreaColor,left,this.ChartBorder.GetTopEx(), left,bottom);
                }

                this.Canvas.fill();
            }
        }

        this.DrawColorLine();
        this.DrawAfterClose();      //收盘集合竞价
        this.DrawMultiDayAfterClose();

        if (this.GetEventCallback)
        {
            var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_DRAW_MINUTE_LAST_POINT);
            if (event)
            {
                var data={ LastPoint:{X:ptLast.X, Y:ptLast.Y}, Price:ptLast.Price };
                event.Callback(event,data,this);
            }
        }
    }

    //画领先指标
    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.DrawBeforeOpen=function()
    {
        if (this.ChartBorder.LeftExtendWidth<10) return;
        if (!this.BeforeOpenData) return;

        this.DrawCallAuction(-1, this.BeforeOpenData, true); 
    }

    this.DrawAfterClose=function()
    {
        if (this.ChartBorder.RightExtendWidth<10) return;
        if (!this.AfterCloseData) return;

        this.DrawCallAuction(-1, this.AfterCloseData, false); 
    }

    this.DrawMultiDayBeforeOpen=function()
    {
        if (this.ChartBorder.MultiDayMinute.Count<=1 || this.ChartBorder.MultiDayMinute.Left<=0) return;
        if (!this.MultiDayBeforeOpenData) return;

        for(var i in this.MultiDayBeforeOpenData)
        {
            var dayItem=this.MultiDayBeforeOpenData[i];
            this.DrawCallAuction(parseInt(i), dayItem, true);
        }
    }

    this.DrawMultiDayAfterClose=function()
    {
        if (this.ChartBorder.MultiDayMinute.Count<=1 || this.ChartBorder.MultiDayMinute.Right<=0) return;
        if (!this.MultiDayAfterCloseData) return;

        for(var i in this.MultiDayAfterCloseData)
        {
            var dayItem=this.MultiDayAfterCloseData[i];
            this.DrawCallAuction(parseInt(i), dayItem, false);
        }
    }

    this.DrawCallAuction=function(indexDay, callAutionData, isBeforeOpen)
    {
        if (!callAutionData) return;

        callAutionData.Index=indexDay;
        var isHScreen=(this.ChartFrame.IsHScreen===true);
        var bFirstPoint=true;
        var drawCount=0;
        var callAutionInfo={ TotalCount:callAutionData.TotalCount };
        if (callAutionData.Ver==3.0)   //均线
        {
            for(var i in callAutionData.Data)
            {
                var item=callAutionData.Data[i];
                if (!item || !IFrameSplitOperator.IsNumber(item.AvPrice)) continue;
    
                if (isBeforeOpen)
                {
                    var x=this.ChartFrame.GetLeftExtendXFromIndex(i,callAutionData);
                    var y=this.ChartFrame.GetLeftExtendYFromData(item.AvPrice);
                }
                else
                {
                    var x=this.ChartFrame.GetRightExtendXFromIndex(i,callAutionData);
                    var y=this.ChartFrame.GetRightExtendYFromData(item.AvPrice);
                }
                
                if (bFirstPoint)
                {
                    this.Canvas.strokeStyle=this.BeforeAvPriceColor;
                    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();
            }
        }

        var bFirstPoint=true;
        var drawCount=0;
        var aryPoint=[];
        for(var i in callAutionData.Data)
        {
            var item=callAutionData.Data[i];
            if (!item || !IFrameSplitOperator.IsNumber(item.Price)) 
            {
                if (i==0 && isBeforeOpen && IFrameSplitOperator.IsNumber(this.YClose))
                {
                    var x=this.ChartFrame.GetLeftExtendXFromIndex(i,callAutionData);
                    var y=this.ChartFrame.GetLeftExtendYFromData(this.YClose);

                    this.Canvas.strokeStyle=this.BeforeLineColor;
                    this.Canvas.beginPath();
                    if (isHScreen) this.Canvas.moveTo(y,x);
                    else this.Canvas.moveTo(x,y);
                    bFirstPoint=false;
                }

                continue;
            }

            if (isBeforeOpen)
            {
                var x=this.ChartFrame.GetLeftExtendXFromIndex(i,callAutionData);
                var y=this.ChartFrame.GetLeftExtendYFromData(item.Price);
            }
            else
            {
                var x=this.ChartFrame.GetRightExtendXFromIndex(i,callAutionData);
                var y=this.ChartFrame.GetRightExtendYFromData(item.Price);
            }

            if (bFirstPoint)
            {
                this.Canvas.strokeStyle=this.BeforeLineColor;
                this.Canvas.beginPath();
                if (isHScreen) this.Canvas.moveTo(y,x);
                else this.Canvas.moveTo(x,y);
                bFirstPoint=false;

                aryPoint.push({X:x, Y:y });
            }
            else
            {
                if (isHScreen) this.Canvas.lineTo(y,x);
                else this.Canvas.lineTo(x,y);

                aryPoint.push({X:x, Y:y });
            }

            ++drawCount;
        }

        if (drawCount>0)
        {
            this.Canvas.stroke();
        }

        if (callAutionData.Ver==2.0 && this.BeforePoint.Radius>0)
        {
            this.Canvas.fillStyle=this.BeforePoint.Color;
            for(var i in aryPoint)
            {
                var item=aryPoint[i];

                this.Canvas.beginPath();
                if (isHScreen)  this.Canvas.arc(item.Y, item.X, this.BeforePoint.Radius, 0, 2 * Math.PI);
                else  this.Canvas.arc(item.X, item.Y, this.BeforePoint.Radius, 0, 2 * Math.PI);
                this.Canvas.fill();
            }
            
        }
    }

    this.FindColorLineItem=function(minuteItem)
    {
        if (!minuteItem || !this.ColorLineData) return null;

        for(var i in this.ColorLineData)
        {
            var item=this.ColorLineData[i];
            if (item.Date==minuteItem.Date && (minuteItem.Time>=item.Start && minuteItem.Time<=item.End))
            {
                return item;
            }
        }

        return null;
    }

    this.DrawColorLine=function()
    {
        if (!this.ColorLineData|| !this.Source || !this.Data) return;
        var isHScreen=(this.ChartFrame.IsHScreen===true);
        var border=this.ChartBorder.GetBorder();
        var xPointCount=this.ChartFrame.XPointCount;
        var minuteCount=this.ChartFrame.MinuteCount;
        var data=this.Data;

        var bFirstPoint=true;
        var ptLast={};  //最后一个点
        var ptFirst={};
        var drawCount=0;
        var preColor=null;
        this.Canvas.save();

        for(var i=data.DataOffset,j=0;i<data.Data.length && j<xPointCount;++i,++j)
        {
            var value=null;
            value=data.Data[i];
            var item=this.Source.Data[i];
            if (!value || !item) continue;

            var colorItem=this.FindColorLineItem(item);
            if (!colorItem)
            {
                if (drawCount>0)
                {
                    this.Canvas.stroke();
                    bFirstPoint=true;
                }
                continue;
            }

            if (preColor && preColor!=colorItem.Color)
            {
                this.Canvas.stroke();
                bFirstPoint=true;

                /*
                this.Canvas.strokeStyle=colorItem.Color;
                this.Canvas.beginPath();
                if (isHScreen) this.Canvas.moveTo(ptLast.Y,ptLast.X);
                else this.Canvas.moveTo(ptLast.X,ptLast.Y);
                bFirstPoint=false;
                preColor=colorItem.Color;
                */
            }

            var x=this.ChartFrame.GetXFromIndex(j);
            var y=this.ChartFrame.GetYFromData(value);

            if (bFirstPoint)
            {
                this.Canvas.strokeStyle=colorItem.Color;
                if (IFrameSplitOperator.IsNumber(colorItem.LineWidth))
                    this.Canvas.lineWidth=colorItem.LineWidth;

                this.Canvas.beginPath();
                if (isHScreen) this.Canvas.moveTo(y,x);
                else this.Canvas.moveTo(x,y);
                bFirstPoint=false;
                ptFirst={X:x,Y:y};
                preColor=colorItem.Color;
            }
            else
            {
                if (isHScreen) this.Canvas.lineTo(y,x);
                else this.Canvas.lineTo(x,y);
            }

            ptLast.X=x;
            ptLast.Y=y;
            ptLast.Price=value;

            ++drawCount;
        }

        if (drawCount>0)
        {
            this.Canvas.stroke();
        }

        this.Canvas.restore();
    }

    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;

        if (this.ChartBorder.LeftExtendWidth>10 && this.BeforeOpenData)
        {
            for(var i in this.BeforeOpenData.Data)
            {
                var item=this.BeforeOpenData.Data[i];
                if (!item) continue;
                if (IFrameSplitOperator.IsNumber(item.Price))
                {
                    if (range.Max==null) range.Max=item.Price;
                    if (range.Min==null) range.Min=item.Price;
    
                    if (range.Max<item.Price) range.Max=item.Price;
                    if (range.Min>item.Price) range.Min=item.Price;
                }
                
                //集合竞价均线统计
                if (this.BeforeOpenData.Ver==3.0 && IFrameSplitOperator.IsNumber(item.AvPrice))
                {
                    if (range.Max==null) range.Max=item.AvPrice;
                    if (range.Min==null) range.Min=item.AvPrice;
    
                    if (range.Max<item.AvPrice) range.Max=item.AvPrice;
                    if (range.Min>item.AvPrice) range.Min=item.AvPrice;
                }
            }
        }
        

        var data=this.Data;
        for(var i=data.DataOffset,j=0;i<data.Data.length && j<xPointCount;++i,++j)
        {
            var value=null;
            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;
    }

    this.GetTooltipData=function(x,y,tooltip)
    {
        var isHScreen=(this.ChartFrame.IsHScreen===true);
        if (isHScreen) return false;
        if (!this.IsShow) return false;
        if (!this.Data || !IFrameSplitOperator.IsNonEmptyArray(this.Data.Data)) return false;
        var position=this.ChartBorder.PtInClient(x,y,this.Canvas,isHScreen);
        if (position!=1) return false;
        
        var data=this.Data;
        var index=this.ChartFrame.GetXData(x);
        var end=Math.ceil(index);
        var start=Math.floor(index);

        if (end>=data.Data.length || start>=data.Data.length) return false;

        var lineWidth=5;
        if (end==start)
        {
            var value=data.Data[start];
        }
        else
        {
            var startValue=data.Data[start];
            var endValue=data.Data[end];
            var ptStart={X:this.ChartFrame.GetXFromIndex(start), Y:this.ChartFrame.GetYFromData(startValue)};
            var ptEnd={X:this.ChartFrame.GetXFromIndex(end), Y:this.ChartFrame.GetYFromData(endValue)};

            this.Canvas.beginPath();
            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))
            {
                tooltip.Data={ Index:index, Start:{ Index:start, Item:data.Data[start] }, End:{ Index:end, Value:data.Data[end]} };
                tooltip.ChartPaint=this;
                tooltip.Type=5; //走势图线
                return true;
            }
        }

        return false;
    }
}

//分钟线叠加 支持横屏
function ChartOverlayMinutePriceLine()
{
    this.newMethod=IChartPainting;   //派生
    this.newMethod();
    delete this.newMethod;

    this.Color="rgb(65,105,225)";
    this.MainData;                  //主图数据
    this.MainYClose;                //主图股票的前收盘价
    this.SourceData;                //原始数据

    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;
        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);
            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;
    }

    this.GetTooltipData=function(x,y,tooltip)
    {
        var isHScreen=(this.ChartFrame.IsHScreen===true);
        if (isHScreen) return false;
        if (!this.IsShow) return false;
        if (!this.Data || !IFrameSplitOperator.IsNonEmptyArray(this.Data.Data)) return false;
        if (!IFrameSplitOperator.IsNumber(this.YClose) || !IFrameSplitOperator.IsNumber(this.MainYClose)) return false;

        var position=this.ChartBorder.PtInClient(x,y,this.Canvas,isHScreen);
        if (position!=1) return false;

        var data=this.Data;
        var index=this.ChartFrame.GetXData(x);
        var end=Math.ceil(index);
        var start=Math.floor(index);

        if (end>=data.Data.length || start>=data.Data.length) return false;

        var lineWidth=5;
        if (end==start)
        {
            var value=data.Data[start];
        }
        else
        {
            var startValue=data.Data[start].Close
            startValue=startValue/this.YClose*this.MainYClose;
            var endValue=data.Data[end].Close
            endValue=endValue/this.YClose*this.MainYClose;
            var ptStart={X:this.ChartFrame.GetXFromIndex(start), Y:this.ChartFrame.GetYFromData(startValue)};
            var ptEnd={X:this.ChartFrame.GetXFromIndex(end), Y:this.ChartFrame.GetYFromData(endValue)};

            this.Canvas.beginPath();
            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))
            {
                tooltip.Data={ Index:index, Start:{ Index:start, Item:data.Data[start] }, End:{ Index:end, Value:data.Data[end]} };
                tooltip.ChartPaint=this;
                tooltip.Type=6; //走势图线
                //tooltip.Stock={Symbol:this.Symbol, Name:this.Title };
                return true;
            }
        }

        return false;
    }
}

//分钟信息地雷 支持横屏
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.TooltipRect=[];    //Rect 

    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()
    {
        this.TooltipRect=[];
        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.Source;

        for(var i=data.DataOffset,j=0;i<data.Data.length && j<xPointCount;++i,++j)
        {
            var item=data.Data[i];
            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);
            if (!this.IsHScreen) 
            {
                var rtBorder=item.Border;
                var textRect=new Rect(rtBorder.X,rtBorder.Y,rtBorder.Width,rtBorder.Height);
                var tooltipData={ Data:{ Item:item }, Rect:textRect };
                this.TooltipRect.push(tooltipData);
            }
        }

        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, Date:showItem.Date, Time:showItem.Time };
        if (showItem.Content) InfoDrawItem.Content=showItem.Content;
        if (showItem.Link) InfoDrawItem.Link=showItem.Link;
        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;
    }

    this.GetTooltipData=function(x,y,tooltip)
    {
        for(var i in this.TooltipRect)
        {
            var item=this.TooltipRect[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('[ChartMinuteInfo::GetTooltipData] info ', item);
                tooltip.Data=item;
                tooltip.ChartPaint=this;
                tooltip.Type=3; //异动信息
                return true;
            }
        }

        return false;
    }
}

//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.LineWidth=1;

    this.Draw=function()
    {
        if (!this.IsShow || this.ChartFrame.IsMinSize) return;

        if (this.NotSupportMessage)
        {
            this.DrawNotSupportmessage();
            return;
        }

        if (this.ChartFrame.IsHScreen===true)
        {
            this.HScreenDraw();
            return;
        }

        var isMinute=this.IsMinuteFrame();
        var dataWidth=this.ChartFrame.DataWidth;
        var distanceWidth=this.ChartFrame.DistanceWidth;
        var border=this.ChartBorder.GetBorder();
        var xOffset=border.LeftEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
        var chartright=border.RightEx;
        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);
        
        var lineWidth=this.LineWidth*GetDevicePixelRatio();
        if (this.LineWidth==50) lineWidth=dataWidth;
        else if (lineWidth>dataWidth) lineWidth=dataWidth;
        
        var backupLineWidth=this.Canvas.lineWidth;
        this.Canvas.lineWidth=lineWidth;
        for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
        //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 (isMinute)
            {
                var x=this.ChartFrame.GetXFromIndex(j);
            }
            else
            {
                var left=xOffset;
                var right=xOffset+dataWidth;
                if (right>chartright) break;
                var x=left+(right-left)/2;
            }
            var y=this.ChartFrame.GetYFromData(value);

            if (x>chartright) break;

            var xFix=ToFixedPoint2(lineWidth, x); //毛边修正
            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.Canvas.lineWidth=backupLineWidth;
    }

    this.HScreenDraw=function()
    {
        var dataWidth=this.ChartFrame.DataWidth;
        var distanceWidth=this.ChartFrame.DistanceWidth;
        var border=this.ChartBorder.GetHScreenBorder();
        var chartright=border.BottomEx;
        var xPointCount=this.ChartFrame.XPointCount;
        var lockRect=this.GetLockRect();
        if (lockRect) chartright=lockRect.Top;

        var yBottom=this.ChartFrame.GetYFromData(0);

        var lineWidth=this.LineWidth*GetDevicePixelRatio();
        if (this.LineWidth==50) lineWidth=dataWidth;
        else if (lineWidth>dataWidth) lineWidth=dataWidth;

        var backupLineWidth=this.Canvas.lineWidth;
        this.Canvas.lineWidth=lineWidth;
        
        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();
        }

        this.Canvas.lineWidth=backupLineWidth;
    }
}

//柱子
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.ChartFrame.IsMinSize) return;

        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.ChartFrame.IsMinSize) return;

        if (this.NotSupportMessage)
        {
            this.DrawNotSupportmessage();
            return;
        }

        var isHScreen=this.ChartFrame.IsHScreen;
        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 = [];
        for(var i=this.Data.DataOffset,j=0; i<this.Data.Data.length && j<xPointCount;++i, ++j, xOffset+=(dataWidth+distanceWidth))
        {
            firstlinePoints = [];
            secondlinePoints = [];
            for(;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) break;
                x=this.ChartFrame.GetXFromIndex(j);
                y=this.ChartFrame.GetYFromData(value.Value);
                y2 = this.ChartFrame.GetYFromData(value.Value2);

                if (isHScreen)
                {
                    firstlinePoints.push({x:y,y:x});
                    secondlinePoints.push({x:y2,y:x});
                }
                else
                {
                    firstlinePoints.push({x:x,y:y});
                    secondlinePoints.push({x:x,y:y2});
                }
                
            }

            if (firstlinePoints.length>1 && secondlinePoints.length>1)
            {
                this.DrawBand(firstlinePoints, secondlinePoints);
            }
        }
    }

    this.DrawBand=function(aryFrist, arySecond)
    {
        this.Canvas.save();
        this.Canvas.beginPath();
        for(var i=0;i<aryFrist.length;++i)
        {
            if (i == 0)
                this.Canvas.moveTo(aryFrist[i].x, aryFrist[i].y);
            else
                this.Canvas.lineTo(aryFrist[i].x, aryFrist[i].y);
        }

        for (var i = arySecond.length-1; i >= 0; --i)
        {
            this.Canvas.lineTo(arySecond[i].x, arySecond[i].y);
        }  
        this.Canvas.closePath();
        this.Canvas.clip();

        this.Canvas.moveTo(aryFrist[0].x, this.ChartBorder.GetBottom());
        for (var i = 0; i < aryFrist.length; ++i)
        {
            this.Canvas.lineTo(aryFrist[i].x, aryFrist[i].y);
        }
        this.Canvas.lineTo(aryFrist[aryFrist.length-1].x, this.ChartBorder.GetBottom());
        this.Canvas.closePath();
        this.Canvas.fillStyle = this.FirstColor;
        this.Canvas.fill();

        this.Canvas.beginPath();
        this.Canvas.moveTo(arySecond[0].x, this.ChartBorder.GetBottom());
        for (var i = 0; i < arySecond.length; ++i)
        {
            this.Canvas.lineTo(arySecond[i].x, arySecond[i].y);
        }
        this.Canvas.lineTo(arySecond[arySecond.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 ChartLineArea()
{
    this.newMethod=IChartPainting;   //派生
    this.newMethod();
    delete this.newMethod;
    this.IsDrawFirst = true;    //面积图在K线前面画,否则回挡住K线的

    this.ClassName="ChartLineArea";
    this.Color='rgb(56,67,99)';
    this.IsHScreen=false;

    this.Draw=function()
    {
        if (this.ChartFrame.IsMinSize) return;

        this.IsHScreen=(this.ChartFrame.IsHScreen===true);

        if (this.NotSupportMessage)
        {
            this.DrawNotSupportmessage();
            return;
        }

        if (!this.Data || !this.Data.Data) return;

        var dataWidth=this.ChartFrame.DataWidth;
        var distanceWidth=this.ChartFrame.DistanceWidth;
        var xPointCount=this.ChartFrame.XPointCount;
        var xOffset=this.ChartBorder.GetLeft()+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
        var x = 0, y = 0, y2 = 0;
        var aryPoint=[];
        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];
            aryPoint[i]=null;
            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);

            if (this.IsHScreen)
                aryPoint[i]={ Line:{ X:y, Y:x }, Line2:{ X:y2, Y:x }};
            else
                aryPoint[i]={ Line:{ X:x, Y:y }, Line2:{ X:x, Y:y2 }};
        }

        this.Canvas.fillStyle = this.Color;
        var firstPoint=true;
        var pointCount=0;
        var aryLine2=[];
        for(var i in aryPoint)
        {
            var item=aryPoint[i];
            if (!item)
            {
                if (pointCount>0)
                {
                    for(var j=aryLine2.length-1; j>=0; --j)
                    {
                        var item2=aryLine2[j];
                        this.Canvas.lineTo(item2.Line2.X, item2.Line2.Y);
                    }
                    this.Canvas.closePath();
                    this.Canvas.fill();
                }

                firstPoint=true;
                pointCount=0;
                aryLine2=[];
                continue;
            }

            if (firstPoint)
            {
                this.Canvas.beginPath();
                this.Canvas.moveTo(item.Line.X, item.Line.Y);
                firstPoint=false;
            }
            else
            {
                this.Canvas.lineTo(item.Line.X, item.Line.Y);
            }

            aryLine2.push(item);
            ++pointCount;
        }

        if (pointCount>0)
        {
            for(var j=aryLine2.length-1; j>=0; --j)
            {
                var item2=aryLine2[j];
                this.Canvas.lineTo(item2.Line2.X, item2.Line2.Y);
            }
            this.Canvas.closePath();
            this.Canvas.fill();
        }
    }

    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 || 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 ChartFillRGN()
{
    this.newMethod=ChartLineArea;   //派生
    this.newMethod();
    delete this.newMethod;
    this.IsDrawFirst = true;    //面积图在K线前面画,否则回挡住K线的
    this.IsHScreen=false;

    this.ClassName="ChartFillRGN";

    this.DrawRGB=function(aryPoint)
    {
        var firstPoint=true;
        var pointCount=0;
        var aryLine2=[];
        var color=null;
        for(var i in aryPoint)
        {
            var item=aryPoint[i];
            if (!item || (color && item.Color!=color) )
            {
                if (pointCount>0)
                {
                    for(var j=aryLine2.length-1; j>=0; --j)
                    {
                        var item2=aryLine2[j];
                        this.Canvas.lineTo(item2.Line2.X, item2.Line2.Y);
                    }
                    this.Canvas.closePath();
                    this.Canvas.fillStyle = color;
                    this.Canvas.fill();
                }

                firstPoint=true;
                pointCount=0;
                aryLine2=[];
                color=null;
            }

            if (!item) continue;

            if (firstPoint)
            {
                this.Canvas.beginPath();
                this.Canvas.moveTo(item.Line.X, item.Line.Y);
                firstPoint=false;
                color=item.Color;
            }
            else
            {
               this.Canvas.lineTo(item.Line.X, item.Line.Y);
            }

            aryLine2.push(item);
            ++pointCount;
        }

        if (pointCount>0)
        {
            for(var j=aryLine2.length-1; j>=0; --j)
            {
                var item2=aryLine2[j];
                this.Canvas.lineTo(item2.Line2.X, item2.Line2.Y);
            }
            this.Canvas.closePath();
            this.Canvas.fillStyle = color;
            this.Canvas.fill();
        }
    }

    this.Draw=function()
    {
        if (this.ChartFrame.IsMinSize) return;

        this.IsHScreen=(this.ChartFrame.IsHScreen===true);

        if (this.NotSupportMessage)
        {
            this.DrawNotSupportmessage();
            return;
        }

        if (!this.Data || !this.Data.Data) return;

        var dataWidth=this.ChartFrame.DataWidth;
        var distanceWidth=this.ChartFrame.DistanceWidth;
        var xPointCount=this.ChartFrame.XPointCount;
        var xOffset=this.ChartBorder.GetLeft()+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
        var x = 0, y = 0, y2 = 0;
        var aryPoint=[];    //点坐标
        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];
            aryPoint[i]=null;
            if (value==null || value.Value==null || value.Value2 == null || !value.Color) continue;

            x=this.ChartFrame.GetXFromIndex(j);
            y=this.ChartFrame.GetYFromData(value.Value);
            y2 = this.ChartFrame.GetYFromData(value.Value2);

            if (this.IsHScreen)
                aryPoint[i]={ Line:{ X:y, Y:x }, Line2:{ X:y2, Y:x }, Color:value.Color };
            else
                aryPoint[i]={ Line:{ X:x, Y:y }, Line2:{ X:x, Y:y2 }, Color:value.Color };
        }

        this.DrawRGB(aryPoint);
    }
}

//支持横屏
//用法:FLOATRGN(PRICE,WIDTH,COND1,COLOR1,COND2,COLOR2...),以PRICE为基础填充宽度为WIDTH像素的区域,WIDTH为负则向下填充,当COND1条件满足时,用COLOR1颜色,当COND2条件满足时,用COLOR2颜色,否则不填充,从COND1之后的参数均可以省略,最多可以有10组条件
//例如:FLOATRGN(CLOSE,VOL/HHV(VOL,10)*15,CLOSE>OPEN,RGB(255,0,0),1,RGB(0,255,0)) 表示沿收盘价填充宽度为成交量的区域,区域最大宽度为15像素,阳线时用红色,阴线时用绿色。
function ChartFLOATRGN()
{
    this.newMethod=IChartPainting;   //派生
    this.newMethod();
    delete this.newMethod;
    this.IsDrawFirst = false;    //面积图在K线前面画,否则回挡住K线的

    this.ClassName="ChartFLOATRGN";
    this.Color='rgb(56,67,99)';
    this.IsHScreen=false;

    this.Draw=function()
    {
        if (this.ChartFrame.IsMinSize) return;

        this.IsHScreen=(this.ChartFrame.IsHScreen===true);

        if (this.NotSupportMessage)
        {
            this.DrawNotSupportmessage();
            return;
        }

        if (!this.Data || !this.Data.Data) return;

        var dataWidth=this.ChartFrame.DataWidth;
        var distanceWidth=this.ChartFrame.DistanceWidth;
        var xPointCount=this.ChartFrame.XPointCount;
        var xOffset=this.ChartBorder.GetLeft()+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;

        var x = 0, y = 0, y2 = 0;
        var aryPoint=[];    //点坐标
        for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
        {
            var item=this.Data.Data[i];
            aryPoint[i]=null;
            if (!item || !IFrameSplitOperator.IsNumber(item.Value)|| !IFrameSplitOperator.IsNumber(item.Value2) || !item.Color) continue;

            x=this.ChartFrame.GetXFromIndex(j);
            y=this.ChartFrame.GetYFromData(item.Value);

            if (this.IsHScreen)
                aryPoint[i]={ Line:{ X:y, Y:x }, Line2:{ X:y+item.Value2*GetDevicePixelRatio(), Y:x }, Color:item.Color };
            else
                aryPoint[i]={ Line:{ X:x, Y:y }, Line2:{ X:x, Y:y-item.Value2*GetDevicePixelRatio() }, Color:item.Color };
        }

        //计算左右位置的点
        var preItem=null;
        for(var i in aryPoint)
        {
            var item=aryPoint[i];
            if (preItem && item)
            {
                if (this.IsHScreen)
                {
                    var xWidth=(item.Line.Y-preItem.Line.Y);
                    x=preItem.Line.Y+xWidth/2;
                    y=preItem.Line.X+(item.Line.X-preItem.Line.X)/2;
                    y2=preItem.Line2.X+(item.Line2.X-preItem.Line2.X)/2;

                    preItem.RightLine={X:y, Y:x};
                    preItem.RightLine2={X:y2, Y:x};
                    item.LeftLine={X:y, Y:x};
                    item.LeftLine2={X:y2, Y:x};
                }
                else
                {
                    var xWidth=(item.Line.X-preItem.Line.X);
                    x=preItem.Line.X+xWidth/2;
                    y=preItem.Line.Y+(item.Line.Y-preItem.Line.Y)/2;
                    y2=preItem.Line2.Y+(item.Line2.Y-preItem.Line2.Y)/2;
                    preItem.RightLine={X:x, Y:y};
                    preItem.RightLine2={X:x, Y:y2};
                    item.LeftLine={X:x, Y:y};
                    item.LeftLine2={X:x, Y:y2};
                }
            }

            preItem=item;  //上一个点
        }

        this.DrawRGB(aryPoint);
    }

    this.DrawRGB=function(aryPoint)
    {
        var firstPoint=true;
        var pointCount=0;
        var aryLine2=[];
        var color=null;

        if (this.IsHScreen)
        {
            var left=this.ChartBorder.GetLeftEx();
            var right=this.ChartBorder.GetRightEx();
            var top=this.ChartBorder.GetTop();
            var bottom=this.ChartBorder.GetBottom();
        }
        else
        {
            var left=this.ChartBorder.GetLeft();
            var right=this.ChartBorder.GetRight();
            var top=this.ChartBorder.GetTopEx();
            var bottom=this.ChartBorder.GetBottomEx();
        }
        

        this.Canvas.save();
        this.Canvas.beginPath();
        this.Canvas.rect(left,top,(right-left),(bottom-top));
        this.Canvas.clip();

        for(var i in aryPoint)
        {
            var item=aryPoint[i];
            if (!item || (color && item.Color!=color) )
            {
                if (pointCount>0)
                {
                    var lastItem=aryLine2[aryLine2.length-1];
                    var firstItem=aryLine2[0];
                    if (lastItem.RightLine)
                    {
                        this.Canvas.lineTo(lastItem.RightLine.X, lastItem.RightLine.Y);
                        this.Canvas.lineTo(lastItem.RightLine2.X, lastItem.RightLine2.Y);
                    }

                    for(var j=aryLine2.length-1; j>=0; --j)
                    {
                        var item2=aryLine2[j];
                        this.Canvas.lineTo(item2.Line2.X, item2.Line2.Y);
                    }

                    if (firstItem.LeftLine2)
                    {
                        this.Canvas.lineTo(firstItem.LeftLine2.X, firstItem.LeftLine2.Y);
                    }
                    
                    this.Canvas.closePath();
                    this.Canvas.fillStyle = color;
                    this.Canvas.fill();
                }

                firstPoint=true;
                pointCount=0;
                aryLine2=[];
                color=null;
            }

            if (!item) continue;

            if (firstPoint)
            {
                this.Canvas.beginPath();
                if (item.LeftLine)
                {
                    this.Canvas.moveTo(item.LeftLine.X, item.LeftLine.Y);
                    this.Canvas.lineTo(item.Line.X, item.Line.Y);
                }
                else 
                {
                    this.Canvas.moveTo(item.Line.X, item.Line.Y);
                }
                firstPoint=false;
                color=item.Color;
            }
            else
            {
                this.Canvas.lineTo(item.Line.X, item.Line.Y);
            }

            aryLine2.push(item);
            ++pointCount;
        }

        if (pointCount>0)
        {
            var lastItem=aryLine2[aryLine2.length-1];
            var firstItem=aryLine2[0];
            if (lastItem.RightLine)
            {
                this.Canvas.lineTo(lastItem.RightLine.X, lastItem.RightLine.Y);
                this.Canvas.lineTo(lastItem.RightLine2.X, lastItem.RightLine2.Y);
            }

            for(var j=aryLine2.length-1; j>=0; --j)
            {
                var item2=aryLine2[j];
                this.Canvas.lineTo(item2.Line2.X, item2.Line2.Y);
            }

            if (firstItem.LeftLine2)
            {
                this.Canvas.lineTo(firstItem.LeftLine2.X, firstItem.LeftLine2.Y);
            }
            
            this.Canvas.closePath();
            this.Canvas.fillStyle = color;
            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 item=this.Data.Data[i];
            if (!item || !IFrameSplitOperator.IsNumber(item.Value)) continue;
            var value=item.Value;
            
            if (range.Max==null) range.Max = value;
            else if (range.Max < value) range.Max = value;
            
            if (range.Min==null) range.Min = value;
            else if (range.Min > value) range.Min = value; 
        }

        return range;
    }
}

//线段围城的顶部或底部面积图 TODO:支持横屏
function ChartFillBGRGN()
{
    this.newMethod=ChartFillRGN;   //派生
    this.newMethod();
    delete this.newMethod;
    this.IsDrawFirst = true;    //面积图在K线前面画,否则回挡住K线的
    this.IsHScreen=false;

    this.ClassName="ChartFillBGRGN";


    this.DrawVerticalRGN=function()
    {
        var dataWidth=this.ChartFrame.DataWidth;
        var distanceWidth=this.ChartFrame.DistanceWidth;
        var xPointCount=this.ChartFrame.XPointCount;
        var xOffset=this.ChartBorder.GetLeft()+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
        var top=this.ChartBorder.GetTopEx();
        var bottom=this.ChartBorder.GetBottomEx();

        var y=top, y2=bottom;

        var aryPoint=[];    //点坐标
        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];
            aryPoint[i]=null;
            if (!value || !value.Color) continue;

            x=this.ChartFrame.GetXFromIndex(j);

            if (this.IsHScreen)
                aryPoint[i]={ Line:{ X:y, Y:x }, Line2:{ X:y2, Y:x }, Color:value.Color };
            else
                aryPoint[i]={ Line:{ X:x, Y:y }, Line2:{ X:x, Y:y2 }, Color:value.Color };
        }

        this.DrawRGB(aryPoint);
    }

    this.Draw=function()
    {
        if (this.ChartFrame.IsMinSize) return;

        this.IsHScreen=(this.ChartFrame.IsHScreen===true);

        if (this.NotSupportMessage)
        {
            this.DrawNotSupportmessage();
            return;
        }

        if (!this.Data || !this.Data.Data) return;

        if (this.Name=="FILLVERTICALRGN")
        {
            this.DrawVerticalRGN();
            return;
        }

        var dataWidth=this.ChartFrame.DataWidth;
        var distanceWidth=this.ChartFrame.DistanceWidth;
        var xPointCount=this.ChartFrame.XPointCount;
        var xOffset=this.ChartBorder.GetLeft()+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
        var top=this.ChartBorder.GetTopEx();
        var bottom=this.ChartBorder.GetBottomEx();
        var x = 0, y = 0, y2 = top;
        if (this.Name=="FILLBOTTOMRGN")  y2=bottom;

        var aryPoint=[];    //点坐标
        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];
            aryPoint[i]=null;
            if (value==null || value.Value==null || !value.Color) continue;

            x=this.ChartFrame.GetXFromIndex(j);
            y=this.ChartFrame.GetYFromData(value.Value);

            if (this.IsHScreen)
                aryPoint[i]={ Line:{ X:y, Y:x }, Line2:{ X:y2, Y:x }, Color:value.Color };
            else
                aryPoint[i]={ Line:{ X:x, Y:y }, Line2:{ X:x, Y:y2 }, Color:value.Color };
        }

        this.DrawRGB(aryPoint);
    }

    this.DrawRGB=function(aryPoint)
    {
        var dataWidth=this.ChartFrame.DataWidth;
        var distanceWidth=this.ChartFrame.DistanceWidth;
        var halfWidth=(distanceWidth+dataWidth)/2;
        var firstPoint=true;
        var pointCount=0;
        var aryLine2=[];
        var color=null;
        for(var i in aryPoint)
        {
            var item=aryPoint[i];
            if (!item || (color && item.Color!=color) )
            {
                if (pointCount>0)
                {
                    for(var j=aryLine2.length-1; j>=0; --j)
                    {
                        var item2=aryLine2[j];
                        this.Canvas.lineTo(item2.Line2.X+halfWidth, item2.Line2.Y);
                        this.Canvas.lineTo(item2.Line2.X-halfWidth, item2.Line2.Y);
                    }
                    this.Canvas.closePath();
                    this.Canvas.fillStyle = color;
                    this.Canvas.fill();
                }

                firstPoint=true;
                pointCount=0;
                aryLine2=[];
                color=null;
            }

            if (!item) continue;

            if (firstPoint)
            {
                this.Canvas.beginPath();
                this.Canvas.moveTo(item.Line.X-halfWidth, item.Line.Y);
                this.Canvas.lineTo(item.Line.X+halfWidth, item.Line.Y);
                firstPoint=false;
                color=item.Color;
            }
            else
            {
                this.Canvas.lineTo(item.Line.X-halfWidth, item.Line.Y);
                this.Canvas.lineTo(item.Line.X+halfWidth, item.Line.Y);
            }

            aryLine2.push(item);
            ++pointCount;
        }

        if (pointCount>0)
        {
            for(var j=aryLine2.length-1; j>=0; --j)
            {
                var item2=aryLine2[j];
                this.Canvas.lineTo(item2.Line2.X+halfWidth, item2.Line2.Y);
                this.Canvas.lineTo(item2.Line2.X-halfWidth, item2.Line2.Y);
            }
            this.Canvas.closePath();
            this.Canvas.fillStyle = color;
            this.Canvas.fill();
        }
    }

    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 || value.Value==null ) continue;

            var value=value.Value;

            if (range.Max==null)  range.Max = value;
            else if (range.Max < value) range.Max = value;
            
            if (range.Min==null) range.Min = value;
            else if (range.Min > value) range.Min = value; 
        }

        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.ChartFrame.IsMinSize) return;

        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;
    }
}

//填充背景 支持横屏
function ChartBackground()
{
    this.newMethod=IChartPainting;   //派生
    this.newMethod();
    delete this.newMethod;

    this.ClassName="ChartBackground";
    this.Color=null;
    this.ColorAngle=0;  //0 竖向 1 横向
    this.IsDrawFirst = true;    //面积图在K线前面画,否则回挡住K线的

    this.Draw=function()
    {
        if (!this.IsShow || this.ChartFrame.IsMinSize) return;
        if (!this.Color) return;
        if (this.Color.length<=0) return;

        this.IsHScreen=(this.ChartFrame.IsHScreen===true);

        if (this.Color.length==2)
        {
            if (this.IsHScreen)
            {
                if (this.ColorAngle==0)
                {
                    var ptStart={ X:this.ChartBorder.GetRight(), Y:this.ChartBorder.GetTopEx() };
                    var ptEnd={ X:this.ChartBorder.GetLeft(), Y:this.ChartBorder.GetTopEx() };
                }
                else
                {
                    var ptStart={ X:this.ChartBorder.GetLeft(), Y:this.ChartBorder.GetTopEx() };
                    var ptEnd={ X:this.ChartBorder.GetLeft(), Y:this.ChartBorder.GetBottomEx() };
                }
            }
            else
            {
                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;
        }

        if (this.Name=="DRAWGBK2" || this.Name=="KLINE_BG")
        {
            this.DrawRegion();
            return;
        }

        if (this.IsHScreen)
        {
            var left=this.ChartBorder.GetLeftEx();
            var top=this.ChartBorder.GetTop();
            var width=this.ChartBorder.GetWidthEx();
            var height=this.ChartBorder.GetHeight();
        }
        else
        {
            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);
    }

    this.DrawRegion=function()
    {
        var xPointCount=this.ChartFrame.XPointCount;
        var xOffset=this.ChartBorder.GetLeft()+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
        var dataWidth=this.ChartFrame.DataWidth;
        var distanceWidth=this.ChartFrame.DistanceWidth;
        var top=this.ChartBorder.GetTopEx();
        var bottom=this.ChartBorder.GetBottomEx();
        if (this.IsHScreen)
        {
            top=this.ChartBorder.GetRightEx();
            bottom=this.ChartBorder.GetLeftEx();
        }

        var aryPoint=[];    //点坐标
        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];
            aryPoint[i]=null;
            if (!IFrameSplitOperator.IsNumber(value) || value<=0) continue;

            var x=this.ChartFrame.GetXFromIndex(j);
            var y=this.ChartFrame.GetYFromData(value.Value);

            if (this.IsHScreen)
                aryPoint[i]={ Line:{ X:bottom, Y:x }, Line2:{ X:top, Y:x } };
            else
                aryPoint[i]={ Line:{ X:x, Y:top }, Line2:{ X:x, Y:bottom } };
        }

        this.DrawBG(aryPoint);
    }

    this.DrawBG=function(aryPoint)
    {
        var dataWidth=this.ChartFrame.DataWidth;
        var distanceWidth=this.ChartFrame.DistanceWidth;
        var halfWidth=(distanceWidth+dataWidth)/2;
        var firstPoint=true;
        var pointCount=0;
        var aryLine2=[];
        var color=null;
        for(var i in aryPoint)
        {
            var item=aryPoint[i];
            if (!item || (color && item.Color!=color) )
            {
                if (pointCount>0)
                {
                    for(var j=aryLine2.length-1; j>=0; --j)
                    {
                        var item2=aryLine2[j];
                        if (this.IsHScreen)
                        {
                            this.Canvas.lineTo(item2.Line2.X, item2.Line2.Y+halfWidth);
                            this.Canvas.lineTo(item2.Line2.X, item2.Line2.Y-halfWidth);
                        }
                        else
                        {
                            this.Canvas.lineTo(item2.Line2.X+halfWidth, item2.Line2.Y);
                            this.Canvas.lineTo(item2.Line2.X-halfWidth, item2.Line2.Y);
                        }
                    }
                    this.Canvas.closePath();
                    this.Canvas.fill();
                }

                firstPoint=true;
                pointCount=0;
                aryLine2=[];
                color=null;
            }

            if (!item) continue;

            if (firstPoint)
            {
                this.Canvas.beginPath();
                if (this.IsHScreen)
                {
                    this.Canvas.moveTo(item.Line.X, item.Line.Y-halfWidth);
                    this.Canvas.lineTo(item.Line.X, item.Line.Y+halfWidth);
                }
                else
                {
                    this.Canvas.moveTo(item.Line.X-halfWidth, item.Line.Y);
                    this.Canvas.lineTo(item.Line.X+halfWidth, item.Line.Y);
                }
                firstPoint=false;
                color=item.Color;
            }
            else
            {
                if (this.IsHScreen)
                {
                    this.Canvas.lineTo(item.Line.X, item.Line.Y-halfWidth);
                    this.Canvas.lineTo(item.Line.X, item.Line.Y+halfWidth);
                }
                else
                {
                    this.Canvas.lineTo(item.Line.X-halfWidth, item.Line.Y);
                    this.Canvas.lineTo(item.Line.X+halfWidth, item.Line.Y);
                }
            }

            aryLine2.push(item);
            ++pointCount;
        }

        if (pointCount>0)
        {
            for(var j=aryLine2.length-1; j>=0; --j)
            {
                var item2=aryLine2[j];
                if (this.IsHScreen)
                {
                    this.Canvas.lineTo(item2.Line2.X, item2.Line2.Y+halfWidth);
                    this.Canvas.lineTo(item2.Line2.X, item2.Line2.Y-halfWidth);
                }
                else
                {
                    this.Canvas.lineTo(item2.Line2.X+halfWidth, item2.Line2.Y);
                    this.Canvas.lineTo(item2.Line2.X-halfWidth, item2.Line2.Y);
                }
            }
            this.Canvas.closePath();
            this.Canvas.fill();
        }
    }

    this.GetMaxMin=function()
    {
        return { Min:null, Max:null };
    }
}

//画矩形
function ChartRectangle()
{
    this.newMethod=IChartPainting;   //派生
    this.newMethod();
    delete this.newMethod;

    this.ClassName="ChartRectangle";

    this.Color=[];
    this.Rect;
    this.BorderColor=g_JSChartResource.FrameBorderPen;

    this.Draw=function()
    {
        if (!this.IsShow || this.ChartFrame.IsMinSize) 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.ClassName="ChartTextLine";

    this.Text;  //Text=内容 Color
    this.Line;  //Type=线段类型 0=不画 1=直线 2=虚线, Color
    this.Price;

    this.Draw=function()
    {
        if (!this.IsShow || this.ChartFrame.IsMinSize) 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 ChartMultiBar()
{
    this.newMethod=IChartPainting;   //派生
    this.newMethod();
    delete this.newMethod;
    
    this.ClassName="ChartMultiBar";
    this.Bars=[];   // [ {Point:[ {Index, Value, Value2 }, ], Color:, Width: , Type: 0 实心 1 空心 }, ] 
    this.IsHScreen=false;

    this.Draw=function()
    {
        if (!this.IsShow || this.ChartFrame.IsMinSize) 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 dataWidth=this.ChartFrame.DataWidth;
        var pixelRatio=GetDevicePixelRatio();

        var drawBars=[];
        for(var i in this.Bars)
        {
            var item=this.Bars[i];
            var drawPoints={ Point:[], Color:item.Color, Width:dataWidth, Type:0 };
            if (item.Type>0) drawPoints.Type=item.Type;
            if (item.Width>0) 
            {
                drawPoints.Width=item.Width*pixelRatio;
                if (drawPoints.Width>dataWidth) drawPoints.Width=dataWidth;
            }
            else
            {
                if(drawPoints.Width<4) drawPoints.Width=1*pixelRatio;
            }

            for(var j in item.Point)
            {
                var point=item.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);
                    var y2=this.ChartFrame.GetYFromData(point.Value2);
                    drawPoints.Point.push({X:x, Y:y, Y2:y2});
                }
            }

            if (drawPoints.Point.length>0) drawBars.push(drawPoints)
        }

        for(var i in drawBars)
        {
            var item=drawBars[i];
            if (item.Width>=4) 
            {
                if (item.Type==1) this.DrawHollowBar(item);
                else this.DrawFillBar(item);
            }
            else 
            {
                this.DrawLineBar(item);
            }
        }
    }

    this.DrawLineBar=function(bar)
    {
        this.Canvas.strokeStyle=bar.Color;
        var backupLineWidth=this.Canvas.lineWidth;
        this.Canvas.lineWidth=bar.Width;
        for(var i in bar.Point)
        {
            var item=bar.Point[i];

            this.Canvas.beginPath();
            if (this.IsHScreen)
            {
                this.Canvas.moveTo(ToFixedPoint(item.Y),ToFixedPoint(item.X));
                this.Canvas.lineTo(ToFixedPoint(item.Y2),ToFixedPoint(item.X));
            }
            else
            {
                this.Canvas.moveTo(ToFixedPoint(item.X),ToFixedPoint(item.Y));
                this.Canvas.lineTo(ToFixedPoint(item.X),ToFixedPoint(item.Y2));
            }
            
            this.Canvas.stroke();
        }

        this.Canvas.lineWidth=backupLineWidth;
    }

    this.DrawFillBar=function(bar)
    {
        this.Canvas.fillStyle=bar.Color;
        for(var i in bar.Point)
        {
            var item=bar.Point[i];
            var x=item.X-(bar.Width/2);
            var y=Math.min(item.Y,item.Y2);
            var barWidth=bar.Width;
            var barHeight=Math.abs(item.Y-item.Y2);
            if (this.IsHScreen)
                this.Canvas.fillRect(ToFixedRect(y),ToFixedRect(x),ToFixedRect(barHeight),ToFixedRect(barWidth));
            else 
                this.Canvas.fillRect(ToFixedRect(x),ToFixedRect(y),ToFixedRect(barWidth),ToFixedRect(barHeight));
        }
    }

    this.DrawHollowBar=function(bar)    //空心柱子
    {
        this.Canvas.strokeStyle=bar.Color;
        var backupLineWidth=1;
        for(var i in bar.Point)
        {
            var item=bar.Point[i];
            var x=item.X-(bar.Width/2);
            var y=Math.min(item.Y,item.Y2);
            var barWidth=bar.Width;
            var barHeight=Math.abs(item.Y-item.Y2);
            this.Canvas.beginPath();
            if (this.IsHScreen)
                this.Canvas.rect(ToFixedPoint(y),ToFixedPoint(x),ToFixedRect(barHeight),ToFixedRect(barWidth));
            else
                this.Canvas.rect(ToFixedPoint(x),ToFixedPoint(y),ToFixedRect(barWidth),ToFixedRect(barHeight));

            this.Canvas.stroke();
        }

        this.Canvas.lineWidth=backupLineWidth;
    }

    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.Bars)
        {
            var item=this.Bars[i];
            for(var j in item.Point)
            {
                var point=item.Point[j];
                if (point.Index>=start && point.Index<end)
                {
                    var minValue=Math.min(point.Value,point.Value2);
                    var maxValue=Math.max(point.Value,point.Value2);
                    if (range.Max==null) range.Max=maxValue;
                    else if (range.Max<maxValue) range.Max=maxValue;
                    if (range.Min==null) range.Min=minValue;
                    else if (range.Min>minValue) range.Min=minValue;
                }
            }
        }

        return range;
    }
}

// 线段集合 支持横屏
function ChartMultiLine()
{
    this.newMethod=IChartPainting;   //派生
    this.newMethod();
    delete this.newMethod;
    
    this.ClassName="ChartMultiLine";
    this.Lines=[];   // [ {Point:[ {Index, Value }, ], Color:  }, ] 
    this.LineDash;
    this.LineWidth=1;
    this.IsHScreen=false;

    //箭头配置
    this.ArrawAngle=35;     //三角斜边一直线夹角
    this.ArrawLength=10;    //三角斜边长度
    this.ArrawLineWidth=5;  //箭头粗细
    this.Arrow={ Start:false, End:false };  //Start=是否绘制开始箭头 <-   End=是否绘制结束箭头 ->

    this.Draw=function()
    {
        if (!this.IsShow || this.ChartFrame.IsMinSize) 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=[];
        var arrowLines=[];
        for(var i in this.Lines)
        {
            var line=this.Lines[i];
            var drawPoints={ Point:[], Color:line.Color };
            var drawArrowPoints={ Start:[], End:[] };
            if (line.BGColor) drawPoints.BGColor=line.BGColor;
            for(var j=0; j<line.Point.length; ++j)
            {
                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, false);
                    var pointItem={X:x, Y:y, End:false};
                    drawPoints.Point.push(pointItem);

                    if (j==0 || j==1) drawArrowPoints.Start.push(pointItem);    //起始点
                    if (j==line.Point.length-1 || j==line.Point.length-2) drawArrowPoints.End.push(pointItem);  //结束点
                }
                else
                {
                    if (drawPoints.Point.length>0) drawPoints.Point[drawPoints.Point.length-1].End=true;  //点断开
                }
            }

            if (drawPoints.Point.length>=2) 
            {
                drawLines.push(drawPoints);
                arrowLines.push(drawArrowPoints);
            }
        }

        var pixelRatio=GetDevicePixelRatio();
        this.Canvas.save();
        for(var i in drawLines)
        {
            if (this.LineDash) this.Canvas.setLineDash(this.LineDash);
            if (IFrameSplitOperator.IsPlusNumber(this.LineWidth)) this.Canvas.lineWidth=this.LineWidth*pixelRatio;
            else this.Canvas.lineWidth=1*pixelRatio;
            var item=drawLines[i];
            this.DrawLine(item, arrowLines[i]);
        }
        this.Canvas.restore();
    }

    this.DrawLine=function(line, arrow)
    {
        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();

        //绘制箭头
        if (arrow.End.length==2 && this.Arrow.End==true)    
            this.DrawArrow(arrow.End[0],arrow.End[1]);

        if (arrow.Start.length==2 && this.Arrow.Start==true)
            this.DrawArrow(arrow.Start[1],arrow.Start[0]);
       
    }

    this.DrawArrow=function(ptStart,ptEnd)
    {
        //计算箭头
        var theta=this.ArrawAngle;       //三角斜边一直线夹角
        var headlen=this.ArrawLength;    //三角斜边长度
        var angle = Math.atan2(ptStart.Y - ptEnd.Y, ptStart.X - ptEnd.X) * 180 / Math.PI,
        angle1 = (angle + theta) * Math.PI / 180,
        angle2 = (angle - theta) * Math.PI / 180,
        topX = headlen * Math.cos(angle1),
        topY = headlen * Math.sin(angle1),
        botX = headlen * Math.cos(angle2),
        botY = headlen * Math.sin(angle2);

        this.Canvas.beginPath();
        var arrowX = ptEnd.X + topX;
        var arrowY = ptEnd.Y + topY;
        this.Canvas.moveTo(arrowX,arrowY);

        this.Canvas.lineTo(ptEnd.X, ptEnd.Y);

        arrowX = ptEnd.X + botX;
        arrowY = ptEnd.Y + botY;
        this.Canvas.lineTo(arrowX,arrowY);

        this.Canvas.setLineDash([]);
        this.Canvas.lineWidth=this.ArrawLineWidth*GetDevicePixelRatio();
        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.ClassName="ChartMultiText";
    this.Texts=[];  //[ {Index:, Value:, Text:, Color:, Font: , Baseline:, Line:{ Color:, Dash:[虚线点], KData:"H/L", Offset:[5,10], Width:线粗细 }} ]
    this.Font=g_JSChartResource.DefaultTextFont;
    this.Color=g_JSChartResource.DefaultTextColor;
    this.IsHScreen=false;   //是否横屏

    this.Draw=function()
    {
        if (!this.IsShow || this.ChartFrame.IsMinSize) 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);
                }

                if (item.Line)
                {
                    var kItem=this.Data.Data[item.Index];
                    var price=item.Line.KData=="H"? kItem.High:kItem.Low;
                    var yPrice=this.ChartFrame.GetYFromData(price);
                    var yText=y;
                    if (Array.isArray(item.Line.Offset) && item.Line.Offset.length==2)
                    {
                        if (yText>yPrice) //文字在下方
                        {
                            yText-=item.Line.Offset[1];
                            yPrice+=item.Line.Offset[0]
                        }
                        else if (yText<yPrice)
                        {
                            yText+=item.Line.Offset[1];
                            yPrice-=item.Line.Offset[0]
                        }
                    }
                    this.Canvas.save();
                    if (item.Line.Dash) this.Canvas.setLineDash(item.Line.Dash);    //虚线
                    if (item.Line.Width>0) this.Canvas.lineWidth=item.Line.Width;   //线宽
                    this.Canvas.strokeStyle = item.Line.Color;
                    this.Canvas.beginPath();
                    if (this.IsHScreen)
                    {
                        this.Canvas.moveTo(yText, ToFixedPoint(x));
                        this.Canvas.lineTo(yPrice,ToFixedPoint(x));
                    }
                    else
                    {
                        this.Canvas.moveTo(ToFixedPoint(x),yText);
                        this.Canvas.lineTo(ToFixedPoint(x),yPrice);
                    }
                    
                    this.Canvas.stroke();
                    this.Canvas.restore();
                }
            }
        }
    }

    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.ClassName="ChartMultiSVGIcon";
    this.Icon;  //[ {Index:, Value:, Symbol:, Color:, Baseline:, Line:{ Color:, Dash:[虚线点], KData:"H/L", Offset:[5,10], Width:线粗细 } } ]
    this.IconSize={ Max: g_JSChartResource.DRAWICON.Icon.MaxSize, Min:g_JSChartResource.DRAWICON.Icon.MinSize ,    //图标的最大最小值
        Zoom:{ Type:g_JSChartResource.DRAWICON.Icon.Zoom.Type , Value:g_JSChartResource.DRAWICON.Icon.Zoom.Value } //放大倍数
    }; 
    this.Family;
    this.Color=g_JSChartResource.DefaultTextColor;
    this.IsHScreen=false;
    this.IconRect=[];   //0=序号,1=区域

    this.Draw=function()
    {
        this.IconRect=[];
        if (!this.IsShow || this.ChartFrame.IsMinSize) return;
        if (!this.Data || this.Data.length<=0) return;
        if (!this.Family || !this.Icon) return;
        if (!IFrameSplitOperator.IsNonEmptyArray(this.Icon)) return;

        this.IsHScreen=(this.ChartFrame.IsHScreen===true);
        var xPointCount=this.ChartFrame.XPointCount;
        var offset=this.Data.DataOffset;
        this.DataWidth=this.ChartFrame.DataWidth;
        this.DistanceWidth=this.ChartFrame.DistanceWidth;

        var border=this.GetBorder();
        if (this.IsHScreen)
        {
            var left=border.TopEx;
            var right=border.BottomEx;
        }
        else
        {
            var left=border.LeftEx;
            var right=border.RightEx;
        }

        var fontSize=this.GetDynamicIconSize(this.DataWidth,this.DistanceWidth,this.IconSize.Max,this.IconSize.Min,this.IconSize.Zoom);
        this.Canvas.font=fontSize+'px '+this.Family;

        for(var i=0; i<this.Icon.length; ++i)
        {
            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';
                var rtIcon=new Rect(x-fontSize/2,y-fontSize/2,fontSize,fontSize);
                if (x+textWidth/2>=right) 
                {
                    this.Canvas.textAlign='right';
                    x+=this.DataWidth/2;
                    rtIcon.X=x-fontSize;
                }
                else if (x-textWidth/2<left)
                {
                    this.Canvas.textAlign = 'left';
                    x-=this.DataWidth/2;
                    rtIcon.X=x;
                }

                if (item.Baseline==1) 
                {
                    this.Canvas.textBaseline='top';
                    rtIcon.Y=y;
                }
                else if (item.Baseline==2) 
                {
                    this.Canvas.textBaseline='bottom';
                    rtIcon.Y=y-fontSize;
                }
                else 
                {
                    this.Canvas.textBaseline = 'middle';
                    rtIcon.Y=y-fontSize/2;
                }

                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);
                    if (item.Text) this.IconRect.push({ Index:i, Rect:rtIcon , Item:item });
                }

                if (item.Line)
                {
                    var kItem=this.Data.Data[item.Index];
                    var price=item.Line.KData=="H"? kItem.High:kItem.Low;
                    var yPrice=this.ChartFrame.GetYFromData(price);
                    var yText=y;
                    if (Array.isArray(item.Line.Offset) && item.Line.Offset.length==2)
                    {
                        if (yText>yPrice) //文字在下方
                        {
                            yText-=item.Line.Offset[1];
                            yPrice+=item.Line.Offset[0]
                        }
                        else if (yText<yPrice)
                        {
                            yText+=item.Line.Offset[1];
                            yPrice-=item.Line.Offset[0]
                        }
                    }
                    this.Canvas.save();
                    if (item.Line.Dash) this.Canvas.setLineDash(item.Line.Dash);    //虚线
                    if (item.Line.Width>0) this.Canvas.lineWidth=item.Line.Width;   //线宽
                    this.Canvas.strokeStyle = item.Line.Color;
                    this.Canvas.beginPath();
                    if (this.IsHScreen)
                    {
                        this.Canvas.moveTo(yText, ToFixedPoint(x));
                        this.Canvas.lineTo(yPrice,ToFixedPoint(x));
                    }
                    else
                    {
                        this.Canvas.moveTo(ToFixedPoint(x),yText);
                        this.Canvas.lineTo(ToFixedPoint(x),yPrice);
                    }
                    
                    this.Canvas.stroke();
                    this.Canvas.restore();
                }
            }
        }
    }

    this.GetTooltipData=function(x,y,tooltip)
    {
        if (!IFrameSplitOperator.IsNonEmptyArray(this.IconRect)) return false;
        for(var i=0; i<this.IconRect.length; ++i)
        {
            var item=this.IconRect[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('[ChartMultiSVGIcon::GetTooltipData] icon ', item);
                tooltip.Data=item;
                tooltip.ChartPaint=this;
                tooltip.Type=4; //指标
                return true;
            }
        }

        return false;
    }

    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.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;
    }
}

// 多dom节点
function ChartMultiHtmlDom()
{
    this.newMethod=IChartPainting;   //派生
    this.newMethod();
    delete this.newMethod;

    this.ClassName="ChartMultiHtmlDom";
    this.Texts=[];  //[ {Index:, Value:, Text: ] Text=dom内容
    this.IsHScreen=false;   //是否横屏
    this.DrawCallback;  //function(op, obj)  op:1=开始 2=结束 3=绘制单个数据
    this.DrawItem=[];
    this.EnableDraw=true;   //是否允许绘制
    this.HQChart;

    this.Draw=function()
    {
        if (!this.EnableDraw) return;

        this.DrawItem=[];
        if (this.DrawCallback) this.DrawCallback(1, {Self:this} );

        this.DrawDom();

        if (this.DrawCallback) this.DrawCallback(2, { Self:this, DrawItem:this.DrawItem } );
    }

    this.DrawDom=function()
    {
        if (!this.IsShow || this.ChartFrame.IsMinSize) 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 top=this.ChartBorder.GetTopEx();
        var bottom=this.ChartBorder.GetBottomEx();
        var pixelTatio = GetDevicePixelRatio();
        if (this.HQChart)
        {
            var elementLeft=this.HQChart.UIElement.getBoundingClientRect().left;
            var elementTop=this.HQChart.UIElement.getBoundingClientRect().top;
        }
        else
        {
            var elementLeft=null,elementTop=null;
        }
        

        for(var i in this.Texts)
        {
            var item=this.Texts[i];

            if (!item.Text) continue;
            if (!IFrameSplitOperator.IsNumber(item.Index)) continue;

            var isMinuteFrame=this.IsMinuteFrame();

            var index=item.Index-offset;
            var kItem=this.Data.Data[item.Index];   //K线数据
            var obj={ KData:kItem, Item:item, IsShow:false, Self:this };
            if (index>=0 && index<xPointCount)
            {
                var x=this.ChartFrame.GetXFromIndex(index);
                if (item.Value=="Top")
                {
                    var y=top;
                }
                else if (item.Value=="Bottom")
                {
                    var y=bottom;
                }
                else
                {
                    var y=this.ChartFrame.GetYFromData(item.Value);
                }

                obj.X=x/pixelTatio;
                obj.Y=y/pixelTatio;
                obj.UIElement={Left:elementLeft, Top:elementTop};
                obj.IsShow=true;
            }

            this.DrawItem.push(obj);
            if (this.DrawCallback) this.DrawCallback(3, obj);

            if (item.Line)
            {
                if (isMinuteFrame)
                {
                    var price=this.Data.Data[item.Index];
                }
                else
                {
                    var kItem=this.Data.Data[item.Index];
                    var price=item.Line.KData=="H"? kItem.High:kItem.Low;
                }
                
                var yPrice=this.ChartFrame.GetYFromData(price);
                var yText=y;
                if (Array.isArray(item.Line.Offset) && item.Line.Offset.length==2)
                {
                    if (yText>yPrice) //文字在下方
                    {
                        yText-=item.Line.Offset[1];
                        yPrice+=item.Line.Offset[0]
                    }
                    else if (yText<yPrice)
                    {
                        yText+=item.Line.Offset[1];
                        yPrice-=item.Line.Offset[0]
                    }
                }
                this.Canvas.save();
                if (item.Line.Dash) this.Canvas.setLineDash(item.Line.Dash);    //虚线
                var pixelRatio=GetDevicePixelRatio();
                var lineWidth=1*pixelRatio;
                if (item.Line.Width>0) lineWidth=item.Line.Width*pixelRatio;
                this.Canvas.lineWidth=lineWidth;   //线宽
                this.Canvas.strokeStyle = item.Line.Color;
                this.Canvas.beginPath();
                if (this.IsHScreen)
                {
                    this.Canvas.moveTo(yText, ToFixedPoint(x));
                    this.Canvas.lineTo(yPrice,ToFixedPoint(x));
                }
                else
                {
                    this.Canvas.moveTo(ToFixedPoint2(lineWidth,x),yText);
                    this.Canvas.lineTo(ToFixedPoint2(lineWidth,x),yPrice);
                }
                
                this.Canvas.stroke();
                this.Canvas.restore();
            }
        }
    }

    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.Texts)
        {
            var item=this.Texts[i];
            if (!IFrameSplitOperator.IsNumber(item.Index)) continue;
            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();                                     //Key=数据索引index Value:Data:[ { Op: 买/卖 0=buy 1=sell, Date:, Time, Price: Vol:}, ] 
    this.IconFont=g_JSChartResource.KLineTrain.IconFont;

    this.AddTradeItem=function(tradeItem)
    {
        if (this.BuySellData.has(tradeItem.Key))
        {
            var Trade=this.BuySellData.get(tradeItem.Key);
            Trade.Data.push(tradeItem);
        }
        else
        {
            this.BuySellData.set(tradeItem.Key, { Data:[tradeItem] });
        }
    }

    this.ClearTradeData=function()
    {
        this.BuySellData=new Map(); 
    }

    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;
            var x=this.ChartFrame.GetXFromIndex(j);
            if (x>chartright) break;

            if (i==this.Data.Data.length-1)
            {
                //最后一个位置 画一个箭头
                var x=this.ChartFrame.GetXFromIndex(j);
                var yHigh=this.ChartFrame.GetYFromData(value.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);
                }
            }

            var key=i;
            if (!this.BuySellData.has(key)) continue;

            var trade=this.BuySellData.get(key);
            var yHigh=this.ChartFrame.GetYFromData(value.High);
            var yLow=this.ChartFrame.GetYFromData(value.Low);
            var drawInfo=[false, false];    //0=buy 1=sell
            for(var k in trade.Data)
            {
                if (drawInfo[0]==true && drawInfo[1]==true) break;  //买卖图标只画一次

                var bsItem=trade.Data[k];
                if (bsItem.Op==0 && drawInfo[0]==false)   //买 标识在最低价上
                {
                    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);
                    }

                    drawInfo[0]=true;
                }
                else if (bsItem.Op==1 && drawInfo[1]==false)   //卖 标识在最高价上
                {
                    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);
                    }

                    drawInfo[1]=true;
                }
            }
        }   
    }
}

//深度图
function ChartOrderbookDepth()
{
    this.newMethod=IChartPainting;   //派生
    this.newMethod();
    delete this.newMethod;

    this.ClassName="ChartOrderbookDepth";
    this.Data=null;

    this.AskColor={ Line:g_JSChartResource.DepthChart.AskColor.Line, Area:g_JSChartResource.DepthChart.AskColor.Area }      //卖
    this.BidColor={ Line:g_JSChartResource.DepthChart.BidColor.Line, Area:g_JSChartResource.DepthChart.BidColor.Area }      //买
    this.LineWidth=g_JSChartResource.DepthChart.LineWidth;

    this.Draw=function()
    {
        if (!this.Data) return;

        var lineWidthBackup=this.Canvas.lineWidth;
        this.Canvas.lineWidth=this.LineWidth * GetDevicePixelRatio();
        this.DrawArea(this.Data.Bids, this.BidColor.Line, this.BidColor.Area, true);
        this.DrawArea(this.Data.Asks, this.AskColor.Line, this.AskColor.Area, false);
        this.Canvas.lineWidth=lineWidthBackup;
    }

    this.DrawArea=function(aryData, colorLine, colorArea, isLeft)
    {
        var xRange=this.ChartFrame.VerticalRange;
        var aryPoint=[];
        for(var i in aryData)
        {
            var item=aryData[i];
            if (isLeft)
            {
                if (item.Price<xRange.Min) break;
            }
            else
            {
                if (item.Price>xRange.Max) break;
            }

            var x=this.ChartFrame.GetXFromIndex(item.Price);
            var y=this.ChartFrame.GetYFromData(item.Vol);
            aryPoint.push({X:x,Y:y});
        }
        if (aryPoint.length<=1) return;

        var left=this.ChartBorder.GetLeft();
        var bottom=this.ChartBorder.GetBottom();
        var right=this.ChartBorder.GetRight();

        this.Canvas.beginPath();
        this.Canvas.moveTo(aryPoint[0].X, bottom);
        for(var i in aryPoint)
        {
            var item=aryPoint[i];
            this.Canvas.lineTo(item.X,item.Y);
        }

        this.Canvas.lineTo(isLeft?left:right,aryPoint[aryPoint.length-1].Y);
        this.Canvas.lineTo(isLeft?left:right,bottom);
        this.Canvas.lineTo(aryPoint[0].X,bottom);
        this.Canvas.closePath();
        this.Canvas.fillStyle = colorArea;
        this.Canvas.fill();

        this.Canvas.beginPath();
        this.Canvas.moveTo(aryPoint[0].X, bottom);
        for(var i in aryPoint)
        {
            var item=aryPoint[i];
            this.Canvas.lineTo(item.X,item.Y);
        }
        this.Canvas.lineTo(isLeft?left:right,aryPoint[aryPoint.length-1].Y);
        this.Canvas.strokeStyle=colorLine;
        this.Canvas.stroke();
    }

    this.GetMaxMin=function()
    {
        var range={ Min:null, Max:null, XMin:null, XMax:null };
        var xRange=this.ChartFrame.VerticalRange;

        for(var i in this.Data.Asks)
        {
            var item=this.Data.Asks[i];
            if (item.Price>xRange.Max) break;
            
            if (range.XMin==null || range.XMin>item.Price) range.XMin=item.Price;
            if (range.XMax==null || range.XMax<item.Price) range.XMax=item.Price;
            if (range.Min==null || range.Min>item.Vol) range.Min=item.Vol;
            if (range.Max==null || range.Max<item.Vol) range.Max=item.Vol;
        }

        for(var i in this.Data.Bids)
        {
            var item=this.Data.Bids[i];
            if (item.Price<xRange.Min) break;

            if (range.XMin==null || range.XMin>item.Price) range.XMin=item.Price;
            if (range.XMax==null || range.XMax<item.Price) range.XMax=item.Price;
            if (range.Min==null || range.Min>item.Vol) range.Min=item.Vol;
            if (range.Max==null || range.Max<item.Vol) range.Max=item.Vol;
        }

        return range;
    }
}

/*
    饼图
*/
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 ExtendChartPaintFactory()
{
    this.DataMap=new Map(
        [
            ["FrameSplitPaint", { Create:function() { return new FrameSplitPaint(); } }],
            ["RectSelectPaint", { Create:function() { return new RectSelectPaint(); } }]
        ]
    );

    this.Create=function(name)
    {
        if (!this.DataMap.has(name)) return null;

        var item=this.DataMap.get(name);
        return item.Create();
    }

    this.Add=function(name, option)
    {
        this.DataMap.set(name, { Create:option.Create } );
    }
}

var g_ExtendChartPaintFactory=new ExtendChartPaintFactory();

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.IsCallbackDraw=false;          //在回调函数里绘制, 不在Draw()中绘制

    //上下左右间距
    this.Left=5;
    this.Right=5;
    this.Top=5;
    this.Bottom=5;

    this.Draw=function()
    {

    }

    //设置参数接口
    this.SetOption=function(option)
    {

    }

    this.GetFontHeight=function(font)
    {
        return GetFontHeight(this.Canvas, font, "擎");
    }

}

//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.DateTimeColor=g_JSChartResource.TooltipPaint.DateTimeColor;      //日期时间颜色
    this.VolColor=g_JSChartResource.TooltipPaint.VolColor;       //标题成交量
    this.AmountColor=g_JSChartResource.TooltipPaint.AmountColor;    //成交金额
    this.LatestPoint;               //手势位置
    this.ShowPosition=0;            //显示位置 0=左 1=右

    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.ReloadResource=function(resource)
    {
        this.BorderColor=g_JSChartResource.TooltipPaint.BorderColor;    //边框颜色
        this.BGColor=g_JSChartResource.TooltipPaint.BGColor;            //背景色
        this.TitleColor=g_JSChartResource.TooltipPaint.TitleColor;      //标题颜色
        this.DateTimeColor=g_JSChartResource.TooltipPaint.DateTimeColor;      //日期时间颜色
        this.VolColor=g_JSChartResource.TooltipPaint.VolColor;       //标题成交量
        this.AmountColor=g_JSChartResource.TooltipPaint.AmountColor;    //成交金额
    }

    this.GetLeft=function()
    {
        if (this.IsHScreen) 
        {
            return this.ChartBorder.GetRightEx()-this.Height-this.Top;
        }
        else
        {
            if (this.ShowPosition==0)
                return this.ChartBorder.GetLeft()+this.Left;
            else 
                return this.ChartBorder.GetRight()-this.Width-this.Left;
        }
    }

    this.GetTop=function()
    {
        if (this.IsHScreen) 
        {
            if (this.ShowPosition==0)
                return this.ChartBorder.GetTop()+this.Left;
            else
                return this.ChartBorder.GetBottom()-this.Width-this.Left;
        }
        else
        {
            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;    //显示函数
        var upperSymbol;
        if (this.HQChart.Symbol) upperSymbol=this.HQChart.Symbol.toUpperCase();
        if (this.ClassName==='MinuteTooltipPaint') 
        {
            lineCount=7;
            if (MARKET_SUFFIX_NAME.IsFutures(upperSymbol)) ++lineCount;    //期货多一个持仓量
        }
        else 
        {
            if (IFrameSplitOperator.IsNumber(klineData.Time) ) ++lineCount;     //分钟K线多一列时间
            if (MARKET_SUFFIX_NAME.IsSHSZStockA(this.HQChart.Symbol) && klineData.FlowCapital>0) ++lineCount;
            if (MARKET_SUFFIX_NAME.IsFutures(upperSymbol) && IFrameSplitOperator.IsNumber(klineData.Position)) ++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;
        var lineHeight=this.GetFontHeight();
        if (lineHeight>this.LineHeight) this.LineHeight=lineHeight;
        this.Height=this.LineHeight*lineCount+2*GetDevicePixelRatio()*2;
        if (klineData && klineData.High>0)  //最大值显示宽度
        {
            maxText=` 擎: ${klineData.High.toFixed(defaultfloatPrecision)} `;
            var textWidth=this.Canvas.measureText(maxText).width;
            if (textWidth>this.Width) this.Width=textWidth;
        }

        this.CalculateShowPosition();
        this.DrawBG();
        this.DrawTooltipData(klineData);
        this.DrawBorder();
    }

    //判断显示位置
    this.CalculateShowPosition=function()
    {
        this.ShowPosition=0;
        if (!this.LatestPoint) return;

        if(this.IsHScreen)
        {
            var top=this.ChartBorder.GetTop();
            var height=this.ChartBorder.GetHeight();
            var yCenter=top+height/2;
            if (this.LatestPoint.Y<yCenter) this.ShowPosition=1;
        }
        else
        {
            var left=this.ChartBorder.GetLeft();
            var width=this.ChartBorder.GetWidth();
            var xCenter=left+width/2;
            if (this.LatestPoint.X<xCenter) this.ShowPosition=1;
        }
    }

    this.DrawTooltipData=function(item)
    {
        //JSConsole.Chart.Log('[KLineTooltipPaint::DrawKLineData] ', item);
        var upperSymbol;
        if (this.HQChart.Symbol) upperSymbol=this.HQChart.Symbol.toUpperCase();
        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.DateTimeColor;
        this.Canvas.fillText(text, left,top);

        var period=this.HQChart.Period;
        if (ChartData.IsMinutePeriod(period,true) && IFrameSplitOperator.IsNumber(item.Time))
        {
            top+=this.LineHeight;  
            text=IFrameSplitOperator.FormatTimeString(item.Time);
            this.Canvas.fillText(text, left,top);
        }
        else if (ChartData.IsSecondPeriod(period) && IFrameSplitOperator.IsNumber(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.YFClose>0 && MARKET_SUFFIX_NAME.IsChinaFutures(upperSymbol))
        {
            var value=(item.Close-item.YFClose)/item.YFClose*100;
            var color = this.KLineTitlePaint.GetColor(value, 0);
            var text = value.toFixed(2)+'%';
        }
        else 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);

        
        top+=this.LineHeight;
        text=g_JSChartLocalization.GetText('Tooltip-Vol',this.LanguageID);
        this.Canvas.fillStyle=this.TitleColor;
        this.Canvas.fillText(text, left,top);
        var vol=item.Vol;
        if (upperSymbol && MARKET_SUFFIX_NAME.IsSHSZ(upperSymbol)) vol/=100; //A股统一转成手
        var text=IFrameSplitOperator.FromatIntegerString(vol,2,this.LanguageID);
        this.Canvas.fillStyle=this.VolColor;
        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.fillStyle=this.TitleColor;
            this.Canvas.fillText(text, left,top);
            var text=IFrameSplitOperator.FormatValueString(item.Amount,2,this.LanguageID);
            this.Canvas.fillStyle=this.AmountColor;
            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.fillStyle=this.TitleColor;
            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);
        }

        //持仓量
        var upperSymbol=this.HQChart.Symbol.toUpperCase();
        if (MARKET_SUFFIX_NAME.IsFutures(upperSymbol) && IFrameSplitOperator.IsNumber(item.Position))
        {
            this.Canvas.fillStyle=this.TitleColor;
            top+=this.LineHeight;
            text=g_JSChartLocalization.GetText('Tooltip-Position',this.LanguageID);
            this.Canvas.fillText(text, left,top);
            var text=IFrameSplitOperator.FromatIntegerString(item.Position,2,this.LanguageID);
            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),ToFixedRect(this.Width),ToFixedRect(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.IsShowAveragePrice=true;   //是否显示均价

    this.GetTop=function()
    {
        if (this.IsHScreen) 
        {
            var border=this.ChartBorder.GetHScreenBorder();
            if (this.ShowPosition==0)
                return border.TopEx+this.Left;
            else
                return border.BottomEx-this.Width-this.Left;
        }
        else
        {
            var border=this.ChartBorder.GetBorder();
            return border.Top+this.Top;
        }
    }

    this.GetLeft=function()
    {
        if (this.IsHScreen) 
        {
            var border=this.ChartBorder.GetHScreenBorder();
            return border.Right-this.Height-this.Top;
        }
        else
        {
            var border=this.ChartBorder.GetBorder();
            if (this.ShowPosition==0)
                return border.LeftEx+this.Left;
            else 
                return border.RightEx-this.Width-this.Left;
        }
    }

    this.DrawTooltipData=function(item)
    {
        //JSConsole.Chart.Log('[KLineTooltipPaint::DrawKLineData] ', item);
        if (!this.HQChart.Symbol) return;
        
        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;
        else if (MARKET_SUFFIX_NAME.IsShowAvPrice && !MARKET_SUFFIX_NAME.IsShowAvPrice(upperSymbol)) isShowAvPrice=false;

        //均价
        if (isShowAvPrice && IFrameSplitOperator.IsNumber(item.AvPrice) && this.IsShowAveragePrice)   
        {
            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=g_JSChartResource.StockChip.InfoColor;
    this.DayInfoColor=g_JSChartResource.StockChip.DayInfoColor;
    this.LineHeight=16;
    this.Left=50*this.PixelRatio;         //左边间距
    this.IsShowX=false;  //是否显示X刻度 成交量
    this.ShowXCount=3;
    this.Width=150*this.PixelRatio;       //筹码图宽度
    this.CalculateType=0;   //0=平均分布 1=三角分布
    this.PriceZoom=100;     //价格放大倍数

    this.ButtonID=Guid();  //工具条Div id
    this.NotSupportMessage="不支持筹码图";

    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();
        if (option.CalculateType>0) this.CalculateType=option.CalculateType;
        if (IFrameSplitOperator.IsNumber(option.PriceZoom)) this.PriceZoom=option.PriceZoom;
    }

    this.ReloadResource=function(resource)
    {
        this.PenBorder=g_JSChartResource.FrameBorderPen;
        this.Font=g_JSChartResource.TitleFont;
        this.InfoColor=g_JSChartResource.StockChip.InfoColor;
        this.DayInfoColor=g_JSChartResource.StockChip.DayInfoColor;
    }
    
    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 (ChartData.IsTickPeriod(this.HQChart.Period))    //分笔图没有筹码
        {
            this.Canvas.font=this.Font;
            this.Canvas.fillStyle=this.InfoColor;

            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.DrawBorder();
            return;
        }

        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?'前':'内')+'成本'+(IFrameSplitOperator.IsNumber(rate)? (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+='&nbsp;&nbsp;';
            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)/this.PriceZoom;
            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)/this.PriceZoom;
            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)/this.PriceZoom;
            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.EvenlyDistribute=function(aryChip, data)    //平均分布 data={Low, High, Vol, MaxVol, MaxPrice, MinPrice }
    {
        var low=data.Low, high=data.High, maxPrice=data.MaxPrice, minPrice=data.MinPrice, maxVol=1;
        if ( (high-low)== 0) return;
        var averageVol=data.Vol/(high-low);

        for(var j=low;j<=high && j<=maxPrice;++j)
        {
            var index=j-minPrice;
            aryChip[index]+=averageVol;
            if (maxVol<aryChip[index]) maxVol=aryChip[index];
        }

        data.MaxVol=maxVol;
    }

    this.TriangleDistribute=function(aryChip, data)  //三角分布
    {
        var low=data.Low, high=data.High, maxPrice=data.MaxPrice, minPrice=data.MinPrice, maxVol=1;
        var ANGLE = 45, PI=3.1415926535;
        var middlePrice = (high - low) / 2.0 + low;

        var totalValue=0;
        var aryVol=[];
        for(var i=low+1, j=1 ;i<=middlePrice;++i,++j)
        {
            var y = Math.tan(ANGLE* PI / 180)*j;

            totalValue+=y;
            aryVol.push({Index:i-minPrice, Value:y});
        }

        for(var i=high-1, j=1 ;i>middlePrice;--i,++j)
        {
            var y = Math.tan(ANGLE* PI / 180)*j;

            totalValue+=y
            aryVol.push({Index:i-minPrice, Value:y});
        }

        if (totalValue>0)
        {
            for(var i=0;i<aryVol.length;++i)
            {
                var item=aryVol[i];
                aryChip[item.Index]+=item.Value*data.Vol/totalValue;
                if (maxVol<aryChip[item.Index]) maxVol=aryChip[item.Index];
            }

            data.MaxVol=maxVol;
        }
    }

    this.CalculateDistribute=function(aryChip, data)
    {
        if (this.CalculateType==1) this.TriangleDistribute(aryChip, data);
        else this.EvenlyDistribute(aryChip, data);
    }

    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;

        var priceZoom=this.PriceZoom;

        maxPrice=parseInt(maxPrice*priceZoom);
        minPrice=parseInt(minPrice*priceZoom);

        var dataCount=maxPrice-minPrice;
        var aryChip=new Array()
        for(let i=0;i<=dataCount;++i)
        {
            aryChip.push(0);
        }

        var dayChip=[];
        var distributeData;
        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*priceZoom);
                var low=parseInt(item.Low*priceZoom);
                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;
                    }
                }

                distributeData={Low:low, High:high, Vol:item.Vol, MaxPrice:maxPrice, MinPrice:minPrice};
                this.CalculateDistribute(aryChip, distributeData );
            }
        }
        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*priceZoom);
                var low=parseInt(item.Low*priceZoom);
                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;
                    }
                }
                
                distributeData={Low:low, High:high, Vol:item.Vol, MaxPrice:maxPrice, MinPrice:minPrice};
                this.CalculateDistribute(aryChip, distributeData);
            }
        }
        else
        {
            for(let i in aryVol)
            {
                var item=aryVol[i];
                var high=parseInt(item.High*priceZoom);
                var low=parseInt(item.Low*priceZoom);
                var averageVol=item.Vol;
                if (high-low>0) averageVol=item.Vol/(high-low);
                if (averageVol<=0.000000001) continue;

                distributeData={Low:low, High:high, Vol:item.Vol, MaxPrice:maxPrice, MinPrice:minPrice};
                this.CalculateDistribute(aryChip, distributeData);
            }
        }

        this.Data={AllChip:aryChip, MaxVol:distributeData.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(var 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-ruler', ID: 'icon_ruler' }, Name: '尺子' },
                    { HTML: { Title: '射线', IClass: 'iconfont icon-draw_rays', ID: 'icon-beam' }, Name: '射线' },
                    { HTML: { Title: '标价线', IClass: 'iconfont icon-price_line', ID: 'icon-price-line' }, Name: '标价线' },
                    { HTML: { Title: '垂直线', IClass: 'iconfont icon-vertical_line', ID: 'icon-vertical-line' }, Name: '垂直线' },
                    { HTML: { Title: '箭头', IClass: 'iconfont icon-draw_rays', ID: 'icon-beam2' }, 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_hlinesegment', ID: 'icon-hlineseg' }, Name: '水平线段' },
                    { HTML: { Title: '平行射线', IClass: 'iconfont icon-draw_p_rays_lines', ID: 'icon-rayslineseg' }, 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_head_shoulders_bt', ID: 'icon-Head-Shoulders' }, Name: '头肩型' },
                    { HTML: { Title: '波浪尺', IClass: 'iconfont icon-waveruler', ID: 'icon-wave-ruler' }, Name: '波浪尺' },
                    { HTML: { Title: 'AB波浪尺', IClass: 'iconfont icon-waveruler', ID: 'icon-wave-ruler' }, Name: 'AB波浪尺' },
                    { HTML: { Title: '箱型线', IClass: 'iconfont icon-draw_box', ID: 'icon-drawbox' }, Name: '箱型线' },
                ],
                [
                    { 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-linear_3', ID: 'icon-waveband2' }, Name: '线形回归线' },
                    { HTML: { Title: '线形回归带', IClass: 'iconfont icon-linear_1', ID: 'icon-waveband3' }, Name: '线形回归带' },
                    { HTML: { Title: '延长线形回归带', IClass: 'iconfont icon-linear_2', ID: 'icon-waveband5' }, 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;
    }
}


//窗口分割
function FrameSplitPaint()
{
    this.newMethod=IExtendChartPainting;   //派生
    this.newMethod();
    delete this.newMethod;

    this.ClassName='FrameSplitPaint';
    this.LineColor='rgb(255,0,0)';
    this.TextColor="rgb(255,0,0)";
    this.LineWidth=2;
    this.Font='bold '+18*GetDevicePixelRatio() +"px 微软雅黑";
    this.TextTopOffset=10*GetDevicePixelRatio();

    //设置参数接口
    this.SetOption=function(option)
    {
        if (option)
        {
            if (option.LineColor) this.LineColor=option.LineColor;
            if (option.TextColor) this.TextColor=option.TextColor;
            if (option.Font) this.Font=option.Font;
            if (IFrameSplitOperator.IsNumber(option.LineWidth)) this.LineWidth=option.LineWidth;
            if (IFrameSplitOperator.IsNumber(option.TextTopOffset)) this.TextTopOffset=option.TextTopOffset;
        }
    }

    this.Draw=function()
    {
        if (!this.HQChart) return;
        if (this.HQChart.Period!=0 && this.HQChart.Period!=1) return;

        if (!this.HQChart.ChartPaint[0]) return;
        var data=this.HQChart.ChartPaint[0].Data;
        if (!data) return;
        this.Data=data;
        if (!this.ChartFrame || !this.ChartFrame.SubFrame) return;
        var subFrame=this.ChartFrame.SubFrame[0].Frame;
        if (!subFrame) return;

        var isHScreen=(subFrame.IsHScreen===true);
        var dataWidth=subFrame.DataWidth;
        var distanceWidth=subFrame.DistanceWidth;
        var xPointCount=subFrame.XPointCount;

        var lineWidth=this.LineWidth * GetDevicePixelRatio();

        if (isHScreen)
        {
            var border=this.ChartBorder.GetHScreenBorder();
            var xOffset=border.TopEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
            var chartright=border.BottomEx;
        }
        else
        {
            var border=this.ChartBorder.GetBorder();
            var xOffset=border.LeftEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
            var chartright=border.RightEx;
            var drawHeight=border.ChartHeight-border.TopTitle-5*GetDevicePixelRatio();
        }

        this.Canvas.save();
        this.Canvas.lineWidth=lineWidth;
        this.Canvas.font=this.Font;
        this.Canvas.textAlign='center';
        this.Canvas.textBaseline='top';
        var preQuarter={ Left:border.LeftEx, Top:ToFixedPoint2(lineWidth,border.TopTitle), Height:drawHeight, LineWidth:lineWidth };
        for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
        {
            var item=this.Data.Data[i];
            if (!item) continue;
            
            var dateInfo=this.GetQuarter(item.Date);
            if (!dateInfo) continue;

            var left=xOffset;
            var right=xOffset+dataWidth;
            if (right>chartright) break;
            var x=left+(right-left)/2;


            if (!preQuarter.DateInfo)
            {
                preQuarter.DateInfo=dateInfo;
                preQuarter.Right=x;
            }
            else
            {
                var preDateInfo=preQuarter.DateInfo;
                if (preDateInfo.Year!=dateInfo.Year || preDateInfo.Quarter!=dateInfo.Quarter)
                {
                    preQuarter.Right=x;
                    this.DrawQuarter(preQuarter);

                    preQuarter.Left=x;
                    preQuarter.Right=null;
                    preQuarter.DateInfo=dateInfo;
                }
                else
                {
                    preQuarter.Right=x;
                }
            }
        }

        this.DrawQuarter(preQuarter);

        this.Canvas.restore();
    }

    this.DrawQuarter=function(quarterInfo)
    {
        if (!IFrameSplitOperator.IsNumber(quarterInfo.Left) || !IFrameSplitOperator.IsNumber(quarterInfo.Right)) return;

        var left=ToFixedPoint2(quarterInfo.LineWidth,quarterInfo.Left);
        var right=ToFixedPoint2(quarterInfo.LineWidth,quarterInfo.Right);
        var drawWidth=right-left;
        this.Canvas.strokeStyle=this.LineColor;
        this.Canvas.strokeRect(left, quarterInfo.Top, drawWidth, quarterInfo.Height);

        var date=quarterInfo.DateInfo;
        var shortYear=date.Year%100;
        if (shortYear<10) var strYear='0'+shortYear;
        else var strYear=shortYear.toString();
        var text=`${strYear}年${date.Quarter}季度`;
        var textWidth = this.Canvas.measureText(text).width;
        if (textWidth<(drawWidth+5))
        {
            var x=left+drawWidth/2;
            var y=quarterInfo.Top+this.TextTopOffset;
            this.Canvas.fillStyle=this.TextColor;
            this.Canvas.fillText(text,x,y);
        }
    }

    this.GetQuarter=function(date)
    {
        if (!IFrameSplitOperator.IsNumber(date)) return null;

        var year=parseInt(date/10000);
        var month=parseInt((date%10000)/100);

        switch(month)
        {
            case 1:
            case 2:
            case 3:
                var quarter=1;
                break;
            case 4:
            case 5:
            case 6:
                var quarter=2;
                break;
            case 7:
            case 8:
            case 9:
                var quarter=3;
                break;
            case 10:
            case 11:
            case 12:
                var quarter=4;
                break;
            default:
                return null;
        }

        return { Year:year, Month:month, Quarter:quarter };
    }
}

function RectSelectPaint()
{
    this.newMethod=IExtendChartPainting;   //派生
    this.newMethod();
    delete this.newMethod;

    this.ClassName='RectSelectPaint';
    this.LineColor=g_JSChartResource.RectSelect.LineColor;          //竖线  
    this.LineWidth=g_JSChartResource.RectSelect.LineWidth;
    this.LineDotted=g_JSChartResource.RectSelect.LineDotted;  
    this.AreaColor=g_JSChartResource.RectSelect.AreaColor;     //面积

    this.FirstPoint;
    this.SecondPoint;
    this.PreventClose=false;        //如果外面有div,可以设置成true, 有外面控制

    this.StartDate; //{ Date:, Index: }
    this.EndDate;   //{ Date:, Index: }

    this.HQChart;
    this.DragRect;      //拖拽边框区域 

    //设置参数接口
    this.SetOption=function(option)
    {
        if (option)
        {
            if (option.LineColor) this.LineColor=option.LineColor;
            if (option.AreaColor) this.AreaColor=option.AreaColor;
        }
    }

    this.ReloadResource=function(resource)
    {
        this.LineColor=g_JSChartResource.RectSelect.LineColor;     //竖线  
        this.LineWidth=g_JSChartResource.RectSelect.LineWidth;
        this.LineDotted=g_JSChartResource.RectSelect.LineDotted;  
        this.AreaColor=g_JSChartResource.RectSelect.AreaColor;     //面积
    }

    this.IsMinuteChart=function()
    {
        var className=this.HQChart.ClassName;
        var isMinuteChart=(className=="MinuteChartContainer" || className=="MinuteChartHScreenContainer") ? true:false;
        return isMinuteChart;
    }

    this.GetKData=function()
    {
        if (!this.HQChart) return null;
        var isMinuteChart=this.IsMinuteChart();

        var data=null;
        if (isMinuteChart)
        {
            if (!this.HQChart.SourceData) return null;
            data=this.HQChart.SourceData;
        }
        else
        {
            if (!this.HQChart.ChartPaint[0]) return null;
            data=this.HQChart.ChartPaint[0].Data;
            if (!data) return null;
        }

        return data;
    }

    this.GetPointCount=function()
    {
        var count=0;
        if (this.FirstPoint) ++count;
        if (this.SecondPoint) ++count;
        return count;
    }

    this.DateToNumber=function(value, isMinuteChart)
    {
        if (isMinuteChart)
        {
            if (IFrameSplitOperator.IsNumber(value.Date)) return value.Date*10000+value.Time;
            else return value.Time;
        }
        else
        {
            var period=this.HQChart.Period;
            if (ChartData.IsDayPeriod(period, true)) return value.Date; //YYYYMMDD
            else if (ChartData.IsMinutePeriod(period, true)) return value.Date*10000+value.Time; //YYYYMMDDHHMM
            else if (ChartData.IsSecondPeriod(period) || ChartData.IsTickPeriod(period)) return value.Date*1000000+value.Time;  //YYYYMMDDHHMMSS
        }

        return null;
    }

    this.GetSelectRectData=function()
    {
        if (!this.FirstPoint && !this.SecondPoint) return null;
        
        var data=this.GetKData();
        if (!data) return null;
        var isMinuteChart=this.IsMinuteChart();
        var firstDate=this.DateToNumber(this.FirstPoint,isMinuteChart);
        var secondDate=this.DateToNumber(this.SecondPoint,isMinuteChart);
        var selectData={ Start:null, End:null, Data:data };
        for(var i=0;i<data.Data.length;++i)
        {
            var item=data.Data[i];
            if (!item) continue;
            var value=this.DateToNumber(item,isMinuteChart);

            if (firstDate==value) selectData.Start=i;
            if (secondDate==value) selectData.End=i;

            if (IFrameSplitOperator.IsNumber(selectData.Start) && IFrameSplitOperator.IsNumber(selectData.End))
            {
                if (selectData.Start>selectData.End)
                {
                    var temp=selectData.Start;
                    selectData.Start=selectData.End;
                    selectData.End=temp;
                }
                return selectData;
            }
        }

        return null;
    }

    this.SortPoint=function()  
    {
        var isMinuteChart=this.IsMinuteChart();
        if (this.FirstPoint && !this.SecondPoint)
        {
            this.StartDate={ Date:this.DateToNumber(this.FirstPoint,isMinuteChart), Index:0 };
        }
        else if (this.FirstPoint && this.SecondPoint)
        {
            var firstValue=this.DateToNumber(this.FirstPoint,isMinuteChart);
            var secondValue=this.DateToNumber(this.SecondPoint,isMinuteChart);
            if (firstValue<secondValue)
            {
                this.StartDate={ Date:firstValue, Index:0 };
                this.EndDate={ Date:secondValue, Index:1 };
            }
            else
            {
                this.StartDate={ Date:secondValue, Index:1 };
                this.EndDate={ Date:firstValue, Index:0 };
            }
        }
    }

    this.SetPoint=function(kItem, option)
    {
        if (!option)
        {
            if (!this.FirstPoint) 
            {
                this.FirstPoint={ Date:kItem.Date, Time:kItem.Time };
                return true;
            }
    
            if (!this.SecondPoint)
            {
                this.SecondPoint={ Date:kItem.Date, Time:kItem.Time };
                return true;
            }
            return false;
        }
        else
        {
            switch(option.Index)
            {
                case 0:
                    this.FirstPoint={ Date:kItem.Date, Time:kItem.Time };
                    return true;
                case 1:
                    this.SecondPoint={ Date:kItem.Date, Time:kItem.Time };
                    return true;
                default:
                    return false;
            }
        }
    }

    this.ClearPoint=function()
    {
        if (this.PreventClose) return false;

        var bRedraw=false;
        if (this.FirstPoint) 
        {
            this.FirstPoint=null;
            bRedraw=true;
        }

        if (this.SecondPoint) 
        {
            this.SecondPoint=null;
            bRedraw=true;
        }

        return bRedraw;
    }

    this.Draw=function()
    {
        this.StartDate=null;
        this.EndDate=null;
        this.DragRect=[];
        if (!this.FirstPoint && !this.SecondPoint) return;
        this.SortPoint();

        var data=this.GetKData();
        if (!data) return;
        this.Data=data;
        if (!this.ChartFrame || !this.ChartFrame.SubFrame) return;
        var subFrame=this.ChartFrame.SubFrame[0].Frame;
        if (!subFrame) return;

        var isHScreen=(subFrame.IsHScreen===true);
        var dataWidth=subFrame.DataWidth;
        var distanceWidth=subFrame.DistanceWidth;
        var xPointCount=subFrame.XPointCount;

        if (isHScreen)
        {
            var border=subFrame.GetBorder();
            var xOffset=border.TopEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
            var chartright=border.BottomEx;
        }
        else
        {
            var border=subFrame.GetBorder();
            var xOffset=border.LeftEx+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
            var chartright=border.RightEx;
            var drawHeight=border.ChartHeight-border.TopTitle-5*GetDevicePixelRatio();
            var top=border.TopEx;
            var bottom=border.BottomEx;
        }

        this.Canvas.save();

        var isDayPeriod=ChartData.IsDayPeriod(this.HQChart.Period,true);
        var isMinuteChart=this.IsMinuteChart();
        var startPoint=null, endPoint=null;
        var startDate=null, startEnd=null;
        var aryLines=[];
        for(var i=this.Data.DataOffset,j=0;i<this.Data.Data.length && j<xPointCount;++i,++j,xOffset+=(dataWidth+distanceWidth))
        {
            var item=this.Data.Data[i];
            if (!item) continue;

            var left=xOffset;
            var right=xOffset+dataWidth;
            
            if (isMinuteChart)
                var x=subFrame.GetXFromIndex(j);
            else
                var x=left+(right-left)/2;

            var value=this.DateToNumber(item, isMinuteChart);

            if (this.StartDate && value==this.StartDate.Date)
            {
                startPoint={ XIndex:i, X:x, Top:top, Bottom: bottom, PointIndex:this.StartDate.Index };
                aryLines.push(startPoint);
            }
                   
            if (this.EndDate && value==this.EndDate.Date)
            {
                endPoint={ XIndex:i, X:x , Top:top, Bottom: bottom, PointIndex:this.EndDate.Index };
                aryLines.push(endPoint);
            }
            

            if (!startDate) 
            {
                startDate={ Date:value, X:x, Top:top, Bottom: bottom };
                startEnd={ Date:value, X:x, Top:top, Bottom: bottom };
            }
            else
            {
                startEnd.Date=value;
                startEnd.X=x;
            }
        
            if (startPoint && endPoint) break;
        }

        this.DrawLines(aryLines);
        this.DrawArea(startPoint, endPoint, startDate, startEnd);
        
        this.Canvas.restore();
    }

    this.DrawLines=function(aryLines)
    {
        if (!IFrameSplitOperator.IsNonEmptyArray(aryLines)) return;

        var lineWidth=this.LineWidth * GetDevicePixelRatio();
        this.Canvas.strokeStyle=this.LineColor;
        this.Canvas.lineWidth=lineWidth;
        if (this.LineDotted) this.Canvas.setLineDash(this.LineDotted);   //虚线
        this.Canvas.beginPath();

        for(var i=0;i<aryLines.length;++i)
        {
            var item=aryLines[i];
            var left=ToFixedPoint2(lineWidth,item.X);
            this.Canvas.moveTo(left,item.Top);
            this.Canvas.lineTo(left,item.Bottom);

            var rtLine=new Rect(left-3,item.Top,10,item.Bottom-item.Top);
            this.DragRect[i]={ Rect:rtLine, PointIndex:item.PointIndex };
        }

        this.Canvas.stroke();
    }

    this.PtInPaint=function(x,y)
    {
        if (!IFrameSplitOperator.IsNonEmptyArray(this.DragRect)) return null;

        for(var i=0;i<this.DragRect.length;++i)
        {
            var item=this.DragRect[i];
            var rtLine=item.Rect;
            this.Canvas.beginPath();
            this.Canvas.rect(rtLine.X,rtLine.Y,rtLine.Width,rtLine.Height);
            if (this.Canvas.isPointInPath(x,y))
            {
                return { Index:i, PointIndex:item.PointIndex, Self:this };
            }
        }

        return null;
    }

    this.DrawArea=function(startPoint, endPoint, startDate, startEnd)
    {
        if (!startDate || !startEnd || !this.StartDate || !this.EndDate) return;

        var aryArea;
        if (startPoint && endPoint) 
            aryArea=[startPoint, endPoint];
        else if (!startPoint && endPoint) 
            aryArea=[startDate, endPoint];
        else if (startPoint && !endPoint) 
            aryArea=[startPoint, startEnd];
        else if (startDate.Date>this.StartDate.Date && startEnd.Date<this.EndDate.Date)
            aryArea=[startDate,startEnd];

        if (aryArea && aryArea.length==2)
        {
            var start=aryArea[0],end=aryArea[1];
            var left=ToFixedPoint(start.X);
            var right=ToFixedPoint(end.X);
            var drawWidth=right-left;
            var drawHeight=start.Bottom-start.Top;
            this.Canvas.fillStyle=this.AreaColor;
            this.Canvas.fillRect(left, start.Top, drawWidth, drawHeight);
        }
    }

}
//深度图 支持横屏
/*
    数据格式:
    [ 
        { 
            Data:[ {X,Y}, ],
            Type: 1=Up 2=Down 0=Default,
            LineColor:
            AreaColor:
            TextColor:
            Range:{X:{Max,Min:}, Y:{Max:,Min:} }
            Height:高度 百分比,
            Order:"ASC", //DESC=降序 ASC=升序
            IsShowCorssCursor:true/false;         //是否显示十字光标的提示信息
        },
    ]
*/

function DepthMapPaint()
{
    this.newMethod=IExtendChartPainting;   //派生
    this.newMethod();
    delete this.newMethod;

    this.ClassName='DepthMapPaint';

    this.LineColor="rgba(0,139,0,0.6)";
    this.AreaColor=["rgba(0,139,0,0.5)","rgba(0,139,0,0.4)","rgba(0,139,0,0.3)",'rgba(0,139,0,0.2)'];
    this.TextColor="rgba(0,0,0)";
    this.TextBGColor="rgba(0,139,0)";

    this.Width=200*GetDevicePixelRatio();
    this.FrameID=0;
    this.ID=Guid(); //唯一的ID

    this.IsDynamic=false;
    this.IsCallbackDraw=true;   //在回调函数里绘制, 不在Draw()中绘制

    this.YRange;    //Y值范围

    /*
    this.Data=[
       { 
           Data: [ {X:100,Y:20}, {X:110,Y:30}, {X:120,Y:40},{X:130,Y:50} ],
           Type:1,
           Range:{ X:{Max:130, Min:100}, Y:{ Max:50, Min:0} },
           Height:0.5,
           LineColor:'rgba(255,106,106,0.6)',
           AreaColor:['rgba(255,106,106,0.5)','rgba(255,106,106,0.4)','rgba(255,106,106,0.3)','rgba(255,106,106,0.2)'],
           IsASC:false, //true=升序 false=降序
       },
       { 
            Data: [ {X:100,Y:20}, {X:110,Y:30}, {X:120,Y:40},{X:130,Y:50} ],
            Type:2,
            Range:{ X:{Max:130, Min:100}, Y:{ Max:50, Min:0} },
            Height:0.5,
            IsASC:true, //true=升序 false=降序
        },
        {
            Data:[ {X:11.60, Y:50}, {X:11.65, Y:80}, {X:11.68, Y:85},{X:11.70, Y:55}],
            Type:0,
            Range:{ Y:{ Max:100, Min:0} },

            LineColor:'rgba(255,165,0,0.6)',
            AreaColor:['rgba(255,165,0,0.5)','rgba(255,165,0,0.4)','rgba(255,165,0,0.3)','rgba(255,165,0,0.2)']
        }
    ];
    */

    this.SetOption=function(option) //设置
    {
        if (option.FrameID>0) this.FrameID=option.FrameID;
        if (option.Width>0) this.Width=option.Width;
        if (IFrameSplitOperator.IsObjectExist(option.ID)) this.ID=option.ID;
        if (option.IsShowCorssCursor) this.IsShowCorssCursor=option.IsShowCorssCursor;
    }

    this.Draw=function()
    {
        if (!this.Data) return;
        if (!this.ChartFrame || !this.ChartFrame.SubFrame || this.ChartFrame.SubFrame.length<=this.FrameID) return;

        var isHScreen=(this.ChartFrame.IsHScreen===true);
        var frame=this.ChartFrame.SubFrame[this.FrameID].Frame;
        var chartBorder=frame.ChartBorder;

        var height=chartBorder.GetHeightEx();
        var left=chartBorder.GetRight();
        var top=chartBorder.GetTopEx();
        var bottom=chartBorder.GetBottomEx();
        var width=this.Width;
        if (width>this.ChartBorder.Right) width=this.ChartBorder.Right;

        if (isHScreen)
        {
            left=chartBorder.GetBottom();
            top=chartBorder.GetRight();
            bottom=chartBorder.GetLeft();
            var width=this.Width;
            if (width>this.ChartBorder.Bottom) width=this.ChartBorder.Bottom;
        }

        var rtClient={ Left:left, Top:top, Right:left+width, Bottom:bottom, Height:height, Width:width };
        this.YRange={ Max:null, Min:0 };
        for(var i in this.Data)
        {
            var item=this.Data[i];
            this.CalculateYRange(item, this.YRange);
        }

        for(var i in this.Data)
        {
            var item=this.Data[i];
            if (item.Height>0 && item.Height<=1) rtClient.Height=height*item.Height;
            else rtClient.Height=height;
            
            if (item.Type==1)
            {
                rtClient.Top=top;
                rtClient.Bottom=top+rtClient.Height;
                this.DrawUpArea(item,rtClient);
            }
            else if (item.Type==2)
            {
                rtClient.Bottom=bottom;
                rtClient.Top=rtClient.Bottom-rtClient.Height;
                this.DrawDownArea(item,rtClient);
            }
            else
            {
                rtClient.Top=top;
                rtClient.Bottom=bottom;
                this.DrawDefaultArea(item,rtClient);
            }
        }
    }

    this.CalculateYRange=function(drawData, yRange)
    {
        for(var i in drawData.Data)
        {
            var item=drawData.Data[i];
            if (yRange.Max==null || yRange.Max<item.Y) yRange.Max=item.Y;
            if (yRange.Min==null || yRange.Min>item.Y) yRange.Min=item.Y;
        }
    }


    this.GetXFromData=function(value, rtClient, minMax)    //获取X轴坐标
    {
        var width = rtClient.Width * (value - minMax.Min) / (minMax.Max - minMax.Min);
        return rtClient.Left + width;
    }

    this.GetYFromData=function(value, rtClient, minMax, isASC)
    {
        if (isASC)
        {
            var height = rtClient.Height * (value - minMax.Min) / (minMax.Max - minMax.Min);
            return rtClient.Bottom - height;
        }
        else
        {
            var height = rtClient.Height * (value - minMax.Min) / (minMax.Max - minMax.Min);
            return rtClient.Top + height;
        }
    }

    this.DrawDefaultArea=function(drawData, rtClient)
    {
        var frame=this.ChartFrame.SubFrame[this.FrameID].Frame;
        var yRange=(drawData.Range && drawData.Range.Y) ? drawData.Range.Y : this.YRange;

        var aryPoint=[];
        for(var i in drawData.Data)
        {
            var item=drawData.Data[i];
            var x=this.GetXFromData(item.Y,rtClient,yRange);
            if (item.X>frame.HorizontalMax || item.X<frame.HorizontalMin) continue;
            var y=frame.GetYFromData(item.X);

            aryPoint.push({X:x,Y:y});
        }

        var lineColor=drawData.LineColor? drawData.LineColor: this.LineColor;
        var areaColor=drawData.AreaColor? drawData.AreaColor: this.AreaColor;
        if (aryPoint.length>0) this.DrawLine(aryPoint,lineColor, areaColor,rtClient);
    }

    this.DrawUpArea=function(drawData,rtClient)
    {
        var aryPoint=[];
        for(var i in drawData.Data)
        {
            var item=drawData.Data[i];
            var x=this.GetXFromData(item.Y,rtClient,drawData.Range.Y);
            var y=this.GetYFromData(item.X,rtClient,drawData.Range.X,drawData.IsASC);

            aryPoint.push({X:x,Y:y});
        }

        var lineColor=drawData.LineColor? drawData.LineColor: this.LineColor;
        var areaColor=drawData.AreaColor? drawData.AreaColor: this.AreaColor;
        if (aryPoint.length>0) this.DrawLine(aryPoint,lineColor, areaColor,rtClient);
    }

    this.DrawDownArea=function(drawData,rtClient)
    {
        var aryPoint=[];
        for(var i in drawData.Data)
        {
            var item=drawData.Data[i];
            var x=this.GetXFromData(item.Y,rtClient,drawData.Range.Y);
            var y=this.GetYFromData(item.X,rtClient,drawData.Range.X,drawData.IsASC);

            aryPoint.push({X:x,Y:y});
        }

        var lineColor=drawData.LineColor? drawData.LineColor: this.LineColor;
        var areaColor=drawData.AreaColor? drawData.AreaColor: this.AreaColor;
        if (aryPoint.length>0) this.DrawLine(aryPoint,lineColor, areaColor,rtClient);
    }

    this.DrawLine=function(aryPoint,lineColor, areaColor,rtClient)
    {
        var isHScreen=(this.ChartFrame.IsHScreen===true);
        var bFirstPoint=true;
        var drawCount=0;
        this.Canvas.strokeStyle=lineColor;
        
        for(var i in aryPoint)
        {
            var item=aryPoint[i];
            if (bFirstPoint)
            {
                this.Canvas.beginPath();
                if (isHScreen) this.Canvas.moveTo(item.Y,item.X);
                else this.Canvas.moveTo(item.X,item.Y);
                bFirstPoint=false;
            }
            else
            {
                if (isHScreen) this.Canvas.lineTo(item.Y,item.X);
                else this.Canvas.lineTo(item.X,item.Y);
            }

            ++drawCount;
        }

        if (drawCount>0) this.Canvas.stroke();

        //面积
        var firstPoint=aryPoint[0];
        var lastPoint=aryPoint[aryPoint.length-1];
        if (isHScreen)
        {
            this.Canvas.lineTo(lastPoint.Y,rtClient.Left);
            this.Canvas.lineTo(firstPoint.Y,rtClient.Left);
        }
        else
        {
            this.Canvas.lineTo(rtClient.Left,lastPoint.Y);
            this.Canvas.lineTo(rtClient.Left,firstPoint.Y);
        }
        this.Canvas.closePath();

        if (Array.isArray(areaColor))
        {
            if (isHScreen)
            {
                let gradient = this.Canvas.createLinearGradient(this.ChartBorder.GetRightEx(),this.ChartBorder.GetTop(), this.ChartBorder.GetLeft(),this.ChartBorder.GetTop());
                gradient.addColorStop(0, areaColor[0]);
                gradient.addColorStop(1, areaColor[1]);
                this.Canvas.fillStyle=gradient;
            }
            else
            {
                let gradient = this.Canvas.createLinearGradient(rtClient.Right,rtClient.Top, rtClient.Left,rtClient.Top);
                var offset=1/areaColor.length;
                for(var i in areaColor)
                {
                    gradient.addColorStop(i*offset, areaColor[i]);
                }
                this.Canvas.fillStyle=gradient;
            }
        }
        else
        {
            this.Canvas.fillStyle=areaColor;
        }
        
        this.Canvas.fill();
        
    }

    this.GetYValueByXValue=function(x,floatPrecision)
    {
        var aryXValue=[];
        var value=0;
        var zoom=ZOOM_VALUE[floatPrecision];
        for(var i in this.Data)
        {
            var item=this.Data[i];
            if (item.Type!=0 || !item.Data || item.Data.length<0 || item.IsShowCorssCursor==false) continue;

            var bFind=false;
            for(var j in item.Data)
            {
                var dataItem=item.Data[j];
                value=parseInt(dataItem.X*zoom);
                if (value==x) 
                {
                    bFind=true;
                    var findItem=
                    { 
                        X:dataItem.X, Y:dataItem.Y, 
                        TextColor:item.TextColor? item.TextColor: this.TextColor,
                        TextBGColor:item.TextBGColor? item.TextBGColor: this.TextBGColor  
                    };
                    if (dataItem.YText) findItem.YText=dataItem.YText;

                    aryXValue.push(findItem);
                    break;
                }
            }

            if (!bFind)
            {
                var first=item.Data[0];
                var last=item.Data[item.Data.length-1];
                if (x>first.X*zoom && x<last.X*zoom)
                {
                    aryXValue.push( 
                    { 
                        X:null, Y:null, 
                        TextColor:item.TextColor? item.TextColor: this.TextColor,
                        TextBGColor:item.TextBGColor? item.TextBGColor: this.TextBGColor  
                    } ); 
                }
            }
        }

        return aryXValue;
    }
}


//背景图 支持横屏
function BackgroundPaint()
{
    this.newMethod=IExtendChartPainting;   //派生
    this.newMethod();
    delete this.newMethod;

    this.ClassName='BackgroundPaint';

    this.IsDynamic=false;
    this.IsCallbackDraw=true;   //在回调函数里绘制, 不在Draw()中绘制

    this.FrameID=0;
    this.Data;      //背景数据 { Start:, End:, Color:[] }
    this.ID=Guid(); //唯一的ID

    /*
    this.Data=
    [ 
        { Start:{ Date:20181201 }, End:{ Date:20181230 }, Color:'rgb(44,55,44)' } , 
        { Start:{ Date:20190308 }, End:{ Date:20190404 }, Color:['rgb(44,55,255)','rgb(200,55,255)'] } 
    ]
    */

    this.ChartSubFrame;
    this.ChartBorder;
    this.KData;
    this.Period;
    this.XPointCount=0;

    this.SetOption=function(option) //设置
    {
        if (option.FrameID>0) this.FrameID=option.FrameID;
        if (IFrameSplitOperator.IsObjectExist(option.ID)) this.ID=option.ID;
    }

    this.Draw=function()
    {
        if (!this.Data || !this.HQChart) return;
        if (!this.ChartFrame || !this.ChartFrame.SubFrame || this.ChartFrame.SubFrame.length<=this.FrameID) return;
        var klineChart=this.HQChart.ChartPaint[0];
        if (!klineChart || !klineChart.Data) return;

        this.ChartSubFrame=this.ChartFrame.SubFrame[this.FrameID].Frame;
        this.ChartBorder=this.ChartSubFrame.ChartBorder;
        this.KData=klineChart.Data;
        this.Period=this.HQChart.Period;
        if (!this.KData || this.KData.Data.length<=0) return;

        var isHScreen=(this.ChartSubFrame.IsHScreen===true);
        this.XPointCount=this.ChartSubFrame.XPointCount;
        var xPointCount=this.ChartSubFrame.XPointCount;
        
        var firstKItem=this.KData.Data[this.KData.DataOffset];
        var endIndex=this.KData.DataOffset+xPointCount-1;
        if (endIndex>=this.KData.Data.length) endIndex=this.KData.Data.length-1;
        var endKItem=this.KData.Data[endIndex];
        var showData=this.GetShowData(firstKItem,endKItem);
        if (!showData || showData.length<=0) return;

        var kLineMap=this.BuildKLineMap();
        var bottom=this.ChartBorder.GetBottomEx();
        var top=this.ChartBorder.GetTopEx();
        var height=this.ChartBorder.GetHeightEx();
        if (isHScreen)
        {
            top=this.ChartBorder.GetRightEx();
            bottom=this.ChartBorder.GetLeftEx();
            height=this.ChartBorder.GetWidthEx(); 
        }

        for(var i in showData)
        {
            var item=showData[i];
            var rt=this.GetBGCoordinate(item,kLineMap);
            if (!rt) continue;

            if (Array.isArray(item.Color))
            {
                var gradient;
                if (isHScreen) gradient = this.Canvas.createLinearGradient(bottom,rt.Left, top, rt.Left);
                else gradient = this.Canvas.createLinearGradient(rt.Left,top, rt.Left,bottom);
                var offset=1/item.Color.length;
                for(var i in item.Color)
                {
                    gradient.addColorStop(i*offset, item.Color[i]);
                }
                this.Canvas.fillStyle=gradient;
            }
            else
            {
                this.Canvas.fillStyle=item.Color;
            }

            if (isHScreen) this.Canvas.fillRect(ToFixedRect(bottom),ToFixedRect(rt.Left),ToFixedRect(height),ToFixedRect(rt.Width));
            else this.Canvas.fillRect(ToFixedRect(rt.Left),ToFixedRect(top),ToFixedRect(rt.Width),ToFixedRect(height));
        }
    }

    this.GetShowData=function(first, end)
    {
        var aryData=[];
        for(var i in this.Data)
        {
            var item=this.Data[i];
            var showItem={ };
            if (item.Start.Date>=first.Date && item.Start.Date<=end.Date) showItem.Start=item.Start;
            if (item.End.Date>=first.Date && item.End.Date<=end.Date) showItem.End=item.End;
            if (showItem.Start || showItem.End) 
            {
                showItem.Color=item.Color;
                aryData.push(showItem);
            }
        }

        //JSConsole.Chart.Log('[BackgroundPaint::GetShowData]  aryData ', aryData);
        return aryData;
    }

    this.BuildKLineMap=function()
    {
        var isHScreen=(this.ChartSubFrame.IsHScreen===true);
        var dataWidth=this.ChartSubFrame.DataWidth;
        var distanceWidth=this.ChartSubFrame.DistanceWidth;
        var xOffset=this.ChartBorder.GetLeft()+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
        if (isHScreen) xOffset=this.ChartBorder.GetTop()+distanceWidth/2.0+g_JSChartResource.FrameLeftMargin;
        var chartright=this.ChartBorder.GetRight();
        if (isHScreen) chartright=this.ChartBorder.GetBottom();

        var mapKLine={ Data:new Map() ,Start:null, End:null } ; //Key: date / date time, Value:索引
        for(var i=this.KData.DataOffset,j=0; i<this.KData.Data.length && j<this.XPointCount; ++i,++j,xOffset+=(dataWidth+distanceWidth))
        {
            var kItem=this.KData.Data[i];
            var left=xOffset;
            var right=xOffset+dataWidth;
            if (right>chartright) break;
            var x=left+(right-left)/2;

            if (j==0) mapKLine.XLeft=left;
            mapKLine.XRight=right;

            var value={ Index:i, ShowIndex:j , X:x, Right:right, Left:left, Date:kItem.Date };
            if (ChartData.IsMinutePeriod(this.Period,true))
            {
                var key=`Date:${kItem.Date} Time:${kItem.Time}`;
                value.Time=kItem.Time;
            }
            else
            {
                var key=`Date:${kItem.Date}`;
            }
               
            mapKLine.Data.set(key,value);

            //保存下起始和结束位置
            if (j==0) mapKLine.Start=value;
            mapKLine.End=value;
        }

        return mapKLine;
    }

    this.GetBGCoordinate=function(item,kLineMap)
    {
        var xLeft=null, xRight=null;
        var isMinutePeriod=ChartData.IsMinutePeriod(this.Period,true);
        var bSingleDate=false;
        //JSConsole.Chart.Log('[BackgroundPaint::GetBGCoordinate]  item ', item);
        if (isMinutePeriod)
        {
            if (item.Start && item.End && item.Start.Date==item.End.Date && item.Start.Time==item.End.Time) bSingleDate=true;
        }
        else
        {
            if (item.Start && item.End && item.Start.Date==item.End.Date) bSingleDate=true;
        }

        if (bSingleDate)
        {
            if (isMinutePeriod)
                var key=`Date:${item.Start.Date} Time:${item.Start.Time}`;
            else 
                var key=`Date:${item.Start.Date}`;

            if (!kLineMap.Data.has(key)) return null;
            var findItem=kLineMap.Data.get(key);
            xLeft=findItem.Left;
            xRight=findItem.Right;
            return { Left:xLeft, Right:xRight, Width:xRight-xLeft };
        }
        
        if (item.Start)
        {
            if (isMinutePeriod)
                var key=`Date:${item.Start.Date} Time:${item.Start.Time}`;
            else 
                var key=`Date:${item.Start.Date}`;

            if (kLineMap.Data.has(key)) 
            {
                var findItem=kLineMap.Data.get(key);
                xLeft=findItem.Left;
            }
            else 
            {
                if (isMinutePeriod)
                {
                    if (item.Start.Date<kLineMap.Start.Date || (item.Start.Date==kLineMap.Start.Date && item.Start.Time<=kLineMap.Start.Time) ) 
                    {
                        xLeft=kLineMap.Start.Left;
                    }
                    else
                    {
                        for(var kItem of kLineMap.Data)
                        {
                            var value=kItem[1];
                            if (value.Date>item.Start.Date || (value.Date==item.Start.Date && value.Time>item.Start.Time))
                            {
                                xLeft=value.Left;
                                break;
                            }
                        }
                    }
                }
                else
                {
                    if (item.Start.Date<=kLineMap.Start.Date) 
                    {
                        xLeft=kLineMap.Start.Left;
                    }
                    else
                    {
                        for(var kItem of kLineMap.Data)
                        {
                            var value=kItem[1];
                            if (value.Date>item.Start.Date)
                            {
                                xLeft=value.Left;
                                break;
                            }
                        }
                    }
                }
            }
        }
        else
        {
            xLeft=kLineMap.XLeft;
        }

        if (item.End)
        {
            if (isMinutePeriod)
                var key=`Date:${item.End.Date} Time:${item.End.Time}`;
            else 
                var key=`Date:${item.End.Date}`;

            if (kLineMap.Data.has(key))
            {
                var findItem=kLineMap.Data.get(key);
                xRight=findItem.Right;
            }
            else
            {
                if (isMinutePeriod)
                {
                    if (item.End.Date<kLineMap.End.Date || (item.End.Date==kLineMap.End.Date && item.End.Time>=kLineMap.End.Time) ) 
                    {
                        xRight=kLineMap.End.Right;
                    }
                    else
                    {
                        var previousX=null;
                        for(var kItem of kLineMap.Data)
                        {
                            var value=kItem[1];
                            if (value.Date>item.End.Date || (value.Date==item.End.Date && value.Time>item.End.Time) )
                            {
                                xRight=previousX;
                                break;
                            }
                            previousX=value.Right;
                        }
                    }
                }
                else
                {
                    if (item.End.Date<=kLineMap.End.Date) 
                    {
                        xRight=kLineMap.End.Right;
                    }
                    else
                    {
                        var previousX=null;
                        for(var kItem of kLineMap.Data)
                        {
                            var value=kItem[1];
                            if (value.Date>item.End.Date)
                            {
                                xRight=previousX;
                                break;
                            }
                            previousX=value.Right;
                        }
                    }
                }
            }
        }
        else
        {
            xRight=kLineMap.XRight;
        }

        if (xLeft==null || xRight==null) return null;

        return { Left:xLeft, Right:xRight, Width:xRight-xLeft };
    }
}


//弹幕数据 { 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;
    this.GetEventCallback;              //事件回调

    //////////////////////
    // 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;

        var fixMax=data.Max, fixMin=data.Min;

        var maxValue=data.Max/splitItem.FixInterval;
        var minValue=data.Min/splitItem.FixInterval;
        //调整到整数倍数,不能整除的 +1
        if (IFrameSplitOperator.IsFloat(maxValue)) fixMax=parseInt((maxValue+0.5).toFixed(0))*splitItem.FixInterval;
        if (IFrameSplitOperator.IsFloat(minValue)) fixMin=parseInt((minValue-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, 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;

            var message = item.Message[2];
            if (!this.IsDecimalZeroEnd(message)) isAllZero[2] = false;

            var message = item.Message[3];
            if (!this.IsDecimalZeroEnd(message)) isAllZero[3] = false;
        }

        if (isAllZero[0] == false && isAllZero[1] == false && isAllZero[2]==false && isAllZero[3]==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, '');
                }
            }

            if (isAllZero[2])
            {
                var message = item.Message[2];
                if (message!=null)
                {
                    if (typeof (message) == 'number') message = message.toString();
                    item.Message[2] = message.replace(/[.][0]+/g, '');
                }
            }

            if (isAllZero[3])
            {
                var message = item.Message[3];
                if (message!=null)
                {
                    if (typeof (message) == 'number') message = message.toString();
                    item.Message[3] = 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 (languageID===JSCHART_LANGUAGE_ID.LANGUAGE_TRADITIONAL_CHINESE_ID)  //繁体
    {
        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)+"萬億";
    }
    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, languageID)
{
    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);
        case "YYYY/MM/DD":
            return year.toString() + '/' + IFrameSplitOperator.NumberToString(month) + '/' + IFrameSplitOperator.NumberToString(day);
        case "YYYY/MM/DD/W":
            {
                var date=new Date(year,month-1,day);
                var week=g_JSChartLocalization.GetText(WEEK_NAME[date.getDay()],languageID);
                return year.toString() + '/' + IFrameSplitOperator.NumberToString(month) + '/' + IFrameSplitOperator.NumberToString(day)+"/"+ week.toString();
            }
        case "DD/MM/YYYY":
            return IFrameSplitOperator.NumberToString(day) + '/' + IFrameSplitOperator.NumberToString(month) + '/' + year.toString();
        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,isShowTime)
{
    var aryValue=value.split(' ');
    if (aryValue.length<2) return "";
    var result="";

    if (isShowDate)
    {
        var date=parseInt(aryValue[0]);
        var year=parseInt(date/10000);
        var month=parseInt(date%10000/100);
        var day=date%100;
        var text=year.toString() +'-'+ (month<10? ('0'+month.toString()) :month.toString()) +'-'+ (day<10? ('0'+day.toString()):day.toString());
        result+=text;
    }

    if (isShowTime)
    {
        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 (result.length>0) result+=" ";
        result+=text;
    }
    
    return result;
}

//字段颜色格式化
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)
{
    var type=typeof(value);
    if (type=='string') return true;
    return false;
}

//是否是非空的数组
IFrameSplitOperator.IsNonEmptyArray=function(ary)
{
    if (!ary) return;
    if (!Array.isArray(ary)) return;

    return ary.length>0;
}

IFrameSplitOperator.IsFloat=function(value)
{
    if (value===undefined) return false;
    if (value==null) return false;
    if (isNaN(value)) return false;

    return value!=parseInt(value);
}

IFrameSplitOperator.RemoveZero=function(strValue)
{
    while(strValue.length>0)
    {
        var index=strValue.length-1;
        var ch=strValue[index];
        if (ch=="0")
        {
            strValue=strValue.substr(0,index);
        }
        else if (ch==".")
        {
            strValue=strValue.substr(0,index);
            break;
        }
        else
        {
            break;
        }
    }

    return strValue;
}

function FrameSplitKLinePriceY()
{
    this.newMethod=IFrameSplitOperator;   //派生
    this.newMethod();
    delete this.newMethod;
    this.CoordinateType=0;  //坐标类型 0=普通坐标  1=百分比坐标 (右边坐标刻度) 2=对数对标 3=等比坐标 4=等分坐标 5=黄金分割
    this.Symbol;
    this.Data;              //K线数据 (计算百分比坐标)
    this.FrameSplitData2;                //坐标轴分割方法(计算百分比刻度)
    this.FloatPrecision=null;   //小数位数 (设置了就使用这个位数,否则使用品种对应的小数位数)

    this.Period;            //周期
    this.KLineChart;
    this.Custom=[]; //[{Type:0}];   定制刻度 0=显示最后的价格刻度
    this.SplitType=0;       //0=自动分割  1=固定分割 2=分笔图价格分割

    this.DefaultYMaxMin;    //{ Max:null, Min:null };    //指定最大,最小, Y轴范围必须比最大值大， 比最小值小
    this.FixedYMaxMin;      //{ Max, Min} 固定Y轴最大最小值
    this.EnableZoomUpDown=false;    //上下左右拖拽
    this.LastMaxMin;        //当前显示的最高最低范围

    this.PercentageTextFormat=0;    //0=显示第1行  1=显示2行 2=单行格式: 价格/百分比

    this.IsEnableDragY=function()
    {
        return this.CoordinateType==0 || this.CoordinateType==1;
    }

    this.Operator=function()
    {
        var splitData={};
        splitData.Max=this.Frame.HorizontalMax;
        splitData.Min=this.Frame.HorizontalMin;
        splitData.Count=this.SplitCount;

        if (splitData.Max==splitData.Min)   //如果一样上下扩大下
		{
			splitData.Max+=splitData.Max*0.01;
			splitData.Min-=splitData.Min*0.01
		}

        var isFixedMaxMin=(this.FixedYMaxMin && IFrameSplitOperator.IsNumber(this.FixedYMaxMin.Max) && IFrameSplitOperator.IsNumber(this.FixedYMaxMin.Min));
        if (isFixedMaxMin)
        {
            splitData.Max=this.FixedYMaxMin.Max;
            splitData.Min=this.FixedYMaxMin.Min;
            //JSConsole.Chart.Log(`[FrameSplitKLinePriceY::Operator] FixedYMaxMin.Max=${this.FixedYMaxMin.Max} FixedYMaxMin.Min=${this.FixedYMaxMin.Min} `);
        }
        else if (this.DefaultYMaxMin)    //指定最小的Y轴范围
        {
            var range=this.DefaultYMaxMin;
            if (IFrameSplitOperator.IsNumber(range.Max))
            {
                if (splitData.Min>range.Max) splitData.Min=range.Max;
                else if (splitData.Max<range.Max) splitData.Max=range.Max;
            }

            if (IFrameSplitOperator.IsNumber(range.Min))
            {
                if (splitData.Max<range.Min) splitData.Max=range.Min;
                else if (splitData.Min>range.Min) splitData.Min=range.Min;
            }
        }

        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} `);

        this.Frame.Logarithmic=null;
        this.Frame.MultiTextFormat=0;
        var bFilter=true;   //是否需要通过高度过滤刻度
        splitData.IsFixedMaxMin=isFixedMaxMin;
        splitData.IsFilter=bFilter;
        if (ChartData.IsTickPeriod(this.Period))
        {
            this.SplitTickData(splitData,defaultfloatPrecision);
            bFilter=splitData.IsFilter;
        }
        else if (FrameSplitKLinePriceY.SplitCustom)
        {
            FrameSplitKLinePriceY.SplitCustom(this,splitData,defaultfloatPrecision);    //自定义分割
            bFilter=false;
        }
        else
        {
            switch(this.CoordinateType)
            {
                case 1:
                    if (!this.SplitPercentage(splitData,defaultfloatPrecision,isFixedMaxMin))
                    {
                        this.SplitDefault(splitData,defaultfloatPrecision,isFixedMaxMin);
                    }
                    else
                    {
                        this.Frame.MultiTextFormat=this.PercentageTextFormat;
                        bFilter=false;
                    }
                    break;
                case 3: //等比坐标 +10%/-10% 涨幅分割
                    if (!this.SplitIncrease(splitData,defaultfloatPrecision))
                        this.SplitDefault(splitData,defaultfloatPrecision);
                    else
                        bFilter=false;
                    break;
                case 4: //等分坐标
                    this.SplitAverage(splitData,defaultfloatPrecision);
                    bFilter=false;
                    break;
                case 5: //黄金分割
                    this.SplitGoldenSection(splitData,defaultfloatPrecision);
                    bFilter=false;
                    break;
                case 2: //对数坐标
                    if (this.SplitLogarithmic(splitData,defaultfloatPrecision))
                    {
                        bFilter=false;
                    }
                    else
                    {
                        this.SplitDefault(splitData,defaultfloatPrecision);
                    }
                    break;
                default:
                    if (this.SplitType==1) 
                    {
                        this.SplitFixed(splitData,defaultfloatPrecision);
                        bFilter=false;
                    }
                    else 
                    {
                        this.SplitDefault(splitData,defaultfloatPrecision,isFixedMaxMin);
                    }
                    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;

        if (this.EnableZoomUpDown==true && !this.FixedYMaxMin)
            this.FixedYMaxMin={ Max:splitData.Max, Min:splitData.Min };

        /*
        for(var i=0;i<this.Frame.HorizontalInfo.length;++i)
        {
            JSConsole.Chart.Log(`[FrameSplitKLinePriceY::Operator] ${i}=${this.Frame.HorizontalInfo[i].Message[0]}`);
        }
        */

        JSConsole.Chart.Log(`[FrameSplitKLinePriceY::Operator] fixed . Max=${splitData.Max} Min=${splitData.Min} Count=${splitData.Count}`);

        if (this.GetEventCallback)
        {
            var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_SPLIT_YCOORDINATE);
            if (event && event.Callback)
            {
                var data={ID:this.Frame.Identify, Frame:this.Frame };
                event.Callback(event,data,this);
            }
        }
    }

    this.SplitTickData=function(splitData,floatPrecision)
    {
        switch(this.CoordinateType)
        {
            case 1: //百分比
                if (!this.SplitPercentage(splitData,floatPrecision,splitData.IsFixedMaxMin))
                {
                    this.SplitDefault(splitData,floatPrecision,splitData.IsFixedMaxMin);
                }
                else
                {
                    this.Frame.MultiTextFormat=this.PercentageTextFormat;
                    splitData.IsFilter=false;
                }
                break;
            default:
                if (this.SplitType==3) 
                {
                    this.SplitTickPrice(splitData,floatPrecision);
                }
                else 
                {
                    this.SplitDefault(splitData, floatPrecision, splitData.IsFixedMaxMin);
                }
        }
    }

    this.SplitTickPrice=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,isFixedMaxMin)    //百分比坐标
    {
        var firstOpenPrice=this.GetFirstOpenPrice();
        if (!IFrameSplitOperator.IsNumber(firstOpenPrice)) return false;

        splitData.Max=(splitData.Max-firstOpenPrice)/firstOpenPrice;
        splitData.Min=(splitData.Min-firstOpenPrice)/firstOpenPrice;
        splitData.Interval=(splitData.Max-splitData.Min)/(splitData.Count-1);
        if (!isFixedMaxMin) this.IntegerCoordinateSplit2(splitData);

        var minValue=(1+splitData.Min)*firstOpenPrice;
        var maxValue=(1+splitData.Max)*firstOpenPrice;

        var textColor;
        if (g_JSChartResource.Frame && g_JSChartResource.Frame.PercentageText)
        {
            var item=g_JSChartResource.Frame.PercentageText;
            textColor={PriceColor:item.PriceColor, PercentageColor:item.PercentageColor, SplitColor:item.SplitColor, Font:item.Font };
        }   

        var aryHorizontal=[];
        for(var value=0;value<=splitData.Max; value+=splitData.Interval)
        {
            var price=(value+1)*firstOpenPrice;
            var item=new CoordinateInfo();
            item.Value=price;
            if (this.IsShowLeftText) item.Message[0]=price.toFixed(floatPrecision);     //左边价格坐标  
            
            if (this.IsShowRightText) 
            {
                var strPrice=price.toFixed(floatPrecision);
                var text=(value*100).toFixed(2);    //右边百分比
                text=IFrameSplitOperator.RemoveZero(text);
                text+='%';
                item.Message[1]=[text,strPrice];
                item.ExtendData=textColor;
            }
            aryHorizontal.push(item);
        }

        for(var value=-splitData.Interval;value>=splitData.Min;value-=splitData.Interval)
        {
            var price=(value+1)*firstOpenPrice;
            if (price<minValue || price>maxValue) continue;

            var item=new CoordinateInfo();
            item.Value=price;
            if (this.IsShowLeftText) item.Message[0]=price.toFixed(floatPrecision);   //左边价格坐标      
            if (this.IsShowRightText) 
            {
                var strPrice=price.toFixed(floatPrecision);
                var text=(value*100).toFixed(2);    //右边百分比
                text=IFrameSplitOperator.RemoveZero(text);
                text+='%';
                item.Message[1]=[text,strPrice];  
                item.ExtendData=textColor;
            }
            aryHorizontal.push(item);
        }

        aryHorizontal.sort((left, right)=> 
        {
            return left.Value - right.Value;
        });

        this.Frame.HorizontalInfo=aryHorizontal;

        splitData.Min=minValue; //最大最小值调整
        splitData.Max=maxValue;
        return true;
    }

    //等比坐标 当前屏最后第2根K线的收盘加为基准, 上下涨幅10%分割
    this.SplitIncrease=function(splitData,floatPrecision)    
    {
        var basePrice=this.GetLast2ndClose();
        if (!IFrameSplitOperator.IsNumber(basePrice)) return false;
        this.IntegerCoordinateSplit(splitData);
        this.Frame.HorizontalInfo=[];

        var increase=g_JSChartResource.FrameSplitIncrease.Increase;
        var aryHorizontal=[];
        for(var price=basePrice; price<splitData.Max; price=price*(1+increase))
        {
            var item= new CoordinateInfo();
            item.Value=price;
            var text=price.toFixed(floatPrecision);
            if (this.IsShowLeftText) item.Message[0]=text;  
            if (this.IsShowRightText) item.Message[1]=text;
            aryHorizontal.push(item);
        }

        for(var price=basePrice*0.9;price>splitData.Min; price=price*(1-increase))
        {
            var item= new CoordinateInfo();
            item.Value=price;
            var text=price.toFixed(floatPrecision);
            if (this.IsShowLeftText) item.Message[0]=text;  
            if (this.IsShowRightText) item.Message[1]=text;
            aryHorizontal.push(item);
        }

        this.Frame.HorizontalInfo=aryHorizontal;
        return true;
    }

    //等分坐标：以画面显示的最高价、最低价为基准，对这个区域N等分，显示分割的数值线
    this.SplitAverage=function(splitData,floatPrecision)
    {
        var max=splitData.Max;
        var min=splitData.Min;
        //this.IntegerCoordinateSplit(splitData);
        this.Frame.HorizontalInfo=[];
        var count=g_JSChartResource.FrameSplitAverage.Count;
        var interval=(max-min)/count;

        for(var i=0;i<=count;++i)
        {
            var item=new CoordinateInfo();
            item.Value=min+interval*i;
            var text=item.Value.toFixed(floatPrecision);
            if (this.IsShowLeftText)  item.Message[0]=text;
            if (this.IsShowRightText)   item.Message[1]=text;

            this.Frame.HorizontalInfo[i]=item;
        }
    }

    this.SplitGoldenSection=function(splitData,floatPrecision)
    {
        var max=splitData.Max;
        var min=splitData.Min;
        //this.IntegerCoordinateSplit(splitData);
        this.Frame.HorizontalInfo=[];

        var aryHorizontal=[];
        var GOLDEN_ARRAY=g_JSChartResource.FrameGoldenSection.Golden;
        for(var i in GOLDEN_ARRAY)
        {
            var value=(max-min)*GOLDEN_ARRAY[i]+min;
            item=new CoordinateInfo();
            item.Value=value;
            var text=value.toFixed(floatPrecision);
            if (this.IsShowLeftText)  item.Message[0]=text;
            if (this.IsShowRightText)   item.Message[1]=text;
            aryHorizontal.push(item);
        }

        this.Frame.HorizontalInfo=aryHorizontal;
    }

    this.SplitLogarithmic=function(splitData,floatPrecision) //对数坐标
    {
        var minInterval=g_JSChartResource.FrameLogarithmic.MinInterval;       //最小间距
        var firstOpenPrice=this.GetFirstOpenPrice();    //获取当前屏第1个K线的开盘价
        if (!IFrameSplitOperator.IsNumber(firstOpenPrice)) return false;
        var height=this.ChartBorder.GetHeightEx();

        var ARRAY_INCREASE=[0.01, 0.02, 0.04, 0.08, 0.1, 0.2];
        var increase=ARRAY_INCREASE[ARRAY_INCREASE.length-1];
        for(var i=0; i<ARRAY_INCREASE.length;++i)
        {
            var value=ARRAY_INCREASE[i];
            var interval=(firstOpenPrice*value)*(height/(splitData.Max-splitData.Min));
            if (interval>minInterval)
            {
                increase=value;
                break;
            }
        }

        var aryUp=[];
        var price=firstOpenPrice;
        var i=increase;
        do
        {
            var item={ Start:price };
            price=firstOpenPrice*(1+i);
            item.End=price;
            aryUp.push(item);

            i+=increase;
        } while(price<splitData.Max);
        var max=price;

        var aryDown=[];
        var price=firstOpenPrice;
        var i=increase;
        do
        {
            var item={ End:price };
            price=firstOpenPrice*(1-i);
            item.Start=price;
            aryDown.push(item);

            i+=increase;
        } while(price>splitData.Min);
        var min=price;

        splitData.Max=max;
        splitData.Min=min;
        
        JSConsole.Chart.Log("[FrameSplitKLinePriceY::SplitLogarithmic] up, down", aryUp, aryDown);

        this.Frame.HorizontalInfo=[];
        var item=new CoordinateInfo();
        item.Value=firstOpenPrice;
        item.Font=g_JSChartResource.FrameLogarithmic.OpenPriceFont;
        var strText=item.Value.toFixed(floatPrecision);
        if (this.IsShowLeftText) item.Message[0]=strText;     //左边价格坐标      
        if (this.IsShowRightText) item.Message[1]=strText;    //右边价格坐标 
        this.Frame.HorizontalInfo.push(item);

        for(var i in aryUp)
        {
            var item=new CoordinateInfo();
            item.Value=aryUp[i].End;
            var strText=item.Value.toFixed(floatPrecision);
            if (this.IsShowLeftText) item.Message[0]=strText;     //左边价格坐标      
            if (this.IsShowRightText) item.Message[1]=strText;    //右边价格坐标 
            this.Frame.HorizontalInfo.push(item);
        }

        for(var i in aryDown)
        {
            var item=new CoordinateInfo();
            item.Value=aryDown[i].End;
            var strText=item.Value.toFixed(floatPrecision);
            if (this.IsShowLeftText) item.Message[0]=strText;     //左边价格坐标      
            if (this.IsShowRightText) item.Message[1]=strText;    //右边价格坐标 
            this.Frame.HorizontalInfo.splice(0,0,item);
        }

        this.Frame.Logarithmic={ Up:aryUp, Down:aryDown, OpenPrice:firstOpenPrice };
        return true;
    }

    this.SplitDefault=function(splitData,floatPrecision,isFixedMaxMin)       //默认坐标
    {
        //固定最大最小值 不自动调整范围
        if (!isFixedMaxMin) 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 dec=floatPrecision;
                //外部设置小数位数
                if (IFrameSplitOperator.IsNumber(item.FloatPrecision) && item.FloatPrecision>=0) dec=item.FloatPrecision;
                var latestItem=this.GetLatestPrice(dec,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;
        info.LineType=2;    //虚线
        var strPrice=latestItem.Close.toFixed(floatPrecision);
        if (option.DateTime=='HH:MM' && ChartData.IsMinutePeriod(this.Period,true))
        {
            var strTime=IFrameSplitOperator.FormatTimeString(latestItem.Time,option.DateTime);
            var aryText=[{Text:strPrice}, { Text:strTime} ];
            if (option.Position=='left') info.Message[0]=aryText;
            else info.Message[1]=aryText;
        }
        else
        {
            if (option.Position=='left') info.Message[0]=strPrice
            else info.Message[1]=strPrice;
        }
        
        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 (IFrameSplitOperator.IsNumber(option.LineType)) info.LineType=option.LineType;
        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;

            if (ChartData.IsTickPeriod(this.Period)) 
                return data.YClose;
            else
                return data.Open;
        }

        return null;
    }

    this.GetLast2ndClose=function() //获取最后第2根K线收盘加
    {
        if (!this.Data) return null;
        if (this.Data.Data.length<=0) return null;

        var xPointCount=this.Frame.XPointCount;
        var endIndex=this.Data.DataOffset+xPointCount-1;
        if (endIndex>=this.Data.Data.length) endIndex=this.Data.Data.length-1;
        var price=null;
        for(var i=endIndex, count=0; i>=0 && i<this.Data.Data.length; --i)
        {
            var data=this.Data.Data[i];
            if (data.Open==null || data.High==null || data.Low==null || data.Close==null) continue;

            if (count==0) price=data.Open;
            else if (count==1) price=data.Close;

            ++count;
            if (count>=2) break;
        }

        return price;
    }

    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 (IFrameSplitOperator.IsNumber(option.LineType)) info.LineType=option.LineType;
            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.SplitType=0;       //0=自动分割  1=固定分割
    this.Custom=[];         //[{Type:0}]; 定制刻度
    this.DefaultYMaxMin;    //{ Max:null, Min:null };    //指定最大,最小, Y轴范围必须比最大值大， 比最小值小
    this.EnableRemoveZero=true;
    this.LineType=null;     //线段样式
    this.IgnoreYValue = null;                 //在这个数组里的数字不显示在刻度上 
    this.FixedYMaxMin;      //{ Max, Min} 固定Y轴最大最小值
    this.EnableZoomUpDown=false;

    this.IsBeforeData=false;
    this.BeforeOpenData;

    this.IsAfterData=false;
    this.AfterCloseData;

    this.MultiDayBeforeOpenData;
    this.MultiDayAfterCloseData;

    this.IsEnableDragY=function()
    {
        return true;
    }

    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 (splitData.Max==splitData.Min)   //如果一样上下扩大下
		{
            if (splitData.Max==0)
            {
                splitData.Max=1;
                splitData.Min=-1;
            }
            else
            {
                splitData.Max+=splitData.Max*0.01;
                splitData.Min-=splitData.Min*0.01;
            }
		}
        
        var isFixedMaxMin=false;
        if (this.FixedYMaxMin && IFrameSplitOperator.IsNumber(this.FixedYMaxMin.Max) && IFrameSplitOperator.IsNumber(this.FixedYMaxMin.Min)) isFixedMaxMin=true;
        if (isFixedMaxMin)
        {
            splitData.Max=this.FixedYMaxMin.Max;
            splitData.Min=this.FixedYMaxMin.Min;
        }
        else if (this.DefaultYMaxMin)    //指定最小的Y轴范围
        {
            var range=this.DefaultYMaxMin;
            if (IFrameSplitOperator.IsNumber(range.Max))
            {
                if (splitData.Min>range.Max) splitData.Min=range.Max;
                else if (splitData.Max<range.Max) splitData.Max=range.Max;
            }

            if (IFrameSplitOperator.IsNumber(range.Min))
            {
                if (splitData.Max<range.Min) splitData.Max=range.Min;
                else if (splitData.Min>range.Min) splitData.Min=range.Min;
            }
        }

        if(this.Frame.YSpecificMaxMin)
        {
            splitData.Count=this.Frame.YSpecificMaxMin.Count;
            splitData.Interval=(splitData.Max-splitData.Min)/(splitData.Count-1);
        }
        else if (this.SplitType==1 || isFixedMaxMin)
        {
            splitData.Count=this.SplitCount;
            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;
                if (IFrameSplitOperator.IsNumber(this.LineType)) coordinate.LineType=this.LineType;

                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)
            {
                var coordinate=new CoordinateInfo();
                this.Frame.HorizontalInfo[i]= coordinate;
                coordinate.Value=value;
                if (IFrameSplitOperator.IsNumber(this.LineType)) coordinate.LineType=this.LineType;

                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.FilterIgnoreYValue();

        this.CustomCoordinate();
        if (this.SplitType!=1) this.Frame.HorizontalInfo = this.Filter(this.Frame.HorizontalInfo,(splitData.Max>0 && splitData.Min<0));
        if (this.EnableRemoveZero) this.RemoveZero(this.Frame.HorizontalInfo);
        this.Frame.HorizontalMax=splitData.Max;
        this.Frame.HorizontalMin=splitData.Min;

        if (this.EnableZoomUpDown==true && !this.FixedYMaxMin)
            this.FixedYMaxMin={ Max:splitData.Max, Min:splitData.Min };

        this.RightFrameSplitY();
        this.CallAcutionSplitY(this.SplitCount,splitData);

        if (this.GetEventCallback)
        {
            var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_SPLIT_YCOORDINATE);
            if (event && event.Callback)
            {
                var data={ID:this.Frame.Identify, Frame:this.Frame };
                event.Callback(event,data,this);
            }
        }
    }

    this.FilterIgnoreYValue = function () 
    {
        if (!this.IgnoreYValue || this.IgnoreYValue.length <= 0) return;

        var setValue = new Set(this.IgnoreYValue);
        this.Frame.HorizontalInfo = this.Frame.HorizontalInfo.filter(item => !setValue.has(item.Value));
    }

    this.CallAcutionSplitY=function(count,splitData)
    {
        if (this.Frame.Identify!=1) return null;
        var aryCallAcution=this.GetCallAcutionSplitY(count,splitData);
        if (!aryCallAcution) return;

        for(var i in this.Frame.HorizontalInfo) //把显示的数据迁移到 Message[2] Message[3]
        {
            var item=this.Frame.HorizontalInfo[i];
            if (aryCallAcution.IsBeforeData)
            {
                item.Message[2]=item.Message[0];    
                item.Message[0]=null;
            }

            if (aryCallAcution.IsAfterData)
            {
                item.Message[3]=item.Message[1];
                item.Message[1]=null;
            }
        }

        //集合竞价的坐标插入最后
        for(var i in aryCallAcution.HorizontalInfo)
        {
            var item=aryCallAcution.HorizontalInfo[i];
            this.Frame.HorizontalInfo.push(item);
        }
    }

    this.GetCallAcutionSplitY=function(count,splitData)
    {
        if (this.Frame.Identify!=1) return null;

        var isBeforeData=(this.IsBeforeData==true && this.BeforeOpenData && (this.BeforeOpenData.Ver==2.0 || this.BeforeOpenData.Ver==3.0));
        var isAfterData=(this.IsAfterData==true && this.AfterCloseData && (this.AfterCloseData.Ver==2.0 || this.AfterCloseData.Ver==3.0));

        if (isBeforeData || isAfterData)
        {
            var intervalY=(splitData.Max-splitData.Min)/(count-1);
            if (isBeforeData) var intervalLeft=(this.BeforeOpenData.VolMax-this.BeforeOpenData.VolMin)/(count-1);
            if (isAfterData)  var intervalRight=(this.AfterCloseData.VolMax-this.AfterCloseData.VolMin)/(count-1);

            var aryHorizontalInfo=[];
            for(var i=0;i<count;++i)
            {
                var item=new CoordinateInfo();
                var yValue=intervalY*i;
                item.Value=yValue;
                item.LineType=8;
                if (isBeforeData)
                {
                    var leftValue=intervalLeft*i;
                    item.Message[0]=leftValue.toFixed(0);
                }

                if (isAfterData)
                {
                    var rightValue=intervalRight*i;
                    item.Message[1]=rightValue.toFixed(0);
                }                
                aryHorizontalInfo.push(item);
            }
            return { HorizontalInfo:aryHorizontalInfo,  IsBeforeData:isBeforeData, IsAfterData:isAfterData };
        }

        var isMultiDayBeforeData=false;
        var intervalLeft=null;
        if (this.MultiDayBeforeOpenData && IFrameSplitOperator.IsNonEmptyArray(this.MultiDayBeforeOpenData))
        {
            isMultiDayBeforeData=true;
            var firstDayData=this.MultiDayBeforeOpenData[0];
            if (firstDayData.Ver==2.0 || firstDayData.Ver==3.0)
            {
                var intervalLeft=(firstDayData.VolMax-firstDayData.VolMin)/(count-1);
            }
        }

        var isMultiDayAfterData=false;
        var intervalRight=null;
        if (this.MultiDayAfterCloseData && IFrameSplitOperator.IsNonEmptyArray(this.MultiDayAfterCloseData))
        {
            isMultiDayAfterData=true;
            var firstDayData=this.MultiDayAfterCloseData[0];
            if (firstDayData.Ver==2.0 || firstDayData.Ver==3.0)
            {
                var intervalRight=(firstDayData.VolMax-firstDayData.VolMin)/(count-1);
            }
        }

        if (isMultiDayBeforeData || isMultiDayAfterData)
        {
            var intervalY=(splitData.Max-splitData.Min)/(count-1);
            var aryHorizontalInfo=[];
            for(var i=0;i<count;++i)
            {
                var item=new CoordinateInfo();
                var yValue=intervalY*i;
                item.Value=yValue;
                item.LineType=9;
                if (intervalLeft!=null)
                {
                    var leftValue=intervalLeft*i;
                    item.Message[0]=leftValue.toFixed(0);
                }

                if (intervalRight!=null)
                {
                    var rightValue=intervalRight*i;
                    item.Message[1]=rightValue.toFixed(0);
                }                
                aryHorizontalInfo.push(item);
            }
            return { HorizontalInfo:aryHorizontalInfo,  IsBeforeData:isMultiDayBeforeData, IsAfterData:isMultiDayAfterData };
        }

        return null;
    }

    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);
        }
    }

    this.CustomCoordinate=function()
    {
        this.Frame.CustomHorizontalInfo=[];
        for(var i in this.Custom)
        {
            var item=this.Custom[i];
            if (item.Type==0)
            {
                
            }
            else if (item.Type==1)
            {
                this.CustomFixedCoordinate(item);
            }
        }
    }

    this.CustomFixedCoordinate=function(option)    //固定坐标刻度
    {
        var defaultfloatPrecision=2;
        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 (IFrameSplitOperator.IsNumber(option.LineType)) info.LineType=option.LineType;
            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);
        }
    }
}

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;
                if (info.Value==0) info.LineType=-1;    //第1个分割线不画
                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;
        var monthCount=0;
        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 (lastMonth!=month) 
                ++monthCount;

            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;
            if (info.Value==0) info.LineType=-1;    //第1个分割线不画

            this.Frame.VerticalInfo.push(info);
            distance=0;
        }

        if (this.Period==0 && monthCount<=2)
            this.SplitShortDate();
    }

    //分隔在2个月一下的格式
    this.SplitShortDate=function()
    {
        this.Frame.VerticalInfo=[];
        var xOffset=this.Frame.Data.DataOffset;
        var xPointCount=this.Frame.XPointCount;
        var minDistance=12;
        var isFirstYear=true;
        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;
            //var day=parseInt(this.Frame.Data.Data[index].Date%100);

            if (distance<minDistance)
            {
                ++distance;
                continue;
            }

            var info= new CoordinateInfo();
            info.Value=index-xOffset;
            var text;
            if (isFirstYear)
            {
                text=year.toString();
                isFirstYear=false;
            }
            else
            {
                text=IFrameSplitOperator.FormatDateString(this.Frame.Data.Data[index].Date,'MM-DD');
            }

            if (this.ShowText) info.Message[0]=text;
            if (info.Value==0) info.LineType=-1;    //第1个分割线不画

            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 if (ChartData.IsTickPeriod(this.Period)) this.SplitSecond();
        else this.SplitDate();

        if (this.GetEventCallback)
        {
            var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_SPLIT_XCOORDINATE);
            if (event && event.Callback)
            {
                var data={ID:this.Frame.Identify, Frame:this.Frame };
                event.Callback(event,data,this);
            }
        }
    }

    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=涨跌停分割 2=数据最大最大值分割
    this.LimitPrice;                    //{Max: Min:} 涨跌停价
    this.Custom;
    this.RightTextFormat=0;           //右边刻度显示模式 0=百分比  1=价格

    this.BeforeOpenData;
    this.IsBeforeData=false;
    this.AfterCloseData;
    this.IsAfterData=false;

    this.MultiDayBeforeOpenData;
    this.MultiDayAfterCloseData;

    this.IsEnableDragY=function()
    {
        return false;
    }

    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 if (this.SplitType==2)
        {
            this.USASplit(range);
        }
        else
        {
            this.DefaultSplit(range);
        }

        this.CustomCoordinate();

        if (this.GetEventCallback)
        {
            var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_SPLIT_YCOORDINATE);
            if (event && event.Callback)
            {
                var data={ID:this.Frame.Identify, Frame:this.Frame };
                event.Callback(event,data,this);
            }
        }
    }

    this.CustomCoordinate=function()    //自定义刻度
    {
        if (!this.Custom) return;

        var defaultfloatPrecision=GetfloatPrecision(this.Symbol);
        for(var i in this.Custom)
        {
            var item=this.Custom[i];
            if (item.Type==1) this.CustomFixedCoordinate(item);
            else if (item.Type==0) 
            {
                var latestItem=this.GetLatestPrice(defaultfloatPrecision,item);
                if (latestItem) this.Frame.CustomHorizontalInfo.push(latestItem);
            }
        }
    }

    this.GetLatestPrice=function(floatPrecision,option)
    {
        if (!this.Data || !this.Data.Data) return null;
        if (this.Data.Data.length<=0) return null;
        var price=this.Data.Data[this.Data.Data.length-1];
        if (!IFrameSplitOperator.IsNumber(price) || !IFrameSplitOperator.IsNumber(this.YClose)) return null;

        var info=new CoordinateInfo();
        info.Type=0;
        info.Value=price;
        info.TextColor=g_JSChartResource.FrameLatestPrice.TextColor;
        info.LineType=2;    //虚线

        var strPrice=price.toFixed(floatPrecision);
        if (option.DateTime=='HH:MM')
        {
            var latestItem=this.Frame.Data.Data[this.Frame.Data.Data.length-1];
            var strTime=IFrameSplitOperator.FormatTimeString(latestItem.Time,option.DateTime);
            var aryText=[{Text:strPrice}, { Text:strTime} ];
            if (option.Position=='left') info.Message[0]=aryText;
            else info.Message[1]=aryText;
        }
        else
        {
            if (option.Position=='left') info.Message[0]=strPrice;
            else info.Message[1]=strPrice;
        }
       
        if (price>this.YClose) info.LineColor=g_JSChartResource.FrameLatestPrice.UpBarColor;
        else if (price<this.YClose) info.LineColor=g_JSChartResource.FrameLatestPrice.DownBarColor;
        else info.LineColor=g_JSChartResource.FrameLatestPrice.UnchagneBarColor;

        if (IFrameSplitOperator.IsNumber(option.LineType)) info.LineType=option.LineType;
        if (option.IsShowLine==false) info.LineType=-1;

        return info;
    }

    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 (IFrameSplitOperator.IsNumber(option.LineType)) info.LineType=option.LineType;
            if (option.IsShowLine==false) info.LineType=-1;

            if (IFrameSplitOperator.IsNumber(item.Increase)) //涨幅计算价格
            {
                if (!IFrameSplitOperator.IsNumber(this.YClose)) continue;
                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.GetCallAuctionMaxMin=function(callAuctionData, range)
    {
        for(var i in callAuctionData.Data)
        {
            var item=callAuctionData.Data[i];
            if (!item) continue;
            if (IFrameSplitOperator.IsNumber(item.Price))
            {
                if (range.Max==null) range.Max=item.Price;
                if (range.Min==null) range.Min=item.Price;

                if (range.Max<item.Price) range.Max=item.Price;
                if (range.Min>item.Price) range.Min=item.Price;
            }
            
            //集合竞价均线统计
            if (callAuctionData.Ver==3.0 && IFrameSplitOperator.IsNumber(item.AvPrice))
            {
                if (range.Max==null) range.Max=item.AvPrice;
                if (range.Min==null) range.Min=item.AvPrice;

                if (range.Max<item.AvPrice) range.Max=item.AvPrice;
                if (range.Min>item.AvPrice) range.Min=item.AvPrice;
            }
        }
    }

    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;
        }

        var range={ Max:null, Min:null };
        if (this.IsAfterData && this.AfterCloseData)
        {
            this.GetCallAuctionMaxMin(this.AfterCloseData,range);
        }

        if (this.IsBeforeData && this.BeforeOpenData)
        {
            this.GetCallAuctionMaxMin(this.BeforeOpenData,range);
        }

        if (this.MultiDayBeforeOpenData && this.ChartBorder.MultiDayMinute.Count>1 && this.ChartBorder.MultiDayMinute.Left>0)
        {
            for(var i in this.MultiDayBeforeOpenData)
            {
                var dayItem=this.MultiDayBeforeOpenData[i];
                this.GetCallAuctionMaxMin(dayItem,range);
            }
        }

        if (this.MultiDayAfterCloseData && this.ChartBorder.MultiDayMinute.Count>1 && this.ChartBorder.MultiDayMinute.Right>0)
        {
            for(var i in this.MultiDayAfterCloseData)
            {
                var dayItem=this.MultiDayAfterCloseData[i];
                this.GetCallAuctionMaxMin(dayItem,range);
            }
        }

        if (IFrameSplitOperator.IsNumber(range.Max) && max<range.Max) max=range.Max;
        if (IFrameSplitOperator.IsNumber(range.Min) && min>range.Min) min=range.Min;

        return { Max:max, Min:min };
    }

    this.USASplit=function(range)
    {
        var max=range.Max;
        var min=range.Min;

        if (max==min)
        {
            max=max+max*0.1;
            min=min-min*0.1;
        }
        else
        {
            var pixelTatio = GetDevicePixelRatio(); //获取设备的分辨率
            var height=this.Frame.ChartBorder.GetHeight();   //画布的高度
            var spacePrice=5*pixelTatio*(max-min)/height;
            max+=spacePrice;
            min-=spacePrice;
            if (min<0) min=range.Min;
        }

        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);
            if (this.YClose && price==this.YClose) continue;
            var coordinate=new CoordinateInfo();
            coordinate.Value=price;
            var strPrice=price.toFixed(defaultfloatPrecision);  //价格刻度字符串
            if (this.IsShowLeftText) coordinate.Message[0]=strPrice;

            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) 
                {
                    if (this.RightTextFormat==1) coordinate.Message[1]=strPrice;
                    else 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;
            coordinate.LineType=2;//中间的线画虚线
            if (g_JSChartResource.FrameDotSplitPen) coordinate.LineColor=g_JSChartResource.FrameDotSplitPen;

            var strPrice=this.YClose.toFixed(defaultfloatPrecision);  //价格刻度字符串
            if (this.IsShowLeftText) coordinate.Message[0]=strPrice;

            if (this.IsShowRightText) 
            {
                if (this.RightTextFormat==1) coordinate.Message[1]=strPrice;
                else coordinate.Message[1]='0.00%'; //百分比
            }

            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;
            if (min<0) min=range.Min;
        }

        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);
            var coordinate=new CoordinateInfo();
            this.Frame.HorizontalInfo[i]=coordinate
            coordinate.Value=price;
            var strPrice=price.toFixed(defaultfloatPrecision);  //价格刻度字符串
            if (this.IsShowLeftText) coordinate.Message[0]=strPrice
            if (price==this.YClose) 
            {
                coordinate.LineType=2;//中间的线画虚线
                if (g_JSChartResource.FrameDotSplitPen) coordinate.LineColor=g_JSChartResource.FrameDotSplitPen;
            }

            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) 
                {
                    if (this.RightTextFormat==1)  coordinate.Message[1]=strPrice;
                    else coordinate.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.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)
        {
            for(var i in xcoordinate)
            {
                var info=new CoordinateInfo();
                if (g_JSChartResource.Minute.FrameSplitTextColor) info.TextColor=g_JSChartResource.Minute.FrameSplitTextColor;
                info.Value=xcoordinate[i][0];
                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);
            }
        }

        if (this.GetEventCallback)
        {
            var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_SPLIT_XCOORDINATE);
            if (event && event.Callback)
            {
                var data={ID:this.Frame.Identify, Frame:this.Frame };
                event.Callback(event,data,this);
            }
        }
    }
}

function FrameSplitXData()
{
    this.newMethod=IFrameSplitOperator;   //派生
    this.newMethod();
    delete this.newMethod;

    this.ShowText=true;                 //是否显示坐标信息
    this.Symbol;                        //股票代码
    this.MinTextDistance=50*GetDevicePixelRatio();
    this.MinBarDistance=5; //刻度间最小的K线间距

    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;
        }
    }
}

//深度图X轴价格信息
function FrameSplitXDepth()
{
    this.newMethod=IFrameSplitOperator;   //派生
    this.newMethod();
    delete this.newMethod;

    this.ShowText=true;                 //是否显示坐标信息
    this.SplitCount=3;
    this.Symbol;
    this.LineType=3;

    this.Operator=function()
    {
        var xRange=this.Frame.VerticalRange;
        if (!xRange) return;
        this.Frame.VerticalInfo=[];

        var floatPrecision=2;
        if (this.Symbol) floatPrecision=GetfloatPrecision(this.Symbol);
        var xMax=xRange.Max;
        var xMin=xRange.Min;
        if (xRange.Bid)
        {
            var interval=(xRange.Bid.Max-xMin)/this.SplitCount;
            for(var i=0;i<this.SplitCount;++i)
            {
                var info= new CoordinateInfo();
                info.Value=xMin+(interval*i);
                if (info.Value<=0) continue;
                
                if (IFrameSplitOperator.IsNumber(this.LineType)) info.LineType=this.LineType;
                if (this.ShowText) info.Message[0]=info.Value.toFixed(floatPrecision);
                this.Frame.VerticalInfo.push(info);
            }
        }

        var info=new CoordinateInfo();
        info.Value=xRange.Center;
        //if (IFrameSplitOperator.IsNumber(this.LineType)) info.LineType=this.LineType;
        this.Frame.VerticalInfo.push(info);

        if (xRange.Ask)
        {
            var interval=(xMax-xRange.Ask.Min)/this.SplitCount;
            for(var i=1;i<=this.SplitCount;++i)
            {
                var info= new CoordinateInfo();
                info.Value=xRange.Ask.Min+(interval*i);
                if (IFrameSplitOperator.IsNumber(this.LineType)) info.LineType=this.LineType;
                if (this.ShowText) info.Message[0]=info.Value.toFixed(floatPrecision);
                this.Frame.VerticalInfo.push(info);
            }
        }
    }
}

//把X位置调整到有数据上面
function CallAcutionXOperator()
{
    this.Frame;
    this.Value;
    this.Point;
    this.ClientPos;
    this.BeforOpeneData;
    this.AfterCloseData;
    this.X;
    this.Item;
    this.DataIndex;
    this.DayIndex;
    this.MultiDayBeforeOpenData;
    this.MultiDayAfterCloseData;

    this.Operator=function()
    {
        this.Item=null;
        this.DataIndex=null;
        this.DayIndex=null;

        if (this.ClientPos==2)
        {
            return this.GetBeforeOpenXIndex();
        }
        else if (this.ClientPos==3)
        {
            return this.GetAfterCloseXIndex();
        }
        else if (this.ClientPos>=200 && this.ClientPos<=299)
        {
            return this.GetMultiDayBeforeOpenXIndex();
        }
        else if (this.ClientPos>=300 && this.ClientPos<=399)
        {
            return this.GetMultiDayAfterCloseXIndex();
        }

        return false;
    }

    this.GetBeforeOpenXIndex=function()
    {
        if (!IFrameSplitOperator.IsNumber(this.Value)) return false;
        if (!this.BeforeOpenData || !this.BeforeOpenData.Data) return false;

        var index=this.Frame.GetLeftExtendXData(this.Value, this.BeforeOpenData);
        index=parseInt(index.toFixed(0));

        if (index>=0 && index<this.BeforeOpenData.Data.length)
        {
            var item=this.BeforeOpenData.Data[index];
            if (IFrameSplitOperator.IsNumber(item.Price)) 
            {
                this.Item=item;
                this.X=this.Value;
                this.DataIndex=index;
                return true;
            }
        }

        if (index<0) index=0;
        else if (index>=this.BeforeOpenData.Data.length) index=this.BeforeOpenData.Data.length-1;

        var findIndex=-1;
        for(var i=index; i>=0; --i)
        {
            var item=this.BeforeOpenData.Data[i];
            if (IFrameSplitOperator.IsNumber(item.Price))
            {
                findIndex=i;
                break;
            }
        }

        if (findIndex<0)
        {
            for(var i=index+1; i<this.BeforeOpenData.Data.length;++i)
            {
                var item=this.BeforeOpenData.Data[i];
                if (IFrameSplitOperator.IsNumber(item.Price))
                {
                    findIndex=i;
                    break;
                }
            }
        }

        if (findIndex<0) return false;

        this.Item=item;
        this.DataIndex=findIndex;
        this.X=this.Frame.GetLeftExtendXFromIndex(findIndex, this.BeforeOpenData);  //调整X轴坐标
        return true;
    }

    this.GetMultiDayBeforeOpenXIndex=function()
    {
        if (!this.MultiDayBeforeOpenData || !IFrameSplitOperator.IsNonEmptyArray(this.MultiDayBeforeOpenData)) return;
        var dayIndex=this.ClientPos-200;
        if (dayIndex<0 || dayIndex>=this.MultiDayBeforeOpenData.length) return;

        var dayData=this.MultiDayBeforeOpenData[dayIndex];
        var indexData=this.Frame.GetLeftExtendXData(this.Value, this.MultiDayBeforeOpenData);
        var index=parseInt(indexData.DataIndex.toFixed(0));
        var dayIndex=indexData.DayIndex;

        if (index>=0 && index<dayData.Data.length)
        {
            var item=dayData.Data[index];
            if (IFrameSplitOperator.IsNumber(item.Price)) 
            {
                this.Item=item;
                this.X=this.Value;
                this.DataIndex=index;
                this.DayIndex=dayIndex;
                return true;
            }
        }

        if (index<0) index=0;
        else if (index>=dayData.Data.length) index=dayData.Data.length-1;
        var findIndex=-1;
        for(var i=index; i>=0; --i)
        {
            var item=dayData.Data[i];
            if (IFrameSplitOperator.IsNumber(item.Price))
            {
                findIndex=i;
                break;
            }
        }

        if (findIndex<0) return false;

        this.Item=item;
        this.DataIndex=findIndex;
        this.DayIndex=dayIndex;
        this.X=this.Frame.GetLeftExtendXFromIndex(findIndex, dayData);  //调整X轴坐标
        return true;
    }

    this.GetAfterCloseXIndex=function()
    {
        if (!IFrameSplitOperator.IsNumber(this.Value)) return false;
        if (!this.AfterCloseData || !this.AfterCloseData.Data) return false;

        var index=this.Frame.GetRightExtendXData(this.Value, this.AfterCloseData);
        index=parseInt(index.toFixed(0));

        if (index>=0 && index<this.AfterCloseData.Data.length)
        {
            var item=this.AfterCloseData.Data[index];
            if (IFrameSplitOperator.IsNumber(item.Price)) 
            {
                this.Item=item;
                this.X=this.Value;
                this.DataIndex=index;
                return true;
            }
        }
        
        if (index<0) index=0;
        else if (index>=this.AfterCloseData.Data.length) index=this.AfterCloseData.Data.length-1;
        var findIndex=-1;
        for(var i=index; i>=0; --i)
        {
            var item=this.AfterCloseData.Data[i];
            if (IFrameSplitOperator.IsNumber(item.Price))
            {
                findIndex=i;
                break;
            }
        }

        if (findIndex<0)
        {
            for(var i=index+1; i<this.AfterCloseData.Data.length;++i)
            {
                var item=this.AfterCloseData.Data[i];
                if (IFrameSplitOperator.IsNumber(item.Price))
                {
                    findIndex=i;
                    break;
                }
            }
        }

        if (findIndex<0) return false;

        this.Item=item;
        this.DataIndex=findIndex;
        this.X=this.Frame.GetRightExtendXFromIndex(findIndex, this.AfterCloseData);  //调整X轴坐标
        return true;
    }

    this.GetMultiDayAfterCloseXIndex=function()
    {
        if (!this.MultiDayAfterCloseData || !IFrameSplitOperator.IsNonEmptyArray(this.MultiDayAfterCloseData)) return;
        var dayIndex=this.ClientPos-300;
        if (dayIndex<0 || dayIndex>=this.MultiDayAfterCloseData.length) return;

        var dayData=this.MultiDayAfterCloseData[dayIndex];
        var indexData=this.Frame.GetRightExtendXData(this.Value, this.MultiDayAfterCloseData);
        var index=parseInt(indexData.DataIndex.toFixed(0));
        var dayIndex=indexData.DayIndex;

        if (index>=0 && index<dayData.Data.length)
        {
            var item=dayData.Data[index];
            if (IFrameSplitOperator.IsNumber(item.Price)) 
            {
                this.Item=item;
                this.X=this.Value;
                this.DataIndex=index;
                this.DayIndex=dayIndex;
                return true;
            }
        }

        if (index<0) index=0;
        else if (index>=dayData.Data.length) index=dayData.Data.length-1;
        var findIndex=-1;
        for(var i=index; i>=0; --i)
        {
            var item=dayData.Data[i];
            if (IFrameSplitOperator.IsNumber(item.Price))
            {
                findIndex=i;
                break;
            }
        }

        if (findIndex<0) return false;

        this.Item=item;
        this.DataIndex=findIndex;
        this.DayIndex=dayIndex;
        this.X=this.Frame.GetRightExtendXFromIndex(findIndex, dayData);  //调整X轴坐标
        return true;
    }
}

///////////////////////////////////////////////////////////////////////////////////////////////////
//十字光标
function ChartCorssCursor()
{
    this.ClassName="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.VLineType=0;   //垂直线 0=默认指标标题栏不画， 1=指标标题栏也画

    this.Font=g_JSChartResource.CorssCursorTextFont;            //字体
    this.TextColor=g_JSChartResource.CorssCursorTextColor;      //文本颜色
    this.TextBGColor=g_JSChartResource.CorssCursorBGColor;      //文本背景色
    this.BorderColor=g_JSChartResource.CorssCursorBorderColor;  //边框颜色
    this.XRangeBGColor=g_JSChartResource.CorssCursorXRangeBGColor;
    this.TextHeight=20;                                         //文本字体高度
    this.LastPoint;
    this.CursorIndex;
    this.IsOnlyDrawKLine=false;                                 //是否只能画在K线上 (手机端)
    this.IsOnlyDrawMinute=false;                                //是否只能画在走势图价格线上
    this.IsFixXLastTime=false;                                  //是否修正X轴,超出当前时间的,X轴调整到当前最后的时间.
    this.IsDrawXRangeBG=false;            //是否绘制十字光标背景

    this.PointX;
    this.PointY;

    this.StringFormatX;
    this.StringFormatY;

    this.ShowTextMode={ Left:1, Right:1, Bottom:1 }; //0=不显示  1=显示在框架外 2=显示在框架内
    this.TextFormat= { Right:0 };               //0=默认 1=价格显示(分时图才有用)
    this.IsShowCorss=true;      //是否显示十字光标
    this.IsShow=true;
    this.IsShowClose=false;     //Y轴始终显示收盘价
    this.ClientPos=-1;
    this.CallAcutionXOperator;

    this.RightButton=
    { 
        Enable:false, Rect:null, 
        BGColor:g_JSChartResource.CorssCursor.RightButton.BGColor , 
        PenColor:g_JSChartResource.CorssCursor.RightButton.PenColor, 
        Icon:g_JSChartResource.CorssCursor.RightButton.Icon
    };

    //内部使用
    this.Close=null;     //收盘价格
    this.Status=0;       //当前状态 0=隐藏 1=显示

    this.ReloadResource=function(resource)
    {
        this.Font=g_JSChartResource.CorssCursorTextFont;            //字体

        this.HPenColor=g_JSChartResource.CorssCursorHPenColor; //水平线颜色
        this.VPenColor=g_JSChartResource.CorssCursorVPenColor; //垂直线颜色
        this.TextColor=g_JSChartResource.CorssCursorTextColor;      //文本颜色
        this.TextBGColor=g_JSChartResource.CorssCursorBGColor;      //文本背景色
        this.BorderColor=g_JSChartResource.CorssCursorBorderColor;  //边框颜色
        this.XRangeBGColor=g_JSChartResource.CorssCursorXRangeBGColor;
    }

    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.GetMinuteCloseYPoint=function(index)
    {
        if (!IFrameSplitOperator.IsNumber(index)) return null;
        index=parseInt(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 close = data.Data[dataIndex];
        if (!IFrameSplitOperator.IsNumber(index)) return null;
        this.Close=close;
        var yPoint = this.Frame.GetYFromData(this.Close);
        return yPoint;
    }

    this.GetDateTimeRange=function(index, option)
    {
        if (!IFrameSplitOperator.IsNumber(index)) return null;
        index=parseInt(index);
        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<0) return null;
        if (!this.Frame || !this.Frame.SubFrame[0] || !this.Frame.SubFrame[0].Frame) return null;
        var frame=this.Frame.SubFrame[0].Frame;

        var dataWidth=frame.DataWidth;
        var distanceWidth=frame.DistanceWidth;
        var xPointCount=frame.XPointCount;

        var kItem = data.Data[dataIndex];
        if (!kItem) return null;

        var date=kItem.Date*1000000;
        var time=parseInt(kItem.Time/100)*100;
        var startTime=date+time;
        var endTime=date+time+59;

        var endIndex=dataIndex;
        for(var i=dataIndex; i<data.Data.length; ++i)
        {
            var item=data.Data[i];
            var dateTime=item.Date*1000000+item.Time;
            if (dateTime>endTime) break;
            if (i-data.DataOffset>=xPointCount) break;
            endIndex=i;
        }

        var startIndex=dataIndex;
        for(var i=dataIndex;i>=0 && i>=data.DataOffset;--i)
        {
            var item=data.Data[i];
            var dateTime=item.Date*1000000+item.Time;
            if (dateTime<startTime) break;
            startIndex=i;
        }

        var range={ StartIndex:startIndex, EndIndex:endIndex };

        range.XStart=this.Frame.GetXFromIndex(startIndex-data.DataOffset);
        range.XEnd=this.Frame.GetXFromIndex(endIndex-data.DataOffset);

        range.XStart-=(distanceWidth+dataWidth)/2;
        range.XEnd+=(distanceWidth+dataWidth)/2;

        return range;
    }

    this.FixMinuteLastTimeXPoint=function(index)
    {
        if (!IFrameSplitOperator.IsNumber(index)) return null;
        index=parseInt(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) return null;

        dataIndex=data.Data.length - 1;
        dataIndex-=data.DataOffset;
        var xPoint=this.Frame.GetXFromIndex(dataIndex);

        return { X:xPoint, Index:dataIndex };
    }

    //返回 -1=不在客户区  1=在主区域  2=左边扩展  3=右边扩展
    this.PtInClient=function(x,y)
    {
        this.Canvas.beginPath();
        if (this.Frame.IsHScreen===true)
        {
            var border=this.Frame.ChartBorder.GetHScreenBorder();
            this.Canvas.rect(border.Left,border.TopEx,border.Right-border.Left,border.BottomEx-border.TopEx);
        }
        else
        {
            var border=this.Frame.ChartBorder.GetBorder();
            this.Canvas.rect(border.LeftEx,border.Top,border.RightEx-border.LeftEx,border.Bottom-border.Top);
        }

        if (this.Canvas.isPointInPath(x,y)) return 1;

        if (this.Frame.ChartBorder.LeftExtendWidth>10)
        {
            this.Canvas.beginPath();
            if (this.Frame.IsHScreen===true)
            {
                this.Canvas.rect(border.Left,border.Top,border.Right-border.Left,border.TopEx-border.Top);
            }
            else
            {
                this.Canvas.rect(border.Left,border.Top,border.LeftEx-border.Left,border.Bottom-border.Top);
            }
    
            if (this.Canvas.isPointInPath(x,y)) return 2;
        }

        if (this.Frame.ChartBorder.RightExtendWidth>10)
        {
            this.Canvas.beginPath();
            if (this.Frame.IsHScreen===true)
            {
                this.Canvas.rect(border.Left,border.BottomEx,border.Right-border.Left,border.Bottom-border.BottomEx);
            }
            else
            {
                this.Canvas.rect(border.RightEx,border.Top,border.Right-border.RightEx,border.Bottom-border.Top);
            }
    
            if (this.Canvas.isPointInPath(x,y)) return 3;
        }
        
        return -1;
    }

    this.GetFontHeight=function(font)
    {
        return GetFontHeight(this.Canvas, font, "擎");
    }

    this.Draw=function()
    {
        this.Status=0;
        this.RightButton.Rect=null;

        if (!this.LastPoint) return;

        this.Close=null;
        var x=this.LastPoint.X;
        var y=this.LastPoint.Y;
        
        var clientPos=this.PtInClient(x,y);

        this.PointY=null;
        this.PointY==null;
        this.ClientPos=clientPos;
        if (clientPos<=0) return;

        if (this.Frame.IsHScreen===true)
        {
            this.HScreenDraw();
            return;
        }

        var border=this.Frame.ChartBorder.GetBorder();
        var left=border.Left
        var right=border.Right;
        var top=border.TopTitle;
        var bottom=border.Bottom;
        var rightWidth=this.Frame.ChartBorder.Right;
        var chartRight=border.ChartWidth;

        if (this.IsOnlyDrawKLine)   //手机端 十字只能画在K线上
        {
            x=this.Frame.GetXFromIndex(this.CursorIndex);
            if (this.IsShowClose)
            {
                var yPoint = this.GetCloseYPoint(this.CursorIndex);
                if (yPoint != null) y=yPoint;
            }
        }
        else if (this.IsOnlyDrawMinute)
        {
            var yPoint = this.GetMinuteCloseYPoint(this.CursorIndex);
            if (yPoint != null) y=yPoint;
        }

        if (this.CallAcutionXOperator)
        {
            this.CallAcutionXOperator.Value=x;
            this.CallAcutionXOperator.Point={X:x, Y:y};
            this.CallAcutionXOperator.ClientPos=clientPos;

            if (this.CallAcutionXOperator.Operator())
            {
                x=this.CallAcutionXOperator.X;
            }
        }

        if (this.IsFixXLastTime)
        {
            var value=this.FixMinuteLastTimeXPoint(this.CursorIndex)
            if (value)
            {
                x=value.X;
                this.CursorIndex=value.Index;
            }
        }

        this.PointY=[[left,y],[right,y]];
        this.PointX=[[x,top],[x,bottom]];

        //十字线
        if (this.IsShowCorss)
        {
            var rangeBG=null;
            if (this.IsDrawXRangeBG)
            {
                rangeBG=this.GetDateTimeRange(this.CursorIndex);
            }

            var pixel=GetDevicePixelRatio();
            if (this.HPenType==1 || this.HPenType==0)   //0=实线 1=虚线
            {
                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();
                if (this.HPenType==0) this.Canvas.setLineDash([]);
            }
            
            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.VLineType==1)
            {
                if (rangeBG)
                {
                    this.Canvas.fillStyle=this.XRangeBGColor;
                    this.Canvas.fillRect(rangeBG.XStart, border.Top, (rangeBG.XEnd-rangeBG.XStart),(border.Bottom-border.Top));
                }

                this.Canvas.moveTo(ToFixedPoint(x),border.Top);
                this.Canvas.lineTo(ToFixedPoint(x),border.Bottom);
            }
            else
            {
                if (this.Frame.SubFrame.length>0)
                {
                    for(var i in this.Frame.SubFrame)
                    {
                        var frame=this.Frame.SubFrame[i].Frame;
                        var subBorder=frame.ChartBorder.GetBorder();
                        top=subBorder.TopTitle;
                        bottom=subBorder.Bottom;

                        if (rangeBG)
                        {
                            this.Canvas.fillStyle=this.XRangeBGColor;
                            this.Canvas.fillRect(rangeBG.XStart, top, (rangeBG.XEnd-rangeBG.XStart),(bottom-top));
                        }

                        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.IsOnlyDrawMinute || this.IsShowClose) && this.Close != null) yValue=this.Close;

        //this.StringFormatX.Value=xValue;
        this.StringFormatX.Value=this.CursorIndex;
        this.StringFormatX.Point={X:x, Y:y};
        this.StringFormatX.ClientPos=clientPos;

        this.StringFormatY.Value=yValue;
        this.StringFormatY.RValue=yValueExtend.RightYValue; //右侧子坐标
        this.StringFormatY.FrameID=yValueExtend.FrameID;
        this.StringFormatY.Point={X:x, Y:y};
        this.StringFormatY.ClientPos=clientPos;

        this.Canvas.font=this.Font;
        var textHeight=this.GetFontHeight();
        if (textHeight>this.TextHeight) this.TextHeight=textHeight;

        //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个像素
            var buttonData={Y:y, YValue:yValue, FrameID:yValueExtend.FrameID };
            if (this.Frame.ChartBorder.Left>=30 && this.ShowTextMode.Left==1)
            {
                if (left<textWidth ) //左边空白的地方太少了画布下
                {
                    this.DrawTextBGRect(ToFixedPoint(2),ToFixedPoint(y-this.TextHeight/2),ToFixedRect(textWidth),ToFixedRect(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.DrawTextBGRect(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.DrawTextBGRect(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)
            {
                if (this.TextFormat.Right==0)
                {
                    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;
                }

                if (isOverlayIndex && textWidth>overlayIndexInterval)   //大于子坐标宽度
                {
                    var drawRight=right+overlayIndexInterval;
                    if (drawRight>chartRight) drawRight=chartRight;
                    this.DrawTextBGRect(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.DrawTextBGRect(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);

                    if (this.RightButton.Enable) this.DrawRightButton(y-this.TextHeight/2, chartRight-2-textWidth,this.TextHeight,this.TextHeight,buttonData);
                }
                else
                {
                    this.DrawTextBGRect(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);

                    if (this.RightButton.Enable) this.DrawRightButton(y-this.TextHeight/2, right+2,this.TextHeight,this.TextHeight,buttonData);
                }

                if (this.StringFormatY.RExtendText && this.StringFormatY.RExtendText.length>0)
                {
                    var yOffset=0;
                    for(var i in this.StringFormatY.RExtendText)
                    {
                        var item=this.StringFormatY.RExtendText[i];
                        var rText='--.--'
                        if (item.YText) rText=item.YText;
                        else if (IFrameSplitOperator.IsNumber(item.Y)) rText=item.Y.toFixed(0);
                        var rTextWidth=this.Canvas.measureText(rText).width+4;    //前后各空2个像素
                        
                        if (rightWidth<rTextWidth)
                        {
                            this.DrawTextBGRect(chartRight-2-rTextWidth,y+yOffset+this.TextHeight/2,rTextWidth,this.TextHeight);
                            this.Canvas.textAlign="right";
                            this.Canvas.textBaseline="middle";
                            this.Canvas.fillStyle=item.TextColor;
                            this.Canvas.fillText(rText,chartRight-4,y+yOffset+this.TextHeight,rTextWidth);
                        }
                        else
                        {
                            this.DrawTextBGRect(right+2,y+yOffset+this.TextHeight/2,rTextWidth,this.TextHeight);
                            this.Canvas.textAlign="left";
                            this.Canvas.textBaseline="middle";
                            this.Canvas.fillStyle=item.TextColor;
                            this.Canvas.fillText(rText,right+4,y+yOffset+this.TextHeight,rTextWidth);
                        }

                        yOffset+=this.TextHeight;
                    }
                }
            }
            else if (this.ShowTextMode.Right==2)
            {
                this.Canvas.fillStyle=this.TextBGColor;
                var showLeft=right-textWidth;
                this.DrawTextBGRect(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);

                if (this.RightButton.Enable) this.DrawRightButton(y-this.TextHeight/2, showLeft,this.TextHeight,this.TextHeight,buttonData);
            }
        }

        //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.DrawTextBGRect(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.DrawTextBGRect(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.DrawTextBGRect(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 isAutoRightBorder=false;
            if (this.Frame.AutoRightBorder) isAutoRightBorder=true;
            var overlayLeft=right;
            if (isAutoRightBorder) overlayLeft=right+this.Frame.AuotRightWidth;
            this.Canvas.font=this.Font;
            for(var i in frame.OverlayIndex)
            {
                var item=frame.OverlayIndex[i];
                if (item.Frame.IsShow===false) continue;

                if (!isAutoRightBorder) 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);

                if (isAutoRightBorder) overlayLeft+=item.RightWidth.Width;
            }
        }

        this.Status=1;
    }

    this.DrawRightButton=function(drawTop, drawRight, drawWidth, drawHeight, data)
    {
        this.Canvas.fillStyle=this.RightButton.BGColor;
        var rtButtom={Left:drawRight-drawWidth, Top:drawTop, Width:drawWidth, Height:drawHeight };
        this.RightButton.Rect=rtButtom;
        this.RightButton.Data=data;
        this.Canvas.fillRect(ToFixedPoint(rtButtom.Left+1),ToFixedPoint(rtButtom.Top),ToFixedRect(rtButtom.Width),ToFixedRect(rtButtom.Height));

        var pixelRatio=GetDevicePixelRatio();
        var spaceWidth=3;
        var yCenter=(rtButtom.Top+spaceWidth)+(rtButtom.Height-spaceWidth*2)/2;
        var xCenter=(rtButtom.Left+spaceWidth)+(rtButtom.Width-spaceWidth*2)/2;

        if (this.RightButton.Icon)
        {
            var icon=this.RightButton.Icon;
            this.Canvas.font=`${icon.Size*pixelRatio}px ${icon.Family}`;
            this.Canvas.textAlign="center";
            this.Canvas.textBaseline="middle";
            this.Canvas.fillStyle=icon.Color;
            this.Canvas.fillText("\ue6a3",xCenter,yCenter);
        }
        else
        {
            //画加号
            this.Canvas.strokeStyle=this.RightButton.PenColor;
            var x=rtButtom.Left+spaceWidth;
            var y=rtButtom.Top+spaceWidth;
            this.Canvas.save();
            this.Canvas.linewidth=1*pixelRatio;
            this.Canvas.beginPath();
            this.Canvas.moveTo(ToFixedPoint(x), ToFixedPoint(yCenter));
            this.Canvas.lineTo(ToFixedPoint(x+rtButtom.Width-spaceWidth*2), ToFixedPoint(yCenter));

            this.Canvas.moveTo(ToFixedPoint(xCenter),ToFixedPoint(y));
            this.Canvas.lineTo(ToFixedPoint(xCenter), ToFixedPoint(y+rtButtom.Height-spaceWidth*2));

            this.Canvas.stroke();
            this.Canvas.restore();
        }
    }

    this.PtInButton=function(x,y)
    {
        if (!this.RightButton.Enable) return null;
        if (!this.RightButton.Rect) return null;

        var rect=this.RightButton.Rect;
        this.Canvas.beginPath();
        this.Canvas.rect(rect.Left,rect.Top,rect.Width,rect.Height);
        if (this.Canvas.isPointInPath(x,y))
        {
            return { Data:this.RightButton.Data, Rect:rect };
        }
    }

    this.DrawTextBGRect=function(x,y, height, width)
    {
        this.Canvas.fillStyle=this.TextBGColor;
        this.Canvas.fillRect(ToFixedPoint(x),ToFixedPoint(y),ToFixedRect(height),ToFixedRect(width));

        if (this.BorderColor) 
        {
            this.Canvas.strokeStyle=this.BorderColor;
            this.Canvas.strokeRect(ToFixedPoint(x),ToFixedPoint(y),ToFixedRect(height),ToFixedRect(width))
        }
    }

    this.HScreenDraw=function()
    {
        var x=this.LastPoint.X;
        var y=this.LastPoint.Y;

        if (this.IsOnlyDrawKLine)   //手机端 十字只能画在K线上
            y=this.Frame.GetXFromIndex(this.CursorIndex);

        var border=this.Frame.ChartBorder.GetHScreenBorder();
        var left=border.Left;
        var right=border.Right;
        var top=border.Top;
        var bottom=border.Bottom;
        var bottomWidth=this.Frame.ChartBorder.Bottom;

        if (this.CallAcutionXOperator)
        {
            this.CallAcutionXOperator.Value=y;
            this.CallAcutionXOperator.Point={X:x, Y:y};
            this.CallAcutionXOperator.ClientPos=this.ClientPos;

            if (this.CallAcutionXOperator.Operator())
            {
                y=this.CallAcutionXOperator.X;
            }
        }

        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.VLineType==1)
            {
                this.Canvas.moveTo(left,ToFixedPoint(y));
                this.Canvas.lineTo(right,ToFixedPoint(y));
            }
            else
            {
                if (this.Frame.SubFrame.length>0)
                {
                    for(var i in this.Frame.SubFrame)
                    {
                        var frame=this.Frame.SubFrame[i].Frame;
                        var subBorder=frame.ChartBorder.GetHScreenBorder();
                        this.Canvas.moveTo(subBorder.Left,ToFixedPoint(y));
                        this.Canvas.lineTo(subBorder.RightEx,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.StringFormatX.Point={X:x, Y:y};
        this.StringFormatX.ClientPos=this.ClientPos;

        this.StringFormatY.Value=yValue;
        this.StringFormatY.FrameID=yValueExtend.FrameID;
        this.StringFormatY.Point={X:x, Y:y};
        this.StringFormatY.ClientPos=this.ClientPos;

        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.StringFormatY.RText) 
            {
                text=this.StringFormatY.RText;
                var textWidth=this.Canvas.measureText(text).width+4;    //前后各空2个像素
            }

            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);
                }

                if (this.StringFormatY.RExtendText && this.StringFormatY.RExtendText.length>0)
                {
                    var yOffset=0;
                    for(var i in this.StringFormatY.RExtendText)
                    {
                        var item=this.StringFormatY.RExtendText[i];
                        var rText='--.--'
                        if (item.YText) rText=item.YText;
                        else if (IFrameSplitOperator.IsNumber(item.Y)) rText=item.Y.toFixed(0);
                        var rTextWidth=this.Canvas.measureText(rText).width+4;    //前后各空2个像素
                        
                        this.Canvas.fillStyle=item.TextBGColor;
                        if (bottomWidth>rTextWidth)
                        {
                            this.Canvas.fillRect(0,yOffset+this.TextHeight/2,rTextWidth,this.TextHeight);
                            this.Canvas.textAlign="left";
                            this.Canvas.textBaseline="middle";
                            this.Canvas.fillStyle=item.TextColor;
                            this.Canvas.fillText(rText,2,yOffset+this.TextHeight,rTextWidth);
                        }
                        else
                        {
                            var rTextLeft=bottomWidth-rTextWidth;
                            this.Canvas.fillRect(rTextLeft,yOffset+this.TextHeight/2,rTextWidth,this.TextHeight);
                            this.Canvas.textAlign="left";
                            this.Canvas.textBaseline="middle";
                            this.Canvas.fillStyle=item.TextColor;
                            this.Canvas.fillText(rText,rTextLeft+2,yOffset+this.TextHeight,rTextWidth);
                        }
                        

                        yOffset+=this.TextHeight;
                    }
                }

                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,2,this.TextHeight/2,textWidth);

                this.Canvas.restore();
            }
            else if (y+textWidth/2>=bottom)
            {
                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,0,textWidth,this.TextHeight);
                this.Canvas.textAlign="right";
                this.Canvas.textBaseline="middle";
                this.Canvas.fillStyle=this.TextColor;
                this.Canvas.fillText(text,-2,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();
            }
        }

        this.Status=1;
    }
}


////////////////////////////////////////////////////////////////////////////////
//深度图十字光标
function DepthChartCorssCursor()
{
    this.Frame;
    this.HQChart;
    this.Canvas;                            //画布
    this.Data;
    this.Symbol;

    this.HPenType=0;  //水平线样式 0=虚线 1=实线
    this.VPenType=0;  //垂直线颜色 0=虚线 1=实线
    this.LineDash=g_JSChartResource.DepthCorss.LineDash;
    this.IsShowTooltip=true;

    this.AskColor=g_JSChartResource.DepthCorss.AskColor.Line;   //卖
    this.BidColor=g_JSChartResource.DepthCorss.BidColor.Line;   //买
    this.LineWidth=g_JSChartResource.DepthCorss.LineWidth;

    this.ClassName="DepthChartCorssCursor";

    this.Tooltip=
    { 
        LineHeight:g_JSChartResource.DepthCorss.Tooltip.LineHeight, 
        Border:
        { 
            Top:g_JSChartResource.DepthCorss.Tooltip.Border.Top, 
            Left:g_JSChartResource.DepthCorss.Tooltip.Border.Left, 
            Bottom:g_JSChartResource.DepthCorss.Tooltip.Border.Bottom, 
            Center: g_JSChartResource.DepthCorss.Tooltip.Border.Center
        },
        Font:g_JSChartResource.DepthCorss.Tooltip.Font,
        TextColor:g_JSChartResource.DepthCorss.Tooltip.TextColor,
        BGColor:g_JSChartResource.DepthCorss.Tooltip.BGColor
    };    // Width: Height:

    this.Font=g_JSChartResource.CorssCursorTextFont;            //字体
    this.TextColor=g_JSChartResource.CorssCursorTextColor;      //文本颜色
    this.TextBGColor=g_JSChartResource.CorssCursorBGColor;      //文本背景色
    this.TextHeight=20;                                         //文本字体高度
    this.LastPoint;

    this.PointX;
    this.PointY;

    this.StringFormatX;
    this.StringFormatY;

    this.IsShowCorss=true;  //是否显示十字光标
    this.IsShow=true;
    //this.LanguageID=JSCHART_LANGUAGE_ID.LANGUAGE_CHINESE_ID;    //多语言

    this.GetVol=function(price, isAsk)
    {
        if (!this.Data) return null;
        var aryData=isAsk? this.Data.Asks:this.Data.Bids;
        if (!aryData || !Array.isArray(aryData) || aryData.length<=0) return null;

        for(var i in aryData)
        {
            var item=aryData[i];
            if (item.Price==price) return item.Vol;
        }

        return null;
    }

    this.Draw=function()
    {
        this.Status=0;
        if (!this.LastPoint) return;
        if (!this.Data) return;
        if (!this.IsShow) return;

        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)
        {
            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();

        var xValue=this.Frame.GetXData(x);
        var xInfo=this.Frame.GetXFromPrice(xValue); //调整价格到有数据的点上

        if (!xInfo) return;

        var yVol=this.GetVol(xInfo.Price, xInfo.IsAsk);
        y=this.Frame.GetYFromData(yVol);    //调整Y轴, 让它在线段上

        xInfo.Vol=yVol;
        xInfo.Y=y;
        
        this.PointY=[[left,y],[right,y]];
        this.PointX=[[x,top],[x,bottom]];

        if (this.IsShowCorss)
        {
            if (xInfo.IsAsk) this.Canvas.strokeStyle=this.AskColor;
            else this.Canvas.strokeStyle=this.BidColor;
            var lineWidthBackup=this.Canvas.lineWidth;
            var pixel=GetDevicePixelRatio();
            this.Canvas.lineWidth=this.LineWidth*pixel;
            var lineWidth=this.Canvas.lineWidth;

            if (this.HPenType==1 || this.HPenType==0)   //0=实线 1=虚线
            {
                if (this.HPenType==0) this.Canvas.setLineDash(this.LineDash);   //虚线
                var yFix=ToFixedPoint2(lineWidth, y);
                this.Canvas.beginPath();
                this.Canvas.moveTo(left,yFix);
                this.Canvas.lineTo(right,yFix);
                this.Canvas.stroke();
                if (this.HPenType==0) this.Canvas.setLineDash([]);
            }
            
            if (this.VPenType==0) this.Canvas.setLineDash(this.LineDash);   //虚线
            var xFix=ToFixedPoint2(lineWidth, xInfo.X);
            this.Canvas.beginPath();
            this.Canvas.moveTo(xFix,top);
            this.Canvas.lineTo(xFix,bottom);
            this.Canvas.stroke();
            if (this.VPenType==0) this.Canvas.setLineDash([]);

            this.Canvas.lineWidth=lineWidthBackup;
        }

        if (this.HQChart)
        {
            var event=this.HQChart.GetEventCallback(JSCHART_EVENT_ID.ON_DRAW_DEPTH_TOOLTIP);
            if (event)
            {
                event.Callback(event,xInfo,this);
            }
        }

        if (this.IsShowTooltip) this.DrawTooltip(xInfo);
    }

    this.DrawTooltip=function(data)
    {
        var price=data.Price;
        var vol=data.Vol;
        var pixel=GetDevicePixelRatio();
        var border=this.Tooltip.Border;
        this.Canvas.font=this.Tooltip.Font;
        var floatPrecision=2;
        if (this.Symbol) floatPrecision=GetfloatPrecision(this.Symbol);//价格小数位数
        var maxText='擎擎: 9999.99亿 ';
        if (floatPrecision>=5) maxText=`擎擎: ${99.99.toFixed(floatPrecision)} `;  //小数位数太多了
        this.Tooltip.Width=this.Canvas.measureText(maxText).width+border.Left*pixel;
        this.Tooltip.Height=this.Tooltip.LineHeight*pixel*4+border.Top*pixel+border.Bottom*pixel+border.Center*pixel;

        var chartRight=this.Frame.ChartBorder.GetRight();
        var chartTop=this.Frame.ChartBorder.GetTop();
        
        var left=data.X+2*pixel;
        var top=data.Y-this.Tooltip.Height-2*pixel;
        if (left+this.Tooltip.Width>=chartRight) left=data.X-this.Tooltip.Width-2*pixel;
        if (top<chartTop) top=data.Y+2*pixel;

        this.Canvas.fillStyle=this.Tooltip.BGColor;
        this.Canvas.fillRect(left,top,this.Tooltip.Width,this.Tooltip.Height);

        var x=border.Left*pixel+left;
        var y=border.Top*pixel+top;

        this.Canvas.textBaseline="top";
        this.Canvas.textAlign="left";
        this.Canvas.fillStyle=this.Tooltip.TextColor;
        var text=g_JSChartLocalization.GetText('Depth-Price',this.HQChart.LanguageID);
        this.Canvas.fillText(text,x,y);
        y+=this.Tooltip.LineHeight*pixel;
        this.Canvas.fillText(data.Price.toFixed(floatPrecision),x,y);
        y+=this.Tooltip.LineHeight*pixel;
        y+=border.Center*pixel;

        var text=g_JSChartLocalization.GetText('Depth-Sum',this.HQChart.LanguageID);
        this.Canvas.fillText(text,x,y);
        y+=this.Tooltip.LineHeight*pixel;
        this.Canvas.fillText(data.Vol.toFixed(4),x,y);
    }

    this.PtInButton=function(x,y)
    {
        return null;
    }
}
////////////////////////////////////////////////////////////////////////////////
// 等待提示
function ChartSplashPaint()
{
    this.Frame;
    this.Canvas;                            //画布
    this.Font=g_JSChartResource.DefaultTextFont;            //字体
    this.TextColor=g_JSChartResource.DefaultTextColor;      //文本颜色
    this.IsEnableSplash=false;
    this.SplashTitle='数据加载中';
    this.HQChart;

    this.EnableSplash=function(bEnable)
    {
        this.IsEnableSplash=bEnable;
        if (this.HQChart)
        {
            var event=this.HQChart.GetEventCallback(JSCHART_EVENT_ID.ON_ENABLE_SPLASH_DRAW);
            if (event)
            {
                var data={ Enable:bEnable };
                event.Callback(event,data,this);
            }
        }
    }

    this.SetTitle=function(title)
    {
        this.SplashTitle=title;
    }

    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;
    }
}

//数值放大
var ZOOM_VALUE= [1,10,100,1000,10000,100000,1000000,10000000,100000000,1000000000,10000000000];

function HQPriceStringFormat()
{
    this.newMethod=IChangeStringFormat;   //派生
    this.newMethod();
    delete this.newMethod;

    this.Symbol;
    this.FrameID;
    this.Frame;
    this.LanguageID=JSCHART_LANGUAGE_ID.LANGUAGE_CHINESE_ID;
    this.YClose;            //收盘价
    this.PercentageText;    //百分比
    this.RValue;            //右边值
    this.RText;
    this.Point;
    this.ClientPos=-1;

    this.ExtendChartPaint;
    this.RExtendText=[];
    this.BeforeOpenData;
    this.AfterCloseData;
    this.MultiDayBeforeOpenData;
    this.MultiDayAfterCloseData;

    //盘前集合竞价
    this.GetBeforeOpen=function()
    {
        if (!this.Frame) return false;

        var item=this.Frame.SubFrame[this.FrameID];
        if (!item || !item.Frame) return false;

        var range={ Max:this.BeforeOpenData.VolMax, Min:this.BeforeOpenData.VolMin };
        var y=this.Frame.IsHScreen? this.Point.X: this.Point.Y;
        var value=item.Frame.GetLeftExtendYData(y,false,{ Range:range } );
        var defaultfloatPrecision=2;     //价格小数位数 
        if (IFrameSplitOperator.IsNumber(value))  
        {
            this.RText=this.Text;
            this.Text=IFrameSplitOperator.FormatValueString(value,defaultfloatPrecision,this.LanguageID);
        }
    }

    //收盘集合竞价
    this.GetAfterClose=function()
    {
        if (!this.Frame) return false;

        var item=this.Frame.SubFrame[this.FrameID];
        if (!item || !item.Frame) return false;

        var range={ Max:this.AfterCloseData.VolMax, Min:this.AfterCloseData.VolMin };
        var y=this.Frame.IsHScreen? this.Point.X: this.Point.Y;
        var value=item.Frame.GetRightExtendYData(y,false,{ Range:range } );
        var defaultfloatPrecision=2;     //价格小数位数 
        if (IFrameSplitOperator.IsNumber(value))  
        {
            this.RText=IFrameSplitOperator.FormatValueString(value,defaultfloatPrecision,this.LanguageID);
        }
    }

    this.GetMultiDayBeforeOpen=function()
    {
        if (!this.Frame) return false;
        var item=this.Frame.SubFrame[this.FrameID];
        if (!item || !item.Frame) return false;
        if (!this.MultiDayBeforeOpenData || !IFrameSplitOperator.IsNonEmptyArray(this.MultiDayBeforeOpenData)) return;
        var dayIndex=this.ClientPos-200;
        if (dayIndex<0 || dayIndex>=this.MultiDayBeforeOpenData.length) return false;
        var dayData=this.MultiDayBeforeOpenData[dayIndex];
        var range={ Max:dayData.VolMax, Min:dayData.VolMin };
        var y=this.Frame.IsHScreen? this.Point.X: this.Point.Y;
        var value=item.Frame.GetLeftExtendYData(y,false,{ Range:range } );
        var defaultfloatPrecision=2;     //价格小数位数 
        if (IFrameSplitOperator.IsNumber(value))  
        {
            this.RText=this.Text;
            this.Text=IFrameSplitOperator.FormatValueString(value,defaultfloatPrecision,this.LanguageID);
        }
    }

    this.GetMultiDayAfterClose=function()
    {
        if (!this.Frame) return false;
        var item=this.Frame.SubFrame[this.FrameID];
        if (!item || !item.Frame) return false;
        if (!this.MultiDayAfterCloseData || !IFrameSplitOperator.IsNonEmptyArray(this.MultiDayAfterCloseData)) return;
        var dayIndex=this.ClientPos-300;
        if (dayIndex<0 || dayIndex>=this.MultiDayAfterCloseData.length) return false;
        var dayData=this.MultiDayAfterCloseData[dayIndex];   
        
        var range={ Max:dayData.VolMax, Min:dayData.VolMin };
        var y=this.Frame.IsHScreen? this.Point.X: this.Point.Y;
        var value=item.Frame.GetRightExtendYData(y,false,{ Range:range } );
        var defaultfloatPrecision=2;     //价格小数位数 
        if (IFrameSplitOperator.IsNumber(value))  
        {
            this.RText=IFrameSplitOperator.FormatValueString(value,defaultfloatPrecision,this.LanguageID);
        }
    }

    this.Operator=function()
    {
        this.RText=null;
        this.RExtendText=[];
        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);   //走势图右边坐标显示百分比

            this.GetExtendPaintData(defaultfloatPrecision);
        }
        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);
            if (this.ClientPos==2) this.GetBeforeOpen();
            else if (this.ClientPos==3) this.GetAfterClose();
            else if (this.ClientPos>=200 && this.ClientPos<=299) this.GetMultiDayBeforeOpen();
            else if (this.ClientPos>=300 && this.ClientPos<=399) this.GetMultiDayAfterClose();
        }
        else
        {
            this.Text=IFrameSplitOperator.FormatValueString(this.Value,defaultfloatPrecision,this.LanguageID);
        }

        return true;
    }

    //深度图刻度
    this.GetExtendPaintData=function(floatPrecision)
    {
        var value=parseInt(this.Value*ZOOM_VALUE[floatPrecision]);
        for(var i in this.ExtendChartPaint)
        {
            var item=this.ExtendChartPaint[i];
            if (item.ClassName=='DepthMapPaint' && item.FrameID==this.FrameID)
            {
                var aryData=item.GetYValueByXValue(value,floatPrecision);
                for(var j in aryData)
                {
                    this.RExtendText.push(aryData[j]);
                }
            }
        }
    }
}

function HQDateStringFormat()
{
    this.newMethod=IChangeStringFormat;   //派生
    this.newMethod();
    delete this.newMethod;

    this.DateFormatType=0;  //0=YYYY-MM-DD 1=YYYY/MM/DD  2=YYYY/MM/DD/W 3=DD/MM/YYYY
    this.LanguageID=0;

    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];
        var dateFormatString="YYYY-MM-DD";
        if (this.DateFormatType==1) dateFormatString="YYYY/MM/DD";
        else if (this.DateFormatType==2) dateFormatString="YYYY/MM/DD/W";
        else if (this.DateFormatType==3) dateFormatString="DD/MM/YYYY";
        this.Text=IFrameSplitOperator.FormatDateString(currentData.Date, dateFormatString,this.LanguageID);
        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.Point;
    this.ClientPos=-1;
    this.BeforeOpenData;    //单日分时图 盘前数据
    this.AfterCloseData;    //单日分时图 收盘数据

    this.MultiDayBeforeOpenData;    //多日分时图 盘前数据
    this.MultiDayAfterCloseData;    //多日分时图 收盘数据

    this.GetBeforeOpen=function()
    {
        if (!this.BeforeOpenData || !this.BeforeOpenData.Data) return false;

        var x=this.Frame.IsHScreen==true?this.Point.Y:this.Point.X;
        var index=this.Frame.GetLeftExtendXData(x, this.BeforeOpenData);
        index=parseInt(index.toFixed(0));
        if (index>=this.BeforeOpenData.Data.length) return false;

        var item=this.BeforeOpenData.Data[index];
        this.Text=this.FormatCallAcutionDateTime(item, this.BeforeOpenData);

        return true;
    }

    this.GetAfterClose=function()
    {
        if (!this.AfterCloseData || !this.AfterCloseData.Data) return false;

        var x=this.Frame.IsHScreen==true?this.Point.Y:this.Point.X;
        var index=this.Frame.GetRightExtendXData(x, this.AfterCloseData);
        index=parseInt(index.toFixed(0));
        if (index>=this.AfterCloseData.Data.length) return false;

        var item=this.AfterCloseData.Data[index];
        this.Text=this.FormatCallAcutionDateTime(item, this.AfterCloseData);

        return true;
    }

    this.GetMultiDayBeforeOpen=function()
    {
        if (!this.MultiDayBeforeOpenData || !this.MultiDayBeforeOpenData ) return false;
        if (this.Frame.ChartBorder.MultiDayMinute.Count<=1 || this.Frame.ChartBorder.MultiDayMinute.Left<=0) return false;

        var x=this.Frame.IsHScreen==true?this.Point.Y:this.Point.X;
        var index=this.Frame.GetLeftExtendXData(x, this.MultiDayBeforeOpenData);
        if (!index) return false;

        if (index.DayIndex>=this.MultiDayBeforeOpenData.length) return false;
        var dayItem=this.MultiDayBeforeOpenData[index.DayIndex];
        index.DataIndex=parseInt(index.DataIndex.toFixed(0));
        if (index.DataIndex>=dayItem.Data.length) return false;

        var item=dayItem.Data[index.DataIndex];
        this.Text=this.FormatCallAcutionDateTime(item, dayItem);

        return true;
    }

    this.GetMultiDayAfterClose=function()
    {
        if (!this.MultiDayAfterCloseData) return false;
        if (this.Frame.ChartBorder.MultiDayMinute.Count<=1 || this.Frame.ChartBorder.MultiDayMinute.Right<=0) return false;

        var x=this.Frame.IsHScreen==true?this.Point.Y:this.Point.X;
        var index=this.Frame.GetRightExtendXData(x, this.MultiDayAfterCloseData);
        if (!index) return false;
        if (index.DayIndex>=this.MultiDayAfterCloseData.length) return false;
        var dayItem=this.MultiDayAfterCloseData[index.DayIndex];
        index.DataIndex=parseInt(index.DataIndex.toFixed(0));
        if (index.DataIndex>=dayItem.Data.length) return false;

        var item=dayItem.Data[index.DataIndex];
        this.Text=this.FormatCallAcutionDateTime(item, dayItem);

        return true;
    }

    this.FormatCallAcutionDateTime=function(item, callAcutionData)
    {
        var time=item.Time;
        if (callAcutionData.Ver==1.0) 
            return IFrameSplitOperator.FormatTimeString(time,"HH:MM");
        else 
            return IFrameSplitOperator.FormatTimeString(time,"HH:MM:SS");
    }

    this.Operator=function()
    {
        if (this.ClientPos==2) return this.GetBeforeOpen();
        else if (this.ClientPos==3) return this.GetAfterClose();
        else if (this.ClientPos>=200 && this.ClientPos<=299) return this.GetMultiDayBeforeOpen();
        else if (this.ClientPos>=300 && this.ClientPos<=399) return this.GetMultiDayAfterClose();

        if (!IFrameSplitOperator.IsNumber(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 (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.Title.VolColor;
    this.AmountColor=g_JSChartResource.Title.AmountColor;
    this.TurnoverRateColor=g_JSChartResource.Title.TurnoverRateColor;
    this.PositionColor=g_JSChartResource.Title.PositionColor;
    this.LanguageID=JSCHART_LANGUAGE_ID.LANGUAGE_CHINESE_ID;
    this.LineCount=0;                   //一共几行
    this.LineHeight=g_JSChartResource.PCTooltip.LineHeight;                 //单行高度
    this.Width=157;                     //宽度
    this.Height=this.LineHeight*5;      //高度
    

    this.Operator=function()
    {
        var data=this.Value.Data;
        if (!data) return false;

        this.Width=157;
        if (this.LanguageID==JSCHART_LANGUAGE_ID.LANGUAGE_ENGLISH_ID) this.Width=180;

        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);
        var isTickPeriod=ChartData.IsTickPeriod(this.Value.ChartPaint.Data.Period);
        if (ChartData.IsMinutePeriod(this.Value.ChartPaint.Data.Period,true)) // 分钟周期
        {
            title2=IFrameSplitOperator.FormatTimeString(data.Time);
        }
        else if (ChartData.IsSecondPeriod(this.Value.ChartPaint.Data.Period) || isTickPeriod)
        {
            title2=IFrameSplitOperator.FormatTimeString(data.Time,'HH:MM:SS');
        }

        var upperSymbol=this.Symbol.toUpperCase();
        var defaultfloatPrecision=GetfloatPrecision(this.Symbol);//价格小数位数
        var increase=null;
        if (data.YClose>0) increase=(data.Close-data.YClose)/data.YClose*100;
        if (isTickPeriod)
        {
            var strText=
            "<span class='tooltip-title'>"+strDate+"&nbsp&nbsp"+title2+"</span>"+
            "<span class='tooltip-con'>"+g_JSChartLocalization.GetText('DivTooltip-Price',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-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=4;
        }
        else
        {
            var vol=data.Vol;
            if (upperSymbol && MARKET_SUFFIX_NAME.IsSHSZ(upperSymbol)) vol/=100; //A股统一转成手
            var strText=
                "<span class='tooltip-title'>"+strDate+"&nbsp&nbsp"+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'>&nbsp;前收: "+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(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.TurnoverRateColor+";'>"+value.toFixed(2)+'%'+"</span><br/>";
                ++this.LineCount;
            }

            if (MARKET_SUFFIX_NAME.IsFutures(upperSymbol) && IFrameSplitOperator.IsNumber(data.Position))
            {
                strText+= "<span class='tooltip-con'>"+g_JSChartLocalization.GetText('DivTooltip-Position',this.LanguageID)+"</span>" +
                    "<span class='tooltip-num' style='color:"+this.PositionColor+";'>"+data.Position+"</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;

        this.Height=this.LineCount*this.LineHeight;
        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.Width=500;

    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+"&nbsp;&nbsp;&nbsp;"+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>&nbsp;&nbsp;<i class='tipBoxTitle'>成交价:&nbsp;"+showPriceInfo.Price.toFixed(2)+"</i><i class='tipBoxTitle'>收盘价:&nbsp;"+showPriceInfo.ClosePrice.toFixed(2)+
            "</i><br/><i class='rate-discount tipBoxTitle'>溢折价率:&nbsp;<strong style='color:"+ this.GetColor(showPriceInfo.Premium.toFixed(2))+"'>"+
            showPriceInfo.Premium.toFixed(2)+"%</strong></i><i class='tipBoxTitle'>成交量(万股):&nbsp;"+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+"&nbsp;&nbsp;&nbsp;上榜原因:&nbsp;&nbsp;</i><i class='reason-list'>"+reasons+"</i><br/><i class='trade-detall'>一周后涨幅:&nbsp;<strong style='color:"+
            this.GetColor(item.ExtendData.FWeek.Week1.toFixed(2))+"'>"+ item.ExtendData.FWeek.Week1.toFixed(2)+
            "%</strong>&nbsp;&nbsp;&nbsp;四周后涨幅:&nbsp;<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'>证券代表&nbsp;&nbsp;&nbsp;</i>";
                else if(levels[j]==1) recPerson+="<i>董秘&nbsp;&nbsp;&nbsp;</i>";
                else if(levels[j]==2) recPerson+="<i style='color:#00a0e9'>总经理&nbsp;&nbsp;&nbsp;</i>";
                else if(levels[j]==3) recPerson+="<i style='color:#00a0e9'>董事长&nbsp;&nbsp;&nbsp;</i>";
            }

            recPerson='接待:&nbsp;&nbsp;&nbsp;'+recPerson;
        }

        var researchType='';
        if (item.ExtendData.Type && item.ExtendData.Type!='其他')
        {
            researchType='&nbsp;&nbsp;&nbsp;'+'<i>'+item.ExtendData.Type+'</i>';
            if (levels.length==0) recPerson='';
        }

        var strDate=IFrameSplitOperator.FormatDateString(item.Date);
        var strText="<span>"+strDate+"&nbsp;&nbsp;&nbsp;"+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+="&nbsp;四周后涨幅:<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/>&nbsp;&nbsp;<i class='prorecast-week'>"+weekData+"</i>";
        }
        var strDate=IFrameSplitOperator.FormatDateString(item.Date);
        var strText="<span>"+strDate+"&nbsp;&nbsp;"+year+reportType+item.Title+"&nbsp;"+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 KLineTradeDataStringFormat()
{
    this.newMethod=IChangeStringFormat;   //派生
    this.newMethod();
    delete this.newMethod;

    this.Width=120;
    this.Operator=function()
    {
        var data=this.Value.Data;
        if (!data) return false;

        var item=data.Data;
        var title=`<span class='tooltip-index-name'>${item.Name}${item.Param}:</span>`;
        var content;
        if (item.Type==1) content=`<span class='tooltip-index-buy'>买入</span>`;
        else content=`<span class='tooltip-index-sell'>卖出</span>`;

        this.Text=title+content;
        return true;
    }
}

//分时图异动信息格式化
function MinuteInfoDataStringFormat()
{
    this.newMethod=IChangeStringFormat;   //派生
    this.newMethod();
    delete this.newMethod;

    this.Width=200;
    this.Operator=function()
    {
        var data=this.Value.Data;
        if (!data) return false;

        var item=data.Data.Item;
        var strTime=IFrameSplitOperator.FormatTimeString(item.Time);
        var time=`<span class='tooltip-minuteinfo-time'>${strTime} </span>`;
        var content=`<span class='tooltip-minuteinfo-content'>${item.Title}</span>`;
        if (item.Content) content=`<span class='tooltip-minuteinfo-content'>${item.Content}</span>`;

        this.Text=time+content;
        return true;
    }
}

function IconDataStringFormat()
{
    this.newMethod=IChangeStringFormat;   //派生
    this.newMethod();
    delete this.newMethod;

    this.Width=200;
    this.Operator=function()
    {
        if (!this.Value || !this.Value.Data) return false;
        var data=this.Value.Data;
        if (!data.Item) return false;
        if (!data.Item.Text) return false;
        
        this.Text=data.Item.Text;
        return true;
    }
}

function DivTooltipDataForamt()
{
    this.DataMap=new Map(
        [
            ["KLineTradeDataStringFormat",      { Create:function() { return new KLineTradeDataStringFormat(); }  }],
            ["MinuteInfoDataStringFormat",      { Create:function() { return new MinuteInfoDataStringFormat(); }  }],
            ["HistoryDataStringFormat",         { Create:function() { return new HistoryDataStringFormat(); }  }],
            ["KLineInfoDataStringFormat",       { Create:function() { return new KLineInfoDataStringFormat(); }  }],
            ["IconDataStringFormat",            { Create:function() { return new IconDataStringFormat(); } }],

            ["CorssCursor_XStringFormat", { Create:function() { return new HQDateStringFormat(); } }],
            ["CorssCursor_YStringFormat", { Create:function() { return new HQPriceStringFormat(); } }]
        ]
    );

    this.Create=function(name)
    {
        if (!this.DataMap.has(name)) return null;

        var item=this.DataMap.get(name);
        return item.Create();
    }
}

var g_DivTooltipDataForamt=new DivTooltipDataForamt();

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//                      标题
//
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////

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';
    this.DrawStatus;
    this.GetEventCallback;

    this.ReloadResource=function()
    {
        this.Font=g_JSChartResource.TitleFont;
        this.TitleColor=g_JSChartResource.DefaultTextColor;
    }
}

//var PERIOD_NAME=["日线","周线","月线","年线","1分","5分","15分","30分","60分","季线","分笔", "2小时","4小时","双周","",""];
var RIGHT_NAME=['不复权','前复权','后复权'];

function DynamicKLineTitlePainting()
{
    this.newMethod=IChartTitlePainting;   //派生
    this.newMethod();
    delete this.newMethod;

    this.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.Title.VolColor;
    this.AmountColor=g_JSChartResource.Title.AmountColor;
    this.DateTimeColor=g_JSChartResource.Title.DateTimeColor;
    this.NameColor = g_JSChartResource.Title.NameColor;
    this.SettingColor=g_JSChartResource.Title.SettingColor;   //周期 复权
    this.TurnoverRateColor=g_JSChartResource.Title.TurnoverRateColor;   //换手率
    this.PositionColor=g_JSChartResource.Title.PositionColor;   //持仓

    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.ReloadResource=function()
    {
        this.Font=g_JSChartResource.TitleFont;

        this.TitleColor=g_JSChartResource.DefaultTextColor;

        this.UpColor=g_JSChartResource.UpTextColor;
        this.DownColor=g_JSChartResource.DownTextColor;
        this.UnchagneColor=g_JSChartResource.UnchagneTextColor;

        this.VolColor=g_JSChartResource.Title.VolColor;
        this.AmountColor=g_JSChartResource.Title.AmountColor;
        this.DateTimeColor=g_JSChartResource.Title.DateTimeColor;
        this.NameColor = g_JSChartResource.Title.NameColor;
        this.SettingColor=g_JSChartResource.Title.SettingColor;
        this.TurnoverRateColor=g_JSChartResource.Title.TurnoverRateColor;   //换手率
        this.PositionColor=g_JSChartResource.Title.PositionColor;   //持仓
    }

    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);//价格小数位数
        var upperSymbol=this.Symbol.toUpperCase();

        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.NameColor,position)) return;
        }

        if (this.IsShowSettingInfo)
        {
            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+")";

            if (!MARKET_SUFFIX_NAME.IsEnableRight(this.Data.Period, this.Symbol)) text="("+periodName+")";
            if (!this.DrawText(text,this.SettingColor,position)) return;
        }

        if (this.IsShowDateTime)    //是否显示日期
        {
            var text=IFrameSplitOperator.FormatDateString(item.Date);
            if (!this.DrawText(text,this.DateTimeColor,position)) return;
        }

        var isTickPeriod=ChartData.IsTickPeriod(this.Period);

        if (ChartData.IsMinutePeriod(this.Period,true) && IFrameSplitOperator.IsNumber(item.Time))
        {
            var text=IFrameSplitOperator.FormatTimeString(item.Time);
            if (!this.DrawText(text,this.DateTimeColor,position)) return;
        }
        else if (ChartData.IsSecondPeriod(this.Period) && IFrameSplitOperator.IsNumber(item.Time))
        {
            var text=IFrameSplitOperator.FormatTimeString(item.Time, "HH:MM:SS");
            if (!this.DrawText(text,this.DateTimeColor,position)) return;
        }
        else if (isTickPeriod)
        {
            var text=IFrameSplitOperator.FormatTimeString(item.Time, "HH:MM:SS");
            if (!this.DrawText(text,this.DateTimeColor,position)) return;
        }

        if (isTickPeriod)
        {
            var color=this.GetColor(item.Open,item.YClose);
            var text=g_JSChartLocalization.GetText('KTitle-Price',this.LanguageID)+item.Open.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;
            }

            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.YFClose>0 && MARKET_SUFFIX_NAME.IsChinaFutures(upperSymbol))
        {
            var value=(item.Close-item.YFClose)/item.YFClose*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;
        }
        else 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 vol=item.Vol;
        if (upperSymbol && MARKET_SUFFIX_NAME.IsSHSZ(upperSymbol)) vol/=100;   //A股原始单位股, 转成股
        var text=g_JSChartLocalization.GetText('KTitle-Vol',this.LanguageID)+IFrameSplitOperator.FromatIntegerString(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.TurnoverRateColor,position)) return;
        }

        if (MARKET_SUFFIX_NAME.IsFutures(upperSymbol) && IFrameSplitOperator.IsNumber(item.Position))  //持仓量
        {
            var text=g_JSChartLocalization.GetText('KTitle-Position',this.LanguageID)+item.Position;
            if (!this.DrawText(text,this.PositionColor,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};
        if (this.Data && this.Data.Data)
        {
            var index=Math.abs(this.CursorIndex);
            index=parseInt(index.toFixed(0));
            var dataIndex=this.Data.DataOffset+index;
            var dataCount=this.Data.Data.length;

            data.DataIndex=dataIndex;
            data.DataCount=dataCount;
        }

        //叠加股票
        if (IFrameSplitOperator.IsNonEmptyArray(this.OverlayChartPaint))
        {
            data.OverlayStock=[];
            for(var i=0; i<this.OverlayChartPaint.length; ++i)
            {
                var item=this.OverlayChartPaint[i];
                if (!item.Symbol || !item.Title) continue;
            
                data.OverlayStock.push({ Symbol:item.Symbol, Name:item.Title });
            }
        }
        

        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.IsShowTime=true;   //标题是否显示时间
    this.IsShowName=true;   //标题是否显示股票名字
    this.IsShowAveragePrice=true;   //是否显示均线价格
    this.OverlayChartPaint; //叠加画法
    this.LanguageID=JSCHART_LANGUAGE_ID.LANGUAGE_CHINESE_ID;
    this.LastShowData;  //保存最后显示的数据 给tooltip用
    this.OnDrawEvent;
    this.PointInfo=null;
    this.IsAlwaysShowLastData=false;    //始终显示最后一个数据

    this.MultiDayBeforeOpenData;    //多日分时图 盘前数据
    this.MultiDayAfterCloseData;    //多日分时图 收盘数据

    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);
        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.GetLatestKLineData=function()  //获取最新一个K线数据
    {
        if (!this.Data || !this.Data.Data) return null;
        var count=this.Data.Data.length;
        if (count<=0) return null;

        return this.Data.Data[count-1];
    }

    this.DrawItem=function(item, isLastOne)    //isLastOne 是否是最后一个数据
    {
        var isHScreen=this.Frame.IsHScreen===true;
        var border=this.Frame.GetBorder();
        var left=border.Left;
        var bottom=border.Top-this.Frame.ChartBorder.Top/2;
        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 xText=border.ChartWidth;
            var yText=border.Top;
            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;
        }

        if (this.IsShowDate || this.IsShowTime)
        {
            var text=IFrameSplitOperator.FormatDateTimeString(item.DateTime,this.IsShowDate, this.IsShowTime);
            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;
        else if (MARKET_SUFFIX_NAME.IsShowAvPrice && !MARKET_SUFFIX_NAME.IsShowAvPrice(upperSymbol)) isShowAvPrice=false;

        if (item.AvPrice && isShowAvPrice && this.IsShowAveragePrice)
        {
            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;
        }

        if (IFrameSplitOperator.IsNumber(item.Position))
        {
            var text=g_JSChartLocalization.GetText('MTitle-Position',this.LanguageID)+IFrameSplitOperator.FromatIntegerString(item.Position,2);
            if (!this.DrawText(text,this.VolColor,position)) return;
        }

        if (isLastOne)  //显示数据最后的更新时间
        {
            if (this.Data && this.Data.UpdateTime && IFrameSplitOperator.IsNumber(this.Data.UpdateTime.Date) && IFrameSplitOperator.IsNumber(this.Data.UpdateTime.Time))
            {
                var text=g_JSChartLocalization.GetText('MTitle-UpdateTime',this.LanguageID)+IFrameSplitOperator.FormatTimeString(this.Data.UpdateTime.Time, "HH:MM:SS");
                if (!this.DrawText(text,this.DateTimeColor,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.DrawCallAuction=function() //集合竞价标题
    {
        var isHScreen=this.Frame.IsHScreen===true;
        var border=this.Frame.GetBorder();

        var left=border.Left;
        var bottom=border.Top-this.Frame.ChartBorder.Top/2;
        var defaultfloatPrecision=GetfloatPrecision(this.Symbol);//价格小数位数
        var bDraw=true;
        if (isHScreen) 
        {
            var left=2;
            var bottom=this.Frame.ChartBorder.Right/2;    //上下居中显示
            var xText=border.ChartWidth;
            var yText=border.Top;
            this.Canvas.translate(xText, yText);
            this.Canvas.rotate(90 * Math.PI / 180);
        }
        else
        {
            if (this.Frame.ChartBorder.Top<5) bDraw=false;
        }

        this.Canvas.textAlign="left";
        this.Canvas.textBaseline="middle";
        this.Canvas.font=this.Font;
        var position = { Left: left, Bottom: bottom, IsHScreen: isHScreen };
        if(bDraw && this.IsShowName)
        {
            if (!this.DrawText(this.Name,this.NameColor,position)) return;
        }

        var strTime;
        var dataVersion=1;
        if (this.PointInfo.ClientPos==2)
        {
            if (!this.BeforeOpenData) return;
            if (!this.CallAcutionXOperator) return;

            this.CallAcutionXOperator.Value=isHScreen?this.PointInfo.Point.Y:this.PointInfo.Point.X;
            this.CallAcutionXOperator.Point={X:this.PointInfo.Point.X, Y:this.PointInfo.Point.Y};
            this.CallAcutionXOperator.ClientPos=this.PointInfo.ClientPos;
            var callbackData={Explain:"BeforeOpen", Data:null, DataIndex:null, DataTotalCount:this.BeforeOpenData.TotalCount };
            if (!this.CallAcutionXOperator.Operator())
            {
                this.OnDrawCallAuctionEventCallback(callbackData);
                return false;
            }

            callbackData.DataIndex=this.CallAcutionXOperator.DataIndex;
            var item=this.CallAcutionXOperator.Item;
            var time=item.Time;
            if (this.BeforeOpenData.Ver==1.0) strTime=IFrameSplitOperator.FormatTimeString(time,"HH:MM");
            else strTime=IFrameSplitOperator.FormatTimeString(time,"HH:MM:SS");

            dataVersion=this.BeforeOpenData.Ver;
            callbackData.Data=item;
        }
        else if (this.PointInfo.ClientPos==3)
        {
            if (!this.AfterCloseData) return;
            if (!this.CallAcutionXOperator) return;
            
            this.CallAcutionXOperator.Value=isHScreen?this.PointInfo.Point.Y:this.PointInfo.Point.X;
            this.CallAcutionXOperator.Point={X:this.PointInfo.Point.X, Y:this.PointInfo.Point.Y};
            this.CallAcutionXOperator.ClientPos=this.PointInfo.ClientPos;
            var callbackData={Explain:"AfterClose", Data:null, DataIndex:null, DataTotalCount:this.AfterCloseData.TotalCount };
            if (!this.CallAcutionXOperator.Operator())
            {
                this.OnDrawCallAuctionEventCallback(callbackData);
                return false;
            }

            callbackData.DataIndex=this.CallAcutionXOperator.DataIndex;
            var item=this.CallAcutionXOperator.Item;
            
            var time=item.Time;
            if (this.AfterCloseData.Ver==1.0) strTime=IFrameSplitOperator.FormatTimeString(time,"HH:MM");
            else strTime=IFrameSplitOperator.FormatTimeString(time,"HH:MM:SS");
            dataVersion=this.AfterCloseData.Ver;
            callbackData.Data=item;
        }
        else if (this.PointInfo.ClientPos>=200 && this.PointInfo.ClientPos<=299)
        {
            if (!this.MultiDayBeforeOpenData || !IFrameSplitOperator.IsNonEmptyArray(this.MultiDayBeforeOpenData) ) return;

            var x=this.Frame.IsHScreen==true?this.PointInfo.Point.Y:this.PointInfo.Point.X;
            this.CallAcutionXOperator.Value=x;
            this.CallAcutionXOperator.Point={X:this.PointInfo.Point.X, Y:this.PointInfo.Point.Y};
            this.CallAcutionXOperator.ClientPos=this.PointInfo.ClientPos;
            var callbackData={Explain:"MultiDayBeforeOpen", Data:null, DataIndex:null };
            if (!this.CallAcutionXOperator.Operator())
            {
                this.OnDrawCallAuctionEventCallback(callbackData);
                return false;
            }

            callbackData.DataIndex=this.CallAcutionXOperator.DataIndex;
            callbackData.DayIndex=this.CallAcutionXOperator.DayIndex;
            var dayItem=this.MultiDayBeforeOpenData[this.CallAcutionXOperator.DayIndex];
            var item=this.CallAcutionXOperator.Item;
            var time=item.Time;
            if (dayItem.Ver==1.0) strTime=IFrameSplitOperator.FormatTimeString(time,"HH:MM");
            else strTime=IFrameSplitOperator.FormatTimeString(time,"HH:MM:SS");
            var strDate=IFrameSplitOperator.FormatDateString(item.Date);

            strTime=`${strDate} ${strTime}`;

            dataVersion=dayItem.Ver;
            callbackData.Data=item;
        }
        else if (this.PointInfo.ClientPos>=300 && this.PointInfo.ClientPos<=399)
        {
            if (!this.MultiDayAfterCloseData || !IFrameSplitOperator.IsNonEmptyArray(this.MultiDayAfterCloseData) ) return;

            var x=this.Frame.IsHScreen==true?this.PointInfo.Point.Y:this.PointInfo.Point.X;
            this.CallAcutionXOperator.Value=x;
            this.CallAcutionXOperator.Point={X:this.PointInfo.Point.X, Y:this.PointInfo.Point.Y};
            this.CallAcutionXOperator.ClientPos=this.PointInfo.ClientPos;
            var callbackData={Explain:"MultiDayAfterClose", Data:null, DataIndex:null };
            if (!this.CallAcutionXOperator.Operator())
            {
                this.OnDrawCallAuctionEventCallback(callbackData);
                return false;
            }

            callbackData.DataIndex=this.CallAcutionXOperator.DataIndex;
            callbackData.DayIndex=this.CallAcutionXOperator.DayIndex;
            var dayItem=this.MultiDayAfterCloseData[this.CallAcutionXOperator.DayIndex];
            var item=this.CallAcutionXOperator.Item;
            var time=item.Time;
            if (dayItem.Ver==1.0) strTime=IFrameSplitOperator.FormatTimeString(time,"HH:MM");
            else strTime=IFrameSplitOperator.FormatTimeString(time,"HH:MM:SS");
            var strDate=IFrameSplitOperator.FormatDateString(item.Date);

            strTime=`${strDate} ${strTime}`;

            dataVersion=dayItem.Ver;
            callbackData.Data=item;
        }
        else
        {
            return;
        }

        if (bDraw && this.IsShowTime && strTime )
        {
            if (!this.DrawText(strTime,this.DateTimeColor,position)) return;
        }

        //匹配价
        if (bDraw && item && IFrameSplitOperator.IsNumber(item.Price))
        {
            var color=this.GetColor(item.Price,this.YClose);
            var filedName='MTitle-AC-Price';
            if (this.BeforeOpenData && this.BeforeOpenData.Ver==1.0) filedName="MTitle-Close";
            var text=g_JSChartLocalization.GetText(filedName,this.LanguageID)+item.Price.toFixed(defaultfloatPrecision);
            if (!this.DrawText(text,color,position)) return;
        }

        //竞价涨幅
        if (bDraw && item && IFrameSplitOperator.IsPlusNumber(this.YClose) && IFrameSplitOperator.IsNumber(item.Price))
        {
            var value=(item.Price-this.YClose)/this.YClose*100;
            var color=this.GetColor(value,0);
            var filedName='MTitle-AC-Increase';
            if (this.BeforeOpenData && this.BeforeOpenData.Ver==1.0) filedName="MTitle-Increase";
            var text=g_JSChartLocalization.GetText(filedName,this.LanguageID)+value.toFixed(2)+"%";
            if (!this.DrawText(text,color,position)) return;
        }

        if (dataVersion==3.0)
        {
            if (bDraw && item && IFrameSplitOperator.IsNumber(item.AvPrice))
            {
                var color=this.GetColor(item.Price,this.YClose);
                var text=g_JSChartLocalization.GetText('MTitle-AC-AvPrice',this.LanguageID)+item.AvPrice.toFixed(defaultfloatPrecision);
                if (!this.DrawText(text,color,position)) return;
            }
        }

        //匹配量
        if (bDraw && IFrameSplitOperator.IsNumber(item.Vol[0]))
        {
            var filedName='MTitle-AC-Vol';
            if (this.BeforeOpenData && this.BeforeOpenData.Ver==1.0) filedName="MTitle-Vol";
            var text=g_JSChartLocalization.GetText(filedName,this.LanguageID)+IFrameSplitOperator.FromatIntegerString(item.Vol[0],2);
            if (!this.DrawText(text,this.VolColor,position)) return;
        }
        
        //未匹配量
        if (bDraw && IFrameSplitOperator.IsNumber(item.Vol[1]))
        {
            var text=g_JSChartLocalization.GetText('MTitle-AC-NotMatchVol',this.LanguageID)+IFrameSplitOperator.FromatIntegerString(item.Vol[1],2);
            if (!this.DrawText(text,this.VolColor,position)) return;
        }

        this.OnDrawCallAuctionEventCallback(callbackData);
    }

    this.OnDrawCallAuctionEventCallback=function(drawData)
    {
        if (!this.OnDrawEvent || !this.OnDrawEvent.Callback) return;
        var data={ Draw: drawData, Name:this.ClassName };
        this.OnDrawEvent.Callback(this.OnDrawEvent,data,this);
    }

    this.Draw=function()
    {
        this.LastShowData=null;
        if (!this.IsShow) return;
        if (this.PointInfo && 
            ( this.PointInfo.ClientPos==2 || this.PointInfo.ClientPos==3 || 
              (this.PointInfo.ClientPos>=200&& this.PointInfo.ClientPos<=299) ||
              (this.PointInfo.ClientPos>=300&& this.PointInfo.ClientPos<=399) ) )
        {   //集合竞价区域
            this.Canvas.save();
            this.DrawCallAuction();
            this.Canvas.restore();
            return;
        }

        if (this.CursorIndex==null || !this.Data || !this.Data.Data || this.Data.Data.length<=0) 
        {
            this.OnDrawEventCallback(null);
            return;
        }

        this.Canvas.font=this.Font;
        this.SpaceWidth = this.Canvas.measureText('0').width;

        var isShowLastData=false;
        if (this.DrawStatus && this.DrawStatus.IsTitleShowLatestData)
        {
            var status=this.DrawStatus;
            if (!IFrameSplitOperator.IsNumber(status.FrameID) || status.FrameID<0)
                isShowLastData=true;
            else if (status.CorssCursorTouchEnd && status.IsOnTouch==false)
                isShowLastData=true;
        }

        var isLastOne=false;
        if (isShowLastData)
        {
            var item=this.GetLatestKLineData();
            isLastOne=true;
        }
        else
        {
            //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];

            if (dataIndex==this.Data.Data.length-1) isLastOne=true;
        }
        
        this.LastShowData=item;

        this.Canvas.save();
        this.OnDrawEventCallback(item);

        if (this.IsAlwaysShowLastData) 
        {
            var lastItem=this.GetLatestKLineData();
            this.DrawItem(lastItem, true);
        }
        else
        {
            this.DrawItem(item,isLastOne);
        }
        
        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;                          //小数位数
    this.IsShow=true;   //是否显示
    this.Callback;      //绘制标题回调
}

function DynamicChartTitlePainting()
{
    this.newMethod=IChartTitlePainting;   //派生
    this.newMethod();
    delete this.newMethod;

    this.ClassName='DynamicChartTitlePainting';

    this.IsDynamic=true;
    this.Data=[];
    this.Explain;

    this.ColorIndex;    //五彩K线名字 {Name:'名字'}
    this.IsShowColorIndexTitle=true;
    this.IsShowUpDownArrow=true;   //指标数据是否显示 上涨下跌箭头
    this.IsShowIndexName=true;     //是否显示指标名字
    this.IsShowIndexTitle=true;    //是否显示指标标题信息

    this.TradeIndex;    //专家系统名字{Name:'名字', Param:'参数'}
    this.IsShowTradeIndexTitle=true;

    this.OverlayIndex=new Map();        //叠加指标 key=Identify value={ Data:数据, Title:标题, Identify:标识}
    this.IsShowOverlayIndexName=true;   //是否显示叠加指标名字
    this.OverlayIndexType={ Position:0, LineSpace:5, BGColor:g_JSChartResource.OverlayIndexTitleBGColor };        //Position 0=主图指标后面显示 1=叠加指标单行显示
                                                                                               //LineSpace 行间距

    this.LanguageID=JSCHART_LANGUAGE_ID.LANGUAGE_CHINESE_ID;
    this.TitleRect;              //指标名字显示区域
    this.IsDrawTitleBG=false;    //是否绘制指标名字背景色
    this.BGColor=g_JSChartResource.IndexTitleBGColor;
    this.OnDrawEvent;
    this.ParamSpace=2;           //参数显示的间距
    this.TitleSpace=2;              //指标名字和参数之间的间距
    this.TitleColor=g_JSChartResource.IndexTitleColor;   //指标名字颜色

    this.IsKLineFrame=false;    //是否是K线框架标题
    

    //动态标题
    //动态标题
    this.DynamicTitle={ OutName:null, OutValue:null };
    this.OverlayDynamicTitle=new Map();  //key , value={ OutName, OutValue }

    this.ReloadResource=function()
    {
        this.Font=g_JSChartResource.TitleFont;
        this.TitleColor=g_JSChartResource.DefaultTextColor;
        this.OverlayIndexType.BGColor=g_JSChartResource.OverlayIndexTitleBGColor;
    }

    this.SetDynamicTitleData=function(outName, args, data)
    {
        if (!data.OutName) data.OutName=new Map();
        else data.OutName.clear();

        if (!data.OutValue) data.OutValue=new Map();
        else data.OutValue.clear();

        var mapArgs=new Map();
        for(var i in args)
        {
            var item=args[i];
            mapArgs.set(`{${item.Name}}`, item);
        }

        for(var i in outName)
        {
            var item=outName[i];
            if (item.DynamicName)
            {
                var aryFond = item.DynamicName.match(/{\w*}/i);
                if (!aryFond || aryFond.length<=0) 
                {
                    data.OutName.set(item.Name, item.DynamicName);
                }
                else
                {
                    var dyName=item.DynamicName;
                    var bFind=true;
                    for(var j=0;j<aryFond.length;++j)
                    {
                        var findItem=aryFond[j];
                        if (mapArgs.has(findItem))
                        {
                            var value=mapArgs.get(findItem).Value;
                            dyName=dyName.replace(findItem,value.toString());
                        }
                        else
                        {
                            bFind=false;
                            break;
                        }
                    }
    
                    if (bFind) data.OutName.set(item.Name, dyName);
                }
    
            }

            if (item.DynamicValue)
            {
                data.OutValue.set(item.Name, item.DynamicValue);
            }
        }
    }

    this.SetDynamicTitle=function(outName, args, overlayID)
    {
        if (IFrameSplitOperator.IsString(overlayID))
        {
            var dynamicTitle=null;
            if (this.OverlayDynamicTitle.has(overlayID)) 
            {
                dynamicTitle=this.OverlayDynamicTitle.get(overlayID);
            }
            else
            {
                dynamicTitle={ OutName:null, OutValue:null };
                this.OverlayDynamicTitle.set(overlayID, dynamicTitle);
            }

            this.SetDynamicTitleData(outName, args, dynamicTitle); 
        }
        else
        {
            this.SetDynamicTitleData(outName, args, this.DynamicTitle);    
        }
    }

    this.GetDynamicOutName=function(key, overlayID)
    {
        if (IFrameSplitOperator.IsString(overlayID))
        {
            if (!this.OverlayDynamicTitle.has(overlayID)) return null;
            var dynamicTitle=this.OverlayDynamicTitle.get(overlayID);
            var outName=dynamicTitle.OutName;
        }
        else
        {
            var outName=this.DynamicTitle.OutName;
        }

        if (!outName || outName.size<=0) return null;
        if (!outName.has(key)) return null;

        return outName.get(key);
    }

    this.GetDynamicOutValue=function(key, value)
    {
        var outValue=this.DynamicTitle.OutValue;

        if (!outValue || outValue.size<=0) return null;
        if (!outValue.has(key)) return null;

        var strFormat=outValue.get(key);
        strFormat=strFormat.replace('{Value}',value);
        return strFormat;
    }

    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.FromatMultiDataLine=function(value, dataInfo)
    {
        var text="";
        if (Array.isArray(value))
        {
            for(var i=0;i<value.length;++i)
            {
                var item=value[i];
                if (item.Type==0) continue;
                if (!IFrameSplitOperator.IsNumber(item.Value)) continue;
                var strValue=this.FormatValue(item.Value,dataInfo);
                if (text.length>0) text+=',';
                text+=strValue;
            }
        }
        else
        {
            if (value.Type!=0 && IFrameSplitOperator.IsNumber(value.Value))
            {
                text=this.FormatValue(value.Value,dataInfo);
            }
        }

        if (text.length<=0) return null;

        return text;
    }

    this.IsShowLastData=function()
    {
        var isShowLastData=false;
        if (this.DrawStatus && this.DrawStatus.IsTitleShowLatestData)
        {
            var status=this.DrawStatus;
            if (!IFrameSplitOperator.IsNumber(status.FrameID) || status.FrameID<0)
                isShowLastData=true;
            else if (status.CorssCursorTouchEnd && status.IsOnTouch==false)
                isShowLastData=true;
        }

        return isShowLastData;
    }

    this.OnDrawTitleEvent=function()
    {
        var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_INDEXTITLE_DRAW);
        if (!event) return;
        
        var data={ Index:null, Data:this.Data ,Title:this.Title, FrameID:this.Frame.Identify, OverlayIndex:this.OverlayIndex };
        if (IFrameSplitOperator.IsNumber(this.CursorIndex))
        {
            var index=Math.abs(this.CursorIndex);
            index=parseInt(index.toFixed(0));
            data.Index=index;   //当前屏数据索引
        }

        var pixelTatio = GetDevicePixelRatio();
        var border=this.Frame.GetBorder();
        data.Left=border.LeftEx/pixelTatio;
        data.Top=border.Top/pixelTatio;
        data.Right=border.RightEx/pixelTatio;

        event.Callback(event,data,this);
        
    }

    this.Draw=function()
    {
        if (this.Frame.IsMinSize) return;

        this.IsKLineFrame= this.Frame.ClassName=='KLineFrame' || this.Frame.ClassName=='KLineHScreenFrame';
        this.IsDrawTitleBG=this.Frame.IsDrawTitleBG;
        this.IsShowUpDownArrow=this.Frame.IsShowTitleArraw;
        this.IsShowIndexName=this.Frame.IsShowIndexName;
        this.IsShowOverlayIndexName=this.Frame.IsShowOverlayIndexName;
        this.OverlayIndexType.Position=this.Frame.OverlayIndexType.Position;
        this.OverlayIndexType.LineSpace=this.Frame.OverlayIndexType.LineSpace;
        this.ParamSpace=this.Frame.IndexParamSpace;
        this.TitleSpace=this.Frame.IndexTitleSpace;
        this.TitleRect=null;

        this.OnDrawTitleEvent();

        if (this.Frame.IsShowIndexTitle==false) return;
        if (this.CursorIndex==null ) return;
        if (!this.Data) return;
        if (this.Frame.ChartBorder.TitleHeight<5) return;

        if (this.Frame.IsHScreen===true)
        {
            this.Canvas.save();
            this.HScreenDraw();
            this.Canvas.restore();
            return;
        }

        var left=this.Frame.ChartBorder.GetLeft()+1;
        var bottom=this.Frame.ChartBorder.GetTop()+this.Frame.ChartBorder.TitleHeight/2;    //上下居中显示
        var right=this.Frame.ChartBorder.GetRight();

        this.Canvas.textAlign="left";
        this.Canvas.textBaseline="middle";
        this.Canvas.font=this.Font;

        if (this.Title && this.IsShowIndexName)
        {
            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;
            left+=this.TitleSpace;
        }

        var isShowLastData=this.IsShowLastData();
        var lockRect=this.Frame.GetLockRect();
        if (lockRect)   //指标上锁区域不显示动态标题
        {
            var index=Math.abs(this.CursorIndex);
            if (this.IsKLineFrame) index=this.CursorIndex;
            var x=this.Frame.GetXFromIndex(index.toFixed(0));
            if (x>=lockRect.Left) return;
            if (isShowLastData) return;
        }

        for(var i in this.Data)
        {
            var item=this.Data[i];
            if (!item || !item.Data || !item.Data.Data) continue;

            if (item.Data.Data.length<=0) continue;
            if (item.IsShow===false) continue;

            var value=null;
            var valueText=null;
            if (item.DataType=="StraightLine")  //直线只有1个数据
            {
                value=item.Data.Data[0];
                valueText=this.FormatValue(value,item);
            }
            else
            {
                if (isShowLastData)
                {
                    var dataIndex=item.Data.Data.length-1;  //显示最后一个数据
                }
                else
                {
                    var index=Math.abs(this.CursorIndex);
                    index=parseInt(index.toFixed(0));
                    if (this.IsKLineFrame) index=this.CursorIndex;
                    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 if (item.DataType=="MULTI_POINT_LINE")
                {
                    valueText=this.FromatMultiDataLine(value, item);
                    if (!valueText) continue;
                }
                else
                {
                    var arrow=null;
                    if (this.IsShowUpDownArrow)
                    {
                        var proValue=null;
                        if (dataIndex-1>=0) proValue=item.Data.Data[dataIndex-1];
                        if (IFrameSplitOperator.IsNumber(proValue))
                        {
                            if (proValue>value) arrow='↓';
                            else if (proValue<value) arrow='↑';
                            else arrow='→';
                        }
                    }
                
                    valueText=this.FormatValue(value,item);
                    if (item.Name) 
                    {
                        var dyValue=this.GetDynamicOutValue(item.Name, valueText);
                        if (dyValue) valueText=dyValue;
                    }

                    if (arrow) valueText+=arrow;
                }
            }

            this.Canvas.fillStyle=item.Color;

            var text=valueText;
            if (item.Name) 
            {
                var dyTitle=this.GetDynamicOutName(item.Name);
                if (dyTitle) text=dyTitle+":"+valueText;
                else text=item.Name+":"+valueText;
            }
            var space=this.ParamSpace*GetDevicePixelRatio();
            var textWidth=this.Canvas.measureText(text).width+space;    //后空2个像素
            if ((left+textWidth)>right) break;

            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.IsShowColorIndexTitle)
        {
            this.Canvas.fillStyle=g_JSChartResource.Title.ColorIndexColor;
            var tradeName=this.ColorIndex.Name+this.ColorIndex.Param;
            var textWidth=this.Canvas.measureText(tradeName).width+2;    //后空2个像素
            this.Canvas.fillText(tradeName,left,bottom,textWidth);
            left+=textWidth;
        }

        if (this.TradeIndex && this.IsShowTradeIndexTitle)
        {
            this.Canvas.fillStyle=g_JSChartResource.Title.TradeIndexColor;
            var tradeName=this.TradeIndex.Name+this.TradeIndex.Param;
            var textWidth=this.Canvas.measureText(tradeName).width+2;    //后空2个像素
            this.Canvas.fillText(tradeName,left,bottom,textWidth);
            left+=textWidth;
        }

        if (this.OverlayIndexType.Position==1) this.DrawOverlayIndexSingleLine();
        else this.DrawOverlayIndex(left+10*GetDevicePixelRatio());   //间距都空点 和主指标区分开
    }

    this.DrawOverlayIndexSingleLine=function()   //叠加指标单行显示
    {
        var pixelRatio=GetDevicePixelRatio();
        var border=this.Frame.GetBorder();
        if (this.Frame.IsHScreen===true) 
        {
            var left=1;
            var top=2*pixelRatio;
            var right=this.Frame.ChartBorder.GetHeight();
            var bottom=this.Frame.ChartBorder.GetWidthEx();
        }
        else
        {
            var top=border.TopTitle+2*pixelRatio;
            var left=border.Left+1;
            var right=border.Right;
            var bottom=border.Bottom;
        }
        

        var lineSpace=this.OverlayIndexType.LineSpace*pixelRatio; 
        var x=left, y=top;
        this.Canvas.textAlign="left";
        this.Canvas.textBaseline="top";
        var fontHeight=GetFontHeight(this.Canvas,this.Font,"擎");
        for(item of this.OverlayIndex)
        {
            var overlayItem=item[1];
            var overlayID=item[0];
            x=left;
            if (overlayItem.Title && this.IsShowOverlayIndexName)
            {
                
                var textWidth=this.Canvas.measureText(overlayItem.Title).width+2;
                if ((x+textWidth)<right) 
                {
                    if (this.OverlayIndexType.BGColor)
                    {
                        this.Canvas.fillStyle=this.OverlayIndexType.BGColor;
                        var rtBG={Left:x, Top:y, Width:textWidth, Height: fontHeight+lineSpace };    //保存下标题的坐标
                        this.Canvas.fillRect(rtBG.Left,rtBG.Top,rtBG.Width,rtBG.Height);
                    } 

                    this.Canvas.fillStyle=this.TitleColor;
                    this.Canvas.fillText(overlayItem.Title,x,y,textWidth);
                }
                x+=textWidth;
            }

            for(var i=0; i<overlayItem.Data.length; ++i)
            {
                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));
                    if (this.IsKLineFrame) index=this.CursorIndex;
                    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);
                    }
                }

                var text=valueText;
                if (item.Name) 
                {
                    var dyTitle=this.GetDynamicOutName(item.Name,overlayID);
                    if (dyTitle) text=dyTitle+":"+valueText;
                    else text=item.Name+":"+valueText;
                }

                var textWidth=this.Canvas.measureText(text).width+2;    //后空2个像素
                if ((x+textWidth)>right) break;
                if (this.OverlayIndexType.BGColor)
                {
                    this.Canvas.fillStyle=this.OverlayIndexType.BGColor;
                    var rtBG={Left:x, Top:y, Width:textWidth, Height: fontHeight+lineSpace };    //保存下标题的坐标
                    this.Canvas.fillRect(rtBG.Left,rtBG.Top,rtBG.Width,rtBG.Height);
                }

                this.Canvas.fillStyle=item.Color;
                this.Canvas.fillText(text,x,y,textWidth);
                x+=textWidth;
            }

            y+=fontHeight+lineSpace;
            if ((y+fontHeight+lineSpace)>=bottom) break;
        }
    }

    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.IsShowOverlayIndexName)
            {
                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));
                    if (this.IsKLineFrame) index=this.CursorIndex;
                    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 border=this.Frame.ChartBorder.GetHScreenBorder();
        var xText=this.Frame.ChartBorder.GetRightTitle();
        var yText=border.TopEx;
        this.Canvas.translate(xText, yText);
        this.Canvas.rotate(90 * Math.PI / 180);

        var left=1;
        var bottom=-this.Frame.ChartBorder.TitleHeight/2;    //上下居中显示
        var right=this.Frame.ChartBorder.GetHeight();

        this.Canvas.textAlign="left";
        this.Canvas.textBaseline="middle";
        this.Canvas.font=this.Font;

        if (this.Title && this.IsShowIndexName)
        {
            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:border.TopEx,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);
            if (this.IsKLineFrame) index=this.CursorIndex;
            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));
                if (this.IsKLineFrame) index=this.CursorIndex;
                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个像素
            if ((left+textWidth)>right) break;

            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.OverlayIndexType.Position==1) this.DrawOverlayIndexSingleLine();
        else 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.Right;         //对应的复权
    this.IsSelected=false;  //是否选中
    this.Option;
    this.EnableMove=true;   //是否可以移动

    this.IsDrawFirst=false;

    this.LineColor=g_JSChartResource.DrawPicture.LineColor[0];                            //线段颜色
    //this.LineColor="#1e90ff";      //线段颜色，input type="color" 不支持rgb和rgba 的格式
    this.LineWidth=2;              //线段宽度
    this.BackupLineWidth=null;
    this.AreaColor='rgba(25,25,25,0.4)';    //面积颜色
    this.PointColor=g_JSChartResource.DrawPicture.PointColor[0];
    this.MoveOnPointColor=g_JSChartResource.DrawPicture.PointColor[1];
    this.PointRadius=5;  //圆点半径
    this.SquareSize=8;   //方框点大小
    this.PointType=g_JSChartResource.DrawPicture.PointType;    // 0=圆点  1=方框
    this.IsShowPoint=g_JSChartResource.DrawPicture.IsShowPoint;     //是否始终显示点
    

    //接口函数
    this.SetLastPoint=null; //this.SetLastPoint=function(obj)  obj={X:,Y:}
    this.Update=null;       //更新数据回调
    this.GetActiveDrawPicture=null;

    this.Draw=function()
    {

    }

    this.SetOption=function(option)
    {
        if (!option) return;

        if (option.LineColor) this.LineColor=option.LineColor;
        if (option.LineWidth>0) this.LineWidth=option.LineWidth;
        if (option.AreaColor) this.AreaColor=option.AreaColor;
        if (option.PointColor) this.PointColor=option.PointColor;
        if (option.MoveOnPointColor) this.SelectPointColor=option.PointColor;
        if (option.PointRadius) this.PointRadius=option.PointRadius;
        if (IFrameSplitOperator.IsNumber(option.SquareSize)) this.SquareSize=option.SquareSize;
        if (IFrameSplitOperator.IsBool(option.IsShowPoint)) this.IsShowPoint=option.IsShowPoint;
    }

    this.SetLineWidth=function()
    {
        this.BackupLineWidth=null;
        if (this.LineWidth>0)
        {
            this.BackupLineWidth=this.Canvas.lineWidth;
            this.Canvas.lineWidth=this.LineWidth*GetDevicePixelRatio();
        }
    }

    this.GetFontHeight=function(font)
    {
        return GetFontHeight(this.Canvas, font, "擎");
    }

    this.RestoreLineWidth=function()
    {
        if (this.BackupLineWidth!=null)
        {
            this.Canvas.lineWidth=this.BackupLineWidth;
        }
    }

    //Point => Value
    this.PointToValue=function()
    {
        if (!this.Frame) return false;

        if (this.Frame.ClassName=="MinuteFrame" || this.Frame.Class=="MinuteHScreenFrame")
        {
            return this.PointToValue_Minute();
        }
        else
        {
            return this.PointToValue_KLine();
        }
    }

    this.PointToKLine=function(aryPoint)
    {
        if (!this.Frame) return null;
        var data=this.Frame.Data;
        if (!data) return null;
        
        var kLine=[];
        var isHScreen=this.Frame.IsHScreen;
        if (isHScreen)
        {
            for(var i in aryPoint)
            {
                var item=aryPoint[i];
                var xValue=parseInt(this.Frame.GetXData(item.Y))+data.DataOffset;
                var yValue=this.Frame.GetYData(item.X);

                var valueItem={ XValue:xValue, YValue:yValue };
                var kline=data.Data[xValue];
                valueItem.DateTime={ Date:kline.Date };
                if (IFrameSplitOperator.IsNumber(kline.Time)) valueItem.DateTime.Time=kline.Time;

                kLine[i]=valueItem;
            }
        }
        else
        {
            for(var i in aryPoint)
            {
                var item=aryPoint[i];
                var index=parseInt(this.Frame.GetXData(item.X,false));
                var xValue=index+data.DataOffset;
                if (xValue<0) xValue=0;
                else if (xValue>=data.Data.length) 
                {
                    xValue=data.Data.length-1;
                    index=xValue-data.DataOffset;
                }
                var yValue=this.Frame.GetYData(item.Y,false);

                var valueItem={ XValue:xValue, YValue:yValue, XIndex:index };
                var kline=data.Data[xValue];
                valueItem.DateTime={ Date:kline.Date };
                if (IFrameSplitOperator.IsNumber(kline.Time)) valueItem.DateTime.Time=kline.Time;

                kLine[i]=valueItem;
            }
        }

        return kLine;
    }

    this.PointToValue_KLine=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);

                var valueItem={ XValue:xValue, YValue:yValue };
                var kline=data.Data[xValue];
                valueItem.DateTime={ Date:kline.Date };
                if (IFrameSplitOperator.IsNumber(kline.Time)) valueItem.DateTime.Time=kline.Time;

                this.Value[i]=valueItem;
            }
        }
        else
        {
            for(var i in this.Point)
            {
                var item=this.Point[i];
                var xValue=parseInt(this.Frame.GetXData(item.X,false))+data.DataOffset;
                if (xValue<0) xValue=0;
                else if (xValue>=data.Data.length) xValue=data.Data.length-1;
                var yValue=this.Frame.GetYData(item.Y,false);

                var valueItem={ XValue:xValue, YValue:yValue };
                var kline=data.Data[xValue];
                valueItem.DateTime={ Date:kline.Date };
                if (IFrameSplitOperator.IsNumber(kline.Time)) valueItem.DateTime.Time=kline.Time;

                this.Value[i]=valueItem;
            }
        }

        return true;
    }

    this.PointToValue_Minute=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=0; i<this.Point.length; ++i)
            {
                var item=this.Point[i];
                var xValue=parseInt(this.Frame.GetXData(item.Y));
                var yValue=this.Frame.GetYData(item.X);

                var valueItem={ XValue:xValue, YValue:yValue };
                var minuteItem=data.Data[xValue];
                valueItem.DateTime={ Date:minuteItem.Date ,Time:minuteItem.Time};
                this.Value[i]=valueItem;
            }
        }
        else
        {
            var xDatetime=g_MinuteTimeStringData.GetTimeData(this.Symbol);
            for(var i=0; i<this.Point.length; ++i)
            {
                var item=this.Point[i];
                var xValue=parseInt(this.Frame.GetXData(item.X));
                var yValue=this.Frame.GetYData(item.Y);

                if (xValue>=data.Data.length) //超过当前数据,直接读固定时间
                {
                    var index=xValue%xDatetime.length;
                    var dataIndex=data.Data.length-1;
                    var valueItem={ XValue:xValue, YValue:yValue };
                    var minuteItem=data.Data[dataIndex];
                    var timeItem=xDatetime[index];
                    valueItem.DateTime={ Date:minuteItem.Date, Time:timeItem };
                    this.Value[i]=valueItem;
                }
                else
                {
                    var valueItem={ XValue:xValue, YValue:yValue };
                    var minuteItem=data.Data[xValue];
                    valueItem.DateTime={ Date:minuteItem.Date, Time:minuteItem.Time };
                    this.Value[i]=valueItem;
                }
            }
        }

        return true;
    }

    this.IsPointIn=function(x,y)
    {
        return false;
    }

    //Value => Point
    this.ValueToPoint=function()
    {
        if (!this.Frame) return false;
        var data=this.Frame.Data;
        if (!data) return false;

        //this.UpdateXValue();
        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, false);
                pt.Y=this.Frame.GetYFromData(item.YValue,false);
            }
            this.Point[i]=pt;
        }
    }

    this.UpdateXValue=function()    //通过datetime更新x的索引
    {
        if (!this.Frame) return false;
        var data=this.Frame.Data;
        if (!data) return false;

        var aryDateTime=[];
        for(var i in this.Value)
        {
            var item=this.Value[i];
            var dateTime={ Date:item.DateTime.Date };
            if (IFrameSplitOperator.IsNumber(item.DateTime.Time)) dateTime.Time=item.DateTime.Time;
            aryDateTime[i]=dateTime;
        }

        data.FindDataIndexByDateTime(aryDateTime);
        for(var i in aryDateTime)
        {
            var findItem=aryDateTime[i];
            var valueItem=this.Value[i];
            if (findItem.Index>=0) valueItem.XValue=findItem.Index;
        }
    }

    //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;

        var color=this.PointColor;
        if (this.IsShowPoint)
        {

        }
        else
        {
            if (this.GetActiveDrawPicture)
            {
                var active=this.GetActiveDrawPicture();
                if (active.Move.Guid!=this.Guid && active.Select.Guid!=this.Guid && active.MoveOn.Guid!=this.Guid) 
                    return;
                
                if (active.Select.Guid!=this.Guid && active.MoveOn.Guid==this.Guid)
                    color=this.MoveOnPointColor;
            }
        }
        
        //画点
        this.ClipFrame();
        var pixel=GetDevicePixelRatio();
        this.Canvas.fillStyle=color;      //填充颜色

        for(var i in aryPoint)
        {
            var item=aryPoint[i];

            if (this.PointType==1)
            {
                var value=this.SquareSize*pixel;
                var x=item.X-value/2;
                var y=item.Y-value/2;
                this.Canvas.fillRect(x,y,value,value);   //画一个背景色, 不然是一个黑的背景
            }
            else
            {
                this.Canvas.beginPath();
                this.Canvas.arc(item.X,item.Y,this.PointRadius*pixel,0,360,false);
                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;
    }

    //计算2个点线的,点0->点1->延长线的点
    this.CalculateExtendLineEndPoint=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;
        }
    }

    //坐标是否在点上 返回在第几个点上
    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,
            LineWidth:this.LineWidth, Right:this.Right
        };
        for(var i in this.Value)
        {
            var item=this.Value[i];
            storageData.Value.push({ XValue:item.XValue, YValue:item.YValue, DateTime:item.DateTime });
        }

        if (this.Text) storageData.Text=this.Text;  //如果有文本, 也导出
        if (this.FontOption) storageData.FontOption=this.FontOption;    //字体也导出

        return storageData;
    }

    this.IsFrameMinSize=function()   //框架是否是最小化模式
    {
        return this.Frame && this.Frame.IsMinSize;
    }


    this.PointRange=function(aryPoint)
    {
        if (!IFrameSplitOperator.IsNonEmptyArray(aryPoint)) return null;
        if (aryPoint.length==1) 
        {
            var data=
            { 
                Points:[ { X:aryPoint[0].X, Y:aryPoint[0].Y } ]
            };

            return data;
        }
        else
        {
            var xMax=aryPoint[0].X;
            var xMin=xMax;
    
            var yMax=aryPoint[0].Y;
            var yMin=yMax;
            var aryData=[{ X:aryPoint[0].X, Y:aryPoint[0].Y }];
            for(var i=1;i<aryPoint.length;++i)
            {
                if (xMax<aryPoint[i].X) xMax=aryPoint[i].X;
                if (xMin>aryPoint[i].X) xMin=aryPoint[i].X;
    
                if (yMax<aryPoint[i].Y) yMax=aryPoint[i].Y;
                if (yMin>aryPoint[i].Y) yMin=aryPoint[i].Y;
    
                aryData.push({X:aryPoint[i].X, Y:aryPoint[i].Y});
            }

            var data=
            { 
                X: { Max: { X:xMax }, Min: { X:xMin} }, 
                Y: { Max: { Y:yMax},  Min: { Y:yMin} },
                Points: aryData //所有的点
            };

            return data;
        }        
    }

    this.GetXYCoordinate_default=function()
    {
        if (this.IsFrameMinSize()) return null;
        var drawPoint=this.CalculateDrawPoint( {IsCheckX:true, IsCheckY:true} );

        return this.PointRange(drawPoint);
    }

    this.GetXYCoordinate=function()
    {
        return null;
    }
}

IChartDrawPicture.ColorToRGBA=function(color,opacity)
{
    var reg = /^(rgb|RGB)/;
    if (reg.test(color)) 
    {
        var strHex = "#";
        var colorArr = color.replace(/(?:\(|\)|rgb|RGB)*/g, "").split(",");    // 把RGB的3个数值变成数组
        // 转成16进制
        for (var i = 0; i < colorArr.length; i++) 
        {
            var hex = Number(colorArr[i]).toString(16);
            if (hex === "0")  hex += hex;
            strHex += hex;
        }

        color=strHex;
    }
    
    return "rgba(" + parseInt("0x" + color.slice(1, 3)) + "," + parseInt("0x" + color.slice(3, 5)) + "," + parseInt("0x" + color.slice(5, 7)) + "," + opacity + ")";
}

IChartDrawPicture.RGBToHex=function(rgb) 
{
    // Choose correct separator
    let sep = rgb.indexOf(",") > -1 ? "," : " ";
    // Turn "rgb(r,g,b)" into [r,g,b]
    rgb = rgb.substr(4).split(")")[0].split(sep);
  
    let r = (+rgb[0]).toString(16),
        g = (+rgb[1]).toString(16),
        b = (+rgb[2]).toString(16);
  
    if (r.length == 1)
      r = "0" + r;
    if (g.length == 1)
      g = "0" + g;
    if (b.length == 1)
      b = "0" + b;
  
    return "#" + r + g + b;
}

IChartDrawPicture.ArrayDrawPricture=
[
    { Name:"线段", ClassName:'ChartDrawPictureLine',  Create:function() { return new ChartDrawPictureLine(); } },
    { Name:"射线", ClassName:'ChartDrawPictureHaflLine',  Create:function() { return new ChartDrawPictureHaflLine(); } },
    { Name:"箭头", ClassName:"ChartDrawArrowLine", Create:function() { return new ChartDrawArrowLine(); } },
    { Name:"水平线", ClassName:'ChartDrawPictureHorizontalLine',  Create:function() { return new ChartDrawPictureHorizontalLine(); }},
    { Name:"趋势线", ClassName:'ChartDrawPictureTrendLine',  Create:function() { return new ChartDrawPictureTrendLine(); }},
    { Name:"矩形", ClassName:'ChartDrawPictureRect', Create:function() { return new ChartDrawPictureRect(); }},
    { Name:"圆弧线", ClassName:'ChartDrawPictureArc',  Create:function() { return new ChartDrawPictureArc(); }},
    { Name:"M头W底", ClassName:'ChartDrawPictureWaveMW',  Create:function() { return new ChartDrawPictureWaveMW(); }},
    { Name:"头肩型", ClassName:"ChartDrawHeadShouldersBT", Create:function() { return new ChartDrawHeadShouldersBT(); }},
    { Name:"平行线", ClassName:'ChartDrawPictureParallelLines',  Create:function() { return new ChartDrawPictureParallelLines(); }},
    { Name:"平行通道", ClassName:'ChartDrawPictureParallelChannel',  Create:function() { return new ChartDrawPictureParallelChannel(); }},
    { Name:"价格通道线", ClassName:'ChartDrawPicturePriceChannel',  Create:function() { return new ChartDrawPicturePriceChannel(); }},
    { Name:"文本", ClassName:'ChartDrawPictureText', Create:function() { return new ChartDrawPictureText(); }},
    { Name:"江恩角度线", ClassName:'ChartDrawPictureGannFan',  Create:function() { return new ChartDrawPictureGannFan(); }},
    { Name:"阻速线", ClassName:'ChartDrawPictureResistanceLine',  Create:function() { return new ChartDrawPictureResistanceLine(); }},
    { Name:"黄金分割", ClassName:'ChartDrawPictureGoldenSection',  Create:function() { return new ChartDrawPictureGoldenSection(); }},
    { Name:"百分比线", ClassName:'ChartDrawPicturePercentage',  Create:function() { return new ChartDrawPicturePercentage(); }},
    { Name:"波段线", ClassName:'ChartDrawPictureWaveBand',  Create:function() { return new ChartDrawPictureWaveBand(); }},
    { Name:"三角形", ClassName:'ChartDrawPictureTriangle',  Create:function() { return new ChartDrawPictureTriangle(); }},
    { Name:"对称角度", ClassName:'ChartDrawPictureSymmetryAngle',  Create:function() { return new ChartDrawPictureSymmetryAngle(); }},
    { Name:"圆", ClassName:'ChartDrawPictureCircle',  Create:function() { return new ChartDrawPictureCircle(); }},
    { Name:"平行四边形", ClassName:'ChartDrawPictureQuadrangle',  Create:function() { return new ChartDrawPictureQuadrangle(); }},
    { Name:"斐波那契周期线", ClassName:'ChartDrawPictureFibonacci',  Create:function() { return new ChartDrawPictureFibonacci(); }},
    { Name:"线形回归线", ClassName:"ChartDrawLinearRegression", Create:function() { return new ChartDrawLinearRegression(); } },
    { Name:"线形回归带", ClassName:"ChartDrawLinearRegression", Create:function() { return new ChartDrawLinearRegression({ IsShowMaxMinLine:true }); } },
    { Name:"延长线形回归带", ClassName:"ChartDrawLinearRegression", Create:function() { return new ChartDrawLinearRegression({ IsShowMaxMinLine:true, IsShowExtendLine:true }); } },
    { Name:"尺子", ClassName:"ChartDrawRuler", Create:function() { return new ChartDrawRuler(); } },
    { Name:"标价线", ClassName:"ChartDrawPriceLine", Create:function() { return new ChartDrawPriceLine(); } },
    { Name:"标价线2", ClassName:"ChartDrawPriceLineV2", Create:function() { return new ChartDrawPriceLineV2(); } },
    { Name:"垂直线", ClassName:"ChartDrawVerticalLine", Create:function() { return new ChartDrawVerticalLine(); } },
    { Name:"波浪尺", ClassName:"ChartDrawWaveRuler", Create:function() { return new ChartDrawWaveRuler(); } },
    { Name:"AB波浪尺", ClassName:"ChartDrawWaveRuler2Point", Create:function() { return new ChartDrawWaveRuler2Point(); } },
    { Name:"箱型线", ClassName:"ChartDrawBox", Create:function() { return new ChartDrawBox(); } },
    { Name:"2点画图例子", ClassName:"ChartDrawTwoPointDemo", Create:function() { return new ChartDrawTwoPointDemo(); } },
    { Name:"3点画图例子", ClassName:"ChartDrawThreePointDemo", Create:function() { return new ChartDrawThreePointDemo(); } },
    { Name:"水平线段", ClassName:"ChartDrawHLineSegment", Create:function() { return new ChartDrawHLineSegment();} },
    { Name:"平行射线", ClassName:"ChartDrawParallelRaysLines", Create:function() { return new ChartDrawParallelRaysLines();}},
    { ClassName:'ChartDrawPictureIconFont',  Create:function() { return new ChartDrawPictureIconFont(); }}
    
];

IChartDrawPicture.MapIonFont=new Map(
[
    ["icon-arrow_up", { Text:'\ue683', Color:'#318757', Family:"iconfont"}],
    ["icon-arrow_down", { Text:'\ue681', Color:'#db563e', Family:"iconfont"}],
    ["icon-arrow_right", {  Text:'\ue682', Color:'#318757', Family:"iconfont"}],
    ["icon-arrow_left", {  Text:'\ue680',Color:'#318757', Family:"iconfont"}]
]);

IChartDrawPicture.GetDrawPictureByName=function(value)
{
    for(var i in IChartDrawPicture.ArrayDrawPricture)
    {
        var item=IChartDrawPicture.ArrayDrawPricture[i];
        if (item.Name==value) return item;
    }

    return null;
}

IChartDrawPicture.GetDrawPictureByClassName=function(value)
{
    for(var i in IChartDrawPicture.ArrayDrawPricture)
    {
        var item=IChartDrawPicture.ArrayDrawPricture[i];
        if (item.ClassName==value) return item;
    }

    return null;
}

//注册一个新的画图工具 {Name:中文名字, ClassName:类名, Create:function()}
IChartDrawPicture.RegisterDrawPicture=function(obj)  
{
    if (!obj.Name || !obj.ClassName || !obj.Create) return false;

    var item={ Name:obj.Name, ClassName:obj.ClassName, Create:obj.Create };
    IChartDrawPicture.ArrayDrawPricture.push(item);

    JSConsole.Chart.Log('[IChartDrawPicture.RegisterDrawPicture] registered new draw picture class. item=',item);
    return true;
}

//注册一个新图标 {Name:, Text: , Color:, Family:}
IChartDrawPicture.RegisterIonFont=function(obj)
{
    if (!obj.Name || !obj.Text || !obj.Family) return false;

    var isOverwirte=IChartDrawPicture.MapIonFont.has(obj.Name);
    IChartDrawPicture.MapIonFont.set(obj.Name, obj);

    JSConsole.Chart.Log('[IChartDrawPicture.RegisterIonFont] registered new icon font, obj=, isOverwirte=',obj, isOverwirte);
    return true;
}

IChartDrawPicture.CreateChartDrawPicture=function(obj)    //创建画图工具
{
    var item=IChartDrawPicture.GetDrawPictureByClassName(obj.ClassName);
    if (!item) return null;

    var chartDraw=item.Create();

    if (obj.Period>=0) chartDraw.Period=obj.Period;
    if (obj.Right>=0) chartDraw.Right=obj.Right;
    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;
    if (obj.Label) chartDraw.Label=obj.Label;
    if (obj.LineWidth>0) chartDraw.LineWidth=obj.LineWidth;
    if (obj.EnableMove===false) chartDraw.EnableMove=obj.EnableMove;

    return chartDraw;
}






//画图工具-线段
function ChartDrawPictureLine()
{
    this.newMethod=IChartDrawPicture;   //派生
    this.newMethod();
    delete this.newMethod;

    this.ClassName='ChartDrawPictureLine';
    this.IsPointIn=this.IsPointIn_XYValue_Line;
    this.GetXYCoordinate=this.GetXYCoordinate_default;

    this.Draw=function()
    {
        this.LinePoint=[];
        if (this.IsFrameMinSize()) return;

        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.SetLineWidth();
        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.RestoreLineWidth();

        /*
        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 ChartDrawArrowLine()
{
    this.newMethod=IChartDrawPicture;   //派生
    this.newMethod();
    delete this.newMethod;

    this.ClassName='ChartDrawArrowLine';
    this.IsPointIn=this.IsPointIn_XYValue_Line;
    this.ArrawLineWidth=5;
    this.ArrawLength=15;        //三角斜边长度
    this.ArrawAngle=35;         //三角斜边一直线夹角
    this.GetXYCoordinate=this.GetXYCoordinate_default;

    this.Draw=function()
    {
        this.LinePoint=[];
        if (this.IsFrameMinSize()) return;

        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];

        //计算箭头
        var theta=this.ArrawAngle;       //三角斜边一直线夹角
        var headlen=this.ArrawLength;    //三角斜边长度
        var angle = Math.atan2(ptStart.Y - ptEnd.Y, ptStart.X - ptEnd.X) * 180 / Math.PI,
        angle1 = (angle + theta) * Math.PI / 180,
        angle2 = (angle - theta) * Math.PI / 180,
        topX = headlen * Math.cos(angle1),
        topY = headlen * Math.sin(angle1),
        botX = headlen * Math.cos(angle2),
        botY = headlen * Math.sin(angle2);


        this.SetLineWidth();
        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.Canvas.beginPath();

        var arrowX = ptEnd.X + topX;
        var arrowY = ptEnd.Y + topY;
        this.Canvas.moveTo(arrowX,arrowY);

        this.Canvas.lineTo(ptEnd.X, ptEnd.Y);

        arrowX = ptEnd.X + botX;
        arrowY = ptEnd.Y + botY;
        this.Canvas.lineTo(arrowX,arrowY);

        this.Canvas.lineWidth=this.ArrawLineWidth*GetDevicePixelRatio();
        this.Canvas.stroke();

        this.RestoreLineWidth();

        /*
        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[0]]);  //画点
        this.Canvas.restore();
    }
}

//画图工具-射线
function ChartDrawPictureHaflLine()
{
    this.newMethod=IChartDrawPicture;   //派生
    this.newMethod();
    delete this.newMethod;

    this.ClassName='ChartDrawPictureHaflLine';
    this.IsPointIn=this.IsPointIn_XYValue_Line;
    this.GetXYCoordinate=this.GetXYCoordinate_default;

    this.Draw=function()
    {
        this.LinePoint=[];
        if (this.IsFrameMinSize()) return;

        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.SetLineWidth();
        this.Canvas.beginPath();
        this.Canvas.moveTo(drawPoint[0].X,drawPoint[0].Y);
        this.Canvas.lineTo(drawPoint[1].X,drawPoint[1].Y);
        var endPoint=this.CalculateExtendLineEndPoint(drawPoint);
        this.Canvas.lineTo(endPoint.X,endPoint.Y);
        this.Canvas.stroke();
        this.RestoreLineWidth();

        var line={Start:ptStart, End:ptEnd};
        this.LinePoint.push(line);

        this.DrawPoint(drawPoint);  //画点
        this.Canvas.restore();
    }
}

// 画图工具-水平线 支持横屏
function ChartDrawPictureHorizontalLine()
{
    this.newMethod=IChartDrawPicture;   //派生
    this.newMethod();
    delete this.newMethod;

    this.Super_SetOption=this.SetOption;    //父类函数
    this.Super_ExportStorageData=this.ExportStorageData;

    this.Label; //{Text:文本, Position: 0=左, 1=右 }

    this.SetOption=function(option)
    {
        if (this.Super_SetOption) this.Super_SetOption(option);
        if (option)
        {
            if (option.Label) this.Label=option.Label;
        }
    }

    this.ExportStorageData=function()
    {
        var storageData;
        if (this.Super_ExportStorageData) 
        {
            storageData=this.Super_ExportStorageData();
            if (this.Label) storageData.Label=this.Label;
        }

        return storageData;
    }

    this.PointCount=1;
    this.ClassName='ChartDrawPictureHorizontalLine';
    this.IsPointIn=this.IsPointIn_XYValue_Line;
    this.Font=16*GetDevicePixelRatio() +"px 微软雅黑";

    this.GetXYCoordinate=function()
    {
        if (this.IsFrameMinSize()) return null;
        var drawPoint=this.CalculateDrawPoint();

        return this.PointRange(drawPoint);
    }

    this.Draw=function()
    {
        this.LinePoint=[];
        if (this.IsFrameMinSize()) return;

        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 isHScreen=this.Frame.IsHScreen;
        var left=this.Frame.ChartBorder.GetLeft();
        var right=this.Frame.ChartBorder.GetRight();
        if (isHScreen)
        {
            left=this.Frame.ChartBorder.GetTop();
            right=this.Frame.ChartBorder.GetBottom();
        }
        this.ClipFrame();

        this.Canvas.strokeStyle=this.LineColor;
        this.SetLineWidth();
        this.Canvas.beginPath();
        if (isHScreen)
        {
            this.Canvas.moveTo(drawPoint[0].X,left);
            this.Canvas.lineTo(drawPoint[0].X,right);
        }
        else
        {
            this.Canvas.moveTo(left,drawPoint[0].Y);
            this.Canvas.lineTo(right,drawPoint[0].Y);
        }
        this.Canvas.stroke();
        this.RestoreLineWidth();

        var line={Start:new Point(), End:new Point()};
        if (isHScreen)
        {
            line.Start.X=drawPoint[0].X;
            line.Start.Y=left;
            line.End.X=drawPoint[0].X;
            line.End.Y=right;
        }
        else
        {
            line.Start.X=left;
            line.Start.Y=drawPoint[0].Y;
            line.End.X=right;
            line.End.Y=drawPoint[0].Y;
        }
        this.LinePoint.push(line);

        //画点
        this.DrawPoint(drawPoint);

        //显示价格
        
        this.Canvas.fillStyle=this.LineColor;
        this.Canvas.font=this.Font;
        if (isHScreen)
        {
            this.Canvas.textAlign="left";
            this.Canvas.textBaseline="bottom";
            var xText=drawPoint[0].X;
            var yText=left;
            this.Canvas.translate(xText, yText);
            this.Canvas.rotate(90 * Math.PI / 180); //数据和框子旋转180度
            var yValue=this.Frame.GetYData(drawPoint[0].X);
            var text=yValue.toFixed(2);
            if (this.Label)
            {
                if (this.Label.Position==0) text=this.Label.Text+yValue.toFixed(2);
                else if (this.Label.Position==1) text=yValue.toFixed(2)+this.Label.Text;
            }
            this.Canvas.fillText(text,0,0);
        }
        else
        {
            this.Canvas.textAlign="left";
            this.Canvas.textBaseline="bottom";
            var yValue=this.Frame.GetYData(drawPoint[0].Y);
            var text=yValue.toFixed(2);
            if (this.Label)
            {
                if (this.Label.Position==0) text=this.Label.Text+yValue.toFixed(2);
                else if (this.Label.Position==1) text=yValue.toFixed(2)+this.Label.Text;
            }
            this.Canvas.fillText(text,left,drawPoint[0].Y);
        }
        
        this.Canvas.restore();
    }
}

//趋势线
function ChartDrawPictureTrendLine()
{
    this.newMethod=IChartDrawPicture;   //派生
    this.newMethod();
    delete this.newMethod;

    this.ClassName='ChartDrawPictureTrendLine';
    this.IsPointIn=this.IsPointIn_XYValue_Line;
    this.GetXYCoordinate=this.GetXYCoordinate_default;

    this.Draw=function()
    {
        this.LinePoint=[];
        if (this.IsFrameMinSize()) return;

        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.SetLineWidth();
        this.Canvas.beginPath();
        this.Canvas.moveTo(extendLine.Start.X,extendLine.Start.Y);
        this.Canvas.lineTo(extendLine.End.X,extendLine.End.Y);
        this.Canvas.stroke();
        this.RestoreLineWidth();

        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.GetXYCoordinate=this.GetXYCoordinate_default;

    this.Draw=function()
    {
        if (this.IsFrameMinSize()) return;

        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.SetLineWidth();
        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.RestoreLineWidth();
        
        //透明背景
        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.IsFrameMinSize()) return -1;
        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()
    {
        if (this.IsFrameMinSize()) return;

        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);
        this.SetLineWidth();
        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.RestoreLineWidth();
        //this.Canvas.closePath();
        this.Canvas.restore();

        //画点
        this.DrawPoint(drawPoint);
    }

    //0-10 鼠标对应的点索引   100=鼠标在正个图形上  -1 鼠标不在图形上
    this.IsPointIn=function(x,y)
    {
        if (this.IsFrameMinSize()) return -1;
        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=5;
    this.IsPointIn=this.IsPointIn_XYValue_Line;
    this.GetXYCoordinate=this.GetXYCoordinate_default;
    this.IsHScreen=false;

    this.Draw=function()
    {
        this.IsHScreen=this.Frame.IsHScreen;
        this.LinePoint=[];
        if (this.IsFrameMinSize()) return;

        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);
        this.SetLineWidth();
        for(var i in this.LinePoint)
        {
            var item=this.LinePoint[i];
            this.DrawLine(item.Start,item.End);
        }
        this.RestoreLineWidth();
       
        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;
            var yMove=points[1].Y-points[0].Y;
            line={Start:new Point(), End:new Point()};
            if (this.IsHScreen)
            {   
                line.Start.Y=points[1].Y;
                line.Start.X=points[1].X;
                line.End.Y=points[1].Y+yMove;
                line.End.X=points[0].X;
            }
            else
            {
                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()};
            if (this.IsHScreen)
            {
                line.Start.Y=ptStart.Y;
                line.Start.X=ptStart.X;
                line.End.Y=ptStart.Y+yMove;
                line.End.X=points[1].X;
            }
            else
            {
                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()};
            if (this.IsHScreen)
            {
                line.Start.Y=ptStart.Y;
                line.Start.X=ptStart.X;
                line.End.Y=ptStart.Y+yMove;
                line.End.X=points[0].X;
            }
            else
            {
                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);
        }
    }
}

//头肩 头肩顶(Head and shoulders top)以及头肩底(Head and shoulders bottom)两种形态
//支持横屏
function ChartDrawHeadShouldersBT()
{
    this.newMethod=ChartDrawPictureWaveMW;   //派生
    this.newMethod();
    delete this.newMethod;

    this.ClassName='ChartDrawHeadShouldersBT';

    this.CalculateLines_Backup=this.CalculateLines;
    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;
            var yMove=points[1].Y-points[0].Y;
            line={Start:new Point(), End:new Point()};
            if (this.IsHScreen)
            {
                line.Start.Y=points[1].Y;
                line.Start.X=points[1].X;

                line.End.Y=points[1].Y+yMove;
                line.End.X=points[0].X-xMove;
            }
            else
            {
                line.Start.Y=points[1].Y;
                line.Start.X=points[1].X;
                line.End.Y=points[0].Y-yMove;
                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()};
            if (this.IsHScreen)
            {
                line.Start.Y=ptStart.Y;
                line.Start.X=ptStart.X;
                line.End.Y=ptStart.Y+yMove;
                line.End.X=points[1].X; 
            }
            else
            {
                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()};
            if (this.IsHScreen)
            {
                line.Start.Y=ptStart.Y;
                line.Start.X=ptStart.X;
                line.End.Y=ptStart.Y+yMove;
                line.End.X=points[0].X;
            }
            else
            {
                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
        {
            return this.CalculateLines_Backup(points);
        }

    }
}

//平行线
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=[];
        if (this.IsFrameMinSize()) return;

        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 ChartDrawParallelRaysLines()
{
    this.newMethod=ChartDrawPictureParallelLines;   //派生
    this.newMethod();
    delete this.newMethod;

    this.ClassName='ChartDrawParallelRaysLines';

    this.DrawArea=function()
    {
    }

    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 endPoint=this.CalculateExtendLineEndPoint([points[0],points[1]]);
            this.LinePoint.push({ Start:points[0], End:endPoint });
        }
        else if (points.length==3)
        {
            var endPoint=this.CalculateExtendLineEndPoint([points[0],points[1]]);
            this.LinePoint.push({ Start:points[0], End:endPoint });

            //计算平行线
            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;
            endPoint=this.CalculateExtendLineEndPoint([ptStart,ptEnd]);
            this.LinePoint.push({ Start:points[2], End:endPoint });
        }
    }
}

//价格通道线
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=[];
        if (this.IsFrameMinSize()) return;

        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.SetOption=function(option)
    {
        if (!option) return;

        if (option.LineColor) this.LineColor=option.LineColor;
        if (option.Text) this.Text=option.Text;
        if (option.FontOption) this.FontOption=option.FontOption;
    }

    this.Draw=function(textFont)
    {
        this.TextRect=null;
        if (this.IsFrameMinSize()) return;

        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;

        var textHeight=this.FontOption.Size*GetDevicePixelRatio();
        this.TextRect={};
        this.TextRect.Left=drawPoint[0].X-textWidth/2;
        this.TextRect.Top=drawPoint[0].Y-textHeight;
        this.TextRect.Width=textWidth;
        this.TextRect.Height=textHeight
        //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.Angle=0;   //旋转角度


    this.SetOption=function(option)
    {
        if (!option) return;

        if (option.LineColor) this.LineColor=option.LineColor;
        if (option.FontOption && option.FontOption.Size>0) this.FontOption.Size=option.FontOption.Size;
        if (IFrameSplitOperator.IsNumber(option.Angle)) this.Angle=option.Angle;
    }

    this.Draw=function()
    {
        this.TextRect=null;
        if (this.IsFrameMinSize()) return;

        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="middle";
        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
        {
            if (this.Angle!=0)
            {
                this.Canvas.translate(drawPoint[0].X, drawPoint[0].Y);
                this.Canvas.rotate(this.Angle*(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=[];
        if (this.IsFrameMinSize()) return;

        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]);

        this.SetLineWidth();
        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.RestoreLineWidth();

        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=[];
        if (this.IsFrameMinSize()) return;

        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();
        
        this.SetLineWidth();
        for(var i in this.LinePoint)
        {
            var item=this.LinePoint[i];
            this.DrawLine(item.Start,item.End,item.IsDottedLine);
        }
        this.RestoreLineWidth();

        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.GetXYCoordinate=this.GetXYCoordinate_default;
    this.LastPoint;

    this.Draw=function()
    {
        this.LinePoint=[];
        if (this.IsFrameMinSize()) return;

        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.GetXYCoordinate=this.GetXYCoordinate_default;

    this.Draw=function()
    {
        this.LinePoint=[];
        if (this.IsFrameMinSize()) return;

        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.GetXYCoordinate=this.GetXYCoordinate_default;

    this.Draw=function()
    {
        this.LinePoint=[];
        if (this.IsFrameMinSize()) return;

        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.IsFrameMinSize()) return -1;
        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.GetXYCoordinate=this.GetXYCoordinate_default;
    this.PointCount=3;
    this.LastPoint;

    this.Draw=function()
    {
        this.LinePoint=[];
        if (this.IsFrameMinSize()) return;

        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=[];
        if (this.IsFrameMinSize()) return;

        var drawPoint=this.CalculateDrawPoint();
        if (!drawPoint) return;

        this.CalculateLines();
        if (this.LinePoint.length<=0) return;

        this.ClipFrame();

        this.SetLineWidth();
        for(var i in this.LinePoint)
        {
            var item=this.LinePoint[i];
            this.DrawLine(item.Start,item.End);
            this.DrawTitle(item.Start,item.Title);
        }
        this.RestoreLineWidth();
        
        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 ChartDrawLinearRegression(option)
{
    this.newMethod=IChartDrawPicture;   //派生
    this.newMethod();
    delete this.newMethod;

    this.ClassName='ChartDrawLinearRegression';
    this.PointCount=2;
    this.IsPointIn=this.IsPointIn_XYValue_Line;
    this.ChartBorder;
    this.Lines=[];  //回归线 { XValue:, YValue: }
    this.IsShowMaxMinLine=false;     //是否显示最高 最低价通道
    this.IsShowExtendLine=false;     //是否显示延长线
    this.ExtendLineDash=[5,5];       //延长线虚线
    this.MaxPoint;
    this.MinPoint;

    if (option) 
    {
        if (option.IsShowMaxMinLine==true) this.IsShowMaxMinLine=true;
        if (option.IsShowExtendLine==true) this.IsShowExtendLine=true;
    }

    //导入
    this.ImportStorageData=function(storageData)
    {
        if (storageData.IsShowMaxMinLine==true) this.IsShowMaxMinLine=true;
        if (storageData.IsShowExtendLine==true) this.IsShowExtendLine=true;
        if (storageData.Lines) this.Lines=storageData.Lines;
        if (storageData.MaxPoint && storageData.MinPoint) 
        {
            this.MaxPoint=storageData.MaxPoint;
            this.MinPoint=storageData.MinPoint;
        }
    }

    //导出
    this.Super_ExportStorageData=this.ExportStorageData;
    this.ExportStorageData=function()
    {
        var storageData;
        if (this.Super_ExportStorageData) 
        {
            storageData=this.Super_ExportStorageData();
            storageData.IsShowMaxMinLine=this.IsShowMaxMinLine;
            storageData.IsShowExtendLine=this.IsShowExtendLine;
            storageData.Lines=this.Lines;
            if (this.IsShowMaxMinLine)
            {
                storageData.MaxPoint=this.MaxPoint;
                storageData.MinPoint=this.MinPoint;
            }
        }

        return storageData;
    }


    this.PointToValue_Backup=this.PointToValue;

    this.PointToValue=function()
    {
        //拖拽完成 把点移动到线段头尾
        this.Point[0]={X:this.Lines[0].X, Y:this.Lines[0].Y};
        this.Point[1]={X:this.Lines[this.Lines.length-1].X, Y:this.Lines[this.Lines.length-1].Y};
        this.PointToValue_Backup();
    }

    this.Draw=function()
    {
        this.LinePoint=[];
        if (this.IsFrameMinSize()) return;

        var drawPoint=this.CalculateDrawPoint( { IsCheckX:true, IsCheckY:true} );
        if (!drawPoint || drawPoint.length!=2) 
        {
            if (this.Status==10)
            {
                this.ClipFrame();
                this.ChartBorder=this.Frame.ChartBorder;
                this.SetLineWidth();
                this.Canvas.strokeStyle=this.LineColor;
                this.DrawLinearLines();
                this.RestoreLineWidth();
                this.Canvas.restore();
            }
            return;
        }

        this.ClipFrame();
        this.ChartBorder=this.Frame.ChartBorder;
        
        //0=开始画 1=完成第1个点  2=完成第2个点 3=完成第3个点  10=完成 20=移动)
        this.SetLineWidth();
        this.Canvas.strokeStyle=this.LineColor;
        var ptStart=drawPoint[0];
        var ptEnd=drawPoint[1];

        if (this.Status==10)
        {
            this.DrawLinearLines();
        }  
        else
        {
            var top=this.ChartBorder.GetTopEx();
            var bottom=this.ChartBorder.GetBottomEx();

            var kPoint=this.PointToKLine([ptStart,ptEnd]);
            //JSConsole.Chart.Log('[ChartDrawLinearRegression::Draw] kPoint', kPoint);
            var linear=this.Calculate(kPoint);
            //JSConsole.Chart.Log('[ChartDrawLinearRegression::Draw] linear', linear);
    
            this.Lines=linear.Points;
            this.MaxPoint=linear.Max;
            this.MinPoint=linear.Min;

            this.DrawLinearLines();

            this.Canvas.beginPath();
            this.Canvas.moveTo(ptStart.X,top);
            this.Canvas.lineTo(ptStart.X,bottom);

            this.Canvas.moveTo(ptEnd.X,top);
            this.Canvas.lineTo(ptEnd.X,bottom);
            this.Canvas.stroke();

        }                            
        
        this.RestoreLineWidth();

        var line={Start:ptStart, End:ptEnd};
        this.LinePoint.push(line);
        
        this.DrawPoint(drawPoint);  //画点
        this.Canvas.restore();
    }

    this.Calculate=function(kPoint)
    {
        var startPoint=kPoint[0];
        var endPoint=kPoint[1];
        if (startPoint.XValue>endPoint.XValue)
        {
            startPoint=kPoint[1];
            endPoint=kPoint[0];
        }
        
        var num=(endPoint.XValue-startPoint.XValue)+1;
        var data=this.Frame.Data.Data;
        var i=endPoint.XValue;
        var Ex = 0, Ey = 0, Sxy = 0, Sxx = 0, Const, Slope;
        var i, j,x, k;
        for(j = 0, x=num; j < num && j <= i; ++j, --x)
        {
            Ex += x;
            Ey += data[i - j].Close;
        }
        Ex /= num;
        Ey /= num;
        for(j = 0, x=num; j < num && j <= i; ++j,--x)
        {
            Sxy += (x-Ex)*(data[i-j].Close-Ey);
            Sxx += (x-Ex)*(x-Ex);
        }
        Slope = Sxy / Sxx;  //斜率
        Const = Ey - Ex*Slope;
        //value=Slope * num + Const; //Y轴值 线性回归公式

        var points=[];
        var max=null, min=null;
        for(j = 0, k=num; j < num && j <= i; ++j,--k)
        {
            var xIndex=endPoint.XIndex-j;
            var xValue=endPoint.XValue-j;
            var x=this.Frame.GetXFromIndex(xIndex);

            var yValue=Slope * k + Const;
            var y=this.Frame.GetYFromData(yValue,false);

            var item={ X:x, Y:y, XValue:xValue, YValue:yValue };
            points.push(item);

            if (max==null || max.High<data[xValue].High)
            {
                max={X:x,Y:y,XValue:xValue, YValue:yValue, High:data[xValue].High };
            }

            if (min==null || min.Low>data[xValue].Low)
            {
                min={X:x,Y:y,XValue:xValue, YValue:yValue, Low:data[xValue].Low };
            }
        }

        return { Points:points, Slope:Slope, Const:Const , Max:max, Min:min };
    }

    this.DrawLinearLines=function()
    {
        if (!this.Frame) return null;
        var data=this.Frame.Data;
        if (!data) return null;

        var showCount=this.Frame.XPointCount;
        var dataOffset=data.DataOffset;
        var isHScreen=this.Frame.IsHScreen;
        var drawLines=[];
        for(var i in this.Lines)
        {
            var item=this.Lines[i];
            var dataIndex=item.XValue-dataOffset;
            if (dataIndex<0 || dataIndex>=showCount) continue;
            var pt={};
            if (isHScreen)  //横屏X,Y对调
            {

            }
            else
            {
                pt.X=this.Frame.GetXFromIndex(dataIndex,false);
                pt.Y=this.Frame.GetYFromData(item.YValue,false);
                pt.YValue=item.YValue;
            }

            drawLines.push(pt);
        }

        if (drawLines.length>1)
        {
            for(var i in drawLines)
            {
                var item=drawLines[i];

                if (i==0)
                {
                    this.Canvas.beginPath();
                    this.Canvas.moveTo(item.X,item.Y);
                }
                else
                {
                    this.Canvas.lineTo(item.X,item.Y);
                    if (i==drawLines.length-1) this.Canvas.stroke();
                }
            }

            this.DrawExtendLine(drawLines);
        }

        //最大 最小通道
        if (this.IsShowMaxMinLine && drawLines.length>1 && this.MaxPoint && this.MinPoint)
        {
            var highOffset=this.MaxPoint.High-this.MaxPoint.YValue;
            for(var i in drawLines)
            {
                var item=drawLines[i];
                item.Y=this.Frame.GetYFromData((item.YValue+highOffset),false);

                if (i==0)
                {
                    this.Canvas.beginPath();
                    this.Canvas.moveTo(item.X,item.Y);
                }
                else
                {
                    this.Canvas.lineTo(item.X,item.Y);
                    if (i==drawLines.length-1) this.Canvas.stroke();
                }
            }
            this.DrawExtendLine(drawLines);

            var lowOffset=this.MinPoint.Low-this.MinPoint.YValue;
            for(var i in drawLines)
            {
                var item=drawLines[i];
                item.Y=this.Frame.GetYFromData((item.YValue+lowOffset),false);

                if (i==0)
                {
                    this.Canvas.beginPath();
                    this.Canvas.moveTo(item.X,item.Y);
                }
                else
                {
                    this.Canvas.lineTo(item.X,item.Y);
                    if (i==drawLines.length-1) this.Canvas.stroke();
                }
            }
            this.DrawExtendLine(drawLines);
        }
    }

    //画延长线
    this.DrawExtendLine=function(lines)
    {
        if (!this.IsShowExtendLine) return;
        
        var ptStart=lines[0];
        var ptEnd=lines[lines.length-1];
        var aryPoint;
        if (ptEnd.X>ptStart.X) aryPoint=[ptStart, ptEnd];
        else aryPoint=[ptEnd, ptStart];

        var ptExtend=this.CalculateExtendLineEndPoint(aryPoint);
        this.Canvas.beginPath();
        this.Canvas.moveTo(ptEnd.X,ptEnd.Y);
        this.Canvas.lineTo(ptExtend.X,ptExtend.Y);
        this.Canvas.setLineDash(this.ExtendLineDash);
        this.Canvas.stroke();
        this.Canvas.setLineDash([]);
    }

}

//尺子
function ChartDrawRuler()
{
    this.newMethod=IChartDrawPicture;   //派生
    this.newMethod();
    delete this.newMethod;

    this.ClassName='ChartDrawRuler';
    this.PointCount=2;
    this.Font=16*GetDevicePixelRatio() +"px 微软雅黑";
    this.IsPointIn=this.IsPointIn_XYValue_Line;
    this.TitleColor=g_JSChartResource.ChartDrawRuler.TitleColor;
    this.IsHScreen=false;

    this.Draw=function()
    {
        this.LinePoint=[];
        var drawPoint=this.CalculateDrawPoint( {IsCheckX:true, IsCheckY:true} );
        if (!drawPoint) return;
        if (drawPoint.length!=2) return;
        this.IsHScreen=this.Frame.IsHScreen;

        this.ClipFrame();

        var ptStart=drawPoint[0];
        var ptEnd=drawPoint[1];

        var kPoint=this.PointToKLine([ptStart,ptEnd]);
        //JSConsole.Chart.Log('[ChartDrawLinearRegression::ChartDrawRuler] kPoint', kPoint);
        var kDataInfo=this.Calculate(kPoint);
        //JSConsole.Chart.Log('[ChartDrawLinearRegression::ChartDrawRuler] kDataInfo', kDataInfo);

        var increase=IFrameSplitOperator.IsNumber(kDataInfo.Increase)? kDataInfo.Increase.toFixed(2)+'%': "--";
        var risefall=IFrameSplitOperator.IsNumber(kDataInfo.Risefall)? kDataInfo.Risefall.toFixed(2): "--";
        var title=`间距:${kDataInfo.Count} 涨跌:${risefall} 涨幅:${increase}`;
        //JSConsole.Chart.Log('[ChartDrawLinearRegression::ChartDrawRuler] title', title);
        
        this.SetLineWidth();
        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.RestoreLineWidth();

        var line={Start:ptStart, End:ptEnd};
        this.LinePoint.push(line);
        
        this.DrawPoint(drawPoint);  //画点

        //绘制信息
        this.Canvas.textBaseline='bottom';
        this.Canvas.textAlign='left';
        this.Canvas.font=this.Font;
        if (this.TitleColor)
        {
            this.Canvas.fillStyle=this.TitleColor;
        }
        else if (IFrameSplitOperator.IsNumber(kDataInfo.Increase))
        {
            if (kDataInfo.Increase>0) this.Canvas.fillStyle=g_JSChartResource.UpTextColor;
            else if (kDataInfo.Increase<0) this.Canvas.fillStyle=g_JSChartResource.DownTextColor;
            else this.Canvas.fillStyle=g_JSChartResource.UnchagneTextColor;
        }
        else
        {
            this.Canvas.fillStyle=g_JSChartResource.UnchagneTextColor;
        }

        var offset=3*GetDevicePixelRatio();
        var xText=ptStart.X
        var yText=ptStart.Y
        if (this.IsHScreen)
        {
            this.Canvas.translate(xText+offset,yText+offset);
            this.Canvas.rotate(90 * Math.PI / 180);
            this.Canvas.fillText(title,0,0);
        }
        else
        {
            this.Canvas.fillText(title,xText+offset,yText-offset);
        }
        
        
        this.Canvas.restore();
    }

    this.Calculate=function(kPoint)
    {
        var startPoint=kPoint[0];
        var endPoint=kPoint[1];
        if (startPoint.XValue>endPoint.XValue)
        {
            startPoint=kPoint[1];
            endPoint=kPoint[0];
        }

        var data=this.Frame.Data.Data;
        var open, high, low, yClose, close;
        var count=0;
        for(var i=startPoint.XValue;i<=endPoint.XValue;++i, ++count)
        {
            var item=data[i];
            if (count==0)
            {
                yClose=item.YClose;
                open=item.Open;
                close=item.Close;
                low=item.Low;
                high=item.High;
            }
            else
            {
                close=item.Close;
                if (low>item.Low) low=item.Low;
                if (high<item.High)  high=item.High;
            }
        }

        if (!IFrameSplitOperator.IsPlusNumber(yClose))  //前收盘无效， 取上一个交易日的收盘价
        {
            var index=startPoint.XValue-1;
            if (index>=0 && index<data.length) yClose=data[index].Close;
        }

        var result={ YClose:yClose, Open:open, High:high, Low:low, Close:close, Count:count };
        if (IFrameSplitOperator.IsPlusNumber(yClose)) 
        {
            result.Increase=(close-yClose)/yClose*100;
            result.Risefall=(close-yClose);
        }
        
        return result;
    }

}

//画图工具-标价线 支持横屏
function ChartDrawPriceLine()
{
    this.newMethod=IChartDrawPicture;   //派生
    this.newMethod();
    delete this.newMethod;

    this.ClassName='ChartDrawPriceLine';
    this.Font=16*GetDevicePixelRatio() +"px 微软雅黑";
    this.PointCount=1;
    this.IsPointIn=this.IsPointIn_XYValue_Line;
    this.IsHScreen=false;

    this.Draw=function()
    {
        this.LinePoint=[];
        if (this.IsFrameMinSize()) return;

        var drawPoint=this.CalculateDrawPoint( { IsCheckX:false, IsCheckY:true } );
        if (!drawPoint) return;
        if (drawPoint.length!=1) return;

        this.IsHScreen=this.Frame.IsHScreen;
        var ptStart=drawPoint[0];
        var chartBorder=this.Frame.ChartBorder;
        if (this.IsHScreen)
        {
            var left=chartBorder.GetLeftEx();
            var right=chartBorder.GetRightEx();
            if (ptStart.X<left || ptStart.X>right) return;

            var bottom=chartBorder.GetBottom();
            var ptEnd={X:ptStart.X, Y:bottom};
            var price=this.Frame.GetYData(ptStart.X, false);
        }
        else
        {
            var bottom=chartBorder.GetBottomEx();
            var top=chartBorder.GetTopEx();
            if (ptStart.Y<top || ptStart.Y>bottom) return;

            var right=chartBorder.GetRight();
            var ptEnd={X:right, Y:ptStart.Y};
            var price=this.Frame.GetYData(ptStart.Y, false);
        }
        
        

        this.ClipFrame();
       
        this.SetLineWidth();
        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.RestoreLineWidth();

        var line={Start:ptStart, End:ptEnd};
        this.LinePoint.push(line);
        
        this.DrawPoint(drawPoint);  //画点
        
        this.Canvas.textBaseline='bottom';
        this.Canvas.textAlign='left';
        this.Canvas.fillStyle=this.LineColor;
        this.Canvas.font=this.Font;
        var offset=2*GetDevicePixelRatio();
        var xText=ptStart.X;
        var yText=ptStart.Y;
        if (this.IsHScreen)
        {
            this.Canvas.translate(xText+offset,yText+offset);
            this.Canvas.rotate(90 * Math.PI / 180);
            this.Canvas.fillText(price.toFixed(2),0,0);
        }
        else
        {
            this.Canvas.fillText(price.toFixed(2),xText+offset,yText-offset);
        }
        
        this.Canvas.restore();
    }
}

//画图工具-标价线2 不支持横屏
function ChartDrawPriceLineV2()
{
    this.newMethod=IChartDrawPicture;   //派生
    this.newMethod();
    delete this.newMethod;

    this.ClassName='ChartDrawPriceLineV2';
    this.Font=12*GetDevicePixelRatio() +"px 微软雅黑";
    this.PointCount=1;
    this.IsPointIn=this.IsPointIn_XYValue_Line;
    this.IsHScreen=false;
    this.LineWidth=1;
    this.IsDrawFirst=true;
    this.TextColor="rgb(255,255,255)";

    this.Super_SetOption=this.SetOption;    //父类函数
    this.SetOption=function(option)
    {
        if (this.Super_SetOption) this.Super_SetOption(option);
        if (option)
        {
            if (option.TextColor) this.TextColor=option.TextColor;
        }
    }

    this.Draw=function()
    {
        this.LinePoint=[];
        if (this.IsFrameMinSize()) return;

        var drawPoint=this.CalculateDrawPoint( { IsCheckX:false, IsCheckY:true } );
        if (!drawPoint) return;
        if (drawPoint.length!=1) return;
        if (!this.IsYValueInFrame(this.Value[0].YValue)) return;

        this.IsHScreen=this.Frame.IsHScreen;
        var ptStart=drawPoint[0];
        var chartBorder=this.Frame.ChartBorder;
        var border=this.Frame.GetBorder();
        if (this.IsHScreen)
        {
            return;

            var left=chartBorder.GetLeftEx();
            var right=chartBorder.GetRightEx();

            var bottom=chartBorder.GetBottom();
            var ptEnd={X:ptStart.X, Y:bottom};
            var price=this.Frame.GetYData(ptStart.X, false);
        }
        else
        {
            var bottom=border.BottomEx;
            var top=border.TopTitle;
            if (ptStart.Y<top || ptStart.Y>bottom) return;

            var left=border.Left;
            var right=border.Right;
            var price=this.Frame.GetYData(ptStart.Y, false);
        }
        
        //this.ClipFrame();
       
        this.SetLineWidth();
        this.Canvas.strokeStyle=this.LineColor;
        this.Canvas.beginPath();
        this.Canvas.moveTo(ToFixedPoint(left),ToFixedPoint(ptStart.Y));
        this.Canvas.lineTo(ToFixedPoint(right),ToFixedPoint(ptStart.Y));
        this.Canvas.stroke();
        this.RestoreLineWidth();

        var line={Start:{X:left, Y:ptStart.Y}, End:{X:right, Y:ptStart.Y}};
        this.LinePoint.push(line);
        
        var pixelTatio = GetDevicePixelRatio();
        this.Canvas.font=this.Font;
        var offset=2*pixelTatio;
        var xText=right;
        var yText=ptStart.Y;
        if (this.IsHScreen)
        {
            //this.Canvas.translate(xText+offset,yText+offset);
            //this.Canvas.rotate(90 * Math.PI / 180);
            //this.Canvas.fillText(price.toFixed(2),0,0);
        }
        else
        {
            this.Canvas.textBaseline='middle';
            this.Canvas.textAlign='left';
            var textHeight=this.GetFontHeight();
            var text=price.toFixed(2);
            var textWidth=this.Canvas.measureText(text).width+2*offset;

            if (chartBorder.Right>10)
            {
                var rtBG={ Left:xText, Top:(yText-textHeight/2-1*pixelTatio) , Width:textWidth, Height: textHeight};
                if (rtBG.Left+rtBG.Width>border.ChartWidth) rtBG.Left=border.ChartWidth-rtBG.Width-2*pixelTatio;
            }
            else    //框架内部显示
            {
                var rtBG={ Left:xText-textWidth, Top:(yText-textHeight/2-1*pixelTatio) , Width:textWidth, Height: textHeight};
            }
            
            this.Canvas.fillStyle=this.LineColor;
            this.Canvas.fillRect(rtBG.Left, rtBG.Top, rtBG.Width, rtBG.Height);

            this.Canvas.fillStyle=this.TextColor;
            this.Canvas.fillText(text, rtBG.Left+offset, yText);
        }
        
        this.Canvas.restore();
    }

    this.DrawPrice=function()
    {

    }
}

//画图工具-竖线 支持横屏
function ChartDrawVerticalLine()
{
    this.newMethod=IChartDrawPicture;   //派生
    this.newMethod();
    delete this.newMethod;

    this.ClassName='ChartDrawVerticalLine';
    this.PointCount=1;
    this.IsPointIn=this.IsPointIn_XYValue_Line;
    this.IsHScreen=false;

    this.Draw=function()
    {
        this.LinePoint=[];
        if (this.IsFrameMinSize()) return;

        if (!this.Frame || !this.Frame.Data) return;
        var data=this.Frame.Data;
        var drawPoint=this.CalculateDrawPoint( { IsCheckX:true, IsCheckY:true } );
        if (!drawPoint) return;
        if (drawPoint.length!=1) return;

        this.IsHScreen=this.Frame.IsHScreen;
        var pt=drawPoint[0];

        var chartBorder=this.Frame.ChartBorder;
        if (this.IsHScreen)
        {
            var xValue=Math.round(this.Frame.GetXData(pt.Y,false))+data.DataOffset;
            if (xValue<0) xValue=0;
            else if (xValue>=data.Data.length) xValue=data.Data.length-1;
            var yLine=this.Frame.GetXFromIndex(xValue-data.DataOffset,false);
            yLine=ToFixedPoint2(this.LineWidth,yLine);
            var left=chartBorder.GetLeftEx();
            var right=chartBorder.GetRightEx();
            var ptStart={ X:left, Y:yLine };
            var ptEnd={ X:right, Y:yLine };
        }
        else
        {
            var xValue=Math.round(this.Frame.GetXData(pt.X,false))+data.DataOffset;
            if (xValue<0) xValue=0;
            else if (xValue>=data.Data.length) xValue=data.Data.length-1;
            var xLine=this.Frame.GetXFromIndex(xValue-data.DataOffset,false);
            xLine=ToFixedPoint2(this.LineWidth,xLine);
            var top=chartBorder.GetTopEx();
            var bottom=chartBorder.GetBottomEx();
            var ptStart={ X:xLine, Y:top };
            var ptEnd={ X:xLine, Y:bottom };
        }
        
        this.ClipFrame();
       
        this.SetLineWidth();
        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.RestoreLineWidth();

        var line={Start:ptStart, End:ptEnd};
        this.LinePoint.push(line);
        
        if (this.Status==10) this.DrawPoint(drawPoint);  //画点 
        this.Canvas.restore();
    }
}

//画图工具-波浪尺
function ChartDrawWaveRuler()
{
    this.newMethod=IChartDrawPicture;   //派生
    this.newMethod();
    delete this.newMethod;

    this.ClassName='ChartDrawWaveRuler';
    this.PointCount=3;
    this.Font=16*GetDevicePixelRatio() +"px 微软雅黑";
    this.IsPointIn=this.IsPointIn_XYValue_Line;
    this.LastPoint;
    this.LinePoint;
    this.ScaleRuler=g_JSChartResource.ChartDrawWaveRuler.ScaleRuler;
    this.RulerWidth=g_JSChartResource.ChartDrawWaveRuler.RulerWidth;;       //刻度尺长度
    this.RulerLineWidth=g_JSChartResource.ChartDrawWaveRuler.RulerLineWidth;
    this.MaxScaleRuler=g_JSChartResource.ChartDrawWaveRuler.MaxScaleRuler;   //尺子最大的高度比
    this.Font=g_JSChartResource.ChartDrawWaveRuler.MaxScaleRuler;
    this.IsHScreen=false;

    this.Draw=function()
    {
        this.LinePoint=[];
        if (this.IsFrameMinSize()) return;

        var drawPoint=this.CalculateDrawPoint({IsCheckX:true, IsCheckY:true});
        if (!drawPoint) return;

        this.IsHScreen=this.Frame.IsHScreen;
        this.CalculateLines(drawPoint);

        this.ClipFrame();
        this.SetLineWidth();

        for(var i in this.LinePoint)
        {
            var item=this.LinePoint[i];
            this.DrawLine(item.Start,item.End);
        }

        //绘制波浪信息
        if (drawPoint.length==3) this.DrawWaveRuler(drawPoint);
        
        this.RestoreLineWidth();
       
        this.DrawPoint(drawPoint); //画点
        this.Canvas.restore();
    }

    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 linePoint=
            { 
                Start:{X:points[0].X,Y:points[0].Y}, 
                End:{X:points[1].X,Y:points[1].Y}
            };
            this.LinePoint.push(linePoint);
        }
        else if (points.length==3)
        {
            var linePoint=
            { 
                Start:{X:points[0].X,Y:points[0].Y}, 
                End:{X:points[1].X,Y:points[1].Y}
            };
            this.LinePoint.push(linePoint);

            linePoint=
            { 
                Start:{X:points[1].X,Y:points[1].Y}, 
                End:{X:points[2].X,Y:points[2].Y}
            };
           
            this.LinePoint.push(linePoint);
        }
    }

    this.DrawWaveRuler=function(points)
    {
        var ptBottom=points[1];
        var ptStart=points[0];
        var ptEnd=points[2];

        var lineWidth=this.RulerLineWidth*GetDevicePixelRatio();
        this.Canvas.lineWidth=lineWidth;
        this.Canvas.textBaseline='middle';
        this.Canvas.textAlign='left';
        this.Canvas.fillStyle=this.LineColor;
        this.Canvas.font=this.Font;
        var rulerWidth=this.RulerWidth*GetDevicePixelRatio();//刻度线长度

        if (this.IsHScreen)
        {
            var rulerHeight=ptStart.X-ptBottom.X;
            var ptExtendBottom={ X:ptEnd.X-this.MaxScaleRuler*rulerHeight, Y:ptEnd.Y};
            this.DrawLine(ptEnd,ptExtendBottom);
            this.LinePoint.push({Start:ptEnd, End:ptExtendBottom});
            var y=ptEnd.Y-rulerWidth/2, y2=ptEnd.Y+rulerWidth/2;
        }
        else
        {
            var rulerHeight=ptStart.Y-ptBottom.Y;
            var ptExtendBottom={ X:ToFixedPoint2(lineWidth,ptEnd.X), Y:ptEnd.Y-this.MaxScaleRuler*rulerHeight };
            this.DrawLine({X:ToFixedPoint2(lineWidth,ptEnd.X), Y:ptEnd.Y},ptExtendBottom);
            this.LinePoint.push({Start:ptEnd, End:ptExtendBottom});
            var x=ptEnd.X-rulerWidth/2, x2=ptEnd.X+rulerWidth/2;
        }

        var textOffset=4*GetDevicePixelRatio();
        for(var i in this.ScaleRuler)
        {
            var item=this.ScaleRuler[i];
            if (this.IsHScreen)
            {
                var x=ptEnd.X - item.Value*rulerHeight;
                var price=this.Frame.GetYData(x, false);
                this.DrawLine({X:x, Y:y}, {X:x, Y:y2});
                var text=`${price.toFixed(2)}  ${item.Text? item.Text: item.Value.toFixed(3)}`;
                this.Canvas.save();
                this.Canvas.translate(x,ptEnd.Y);
                this.Canvas.rotate(90 * Math.PI / 180);
                this.Canvas.fillText(text,textOffset,0);
                this.Canvas.restore();
            }
            else
            {
                var y=ptEnd.Y - item.Value*rulerHeight;
                var price=this.Frame.GetYData(y, false);
                this.DrawLine({X:x, Y:ToFixedPoint2(lineWidth,y)}, {X:x2, Y:ToFixedPoint2(lineWidth,y)});
                var text=`${price.toFixed(2)}  ${item.Text? item.Text: item.Value.toFixed(3)}`;
                this.Canvas.fillText(text,x2+textOffset,y);
            }
        }
    }
}

//画图工具-波浪尺 2个点的
function ChartDrawWaveRuler2Point()
{
    this.newMethod=IChartDrawPicture;   //派生
    this.newMethod();
    delete this.newMethod;

    this.ClassName='ChartDrawWaveRuler2Point';
    this.PointCount=2;
    this.Font=14*GetDevicePixelRatio() +"px 微软雅黑";
    this.IsPointIn=this.IsPointIn_XYValue_Line;
    this.PointRate=[ 510, 517, 511.4];
    this.LinePoint;
    this.CPoint;
    this.ScaleRuler=g_JSChartResource.ChartDrawWaveRuler2Point.ScaleRuler;
    this.RulerWidth=g_JSChartResource.ChartDrawWaveRuler2Point.RulerWidth;;       //刻度尺长度
    this.RulerLineWidth=g_JSChartResource.ChartDrawWaveRuler2Point.RulerLineWidth;
    this.MaxScaleRuler=g_JSChartResource.ChartDrawWaveRuler2Point.MaxScaleRuler;   //尺子最大的高度比
    this.Font=g_JSChartResource.ChartDrawWaveRuler2Point.MaxScaleRuler;
    this.IsHScreen=false;
    this.Super_SetOption=this.SetOption;    //父类函数

    this.SetOption=function(option)
    {
        if (this.Super_SetOption) this.Super_SetOption(option);
        if (option)
        {
            if (option.PointRate) this.PointRate=option.PointRate;
        }
    }

    this.Draw=function()
    {
        this.LinePoint=[];
        if (this.IsFrameMinSize()) return;

        var drawPoint=this.CalculateDrawPoint({IsCheckX:true, IsCheckY:true});
        if (!drawPoint) return;

        this.IsHScreen=this.Frame.IsHScreen;
        this.CalculateLines(drawPoint);

        this.ClipFrame();
        this.SetLineWidth();

        for(var i in this.LinePoint)
        {
            var item=this.LinePoint[i];
            this.DrawLine(item.Start,item.End);
        }

        var points=[drawPoint[0],drawPoint[1],this.CPoint];
        this.DrawWaveRuler(points);
        
        this.RestoreLineWidth();
       
        this.DrawPoint(drawPoint); //画点
        this.Canvas.restore();
    }

    this.CalculateLines=function(points)
    {
        var firstLine=
        { 
            Start:{ X:points[0].X,Y:points[0].Y }, 
            End:{ X:points[1].X,Y:points[1].Y }
        };
        this.LinePoint.push(firstLine);

        var a=points[0].Y;
        var b=points[1].Y;

        var width=this.PointRate[1]-this.PointRate[0];
        var offset=this.PointRate[2]-this.PointRate[0];

        var c=a-((a-b)*offset)/width;

        this.CPoint={ X:points[1].X, Y:c };
    }

    this.DrawWaveRuler=function(points)
    {
        var ptBottom=points[1];
        var ptStart=points[0];
        var ptEnd=points[2];

        var lineWidth=this.RulerLineWidth*GetDevicePixelRatio();
        this.Canvas.lineWidth=lineWidth;
        this.Canvas.textBaseline='middle';
        this.Canvas.textAlign='left';
        this.Canvas.fillStyle=this.LineColor;
        this.Canvas.font=this.Font;
        var rulerWidth=this.RulerWidth*GetDevicePixelRatio();//刻度线长度

        if (this.IsHScreen)
        {
            var rulerHeight=ptStart.X-ptBottom.X;
            var ptExtendBottom={ X:ptEnd.X-this.MaxScaleRuler*rulerHeight, Y:ptEnd.Y};
            this.DrawLine(ptEnd,ptExtendBottom);
            this.LinePoint.push({Start:ptEnd, End:ptExtendBottom});
            var y=ptEnd.Y-rulerWidth/2, y2=ptEnd.Y+rulerWidth/2;
        }
        else
        {
            var rulerHeight=ptStart.Y-ptBottom.Y;
            var ptExtendBottom={ X:ToFixedPoint2(lineWidth,ptEnd.X), Y:ptEnd.Y-this.MaxScaleRuler*rulerHeight };
            this.DrawLine({X:ToFixedPoint2(lineWidth,ptEnd.X), Y:ptEnd.Y},ptExtendBottom);
            this.LinePoint.push({Start:ptEnd, End:ptExtendBottom});
            var x=ptEnd.X, x2=ptEnd.X+rulerWidth;
        }

        var textOffset=4*GetDevicePixelRatio();
        for(var i in this.ScaleRuler)
        {
            var item=this.ScaleRuler[i];
            if (this.IsHScreen)
            {
                var x=ptEnd.X - item.Value*rulerHeight;
                var price=this.Frame.GetYData(x, false);
                this.DrawLine({X:x, Y:y}, {X:x, Y:y2});
                var text=`${price.toFixed(2)}  ${item.Text? item.Text: item.Value.toFixed(3)}`;
                this.Canvas.save();
                this.Canvas.translate(x,ptEnd.Y);
                this.Canvas.rotate(90 * Math.PI / 180);
                this.Canvas.fillText(text,textOffset,0);
                this.Canvas.restore();
            }
            else
            {
                var y=ptEnd.Y - item.Value*rulerHeight;
                var price=this.Frame.GetYData(y, false);
                this.DrawLine({X:x, Y:ToFixedPoint2(lineWidth,y)}, {X:x2, Y:ToFixedPoint2(lineWidth,y)});
                var text=`${price.toFixed(2)}  ${item.Text? item.Text: item.Value.toFixed(3)}`;
                this.Canvas.fillText(text,x2+textOffset,y);
            }
        }
    }
}

//画图工具-箱型线 支持横屏
function ChartDrawBox()
{
    this.newMethod=IChartDrawPicture;   //派生
    this.newMethod();
    delete this.newMethod;

    this.ClassName='ChartDrawBox';
    this.PointCount=2;
    this.Font=16*GetDevicePixelRatio() +"px 微软雅黑";
    this.IsPointIn=this.IsPointIn_XYValue_Line;
    this.IsHScreen=false;
    this.AvPriceLineDash=[5*GetDevicePixelRatio(),5*GetDevicePixelRatio()];
    this.KLineBorder;

    this.PointToValue_Backup=this.PointToValue;
    this.PointToValue=function()
    {
        //拖拽完成 把点移动到线段头尾
        this.Point[0]={X:this.KLineBorder.Left, Y:this.KLineBorder.Top};
        this.Point[1]={X:this.KLineBorder.Right, Y:this.KLineBorder.Bottom};
        this.PointToValue_Backup();
    }

    this.Draw=function()
    {
        this.LinePoint=[];
        if (this.IsFrameMinSize()) return;

        var drawPoint=this.CalculateDrawPoint( {IsCheckX:true, IsCheckY:true} );
        if (!drawPoint) return;
        if (drawPoint.length!=2) return;
        this.IsHScreen=this.Frame.IsHScreen;

        this.ClipFrame();

        var ptStart=drawPoint[0];
        var ptEnd=drawPoint[1];

        var kPoint=this.PointToKLine([ptStart,ptEnd]);
        JSConsole.Chart.Log('[ChartDrawBox::Draw] kPoint', kPoint);
        var kDataInfo=this.Calculate(kPoint);
        JSConsole.Chart.Log('[ChartDrawBox::Draw] kDataInfo', kDataInfo);
        var klineBorder=this.GetKLineBorder(drawPoint, kDataInfo);
        this.KLineBorder=klineBorder;
        
        this.SetLineWidth();
        this.Canvas.strokeStyle=this.LineColor;
        this.Canvas.strokeRect(ToFixedRect(klineBorder.Left), ToFixedRect(klineBorder.Top), ToFixedRect(klineBorder.Right-klineBorder.Left), ToFixedRect(klineBorder.Bottom-klineBorder.Top));

        //均价
        var avPriceText;
        if (kDataInfo.Amount>0 && kDataInfo.Vol>0)
        {
            var price=kDataInfo.Amount/kDataInfo.Vol;
            avPriceText=`均价${price.toFixed(2)}`;
            
            this.Canvas.beginPath();
            if (this.IsHScreen)
            {
                var x=this.Frame.GetYFromData(price,false);
                this.Canvas.moveTo(ToFixedPoint2(this.Canvas.lineWidth,x),klineBorder.Top);
                this.Canvas.lineTo(ToFixedPoint2(this.Canvas.lineWidth,x),klineBorder.Bottom);
            }
            else
            {
                var y=this.Frame.GetYFromData(price,false);
                this.Canvas.moveTo(klineBorder.Left,ToFixedPoint2(this.Canvas.lineWidth,y));
                this.Canvas.lineTo(klineBorder.Right,ToFixedPoint2(this.Canvas.lineWidth,y));
            }
            
            this.Canvas.setLineDash(this.AvPriceLineDash);
            this.Canvas.stroke();
            this.Canvas.setLineDash([]);
        }
        this.RestoreLineWidth();

        this.DrawPoint(drawPoint);  //画点

        //绘制信息
        this.Canvas.textBaseline='top';
        this.Canvas.textAlign='left';
        this.Canvas.font=this.Font;
        this.Canvas.fillStyle=this.LineColor;
        var textOffset=2*GetDevicePixelRatio();
        var text=`K线数${kDataInfo.Count}`;
        if (this.IsHScreen) this.DrawText(text,klineBorder.Right,klineBorder.Top, textOffset, textOffset);
        else this.DrawText(text,klineBorder.Left,klineBorder.Top, textOffset, textOffset);

        if (avPriceText) 
        {
            if (this.IsHScreen) this.DrawText(avPriceText,x,klineBorder.Top, textOffset, textOffset);   //均价
            else this.DrawText(avPriceText,klineBorder.Left,y, textOffset, textOffset);   //均价
        }

        var yClose=IFrameSplitOperator.IsNumber(kDataInfo.YClose)? kDataInfo.YClose:kDataInfo.Open;
        var value=(kDataInfo.Close-yClose)/yClose*100;
        text=`${value.toFixed(2)}%`;
        if (this.IsHScreen) this.DrawText(text,klineBorder.Right,klineBorder.Bottom, textOffset, textOffset);
        else this.DrawText(text,klineBorder.Right,klineBorder.Top, textOffset, textOffset);

        value=kDataInfo.Close-yClose;
        text=`${value.toFixed(2)}`;
        this.Canvas.textBaseline='bottom';
        if (this.IsHScreen) this.DrawText(text,klineBorder.Left,klineBorder.Bottom, textOffset, 0);
        else this.DrawText(text,klineBorder.Right,klineBorder.Bottom, textOffset, 0);

        this.Canvas.restore();
    }

    this.Calculate=function(kPoint)
    {
        var startPoint=kPoint[0];
        var endPoint=kPoint[1];
        if (startPoint.XValue>endPoint.XValue)
        {
            startPoint=kPoint[1];
            endPoint=kPoint[0];
        }

        var data=this.Frame.Data.Data;
        var open, high, low, yClose, close, vol=0, amount=0;
        var count=0;
        for(var i=startPoint.XValue;i<=endPoint.XValue;++i, ++count)
        {
            var item=data[i];
            if (count==0)
            {
                yClose=item.YClose;
                open=item.Open;
                close=item.Close;
                low=item.Low;
                high=item.High;
            }
            else
            {
                close=item.Close;
                if (low>item.Low) low=item.Low;
                if (high<item.High)  high=item.High;
            }

            vol+=item.Vol;
            amount+=item.Amount;
        }

        var result={ YClose:yClose, Open:open, High:high, Low:low, Close:close, Count:count,Vol:vol, Amount:amount  };

        return result;
    }

    this.GetKLineBorder=function(drawPoint, kInfo)
    {
        var ptStart=drawPoint[0];
        var ptEnd=drawPoint[1];
        var data=this.Frame.Data;
        if (this.IsHScreen)
        {
            var xValue=Math.round(this.Frame.GetXData(ptStart.Y,false))+data.DataOffset;
            if (xValue<0) xValue=0;
            else if (xValue>=data.Data.length) xValue=data.Data.length-1;
            var yStart=this.Frame.GetXFromIndex(xValue-data.DataOffset,false);

            xValue=Math.round(this.Frame.GetXData(ptEnd.Y,false))+data.DataOffset;
            if (xValue<0) xValue=0;
            else if (xValue>=data.Data.length) xValue=data.Data.length-1;
            var yEnd=this.Frame.GetXFromIndex(xValue-data.DataOffset,false);

            var xHigh=this.Frame.GetYFromData(kInfo.High,false);
            var xLow=this.Frame.GetYFromData(kInfo.Low,false);

            var result= { Left:xLow, Top:yStart, Right:xHigh, Bottom:yEnd };

            this.LinePoint.push({Start:{X:xLow, Y:yStart}, End:{X:yEnd, Y:yStart}});
            this.LinePoint.push({Start:{X:xLow, Y:yEnd}, End:{X:yEnd, Y:yEnd}});
            this.LinePoint.push({Start:{X:xLow, Y:yStart}, End:{X:xLow, Y:yEnd}});
            this.LinePoint.push({Start:{X:xHigh, Y:yStart}, End:{X:xHigh, Y:yEnd}});

            return result;
        }
        else
        {
            var xValue=Math.round(this.Frame.GetXData(ptStart.X,false))+data.DataOffset;
            if (xValue<0) xValue=0;
            else if (xValue>=data.Data.length) xValue=data.Data.length-1;
            var xStart=this.Frame.GetXFromIndex(xValue-data.DataOffset,false);

            xValue=Math.round(this.Frame.GetXData(ptEnd.X,false))+data.DataOffset;
            if (xValue<0) xValue=0;
            else if (xValue>=data.Data.length) xValue=data.Data.length-1;
            var xEnd=this.Frame.GetXFromIndex(xValue-data.DataOffset,false);

            var yHigh=this.Frame.GetYFromData(kInfo.High,false);
            var yLow=this.Frame.GetYFromData(kInfo.Low,false);
            var result= { Left:xStart, Top:yHigh, Right:xEnd, Bottom:yLow };

            this.LinePoint.push({Start:{X:xStart, Y:yHigh}, End:{X:xEnd, Y:yHigh}});
            this.LinePoint.push({Start:{X:xStart, Y:yLow}, End:{X:xEnd, Y:yLow}});
            this.LinePoint.push({Start:{X:xStart, Y:yHigh}, End:{X:xStart, Y:yLow}});
            this.LinePoint.push({Start:{X:xEnd, Y:yHigh}, End:{X:xEnd, Y:yLow}});

            return result;
        }
    }

    this.DrawText=function(text, x, y, xOffset, yOffset)
    {
        if (this.IsHScreen)
        {
            this.Canvas.save();
            this.Canvas.translate(x,y);
            this.Canvas.rotate(90 * Math.PI / 180);
            this.Canvas.fillText(text,xOffset,yOffset);
            this.Canvas.restore();
        }
        else
        {
            this.Canvas.fillText(text,x+xOffset,y+yOffset);
        }   
    }

}

function ChartDrawTwoPointDemo()
{
    this.newMethod=IChartDrawPicture;   //派生
    this.newMethod();
    delete this.newMethod;

    this.ClassName='ChartDrawTwoPointDemo';
    this.PointCount=2;
    this.Font=16*GetDevicePixelRatio() +"px 微软雅黑";
    this.IsPointIn=this.IsPointIn_XYValue_Line;
    this.IsHScreen=false;
    this.PointInfo=[];  //保存点及点对应K线的信息

    this.PointToValue_Backup=this.PointToValue;
    this.PointToValue=function()
    {
        this.OnFinish();
        this.PointToValue_Backup();
    }

    //移动或创建完成
    this.OnFinish=function()
    {
        for(var i in this.PointInfo)
        {
            var item=this.PointInfo[i];
            if (!item || !item.Point || !IFrameSplitOperator.IsNumber(item.Point.Y2)) continue;
            this.Point[i].Y=this.PointInfo[i].Point.Y2; //点Y轴坐标调整
        }
    }

    this.Draw=function()
    {
        this.LinePoint=[];
        this.PointInfo=[];
        if (this.IsFrameMinSize()) return;

        var drawPoint=this.CalculateDrawPoint({IsCheckX:true, IsCheckY:true});
        if (!drawPoint) return;

        this.IsHScreen=this.Frame.IsHScreen;
        //this.CalculateLines(drawPoint);

        this.ClipFrame();
        this.SetLineWidth();

        var ptStart=drawPoint[0];
        var ptEnd=drawPoint[1]
        this.CalculatePointInfo(drawPoint); 
        if (this.Status==10)    //绘制完成
        {
            this.DrawEx();
        }
        else    //绘制中只画连线
        {
            for(var i=1;i<drawPoint.length;++i)
            {
                this.DrawLine(drawPoint[i-1],drawPoint[i]);
            }
        }

        this.RestoreLineWidth();
        this.DrawPoint(drawPoint); //画点
        this.Canvas.restore();
    }

    //计算点信息及K线信息
    this.CalculatePointInfo=function(drawPoint)
    {
        if (!this.Frame || !this.Frame.Data) return;
        var kPoint=this.PointToKLine(drawPoint);

        //3个点
        if (this.PointCount==3 && this.PointStatus==2 && this.LastPoint)
        {
            var pt=new Point();
            pt.X=this.LastPoint.X;
            pt.Y=this.LastPoint.Y;
            drawPoint[2]=pt;
        }

        var data=this.Frame.Data;
        for(var i in kPoint)
        {
            var item=kPoint[i];
            var pt=drawPoint[i];
            var kItem=data.Data[item.XValue];
            var obj={ KItem: kItem, Data:item, Point:{ X:pt.X, Y:pt.Y } };
            this.PointInfo.push(obj);
        }

        this.CalculateYPoint();

        JSConsole.Chart.Log('[ChartDrawTwoPointDemo::CalculateLines] kPoint', this.PointInfo);
    }

    //计算需要调整的Y轴坐标
    this.CalculateYPoint=function()
    {
        var ptStart=this.PointInfo[0];
        var yStart=this.Frame.GetYFromData(ptStart.KItem.Low,false);
        ptStart.Point.Y2=yStart;

        var ptEnd=this.PointInfo[1];
        var yEnd=this.Frame.GetYFromData(ptEnd.KItem.High,false);
        ptEnd.Point.Y2=yEnd;
    }

    this.DrawEx=function()
    {
        //起始点 结束点信息
        var startInfo=this.PointInfo[0];
        var endInfo=this.PointInfo[1];

        //K线边框信息
        var chartBorder=this.Frame.ChartBorder;
        var frameRight=chartBorder.GetRight();  //最右边

        var ptStart={X:startInfo.Point.X, Y:startInfo.Point.Y2 };
        var ptEnd={X:endInfo.Point.X, Y:endInfo.Point.Y2 };

        this.DrawLine(ptStart,ptEnd);
        this.LinePoint.push({Start:ptStart, End:ptEnd});

        this.Canvas.setLineDash([5,5]);
        //this.Canvas.lineWidth=2;
        var topPrice=endInfo.KItem.YClose*0.09+endInfo.KItem.High;    //结束点最高价+涨幅6% 画竖线
        var y=this.Frame.GetYFromData(topPrice,false);
        this.DrawLine({X:this.ToFixedPoint(ptEnd.X), Y:ptEnd.Y}, {X:this.ToFixedPoint(ptEnd.X), Y:y});

        this.Canvas.textAlign="right";
        this.Canvas.textBaseline = 'center';
        this.Canvas.fillStyle='rgb(33,45,100)';

        for(var i=3;i>0;--i)
        {
            var price=endInfo.KItem.YClose*(0.03*i)+endInfo.KItem.High;     //%2涨幅一档画线
            var y=this.Frame.GetYFromData(price,false);
            y=this.ToFixedPoint(y);

            //线段
            this.DrawLine({X:ptEnd.X, Y:y}, {X:ptEnd.X+100, Y:y});

            //文字
            this.Canvas.fillText(price.toFixed(2), ptEnd.X-5, y);
        }
        this.Canvas.setLineDash([]);
    }

    //防止竖线或横线模糊调整坐标
    this.ToFixedPoint=function(value,width)
    {
        if (!IFrameSplitOperator.IsNumber(width)) width=this.LineWidth;
        return ToFixedPoint2(width, value)
    }
}

function ChartDrawThreePointDemo()
{
    this.newMethod=ChartDrawTwoPointDemo;   //派生
    this.newMethod();
    delete this.newMethod;

    this.ClassName='ChartDrawThreePointDemo';
    this.PointCount=3;

    this.SetLastPoint=function(obj)
    {
        this.LastPoint={X:obj.X,Y:obj.Y};
    }

    //计算需要调整的Y轴坐标
    this.CalculateYPoint=function()
    {
        var y;
        for(var i in this.PointInfo)
        {
            var item=this.PointInfo[i];
            if (i==0 || i==2) y=this.Frame.GetYFromData(item.KItem.Low,false);
            else y=this.Frame.GetYFromData(item.KItem.High,false);
            item.Point.Y2=y;
        }
    }

    this.DrawEx=function()
    {
        //起始点 结束点信息
        var startInfo=this.PointInfo[0];
        var secondInfo=this.PointInfo[1];
        var endInfo=this.PointInfo[2];

        //K线边框信息
        var chartBorder=this.Frame.ChartBorder;
        var frameRight=chartBorder.GetRight();  //右边
        var frameLeft=chartBorder.GetLeft();    //左边

        var ptStart={ X:startInfo.Point.X, Y:startInfo.Point.Y2 };
        var ptSecond={ X:secondInfo.Point.X, Y:secondInfo.Point.Y2};
        var ptEnd={ X:endInfo.Point.X, Y:endInfo.Point.Y2 };

        this.DrawLine(ptStart,ptSecond);
        this.DrawLine(ptSecond,ptEnd);
        this.LinePoint.push({Start:ptStart, End:ptSecond});
        this.LinePoint.push({Start:ptSecond, End:ptEnd});

        this.Canvas.setLineDash([5,5]);
        //this.Canvas.lineWidth=2;
        var topPrice=endInfo.KItem.YClose*0.09+endInfo.KItem.High;    //结束点最高价+涨幅6% 画竖线
        var y=this.Frame.GetYFromData(topPrice,false);
        this.DrawLine({X:this.ToFixedPoint(ptEnd.X), Y:ptEnd.Y}, {X:this.ToFixedPoint(ptEnd.X), Y:y});

        this.Canvas.textAlign="right";
        this.Canvas.textBaseline = 'center';
        this.Canvas.fillStyle='rgb(33,45,100)';

        for(var i=3;i>0;--i)
        {
            var price=endInfo.KItem.YClose*(0.03*i)+endInfo.KItem.High;     //%2涨幅一档画线
            var y=this.Frame.GetYFromData(price,false);
            y=this.ToFixedPoint(y);

            //线段
            this.DrawLine({X:ptEnd.X, Y:y}, {X:ptEnd.X+100, Y:y});

            //文字
            this.Canvas.fillText(price.toFixed(2), ptEnd.X-5, y);
        }
        this.Canvas.setLineDash([]);
    }
}

//画图工具-水平线段
function ChartDrawHLineSegment()
{
    this.newMethod=IChartDrawPicture;   //派生
    this.newMethod();
    delete this.newMethod;

    this.ClassName='ChartDrawHLineSegment';
    this.PointCount=2;
    this.IsPointIn=this.IsPointIn_XYValue_Line;
    this.ChartBorder;

    this.PointToValue_Backup=this.PointToValue;
    this.PointToValue=function()
    {
        //拖拽完成 把点移动到线段头尾
        if (this.Frame.IsHScreen)
        {
            this.Point[1].X=this.Point[0].X;
        }
        else
        {
            this.Point[1].Y=this.Point[0].Y;
        }
        
        this.PointToValue_Backup();
    }

    this.GetXYCoordinate=function()
    {
        if (this.IsFrameMinSize()) return null;
        var drawPoint=this.CalculateDrawPoint({ IsCheckX:false, IsCheckY:true });

        return this.PointRange(drawPoint);
    }

    this.Draw=function()
    {
        if (!this.Frame) return;
        this.IsHScreen=this.Frame.IsHScreen;
        this.LinePoint=[];
        if (this.IsFrameMinSize()) return;

        var drawPoint=this.CalculateDrawPoint( { IsCheckX:false, IsCheckY:true} );
        if (!drawPoint || drawPoint.length!=2) return;

        this.ClipFrame();
        this.ChartBorder=this.Frame.ChartBorder;
        
        this.SetLineWidth();
        this.Canvas.strokeStyle=this.LineColor;
        var ptStart=drawPoint[0];
        var ptEnd=drawPoint[1];

        if (this.Status==10)    //0=开始画 1=完成第1个点  2=完成第2个点 3=完成第3个点  10=完成 20=移动)
        {
            this.DrawLine(ptStart,ptEnd,false);
        }  
        else
        {
            //var kPoint=this.PointToKLine([ptStart,ptEnd]);
            this.DrawVerticalLine(ptStart,ptEnd);
        }                            
        
        this.RestoreLineWidth();

        var line={ Start:ptStart, End:ptEnd };
        this.LinePoint.push(line);
        
        this.DrawPoint(drawPoint);  //画点
        this.Canvas.restore();
    }

    this.DrawVerticalLine=function(ptStart, ptEnd)
    {
        var data=this.Frame.Data;
        if (this.IsHScreen)
        {
            var left=this.ChartBorder.GetLeft();
            var right=this.ChartBorder.GetRight();
            var xValue=Math.round(this.Frame.GetXData(ptStart.Y,false))+data.DataOffset;
            if (xValue<0) xValue=0;
            else if (xValue>=data.Data.length) xValue=data.Data.length-1;
            var yStart=this.Frame.GetXFromIndex(xValue-data.DataOffset,false);

            xValue=Math.round(this.Frame.GetXData(ptEnd.Y,false))+data.DataOffset;
            if (xValue<0) xValue=0;
            else if (xValue>=data.Data.length) xValue=data.Data.length-1;
            var yEnd=this.Frame.GetXFromIndex(xValue-data.DataOffset,false);

            this.Canvas.beginPath();
            this.Canvas.moveTo(left,yStart);
            this.Canvas.lineTo(right,yStart);
    
            this.Canvas.moveTo(left,yEnd);
            this.Canvas.lineTo(right,yEnd);
            this.Canvas.stroke();

            this.Canvas.beginPath();
            this.Canvas.moveTo(ptStart.X,yStart);
            this.Canvas.lineTo(ptStart.X,yEnd);
            this.Canvas.stroke();
        }
        else
        {
            var top=this.ChartBorder.GetTopEx();
            var bottom=this.ChartBorder.GetBottomEx();
            
            var xValue=Math.round(this.Frame.GetXData(ptStart.X,false))+data.DataOffset;
            if (xValue<0) xValue=0;
            else if (xValue>=data.Data.length) xValue=data.Data.length-1;
            var xStart=this.Frame.GetXFromIndex(xValue-data.DataOffset,false);
    
            xValue=Math.round(this.Frame.GetXData(ptEnd.X,false))+data.DataOffset;
            if (xValue<0) xValue=0;
            else if (xValue>=data.Data.length) xValue=data.Data.length-1;
            var xEnd=this.Frame.GetXFromIndex(xValue-data.DataOffset,false);
    
            this.Canvas.beginPath();
            this.Canvas.moveTo(xStart,top);
            this.Canvas.lineTo(xStart,bottom);
    
            this.Canvas.moveTo(xEnd,top);
            this.Canvas.lineTo(xEnd,bottom);
            this.Canvas.stroke();
    
            this.Canvas.beginPath();
            this.Canvas.moveTo(xStart,ptStart.Y);
            this.Canvas.lineTo(xEnd,ptStart.Y);
            this.Canvas.stroke();
        }
    }
}

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;

        var mapDraw=this.DrawData.get(strKey);
        if (!mapDraw.has(drawPicture.Guid)) return;

        mapDraw.delete(drawPicture.Guid);
        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,		20,		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.EmptyBarBGColor="rgb(255,255,255)";  //空心柱子背景色

    this.Minute={};
    this.Minute.VolBarColor=null;                       //分时图成交量柱子颜色 默认不用, 设置了柱子就不是红绿了
    this.Minute.VolTitleColor="rgb(105,105,105)";
    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.PositionColor='rgb(218,165,32)';        //持仓量线段颜色
    this.Minute.FrameSplitTextColor=null;   //刻度文字颜色 (缺省使用 this.FrameSplitTextColor)
    
    this.Minute.Before=
    {
        BGColor:'rgba(240,240,240,0.7)',    //分钟 集合竞价背景
        LineColor:"rgb(50,171,205)",        //集合竞价线段颜色
        VolColor:["rgb(192,192,0)"],        //成交量其他的颜色 colorID=3 开始
        AvPriceColor:'rgb(190,190,190)',    //均线
        Point:{ Color:"rgb(65,105,225)", Radius:2*GetDevicePixelRatio() },
        CloseIcon:
        { 
            Family:'iconfont', 
            Text:"\ue60c", 
            Color:"rgb(112,128,144)",
            Size:12
        }                        //关闭按钮
    };

    this.DefaultTextColor="rgb(43,54,69)";                          //图形中默认的字体颜色
    this.DefaultTextFont=14*GetDevicePixelRatio() +'px 微软雅黑';    //图形中默认的字体
    this.TitleFont=13*GetDevicePixelRatio() +'px 微软雅黑';          //指标显示,tooltip显示字体
    this.IndexTitleBGColor='rgb(217,219,220)';                      //指标名字背景色
    this.IndexTitleColor="rgb(43,54,69)";                           //指标名字颜色
    this.OverlayIndexTitleBGColor='rgba(255,255,255,0.7)';

    this.Title={
        TradeIndexColor:'rgb(105,105,105)', //交易指标颜色
        ColorIndexColor:'rgb(112,128,144)',  //五彩K线颜色

        VolColor:"rgb(43,54,69)",       //标题成交量
        AmountColor:"rgb(43,54,69)",    //成交金额 
        DateTimeColor:"rgb(43,54,69)",  //时间,日期  
        SettingColor:"rgb(43,54,69)",   //周期,复权
        NameColor:"rgb(43,54,69)" ,     //股票名称
        TurnoverRateColor:'rgb(43,54,69)',       //换手率
        PositionColor:"rgb(43,54,69)"       //持仓
    };

    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.CloseLineWidth=2;  //收盘价面积|收盘价|叠加的收盘价线段宽度

    this.FrameBorderPen="rgb(225,236,242)";         //边框颜色
    this.FrameSplitPen="rgb(225,236,242)";          //刻度分割线
    this.FrameDotSplitPen='rgb(105,105,105)';       //分割虚线
    this.FrameYLineDash= null; //[5*GetDevicePixelRatio(), 5*GetDevicePixelRatio()];                     //Y轴线段虚线点间距,填null 就是实线
    this.FrameXLineDash= null; //[5*GetDevicePixelRatio(), 5*GetDevicePixelRatio()];                   //X轴线段虚线点间距,填null 就是实线
    this.FrameSplitTextColor="rgb(117,125,129)";    //刻度文字颜色
    this.FrameSplitTextFont=14*GetDevicePixelRatio() +"px 微软雅黑";            //坐标刻度文字字体
    this.FrameTitleBGColor="rgb(246,251,253)";  //标题栏背景色
    this.Frame={ 
        XBottomOffset:1*GetDevicePixelRatio(),  //X轴文字向下偏移
        YTopOffset:2*GetDevicePixelRatio(),      //Y轴顶部文字向下偏移
        YTextPadding:[2,2]
    };

    //百分比坐标文字颜色
    this.Frame.PercentageText= { 
        PriceColor:'rgb(117,125,129)', 
        PercentageColor:"rgb(117,125,129)", 
        SplitColor:"rgb(117,125,129)",
        Font:14*GetDevicePixelRatio() +"px 微软雅黑"
    };

    //对数坐标
    this.FrameLogarithmic= {
        OpenPriceFont: "bold "+14*GetDevicePixelRatio() +"px 微软雅黑",     //开盘价刻度文字字体
        MinInterval: 45*GetDevicePixelRatio()       //刻度最小间距
    };  

    //等比坐标
    this.FrameSplitIncrease= { 
        Increase:0.1    //涨幅
    };

    //等分坐标
    this.FrameSplitAverage= { 
        Count:4     //分割个数
    };

    //黄金分割坐标
    this.FrameGoldenSection=
    {
        Golden:[0, 0.191, 0.382, 0.5, 0.618, 0.809, 1]
    };

    //Y轴最新价格刻度颜色
    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.FrameMargin=4;     //左右一共的边距
    this.FrameLeftMargin=2;
    this.FrameRightMargin=2;

    this.DragSubFrameBorder= {
        TopBorderHeight:6*GetDevicePixelRatio(), //拖拽边框高度
        MinFrameHeight:50*GetDevicePixelRatio() //指标窗口最小高度
    },

    //叠加指标框架
    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.CorssCursorXRangeBGColor="rgba(100,149,237,0.3)";  //十字光标X轴访问背景色

    this.CorssCursor=
    { 
        RightButton : 
        { 
            BGColor:'rgb(43,54,69)', 
            PenColor:'rgb(255,255,255)',
            Icon: { Text:'\ue6a3', Color:'rgb(255,255,255)', Family:"iconfont", Size:18 }
        } 
    };

    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指标计算域名

    //K线配置
    this.KLine=
    {
        MaxMin: {Font:12*GetDevicePixelRatio() +'px 微软雅黑',Color:'rgb(43,54,69)', RightArrow:"→", LeftArrow:"←", HighYOffset:0, LowYOffset:0},   //K线最大最小值显示
        Info:  //信息地雷
        {
            Investor:
            {
                ApiUrl:'/API/NewsInteract', //互动易
                IconFont: { Family:'iconfont', Text:'\ue631' , HScreenText:'\ue684', Color:'#1c65db'} //SVG 文本
            },
            Announcement:                                           //公告
            {
                ApiUrl:'/API/ReportList',
                IconFont: { Family:'iconfont', Text:'\ue633', HScreenText:'\ue685', Color:'#f5a521' },  //SVG 文本
                IconFont2: { Family:'iconfont', Text:'\ue634', HScreenText:'\ue686', Color:'#ed7520' }, //SVG 文本 //季报
            },
            Pforecast:  //业绩预告
            {
                ApiUrl:'/API/StockHistoryDay',
                IconFont: { Family:'iconfont', Text:'\ue62e', HScreenText:'\ue687', Color:'#986cad' } //SVG 文本
            },
            Research:   //调研
            {
                ApiUrl:'/API/InvestorRelationsList',
                IconFont: { Family:'iconfont', Text:'\ue632', HScreenText:'\ue688', Color:'#19b1b7' } //SVG 文本
            },
            BlockTrading:   //大宗交易
            {
                ApiUrl:'/API/StockHistoryDay',
                IconFont: { Family:'iconfont', Text:'\ue630', HScreenText:'\ue689', Color:'#f39f7c' } //SVG 文本
            },
            TradeDetail:    //龙虎榜
            {
                ApiUrl:'/API/StockHistoryDay',
                IconFont: { Family:'iconfont', Text:'\ue62f', HScreenText:'\ue68a' ,Color:'#b22626' } //SVG 文本
            },

            //扩展图标库
            IconLibrary:
            {
                Family:'iconfont',
                Icon:
                [
                    { Text:'\ue630', HScreenText:'\ue689', Color:'#f39f7c' }, 
                    { Text:'\ue632', HScreenText:'\ue688', Color:'#19b1b7' },
                    { Text:'\ue62f', HScreenText:'\ue68a' ,Color:'#b22626' },
                    { Text:'\ue634', HScreenText:'\ue686', Color:'#ed7520' }
                ]
            },

        },
        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.OrderFlow=
    { 
        UpColor:{BG:'rgb(223,191,180)', Border:"rgb(196,84,86)" },          //阳线
        DownColor:{ BG:"rgb(176,212,184)", Border:'rgb(66,94,74)' },        //阴线
        UnchagneColor: {BG:"rgb(216,221,177)", Border:"rgb(209,172,129)"},  //平盘
        Text:{ Color: "rgb(92,96,89)" , Family:'Arial', FontMaxSize:16, MaxValue:"8888" },  //文字
        Line:{ UpDownColor: "rgb(0,0,0)", MiddleColor:"rgb(211,211,211)" }  //最大, 最低,中间 竖线
    };

    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={
        LineColor:
        [ 
            "rgb(30,144,255)" 
        ],
        PointColor:
        [
            "rgb(128,128,128)",         //选中颜色
            "rgb(192,192,192)"        //moveon颜色
        ],

        XYCoordinate:
        {
            BGColor:'rgba(203,216,255,0.5)',    //区间段背景色
            TextBGColor:"rgb(52,101,255)",      //文字背景色
            TextColor:"rgb(255,255,255)",       //文字颜色
            Font:14*GetDevicePixelRatio() +"px 微软雅黑"   //文字字体
        },

        PointType:0,    // 0=圆点  1=方框
        IsShowPoint:false //是否始终显示点
    };

    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 微软雅黑',   //字体
        DateTimeColor:'rgb(210,210,210)',
        VolColor:"rgb(210,210,210)",       //标题成交量
        AmountColor:"rgb(210,210,210)",    //成交金额
    };

    this.PCTooltip= {
        LineHeight:25   //单行高度
    };

    //弹幕
    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.ChartDrawRuler=
    {
        TitleColor:null,    //K线信息标题颜色, (可选,不填使用涨跌颜色)
    }

    //画图工具-波浪尺
    this.ChartDrawWaveRuler=
    {
        RulerWidth:10,          //刻度尺长度
        RulerLineWidth:1,       //刻度线粗细
        MaxScaleRuler:2,       //尺子最大的高度比
        Font:14*GetDevicePixelRatio() +"px 微软雅黑",
        ScaleRuler:
        [
            {Value:0, Text:"0.0%"}, { Value:0.382, Text:"38.2%" }, { Value:0.618, Text:"61.8%" } ,{ Value:1, Text:"100%"},
            { Value:1.618, Text:"161.8%" }, { Value:2.0, Text:"200%" }
        ]
    }

    this.ChartDrawWaveRuler2Point=
    {
        RulerWidth:20,          //刻度尺长度
        RulerLineWidth:1,       //刻度线粗细
        MaxScaleRuler:2,        //尺子最大的高度比
        Font:14*GetDevicePixelRatio() +"px 微软雅黑",
        ScaleRuler:
        [
            {Value:0, Text:"base"},  { Value:0.618, Text:"61.8%" } ,{ Value:1, Text:"100%"},
            { Value:1.618, Text:"161.8%" }
        ]
    }

    //多图标指标ChartMultiSVGIcon -> MULTI_SVGICON
    //单图标指标ChartSingleText -> DRAWICON
    this.DRAWICON=
    {
        Icon:
        {
            MaxSize:24,  //图标最大
            MinSize:12,  //图标最小
            YOffset:0,
    
            Zoom:
            {
                Type:1,    //0=放大(K线宽度*Value) 1=放大(K线+间距)*Value 2=(K线+间距)+2*Value;
                Value:1
            }
        },
       
        Text:
        {
            MaxSize:50,  //字体最大
            MinSize:12,  //字体最小
            YOffset:0,
    
            Zoom:
            {
                Type:1,    //0=放大(K线宽度*Value) 1=放大(K线+间距)*Value 2=(K线+间距)+2*Value;
                Value:1
            },

            FontName:'Arial'    //字体
        }
    }

    this.DRAWTEXT=
    {
        MaxSize:30,  //字体最大
        MinSize:20,  //字体最小
        YOffset:0,

        Zoom:
        {
            Type:1,    //0=放大(K线宽度*Value) 1=放大(K线+间距)*Value 2=(K线+间距)+2*Value;
            Value:1
        },

        FontName:'微软雅黑'    //字体
    }

    this.DRAWNUMBER=
    {
        MaxSize:30,  //字体最大
        MinSize:20,  //字体最小
        YOffset:0,

        Zoom:
        {
            Type:1,    //0=放大(K线宽度*Value) 1=放大(K线+间距)*Value 2=(K线+间距)+2*Value;
            Value:1
        },

        FontName:'微软雅黑'    //字体
    }

    this.DRAWABOVE=
    {
        YOffset:0   //y坐标向上偏移
    }

    this.DRAWTEXT_FIX={ Font:14*GetDevicePixelRatio() +'px 微软雅黑' }
    this.DRAWNUMBER_FIX={ Font:14*GetDevicePixelRatio() +'px 微软雅黑' }

    //虚线配置
    this.DOTLINE=
    {
        LineDash:[3,5]  //虚线配置
    }

    this.DRAWSL=
    {
        PixelWidth:15   //1个像素点宽度
    }

    this.CIRCLEDOT=
    {
        Radius:1.3*GetDevicePixelRatio()
    }

    this.POINTDOT=
    {
        Radius:2*GetDevicePixelRatio()
    }

    //筹码分布图
    this.StockChip=
    {
        InfoColor:'rgb(0,0,0)', //文字颜色
        DayInfoColor:'rgb(255,255,255)' //周期颜色内文字颜色
    }

    //深度图
    this.DepthChart=
    {
        BidColor: { Line:"rgb(82,176,123)", Area:"rgba(82,176,123,0.8)"},  //卖
        AskColor: { Line:"rgb(207,76,89)", Area:"rgba(207,76,89, 0.8)"},   //买
        LineWidth:4
    }

    this.DepthCorss=
    {
        BidColor: { Line:"rgb(82,176,123)" },  //卖
        AskColor: { Line:"rgb(207,76,89)" },   //买
        LineWidth:2,    //线段宽度
        LineDash:[3,3],
        Tooltip:
        { 
            BGColor:'rgba(236,240,245, 0.8)', TextColor:"rgb(130,140,151)",
            Border:{ Top:5, Left:20, Bottom:5, Center: 5},
            Font:14*GetDevicePixelRatio() +"px 微软雅黑",
            LineHeight:16   //单行高度
        }
    }

    //区间选择
    this.RectSelect=
    {
        LineColor:"rgb(64,64,64)",          //竖线  
        LineWidth:1*GetDevicePixelRatio(),
        LineDotted:[3,3], 
        AreaColor:"rgba(234,234,234,0.5)",     //面积
    }

    //自定义风格
    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.EmptyBarBGColor) this.EmptyBarBGColor=style.EmptyBarBGColor;
        if (style.Minute) 
        {
            if (style.Minute.VolBarColor) this.Minute.VolBarColor = style.Minute.VolBarColor;
            if (style.Minute.VolTitleColor) this.Minute.VolTitleColor = style.Minute.VolTitleColor;
            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.Minute.FrameSplitTextColor) this.Minute.FrameSplitTextColor = style.Minute.FrameSplitTextColor;
            if (style.Minute.Before)
            {
                var item=style.Minute.Before;
                if (item.BGColor) this.Minute.Before.BGColor=item.BGColor;
                if (item.LineColor) this.Minute.Before.LineColor=item.LineColor;
                if (item.VolColor) this.Minute.Before.VolColor=item.VolColor;
                if (item.AvPriceColor) this.Minute.Before.AvPriceColor=item.AvPriceColor;
                if (item.CloseIcon) this.Minute.Before.CloseIcon=item.CloseIcon;
                if (item.Point) 
                {
                    if (item.Point.Color)  this.Minute.Before.Point.Color=item.Point.Color;
                    if (item.Point.Radius)  this.Minute.Before.Point.Radius=item.Point.Radius;
                }
            }
        }

        if (style.DefaultTextColor) this.DefaultTextColor = style.DefaultTextColor;
        if (style.DefaultTextFont) this.DefaultTextFont = style.DefaultTextFont;
        if (style.TitleFont) this.TitleFont = style.TitleFont;
        if (style.IndexTitleBGColor) this.IndexTitleBGColor=style.IndexTitleBGColor;
        if (style.IndexTitleColor) this.IndexTitleColor=style.IndexTitleColor;
        if (style.OverlayIndexTitleBGColor) this.OverlayIndexTitleBGColor=style.OverlayIndexTitleBGColor;
        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.CloseLineWidth) this.CloseLineWidth=style.CloseLineWidth;
        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.Frame.YTopOffset) this.Frame.YTopOffset=style.Frame.YTopOffset;
            if (style.Frame.PercentageText)
            {
                var item=style.Frame.PercentageText;
                if (item.PriceColor) this.Frame.PercentageText.PriceColor=item.PriceColor;
                if (item.PercentageColor) this.Frame.PercentageText.PercentageColor=item.PercentageColor;
                if (item.SplitColor) this.Frame.PercentageText.SplitColor=item.SplitColor;
                if (item.Font) this.Frame.PercentageText.Font=item.Font;
            }
        }

        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.CorssCursorBorderColor) this.CorssCursorBorderColor=style.CorssCursorBorderColor;
        if (style.CorssCursorXRangeBGColor) this.CorssCursorXRangeBGColor=style.CorssCursorXRangeBGColor;
        if (style.CorssCursor && style.CorssCursor.RightButton)
        {
            var item=style.CorssCursor.RightButton;
            if (item.BGColor) this.CorssCursor.RightButton.BGColor=item.BGColor;
            if (item.PenColor) this.CorssCursor.RightButton.PenColor=item.PenColor;
            if (item.Icon) this.CorssCursor.RightButton.Icon=item.Icon;
        }
        
        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)
        {
            var item=style.DrawPicture;
            if (item.LineColor) this.DrawPicture.LineColor = item.LineColor;
            if (item.PointColor) this.DrawPicture.PointColor = item.PointColor;
            if (item.XYCoordinate) this.DrawPicture.XYCoordinate=item.XYCoordinate;
            if (IFrameSplitOperator.IsNumber(item.PointType)) this.DrawPicture.PointType=item.PointType;
            if (IFrameSplitOperator.IsBool(item.IsShowPoint)) this.DrawPicture.IsShowPoint=item.IsShowPoint;
        }

        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.TooltipPaint.DateTimeColor) this.TooltipPaint.DateTimeColor=style.TooltipPaint.DateTimeColor;
            if (style.TooltipPaint.VolColor) this.TooltipPaint.VolColor=style.TooltipPaint.VolColor;
            if (style.TooltipPaint.AmountColor) this.TooltipPaint.AmountColor=style.TooltipPaint.AmountColor;
        }

        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;
        }

        if (style.Title)
        {
            if (style.Title.TradeIndexColor) this.Title.TradeIndexColor=style.Title.TradeIndexColor;
            if (style.Title.ColorIndexColor) this.Title.ColorIndexColor=style.Title.ColorIndexColor;

            if (style.Title.VolColor) this.Title.VolColor=style.Title.VolColor;
            if (style.Title.AmountColor) this.Title.AmountColor=style.Title.AmountColor;
            if (style.Title.DateTimeColor) this.Title.DateTimeColor=style.Title.DateTimeColor;
            if (style.Title.NameColor) this.Title.NameColor=style.Title.NameColor;
            if (style.Title.SettingColor) this.Title.SettingColor=style.Title.SettingColor;
            if (style.Title.TurnoverRateColor) this.Title.TurnoverRateColor=style.Title.TurnoverRateColor;
            if (style.Title.PositionColor) this.Title.PositionColor=style.Title.PositionColor;
        }

        if (style.DRAWICON) 
        {
            if (style.DRAWICON.Icon)
            {
                var item=style.DRAWICON.Icon;
                if (IFrameSplitOperator.IsPlusNumber(item.MaxSize)) this.DRAWICON.Icon.MaxSize=item.MaxSize;
                if (IFrameSplitOperator.IsPlusNumber(item.MinSize)) this.DRAWICON.Icon.MinSize=item.MinSize;
                if (item.Zoom) this.DRAWICON.Icon.Zoom=item.Zoom;
                if (IFrameSplitOperator.IsNumber(item.YOffset)) this.DRAWICON.Icon.YOffset=item.YOffset;
            }

            if (style.DRAWICON.Text)
            {
                var item=style.DRAWICON.Text;
                if (IFrameSplitOperator.IsPlusNumber(item.MaxSize)) this.DRAWICON.Text.MaxSize=item.MaxSize;
                if (IFrameSplitOperator.IsPlusNumber(item.MinSize)) this.DRAWICON.Text.MinSize=item.MinSize;
                if (item.Zoom) this.DRAWICON.Text.Zoom=item.Zoom;
                if (item.FontName) this.DRAWICON.Text.FontName=item.FontName;
                if (IFrameSplitOperator.IsNumber(item.YOffset)) this.DRAWICON.Text.YOffset=item.YOffset;
            }
        }

        if (style.DRAWTEXT)
        {
            var item=style.DRAWTEXT;
            if (IFrameSplitOperator.IsPlusNumber(item.MaxSize)) this.DRAWICON.MaxSize=item.MaxSize;
            if (IFrameSplitOperator.IsPlusNumber(item.MinSize)) this.DRAWICON.MinSize=item.MinSize;
            if (item.Zoom) this.DRAWTEXT.Zoom=item.Zoom;
            if (item.FontName) this.DRAWTEXT.FontName=item.FontName;
            if (IFrameSplitOperator.IsNumber(item.YOffset)) this.DRAWTEXT.YOffset=item.YOffset;
        }

        if (style.DRAWTEXT_FIX)
        {
            var item=style.DRAWTEXT_FIX;
            if (item.Font) this.DRAWTEXT_FIX.Font=item.Font;
        }

        if (style.DRAWNUMBER_FIX)
        {
            var item=style.DRAWNUMBER_FIX;
            if (item.Font) this.DRAWNUMBER_FIX.Font=item.Font;
        }

        if (style.DRAWNUMBER)
        {
            var item=style.DRAWNUMBER;
            if (IFrameSplitOperator.IsPlusNumber(item.MaxSize)) this.DRAWNUMBER.MaxSize=item.MaxSize;
            if (IFrameSplitOperator.IsPlusNumber(item.MinSize)) this.DRAWNUMBER.MinSize=item.MinSize;
            if (item.Zoom) this.DRAWNUMBER.Zoom=item.Zoom;
            if (item.FontName) this.DRAWNUMBER.FontName=item.FontName;
            if (IFrameSplitOperator.IsNumber(item.YOffset)) this.DRAWNUMBER.YOffset=item.YOffset;
        }

        if (style.DRAWABOVE)
        {
            var item=style.DRAWABOVE;
            if (IFrameSplitOperator.IsNumber(item.YOffset)) this.DRAWABOVE.YOffset=item.YOffset;
        }

        if (style.DOTLINE) this.DOTLINE=style.DOTLINE;
        if (style.DRAWSL) this.DOTLINE=style.DRAWSL;

        if (style.DragSubFrameBorder) this.DragSubFrameBorder=style.DragSubFrameBorder;

        if (style.StockChip)
        {
            var item=style.StockChip;
            if (item.InfoColor) this.StockChip.InfoColor=item.InfoColor;
            if (item.DayInfoColor) this.StockChip.DayInfoColor=item.DayInfoColor;
        }

        if (style.DepthChart)
        {
            var item=style.DepthChart;
            if (item.BidColor)
            {
                if (item.BidColor.Line) this.DepthChart.BidColor.Line=item.BidColor.Line;
                if (item.BidColor.Area) this.DepthChart.BidColor.Area=item.BidColor.Area;
            }
            if (item.AskColor)
            {
                if (item.AskColor.Line) this.DepthChart.AskColor.Line=item.AskColor.Line;
                if (item.AskColor.Area) this.DepthChart.AskColor.Area=item.AskColor.Area;
            }

            if (item.LineWidth) this.DepthChart.LineWidth=item.LineWidth;
        }

        if (style.DepthCorss)
        {
            var item=style.DepthCorss;
            if (item.BidColor)
            {
                if (item.BidColor.Line) this.DepthCorss.BidColor.Line=item.BidColor.Line;
            }

            if (item.AskColor)
            {
                if (item.AskColor.Line) this.DepthCorss.AskColor.Line=item.AskColor.Line;
            }

            if (item.LineWidth) this.DepthCorss.LineWidth=item.LineWidth;
            if (item.LineDash) this.DepthCorss.LineDash=item.LineDash;

            if (item.Tooltip)
            {
                var tooltip=item.Tooltip;
                if (tooltip.BGColor) this.DepthCorss.Tooltip.BGColor=tooltip.BGColor;
                if (tooltip.TextColor) this.DepthCorss.Tooltip.TextColor=tooltip.TextColor;
                if (tooltip.Font) this.DepthCorss.Tooltip.Font=tooltip.Font;
                if (tooltip.LineHeight) this.DepthCorss.Tooltip.LineHeight=tooltip.LineHeight;

                var border=tooltip.Border;
                if (IFrameSplitOperator.IsNumber(border.Top)) this.DepthCorss.Tooltip.Border.Top=border.Top;
                if (IFrameSplitOperator.IsNumber(border.Left)) this.DepthCorss.Tooltip.Border.Left=border.Left;
                if (IFrameSplitOperator.IsNumber(border.Bottom)) this.DepthCorss.Tooltip.Border.Bottom=border.Bottom;
                if (IFrameSplitOperator.IsNumber(border.Center)) this.DepthCorss.Tooltip.Border.Center=border.Center;
            }
        }

        if (style.CIRCLEDOT)
        {
            var item=style.CIRCLEDOT;
            if (IFrameSplitOperator.IsNumber(item.Radius)) this.CIRCLEDOT.Radius=item.Radius;
        }

        if (style.POINTDOT)
        {
            var item=style.POINTDOT;
            if (IFrameSplitOperator.IsNumber(item.Radius)) this.POINTDOT.Radius=item.Radius;
        }

        if (style.RectSelect)
        {
            var item=style.RectSelect;
            if (item.LineColor) this.RectSelect.LineColor=item.LineColor;
            if (item.LineWidth>0) this.RectSelect.LineWidth=item.LineWidth;
            if (item.LineDotted) this.RectSelect.LineDotted=item.LineDotted;
            if (item.AreaColor) this.RectSelect.AreaColor=item.AreaColor;
        }

        if (style.OrderFlow)
        {
            item=style.OrderFlow;
            if (item.UpColor) this.OrderFlow.UpColor=item.UpColor;
            if (item.DownColor) this.OrderFlow.DownColor=item.DownColor;
            if (item.UnchagneColor) this.OrderFlow.UnchagneColor=item.UnchagneColor;
            if (item.Text) this.OrderFlow.Text=item.Text;
            if (item.Line) this.OrderFlow.Line=item.Line;
        }
    }
}

var g_JSChartResource=new JSChartResource();


/////////////////////////////////////////////////////////////////////////////////
//
//
//
var JSCHART_LANGUAGE_ID=
{
    LANGUAGE_CHINESE_ID:0,  //简体中文 CN
    LANGUAGE_ENGLISH_ID:1,  //英文 EN
    LANGUAGE_TRADITIONAL_CHINESE_ID:2,  //繁体中文 TC
};

function JSChartLocalization()
{
    this.TextResource=new Map([
        //内部tooltip
        ['Tooltip-Open', {CN:'开:', EN:'O:', TC:'開'}],
        ['Tooltip-High', {CN:'高:', EN:'H:', TC:'高'}],
        ['Tooltip-Low', {CN:'低:', EN:'L:', TC:'低'}],
        ['Tooltip-Close', {CN:'收:', EN:'C:', TC:'收'}],
        ['Tooltip-Increase', {CN:'幅:', EN:'I:', TC:'幅'}],
        ['Tooltip-Vol', {CN:'量:', EN:'V:', TC:'量'}],
        ['Tooltip-Amount', {CN:'额:', EN:'A:', TC:'額'}],
        ['Tooltip-AvPrice', {CN:'均:', EN:'AP:', TC:'均'}],
        ['Tooltip-Price', {CN:'价:', EN:'P:', TC:'價'}],
        ['Tooltip-Exchange', {CN:'换:', EN:'E:', TC:'換'}],
        ['Tooltip-Position',{CN:'持:', EN:'P:', TC:'持'}],

        ['DivTooltip-Open', {CN:'开盘:', EN:'Open:', TC:'開盤'}],
        ['DivTooltip-High', {CN:'最高:', EN:'High:', TC:'最高'}],
        ['DivTooltip-Low', {CN:'最低:', EN:'Low:', TC:'最低'}],
        ['DivTooltip-Close', {CN:'收盘:', EN:'Close:', TC:'收盤'}],
        ['DivTooltip-Increase', {CN:'涨幅:', EN:'Increase:', TC:'漲幅'}],
        ['DivTooltip-Vol', {CN:'数量:', EN:'Volume:', TC:'數量'}],
        ['DivTooltip-Amount', {CN:'金额:', EN:'Amount:', TC:'金額'}],
        ['DivTooltip-Exchange', {CN:'换手:', EN:'Exchange:', TC:'換手'}],
        ['DivTooltip-Position', {CN:'持仓:', EN:'Position:', TC:'持倉'}],
        ['DivTooltip-Price', {CN:'价格:', EN:'Open:', TC:'價格'}],

        //K线动态标题
        ['KTitle-Open', {CN:'开:', EN:'O:', TC:'開'}],
        ['KTitle-High', {CN:'高:', EN:'H:', TC:'高'}],
        ['KTitle-Low', {CN:'低:', EN:'L:', TC:'低'}],
        ['KTitle-Close', {CN:'收:', EN:'C:', TC:'收'}],
        ['KTitle-Increase', {CN:'幅:', EN:'I:', TC:'幅'}],
        ['KTitle-Vol', {CN:'量:', EN:'V:', TC:'量'}],
        ['KTitle-Amount', {CN:'额:', EN:'A:', TC:'額'}],
        ['KTitle-Exchange', {CN:'换:', EN:'E:', TC:'換'}],
        ['KTitle-Position', {CN:'持:', EN:'P:', TC:'持'}],
        ['KTitle-Price', {CN:'价:', EN:'Price:', TC:'價'}],
        
        //走势图动态标题
        ['MTitle-AC-Price', {CN:'匹配价:', EN:'C:', TC:'匹配價'}],
        ['MTitle-AC-AvPrice', {CN:'匹配均价:', EN:'C:', TC:'匹配均價'}],
        ['MTitle-AC-Increase', {CN:'竞价涨幅:', EN:'I:', TC:'競價漲幅'}],
        ['MTitle-AC-Vol', {CN:'匹配量:', EN:'V:', TC:'匹配量'}],
        ['MTitle-AC-NotMatchVol', {CN:'未匹配量:', EN:'NV:', TC:'未匹配量'}],

        //走势图标题
        ['MTitle-Close', {CN:'价:', EN:'C:', TC:'價'}],
        ['MTitle-AvPrice', {CN:'均:', EN:'AC:', TC:'均'}],
        ['MTitle-Increase', {CN:'幅:', EN:'I:', TC:'幅'}],
        ['MTitle-Vol', {CN:'量:', EN:'V:', TC:'量'}],
        ['MTitle-Amount', {CN:'额:', EN:'A:', TC:'額'}],
        ['MTitle-Position', {CN:'持:', EN:'P:', TC:'持'}],
        ["MTitle-UpdateTime", {CN:"更新:", EN:"Update:", TC:"更新:"}],

        //周期
        ['日线', {CN:'日线', EN:'1D', TC:'日綫'}],
        ['周线', {CN:'周线', EN:'1W', TC:'周綫'}],
        ['双周', {CN:'双周', EN:"2W", TC:'雙周'}],
        ['月线', {CN:'月线', EN:'1M', TC:'月綫'}],
        ["半年", {CN:'半年', EN:'HY', TC:'半年'}],
        ['年线', {CN:'年线', EN:'1Y', TC:'年綫'}],
        ['1分', {CN:'1分', EN:'1Min', TC:'1分'}],
        ['5分', {CN:'5分', EN:'5Min', TC:'5分'}],
        ['15分', {CN:'15分', EN:'15Min', TC:'15分'}],
        ['30分', {CN:'30分', EN:'30Min', TC:'30分'}],
        ['60分', {CN:'60分', EN:'60Min', TC:'60分'}],
        ['季线', {CN:'季线', EN:'1Q', TC:'季綫'}],
        ['分笔', {CN:'分笔', EN:'Tick', TC:'分筆'}],
        ['2小时', {CN:'2小时', EN:'2H', TC:'2小時'}],
        ['4小时', {CN:'4小时', EN:'4H', TC:'4小時'}],

        //复权
        ['不复权', {CN:'不复权', EN:'No Right', TC:'不復權'}],
        ['前复权', {CN:'前复权', EN:'Pro Right', TC:'前復權'}],
        ['后复权', {CN:'后复权', EN:'Post Right', TC:'后復權'}],

        //week
        ['日', {CN:'日', EN:'Sun.', TC:'日'}],
        ['一', {CN:'一', EN:'Mon.', TC:'壹'}],
        ['二', {CN:'二', EN:'Tues.', TC:'貳'}],
        ['三', {CN:'三', EN:'Wed.', TC:'叁'}],
        ['四', {CN:'四', EN:'Thur.', TC:'肆'}],
        ['五', {CN:'五', EN:'Fri.', TC:'伍'}],
        ['六', {CN:'六', EN:'Sat.', TC:'陸'}],

        ['1月', {CN:'1月', EN:'Jan', TC:'1月'}],
        ['2月', {CN:'2月', EN:'Feb', TC:'2月'}],
        ['3月', {CN:'3月', EN:'Mar', TC:'3月'}],
        ['4月', {CN:'4月', EN:'Apr', TC:'4月'}],
        ['5月', {CN:'5月', EN:'May', TC:'5月'}],
        ['6月', {CN:'6月', EN:'Jun', TC:'6月'}],
        ['7月', {CN:'7月', EN:'Jul', TC:'7月'}],
        ['8月', {CN:'8月', EN:'Aug', TC:'8月'}],
        ['9月', {CN:'9月', EN:'Sept', TC:'9月'}],
        ['10月', {CN:'10月', EN:'Oct', TC:'10月'}],
        ['11月', {CN:'11月', EN:'Nov', TC:'11月'}],
        ['12月', {CN:'12月', EN:'Dec', TC:'12月'}],

        ['自定义分钟', {CN:'分', EN:'Min', TC:'分'}],
        ['自定义日线', {CN:'日', EN:'D', TC:'日'}],
        ['自定义秒', {CN:'秒', EN:'S', TC:'秒'}],

        ["MVol-Vol", {CN:"成交量", EN:"Volume", TC:'成交量'} ],
        ["MVol-Position", {CN:"持仓量", EN:"Position", TC:'持倉量'} ],

        //深度图
        ["Depth-Price", {CN:"委托价", EN:"Price", TC:'委托價'}],
        ["Depth-Sum", {CN:"累计", EN:"Sum", TC:'累計'}]

    ]);

    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;
            case JSCHART_LANGUAGE_ID.LANGUAGE_TRADITIONAL_CHINESE_ID:
                return item.TC;
            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:'点位研判'  }],  //废弃

        ['CJL',  { IsMainIndex:false,  Create:function(){ return new JSIndex_CJL(); }  } ],    //期货指标
    ]
    );

    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,OffscreenElement)
{
    var _self =this;
    this.newMethod=JSChartContainer;   //派生
    this.newMethod(uielement,OffscreenElement);
    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.RightFormula=0                 //复权公式 0=简单复权, 1=复权因子复权
    this.SourceData;                    //原始的历史数据
    this.MaxReqeustDataCount=3000;      //数据个数
    this.MaxRequestMinuteDayCount=5;    //分钟数据请求的天数
    this.PageSize=200;                  //每页数据个数
    this.KLineDrawType=0;
    this.ScriptErrorCallback;           //脚本执行错误回调
    this.FlowCapitalReady=false;        //流通股本是否下载完成
    this.EnableFlowCapital={};          //强制现在流通股 { BIT:数据货币true/false, }
    this.EnableZoomUpDown=null;         //是否手势/键盘/鼠标允许缩放{ Touch:true/false, Mouse:true/false, Keyboard:true/false, Wheel:true/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.ZoomType=0;                    //缩放模式 0=最右边固定缩放, 1=十字光标两边缩放
    this.KLineSize=null;                //{ DataWidth:, }
    //this.EnableYDrag={ Left:false, Right:true };

    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 },    //分钟/秒数据拖拽下载
        Tick: { 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.BeforeBindMainData=null;   //function(funcName)   在BindMainData() 调用前回调用
    this.AfterBindMainData=null;    //function(funcName)   在BindMainData() 调用前后调用

    this.ResetDragDownload=function()
    {
        this.DragDownload.Day.Status=0;
        this.DragDownload.Day.IsEnd=false;

        this.DragDownload.Minute.Status=0;
        this.DragDownload.Minute.IsEnd=false;

        this.DragDownload.Tick.Status=0;
        this.DragDownload.Tick.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.AddCustomKLine=function(kline, option)
    {
        var klineChart=this.ChartPaint[0];
        if (!klineChart) return;

        if (!kline) return;

        if (!klineChart.CustomKLine) klineChart.CustomKLine=new Map();

        if (Array.isArray(kline))
        {
            for(var i=0;i<kline.length;++i)
            {
                var item=kline[i];
                klineChart.CustomKLine.set(item.Key, item.Data);
            }
        }
        else if (kline)
        {
            klineChart.CustomKLine.set(kline.Key, kline.Data);
        }
        
        if (option && option.Draw==true) this.Draw();
    }

    this.ClearCustomKLine=function(option)
    {
        var klineChart=this.ChartPaint[0];
        if (!klineChart) return;

        klineChart.ClearCustomKLine();

        if (option && option.Draw==true) this.Draw();
    }

    this.StopAutoUpdate=function()
    {
        this.CancelAutoUpdate();
        this.AutoUpdateEvent(false,'KLineChartContainer::StopAutoUpdate');
        if (!this.IsAutoUpdate) return;
        this.IsAutoUpdate=false;
    }

    //沙盘操作 { ID: 1=开始, Data:绑定K线数据(可选)
    //          ID: 2=更新数据, Data:绑定K线数据
    //          ID: 3=结束, IsAutoUpdate:是否启动自动更新(可选) }
    this.SandTableOperator=function(obj)
    {
        switch(obj.ID)
        {
            case 1:
                this.StopAutoUpdate();
                if (obj.Data) this.ManualUpdateKData(obj);
                break;
            case 2:
                this.ManualUpdateKData(obj);
                break;
            case 3:
                if (obj.IsAutoUpdate) this.IsAutoUpdate=obj.IsAutoUpdate;
                this.ChangeSymbol(this.Symbol);
                break;
        }
    }

    //外部手动更新K线数据, 内部不计算周期和复权
    this.ManualUpdateKData=function(obj)
    {
        var kData=obj.Data;
        var lastDataCount=kData.length;
        var bindData=new ChartData();
        bindData.Data=kData;
        bindData.Period=this.Period;
        bindData.Right=this.Right;
        bindData.Symbol=this.Symbol;

        this.UpdateMainData(bindData,lastDataCount);//更新主图数据
        this.BindInstructionIndexData(bindData);    //执行指示脚本

        for(var i=0; i<this.Frame.SubFrame.length; ++i)
        {
            this.BindIndexData(i,bindData);
        }

        //更新当前屏K线索引
        if (IFrameSplitOperator.IsNumber(obj.DataOffset) && obj.DataOffset>=0)
        {
            var data=null;
            if (this.Frame.Data)
                data=this.Frame.Data;
            else
                data=this.Frame.SubFrame[0].Frame.Data;
            if (data) data.DataOffset=obj.DataOffset;
        }

        this.UpdataDataoffset();           //更新数据偏移
        this.UpdatePointByCursorIndex(1);  //更新十字光标位子
        this.UpdateFrameMaxMin();          //调整坐标最大 最小值
        this.Frame.SetSizeChage(true);
        this.Draw();                        //刷新画图

        this.SendManualKLineUpdateEvent(bindData);
    }

    //获取k线数据
    this.GetKDataInfo=function()
    {
        if (!this.ChartPaint[0]) return null;

        var chartKLine=this.ChartPaint[0];
        var obj={};
        if (chartKLine.Data && chartKLine.Data.Data)
            obj.Data=chartKLine.Data.CloneData("HistoryData");
        obj.ShowRange=chartKLine.ShowRange;
        obj.Period=this.Period;
        obj.RightSpaceCount=this.RightSpaceCount;

        return obj;
    }

    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;
            var oneStepWidth=this.GetMoveOneStepWidth();
            if(this.DataMove(step*oneStepWidth,isLeft))    //每次移动一个数据
            {
                this.UpdataDataoffset();
                this.UpdatePointByCursorIndex();
                this.UpdateFrameMaxMin();
                this.ResetFrameXYSplit();
                this.Draw();
            }
            else
            {
                if (id===JSCHART_OPERATOR_ID.OP_SCROLL_RIGHT && this.DragDownloadData) 
                    this.DragDownloadData();
            }
        }
        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=this.ChartOperator_Temp_GetHistroyData();;
            if (!hisData) return;  //数据还没有到达

            var showCount=this.Frame.SubFrame[0].Frame.XPointCount; //获取一屏显示的数据个数
            showCount-=this.RightSpaceCount;
            var index=hisData.Data.length-showCount;
            hisData.DataOffset=index;
            this.CursorIndex=0;

            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.ChartOperator_Temp_Update();
        }
        else if (id===JSCHART_OPERATOR_ID.OP_GOTO_END)
        {
            var hisData=this.ChartOperator_Temp_GetHistroyData();
            if (!hisData) return;  //数据还没有到达

            hisData.DataOffset=0;
            this.CursorIndex=0;

            this.LastPoint.X=null;
            this.LastPoint.Y=null;

            JSConsole.Chart.Log(`[KLineChartContainer::ChartOperator] OP_GOTO_END `);

            this.ChartOperator_Temp_Update();
        }
        else if (id==JSCHART_OPERATOR_ID.OP_LEFT_ZOOM_IN || id==JSCHART_OPERATOR_ID.OP_LEFT_ZOOM_OUT)　//{ Step：增加/减少数量 } 左边增加/减少显示个数
        {
            var hisData=this.ChartOperator_Temp_GetHistroyData();
            if (!hisData) return;  //数据还没有到达

            var dataCount=hisData.Data.length;
            var showCount=this.Frame.SubFrame[0].Frame.XPointCount; //获取一屏显示的数据个数
            var dataOffset=hisData.DataOffset;

            if (id==JSCHART_OPERATOR_ID.OP_LEFT_ZOOM_IN)    //增加
            {
                if (IFrameSplitOperator.IsNumber(obj.Step))
                {
                    if (showCount>=dataCount) return;
                    var step=obj.Step;
                    if (step>dataOffset) step=dataOffset;
                    if (showCount+step>dataCount) step=dataCount-showCount;
                    if (step<=0) return;

                    showCount+=step;
                    hisData.DataOffset-=step;
                }
            }
            else if (id==JSCHART_OPERATOR_ID.OP_LEFT_ZOOM_OUT)  //减少
            {
                var pageSize = this.GetMaxMinPageSize();
                var minShowCount=pageSize.Min;
                if (IFrameSplitOperator.IsNumber(obj.Step))
                {
                    if (showCount<minShowCount) return;
                    var step=obj.Step;
                    if (showCount-step<minShowCount) step=showCount-minShowCount;
                    if (step<=0) return;

                    showCount-=step;
                    hisData.DataOffset+=step;
                }
            }
            
            for(var i in this.Frame.SubFrame)   //设置一屏显示的数据个数
            {
                var item =this.Frame.SubFrame[i].Frame;
                item.XPointCount=showCount;
            }

            if (hisData.DataOffset<0) hisData.DataOffset=0;
            this.ChartOperator_Temp_Update();
        }
        else if (id==JSCHART_OPERATOR_ID.OP_RIGHT_ZOOM_IN || id==JSCHART_OPERATOR_ID.OP_RIGHT_ZOOM_OUT)　//{ Step：增加/减少数量 , ShowCount:显示个数 } 右边增加/减少显示个数
        {
            var hisData=this.ChartOperator_Temp_GetHistroyData();
            if (!hisData) return;  //数据还没有到达

            var dataCount=hisData.Data.length;
            var showCount=this.Frame.SubFrame[0].Frame.XPointCount; //获取一屏显示的数据个数
            var dataOffset=hisData.DataOffset;

            if (id==JSCHART_OPERATOR_ID.OP_RIGHT_ZOOM_IN)   //增加
            {
                if (IFrameSplitOperator.IsNumber(obj.Step))
                {
                    if (showCount>=dataCount) return;
                    var endPos=dataOffset+showCount;
                    var rightCount=dataCount-endPos;
                    if (rightCount<=0) return;

                    var step=obj.Step;
                    if (step>rightCount) step=rightCount;
                    if (step<=0) return;

                    showCount+=step;
                }
            }
            else if (id==JSCHART_OPERATOR_ID.OP_RIGHT_ZOOM_OUT) //减少
            {
                var pageSize = this.GetMaxMinPageSize();
                var minShowCount=pageSize.Min;
                if (IFrameSplitOperator.IsNumber(obj.Step))
                {
                    if (showCount<minShowCount) return;
                    var step=obj.Step;
                    if (step>showCount) step=showCount;
                    if (showCount-step<minShowCount) step=showCount-minShowCount;
                    if (step<=0) return;

                    showCount-=step;
                }
            }

            for(var i in this.Frame.SubFrame)   //设置一屏显示的数据个数
            {
                var item =this.Frame.SubFrame[i].Frame;
                item.XPointCount=showCount;
            }

            if (hisData.DataOffset<0) hisData.DataOffset=0;
            this.ChartOperator_Temp_Update();
        }
    }

    //内部函数
    this.ChartOperator_Temp_GetHistroyData=function()
    {
        var hisData=null;
        if (!this.Frame.Data) hisData=this.Frame.Data;
        else hisData=this.Frame.SubFrame[0].Frame.Data;
        if (!hisData) return null;  //数据还没有到达

        return hisData;
    }

    this.ChartOperator_Temp_Update=function()
    {
        this.UpdataDataoffset();           //更新数据偏移
        this.UpdateFrameMaxMin();          //调整坐标最大 最小值
        this.Frame.SetSizeChage(true);
        this.Draw();
        this.UpdatePointByCursorIndex();   //更新十字光标位子
    }

    this.OnWheel=function(e)
    {
        JSConsole.Chart.Log('[KLineChartContainer::OnWheel]',e);
        if (this.ChartSplashPaint && this.ChartSplashPaint.IsEnableSplash == true) return;

        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);

        var wheelValue=e.wheelDelta;
        if (!IFrameSplitOperator.IsObjectExist(e.wheelDelta))
            wheelValue=e.deltaY* -0.01;
        
        var enableZoomUpDown=true;  //是否允许缩放
        if (this.EnableZoomUpDown && this.EnableZoomUpDown.Wheel===false) enableZoomUpDown=false;
        
        if (this.SourceData && this.SourceData.Data)
        {
            if (isInClient && wheelValue<0 && enableZoomUpDown)       //缩小
            {
                var cursorIndex={ ZoomType:this.ZoomType };
                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();
                    this.OnKLinePageChange("wheel");
                }
            }
            else if (isInClient && wheelValue>0 && enableZoomUpDown)  //放大
            {
                var cursorIndex={ ZoomType:this.ZoomType };
                cursorIndex.Index=parseInt(Math.abs(this.CursorIndex-0.5).toFixed(0));
                if (this.Frame.ZoomUp(cursorIndex))
                {
                    JSConsole.Chart.Log("[KLineChartContainer::OnWheel] cursorIndex ",cursorIndex)

                    this.CursorIndex=cursorIndex.Index;
                    this.UpdatePointByCursorIndex();
                    this.UpdataDataoffset();
                    this.UpdateFrameMaxMin();
                    this.Draw();
                    this.OnKLinePageChange("wheel");
                }
            }
        }

        if (!isInClient) return;

        if(e.preventDefault) e.preventDefault();
        else e.returnValue = false;
    }

    //创建
    //windowCount 窗口个数
    this.Create=function(windowCount, option)
    {
        this.UIElement.JSChartContainer=this;

        //创建十字光标
        this.ChartCorssCursor=new ChartCorssCursor();
        this.ChartCorssCursor.Canvas=this.Canvas;
        this.ChartCorssCursor.StringFormatX=g_DivTooltipDataForamt.Create("CorssCursor_XStringFormat");
        this.ChartCorssCursor.StringFormatX.LanguageID=this.LanguageID;
        this.ChartCorssCursor.StringFormatY=g_DivTooltipDataForamt.Create("CorssCursor_YStringFormat");
        this.ChartCorssCursor.StringFormatY.LanguageID=this.LanguageID;
        this.ChartCorssCursor.StringFormatY.ExtendChartPaint=this.ExtendChartPaint;

        //创建等待提示
        this.ChartSplashPaint = new ChartSplashPaint();
        this.ChartSplashPaint.Canvas = this.Canvas;
        this.ChartSplashPaint.HQChart=this;

        //创建框架容器
        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.Frame.GetExtendChartRightWidth=()=> { return this.GetExtendChartRightWidth() }
        this.ChartCorssCursor.Frame=this.Frame; //十字光标绑定框架
        this.ChartSplashPaint.Frame = this.Frame;

        this.CreateChildWindow(windowCount);
        this.CreateMainKLine();
        this.CreateExtendChart("RectSelectPaint");  //区间统计

        //子窗口动态标题
        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;
            titlePaint.GetEventCallback=(id)=> { return this.GetEventCallback(id); }

            this.TitlePaint.push(titlePaint);
        }

        var bRegisterKeydown=true;
        var bRegisterWheel=true;

        if (option)
        {
            if (option.KeyDown===false) 
            {
                bRegisterKeydown=false;
                JSConsole.Chart.Log('[KLineChartContainer::Create] not register keydown event.');
            }

            if (option.Wheel===false) 
            {
                bRegisterWheel=false;
                JSConsole.Chart.Log('[KLineChartContainer::Create] not register wheel event.');
            }
        }

        if (bRegisterKeydown) this.UIElement.addEventListener("keydown", (e)=>{ this.OnKeyDown(e); }, true);            //键盘消息
        if (bRegisterWheel) 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;                           //窗口序号
            frame.RightSpaceCount=this.RightSpaceCount; //右边

            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');
                frame.YSplitOperator.GetEventCallback=(id)=> { return this.GetEventCallback(id); }
                var pixelTatio = GetDevicePixelRatio(); //获取设备的分辨率
                border.BottomSpace=15*pixelTatio;  //主图上下留空间
                border.TopSpace=15*pixelTatio;
            }
            else
            {
                frame.YSplitOperator=new FrameSplitY();
                frame.YSplitOperator.FrameSplitData=this.FrameSplitData.get('double');
                frame.YSplitOperator.LanguageID=this.LanguageID;
                frame.YSplitOperator.GetEventCallback=(id)=> { return this.GetEventCallback(id); };
                //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;
            frame.XSplitOperator.GetEventCallback=(id)=> { return this.GetEventCallback(id); }

            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;
        frame.YSplitOperator.GetEventCallback=(id)=> { return this.GetEventCallback(id); };
        frame.XSplitOperator.Symbol=this.Symbol;
        frame.XSplitOperator.Period=this.Period;

        //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;
        kline.GetEventCallback=(id)=>{ return this.GetEventCallback(id); };

        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;

        if (this.KLineSize)
        {
            if (this.KLineSize.DataWidth==null)
            {
                showCount=this.Frame.SubFrame[0].Frame.XPointCount-this.RightSpaceCount;
            }
            else
            {
                var obj=this.Frame.SetDataWidth(this.KLineSize.DataWidth);
                showCount=obj.XPointCount-this.RightSpaceCount;
                this.KLineSize.DataWidth=null;
            }
        }

        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 xPointCount=this.Frame.SubFrame[0].Frame.XPointCount;   //当前一屏能显示的数据个数

        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}], [Pagesize=${xPointCount}]`);
        }
        else if (lastDataCount==0 && hisData.Data.length>xPointCount)   //历史数据为空,当前收到数据大于一屏的数据,显示最新数据
        {
            newDataCount=hisData.Data.length-xPointCount;
            JSConsole.Chart.Log(`[KLineChartContainer::UpdateMainData] history data is empty. [count=${lastDataCount}->${hisData.Data.length}], [newDataCount=${newDataCount}], [Pagesize=${xPointCount}]`);
        }

        this.ChartPaint[0].Data=hisData;
        this.ChartPaint[0].Symbol=this.Symbol;
        if (hisData.Data.length>xPointCount) //不满一屏的, 不需要调整索引
            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;

            if (i==0)   //更新Y轴K线数据
            {
                item.YSplitOperator.Symbol=this.Symbol;
                item.YSplitOperator.Data=this.ChartPaint[0].Data;          //K线数据
                item.YSplitOperator.Period=this.Period;                    //周期
            }
        }

        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<19910101) 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;
    }

    this.OnDragSelectRectMouseUp=function(e)
    {
        var paint=this.GetRectSelectPaint();
        if (!paint) return;
        
        var selectData=paint.GetSelectRectData();
        if (!selectData) return;

        var pixelTatio = GetDevicePixelRatio();
        var corssCursor=this.ChartCorssCursor;  //十字光标
        e.data=
        {
            Chart:this,
            X:corssCursor.LastPoint.X/pixelTatio,
            Y:corssCursor.LastPoint.Y/pixelTatio,
            SelectData:selectData,          //区间选择的数据
            RectSelectPaint:paint           //区间选择背景
        };

        if (this.SelectRectRightMenu)
            this.SelectRectRightMenu.DoModal(e);
    }

    this.ShowSelectData=function(selectData)
    {
        this.HideSelectRect();
        if (this.SelectRectRightMenu) this.SelectRectRightMenu.Hide();

        JSConsole.Chart.Log('[KLineChartContainer::ShowSelectData] selectData', selectData);
        var dataOffset=selectData.Start;
        var showCount=(selectData.End-selectData.Start)+1;

        JSConsole.Chart.Log(`[KLineChartContainer::ShowSelectData] DataOffset=${dataOffset}, ShowCount=${showCount}`);

        for(var i in this.Frame.SubFrame)
        {
            var item =this.Frame.SubFrame[i].Frame;
            item.XPointCount=showCount;
        }
        this.ChartPaint[0].Data.DataOffset=dataOffset;
        this.CursorIndex=0;

        this.UpdataDataoffset();           //更新数据偏移
        this.UpdateFrameMaxMin();          //调整坐标最大 最小值
        this.Frame.SetSizeChage(true);
        this.Draw();
        this.UpdatePointByCursorIndex();   //更新十字光标位子
    }

    this.OnMarkRectSelect=function(e)
    {
        var corssCursor=this.ChartCorssCursor;  //十字光标
        if (!corssCursor || corssCursor.Status==0) return;
        if (!IFrameSplitOperator.IsNumber(corssCursor.CursorIndex)) return;
        if (!this.ChartPaint[0] || !this.ChartPaint[0].Data) return;
        var paint=this.GetRectSelectPaint();
        if (!paint) return;

        var cursorIndex=corssCursor.CursorIndex;
        JSConsole.Chart.Log("[KLineChartContainer::OnMarkRectSelect] dataIndex", cursorIndex);

        var kData=this.ChartPaint[0].Data;
        cursorIndex=parseInt(cursorIndex.toFixed(0));
        var index=cursorIndex+kData.DataOffset;
        if (index>=kData.Data.length) index=kData.Data.length-1;

        var item = kData.Data[index];

        JSConsole.Chart.Log("[KLineChartContainer::OnMarkRectSelect] item", item);

        if (!this.SetRectSelectData(item)) return;

        if (paint.GetPointCount()==2)
        {
            var selectData=paint.GetSelectRectData();
            var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_KEYDOWN_SELECT_RECT);
            var pixelTatio = GetDevicePixelRatio();
            if (event && event.Callback)
            {
                var data=
                { 
                    X:corssCursor.LastPoint.X/pixelTatio,
                    Y:corssCursor.LastPoint.Y/pixelTatio,
                    SelectData:selectData,   //区间选择的数据
                    RectSelectPaint:paint    //区间选择背景
                };
                event.Callback(event,data,this);
            }

            if (this.SelectRectRightMenu)
            {
                e.data=
                {
                    Chart:this,
                    X:corssCursor.LastPoint.X/pixelTatio,
                    Y:corssCursor.LastPoint.Y/pixelTatio,
                    SelectData:selectData,          //区间选择的数据
                    RectSelectPaint:paint           //区间选择背景
                };
                this.SelectRectRightMenu.DoModal(e);
            }
        }
        

        this.Draw();
    }

    //创建指定窗口指标
    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.SendManualKLineUpdateEvent=function(bindData)
    {
        var event=this.GetEventCallback(JSCHART_EVENT_ID.RECV_KLINE_MANUAL_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.GetKLineDrawType=function()
    {
       return this.KLineDrawType;
    }

    this.RequestHistoryData=function()
    {
        var self=this;
        this.ChartSplashPaint.SetTitle(this.LoadDataSplashTitle);
        this.ChartSplashPaint.EnableSplash(true);
        this.FlowCapitalReady=false;
        this.ResetPage(); //重置分页
        this.ResetDragDownload();
        this.Draw();

        if (this.NetworkFilter)
        {
            var kLineDrawType=this.GetKLineDrawType();
            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"],
                        period:this.Period, right:this.Right, klineDrawType:kLineDrawType
                    } }, 
                Self:this,
                PreventDefault:false
            };
            this.NetworkFilter(obj, function(data) 
            { 
                self.ChartSplashPaint.EnableSplash(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.EnableSplash(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.BindAllOverlayIndexData=function(hisData)
    {
        if (!this.Frame || !this.Frame.SubFrame) return;

        //叠加指标
        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,hisData)
            }
        }
    }

    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;
        this.SourceData=sourceData;

        if (this.BeforeBindMainData) this.BeforeBindMainData("RecvHistoryData");

        //显示的数据
        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.GetRightData(bindData.Right, { AlgorithmType: this.RightFormula } );
            bindData.Data=rightData;
        }

        if (ChartData.IsDayPeriod(bindData.Period,false) && !this.IsApiPeriod)   //周期数据
        {
            var periodData=bindData.GetPeriodData(bindData.Period);
            bindData.Data=periodData;
        }

        //绑定数据
        this.Symbol=data.symbol;
        this.Name=data.name;

        this.BindMainData(bindData,this.PageSize);
        if (this.AfterBindMainData) this.AfterBindMainData("RecvHistoryData");
        this.Frame.SetSizeChage(true);
        
        var firstSubFrame;
        if (this.Frame.SubFrame[0]) firstSubFrame=this.Frame.SubFrame[0].Frame;
        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.ReqeustKLineInfoData({ FunctionName:"RecvHistoryData" });            //请求信息地雷
            this.RequestFlowCapitalData();          //请求流通股本数据 (主数据下载完再下载)
            this.RequestOverlayHistoryData();       //请求叠加数据 (主数据下载完再下载)
            this.CreateChartDrawPictureByStorage(); //创建画图工具
        }

        if (page.Enable) page.Index=1;    //第一页下载完成

        //刷新画图
        this.UpdataDataoffset();           //更新数据偏移
        this.UpdateFrameMaxMin();          //调整坐标最大 最小值
        this.Frame.SetSizeChage(true);
        this.UpdatePointByCursorIndex(2);   //取消十字光标
        this.Draw();

        this.BindInstructionIndexData(bindData);    //执行指示脚本
        for(var i=0; i<this.Frame.SubFrame.length; ++i) //执行指标
        {
            this.BindIndexData(i,bindData);
        }
        
        //叠加指标
        this.BindAllOverlayIndexData(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.GetRightData(bindData.Right,{ AlgorithmType: this.RightFormula });
            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.SetTitle(this.LoadDataSplashTitle);
        this.ChartSplashPaint.EnableSplash(true);
        this.FlowCapitalReady=false;
        this.ResetPage(); //重置分页
        this.ResetDragDownload();
        this.Draw();

        if (this.NetworkFilter)
        {
            var kLineDrawType=this.GetKLineDrawType();
            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"],
                        period:this.Period, right:this.Right, klineDrawType:kLineDrawType
                    }  
                }, 
                Self:this,
                PreventDefault:false
            };
            this.NetworkFilter(obj, function(data) 
            { 
                self.ChartSplashPaint.EnableSplash(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.EnableSplash(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;
        this.SourceData=sourceData;
        if (this.BeforeBindMainData) this.BeforeBindMainData("RecvMinuteHistoryData");

        //显示的数据
        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.Symbol=data.symbol;
        this.Name=data.name;
        
        this.BindMainData(bindData,this.PageSize);
        if (this.AfterBindMainData) this.AfterBindMainData("RecvMinuteHistoryData");
        this.Frame.SetSizeChage(true);
        
        var firstSubFrame;
        if (this.Frame.SubFrame[0]) firstSubFrame=this.Frame.SubFrame[0].Frame;
        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(2);  //切换周期了取消十字光标
        this.UpdateFrameMaxMin();          //调整坐标最大 最小值
        this.Frame.SetSizeChage(true);
        this.Draw();

        this.BindInstructionIndexData(bindData);        //执行指示脚本
        for(var i=0; i<this.Frame.SubFrame.length; ++i) //执行指标
        {
            this.BindIndexData(i,bindData);
        }
        
        //叠加指标
        this.BindAllOverlayIndexData(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.GetRightData(bindData.Right,{ AlgorithmType: this.RightFormula });
            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 kLineDrawType=this.GetKLineDrawType();
            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"],
                        period:this.Period, right:this.Right, klineDrawType:kLineDrawType
                    }, 
                    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 (this.SourceData.Data.length==0) //第1条数据
        {
            var newItem =new HistoryData();
            HistoryData.CopyTo(newItem,realtimeData);
            this.SourceData.Data.push(newItem);
        }
        else if (item.Date==realtimeData.Date)   //实时行情数据更新
        {
            JSConsole.Chart.Log('[KLineChartContainer::RecvRealtimeData] update kline by realtime data',realtimeData);
            HistoryData.CopyTo(item,realtimeData);
        }
        else if (item.Date<realtimeData.Date)   //新增加数据
        {
            JSConsole.Chart.Log('[KLineChartContainer::RecvRealtimeData] insert kline by realtime data',realtimeData);
            
            var newItem =new HistoryData();
            HistoryData.CopyTo(newItem,realtimeData);

            if (!IFrameSplitOperator.IsNumber(newItem.YClose) && this.SourceData.Data.length>0)
                newItem.YClose=this.SourceData.Data[this.SourceData.Data.length-1].YClose;

            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) && MARKET_SUFFIX_NAME.IsSHSZStockA(this.Symbol) && !this.IsApiPeriod)    //复权(A股日线数据才复权)
        {
            var rightData=bindData.GetRightData(bindData.Right,{ AlgorithmType: this.RightFormula });
            bindData.Data=rightData;
        }

        if (!this.IsApiPeriod)
        {
            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(1);  //更新十字光标位子
        this.UpdateFrameMaxMin();          //调整坐标最大 最小值
        this.Frame.SetSizeChage(true);
        this.Draw();

        this.SendKLineUpdateEvent(bindData);

        //叠加指标计算
        this.BindAllOverlayIndexData(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) && !this.IsApiPeriod)    //复权数据 ,A股才有有复权
            {
                var rightData=bindData.GetRightData(bindData.Right, { AlgorithmType: this.RightFormula });
                bindData.Data=rightData;
            }

            var aryOverlayData=this.SourceData.GetOverlayData(bindData.Data, this.IsApiPeriod);      //和主图数据拟合以后的数据
            bindData.Data=aryOverlayData;

            if (ChartData.IsDayPeriod(bindData.Period,false) && !this.IsApiPeriod)   //周期数据
            {
                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 kLineDrawType=this.GetKLineDrawType();
            var obj=
            {
                Name:'KLineChartContainer::RequestMinuteRealtimeData', //类名::
                Explain:'当天1分钟K线数据',
                Request:
                { 
                    Url:self.RealtimeApiUrl, 
                    Data:
                    { 
                        symbol: arySymbol, 
                        field:["name","symbol","price","yclose","minutecount","minute","date","time"],
                        period:this.Period, right:this.Right, klineDrawType:kLineDrawType
                    }, 
                    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) return;
        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.GetRightData(bindData.Right, { AlgorithmType: this.RightFormula });
            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(1);  //更新十字光标位子
        this.UpdateFrameMaxMin();          //调整坐标最大 最小值
        this.Frame.SetSizeChage(true);
        this.Draw();

        this.SendKLineUpdateEvent(bindData);

        //更新叠加指标
        this.BindAllOverlayIndexData(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) && !this.IsApiPeriod)    //复权(日线数据才复权)
        {
            var rightData=bindData.GetRightData(bindData.Right, { AlgorithmType: this.RightFormula });
            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.UpdateOverlayMinuteRealtimeData(data);       //更新叠加股票数据
        this.BindInstructionIndexData(bindData);          //执行指示脚本

        for(var i=0; i<this.Frame.SubFrame.length; ++i)
        {
            this.BindIndexData(i,bindData);
        }

        //刷新画图
        this.UpdataDataoffset();           //更新数据偏移
        this.UpdatePointByCursorIndex(1);  //更新十字光标位子
        this.UpdateFrameMaxMin();          //调整坐标最大 最小值
        this.Frame.SetSizeChage(true);
        this.Draw();

        this.SendKLineUpdateEvent(bindData);

        //更新叠加指标
        this.BindAllOverlayIndexData(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;
            if (data.ver==2.0) 
                var realtimeData=KLineChartContainer.JsonDataToMinuteRealtimeDataV2(data,item.Symbol);  //获取叠加股票的最新数据
            else 
                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,this.IsApiPeriod);      //和主图数据拟合以后的数据
            bindData.Data=aryOverlayData;

            if (ChartData.IsMinutePeriod(bindData.Period,false) && !this.IsApiPeriod)   //周期数据
            {
                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;
        this.ChartSplashPaint.SetTitle(this.LoadDataSplashTitle);
        self.ChartSplashPaint.EnableSplash(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.EnableSplash(false);
                self.RecvTickData(data);
                self.AutoUpdate();
            });

            if (obj.PreventDefault==true) return;   //已被上层替换,不调用默认的网络请求
        }

        JSNetwork.HttpRequest({
            url: cacheUrl,
            data:{"symbol":self.Symbol},
            type:"get",
            dataType: "json",
            async:true,
            success: function (data)
            {
                self.ChartSplashPaint.EnableSplash(false);
                self.RecvTickData(data);
                self.AutoUpdate(1);
            },
            error: function(http,e)
            {
                self.ChartSplashPaint.EnableSplash(false);
                self.AutoUpdate();
                //self.RecvError(http,e,param);;
            }
        });
       
    }

    this.RecvTickData=function(data)
    {
        if (data.ver==2.0) 
            var aryDayData=KLineChartContainer.JsonDataToTickDataV2(data);
        else
            var aryDayData=KLineChartContainer.JsonDataToTickData(data);

        //原始数据
        var sourceData=new ChartData();
        sourceData.Data=aryDayData;
        sourceData.DataType=2;      //0=日线数据 1=分钟数据 2=分笔数据
        this.SourceData=sourceData;
        if (this.BeforeBindMainData) this.BeforeBindMainData("RecvTickData");

        //显示的数据
        var bindData=new ChartData();
        bindData.Data=aryDayData;
        bindData.Right=this.Right;
        bindData.Period=this.Period;
        bindData.DataType=2;

        //绑定数据
        
        this.Symbol=data.symbol;
        this.Name=data.name;
        this.BindMainData(bindData,this.PageSize);
        if (this.AfterBindMainData) this.AfterBindMainData("RecvTickData");

        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();   //更新十字光标位子

        //叠加指标
        this.BindAllOverlayIndexData(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.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.EnableSplash(false);
                self.RecvTickRealtimeData(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.EnableSplash(false);
                self.RecvTickRealtimeData(data);
                self.AutoUpdate();
            }
        });
    }

    this.RecvTickRealtimeData=function(data)
    {
        if (data.ver==2.0)
            var aryDayData=KLineChartContainer.JsonDataToTickDataV2(data);    //增量数据
        else
            var aryDayData=KLineChartContainer.JsonDataToTickData(data);    //增量数据
        if (!aryDayData || aryDayData.length<=0) return;

        var redraw=false;   //强制重绘
        if (data.redraw==true) redraw=true;
        //更新原始数据
        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 && redraw==false) 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.BindAllOverlayIndexData(bindData);
    }


    this.ClearIndexPaint=function()
    {
        //清空指标
        if (this.Frame && this.Frame.SubFrame)
        {
            for(var i=0;i<this.Frame.SubFrame.length;++i)
            {
                this.DeleteIndexPaint(i);
                var item=this.Frame.SubFrame[i];
                if (IFrameSplitOperator.IsNonEmptyArray(item.OverlayIndex))
                {
                    for(var j=0; j<item.OverlayIndex.length; ++j ) //清空叠加指标
                    {
                        var overlayItem=item.OverlayIndex[j];
                        overlayItem.ChartPaint=[];
                    }
                }
            }
        }
    }

    //周期切换
    this.ChangePeriod=function(period,option)
    {
        var isChangeKLineDrawType=false;
        var isReload=false; //是否重新请求数据
        var right=null; //复权
        if (option)
        {
            if (option.KLine)
            {
                if (IFrameSplitOperator.IsNumber(option.KLine.DrawType)) isChangeKLineDrawType=true;
                if (IFrameSplitOperator.IsNumber(option.KLine.Right)) right=option.KLine.Right;
            }

            if (option.Reload==true) isReload=true;
        };

        if (this.Period==period && isReload==false) 
        {
            if (isChangeKLineDrawType) this.ChangeKLineDrawType(option.KLine.DrawType);
            return;
        }

        if (isChangeKLineDrawType) this.ChangeKLineDrawType(option.KLine.DrawType,false);   //切换K线类型, 不重绘

        var isDataTypeChange=true;
        if (this.SourceData)
        {
            var isDataTypeChange=false;
            if (period>CUSTOM_DAY_PERIOD_START && period<=CUSTOM_DAY_PERIOD_END)
            {
                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 if (ChartData.IsSecondPeriod(period)) 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;
        if (right!=null) this.Right=right;
        this.ReloadChartDrawPicture();   //切换周期了 清空画图工具
        this.ClearRectSelect(true);
        this.Frame.ClearUpDonwFrameYData();
        this.ClearCustomKLine();

        if (isDataTypeChange==false && !this.IsApiPeriod)
        {
            this.Update( {UpdateCursorIndexType:2} ); //更新的时候 取消显示十字光标
            return;
        }

        this.ClearIndexPaint();

        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.IsEnableRight(this.Period,this.Symbol)) 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.ClearIndexPaint();
                this.ResetOverlaySymbolStatus();
                this.RequestHistoryData();                  //请求日线数据
            }
            else if (ChartData.IsMinutePeriod(this.Period,true) || ChartData.IsSecondPeriod(this.Period))
            {
                this.CancelAutoUpdate();                    //先停止定时器
                this.AutoUpdateEvent(false,'KLineChartContainer::ChangeRight');                //切换复权先停止更新
                this.ClearIndexPaint();
                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(findTime))
            {
                for(var i=0;i<hisData.Data.length;++i)
                {
                    var item=hisData.Data[i];
                    if (item.Date>obj.Date || (item.Date==obj.Date && item.Time>=findTime))
                    {
                        index=i;
                        break;
                    }
                }
            }
            else    //只有日期
            {
                for(var i=0;i<hisData.Data.length;++i)
                {
                    var item=hisData.Data[i];
                    if (item.Date>=obj.Date)
                    {
                        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.UpdatePointByCursorIndex(2);   //更新十字光标位子
        this.Draw();
    }

    //删除某一个窗口的指标
    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, Param:instructionData.Param };
        }
        else if (type==1)   //专家指示
        {
            this.ChartPaint[0].TradeData={Sell:instructionData.Sell, Buy:instructionData.Buy, Name:instructionData.Name, Param:instructionData.Param };
            if (title) title.TradeIndex={ Name:instructionData.Name, Param:instructionData.Param };
        }
    }

    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.SetFrameToolbar=function(windowIndex,window)
    {
        if (!window || !this.Frame.SubFrame[windowIndex] || !this.Frame.SubFrame[windowIndex].Frame) return;

        var frame=this.Frame.SubFrame[windowIndex].Frame;
        var bChanged=false;
        if (IFrameSplitOperator.IsBool(window.Modify)) 
        {
            frame.ModifyIndex=window.Modify;
            bChanged=true;
        }

        if (IFrameSplitOperator.IsBool(window.Change)) 
        {
            frame.ChangeIndex=window.Change;
            bChanged=true;
        }

        if (IFrameSplitOperator.IsBool(window.Close)) 
        {
            frame.CloseIndex=window.Close;
            bChanged=true;
        }

        if (IFrameSplitOperator.IsBool(window.Overlay)) 
        {
            frame.OverlayIndex=window.Overlay;
            bChanged=true;
        }

        //工具栏变 先刷新工具栏
        if (bChanged)
        {
            frame.SizeChange=true;
            frame.ToolbarRect=null; //清空工具栏缓存
            frame.DrawToolbar();
        }
    }

    //切换成 脚本指标
    this.ChangeScriptIndex=function(windowIndex,indexData,option)
    {
        this.DeleteIndexPaint(windowIndex);
        this.WindowIndex[windowIndex]=new ScriptIndex(indexData.Name,indexData.Script,indexData.Args,indexData);    //脚本执行

        if (option)
        {
            if (option.Window) this.SetFrameToolbar(windowIndex,option.Window);
        }

        this.Frame.ClearUpDonwFrameYData({ Index:windowIndex });
        var bindData=this.ChartPaint[0].Data;
        this.BindIndexData(windowIndex,bindData);   //执行脚本

        this.UpdataDataoffset();           //更新数据偏移
        this.UpdateFrameMaxMin();          //调整坐标最大 最小值
        this.Draw();
    }

    this.OnKLinePageChange=function(eventid)
    {
        if (!this.ChartPaint[0]) return;

        var bindData=this.ChartPaint[0].Data;
        for(var i=0;i<this.WindowIndex.length;++i)
        {
            var item=this.WindowIndex[i];
            if (!item) continue;
            if (item.IsUsePageData===true) this.BindIndexData(i,bindData);   //执行脚本
        }

        //叠加指标
        for(var i=0;i<this.Frame.SubFrame.length;++i)
        {
            var item=this.Frame.SubFrame[i];
            for(var j=0; j<item.OverlayIndex.length; ++j)
            {
                var overlayItem=item.OverlayIndex[j];
                if (overlayItem && overlayItem.Script && overlayItem.Script.IsUsePageData==true)
                    this.BindOverlayIndexData(overlayItem,i,bindData);
            }
        }
    }

    //切换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);

        if (indexData)
        {
            if (indexData.Window) this.SetFrameToolbar(windowIndex,indexData.Window);
        }

        this.Frame.ClearUpDonwFrameYData({ Index:windowIndex });
        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 = indexInfo;
            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,option);
        }

        //主图指标
        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:, API:}
    {
        let indexName=obj.IndexName;
        let windowIndex=obj.WindowIndex;
        var apiItem=null, indexInfo=null, indexCustom=null;
        if (obj.API)
        {
            apiItem=obj.API;
        }
        else if (obj.Script)    //动态执行脚本
        {
            indexInfo={ Script:obj.Script, ID:obj.indexName, Name:obj.indexName};
            if (obj.Name) indexInfo.Name=obj.Name;
        }
        else
        {
            let scriptData = new JSIndexScript();
            indexInfo = scriptData.Get(indexName);  //系统指标
            if (!indexInfo) 
            {
                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;
        if (obj.IsShareY===true) frame.IsShareY=true;
        if (IFrameSplitOperator.IsBool(obj.IsCalculateYMaxMin)) frame.IsCalculateYMaxMin=obj.IsCalculateYMaxMin;   //是否计算Y最大最小值

        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 (apiItem)
        {
            var apiIndex=new APIScriptIndex(apiItem.Name,apiItem.Script,apiItem.Args,obj, true);
            apiIndex.OverlayIndex={ IsOverlay:true, Identify:overlayFrame.Identify, WindowIndex:windowIndex, Frame:overlayFrame };    //叠加指标信息
            overlayFrame.Script=apiIndex;
        }
        else if (indexInfo)
        {
            let indexData = indexInfo;
            if (obj.Args) indexData.Args=obj.Args;  //外部可以设置参数

            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) //删除叠加指标
    {
        if (!this.DeleteOverlayIndex(identify, null)) return;

        this.Frame.ResetXYSplit(true);
        this.Draw();
    }
    
    this.ChangeKLineDrawType=function(drawType, isDraw)
    {
        if (this.KLineDrawType==drawType) return;

        this.KLineDrawType=drawType;

        if (this.KLineDrawType==5)    //订单流
        {
            var chart=this.ChartPaint[0];
            if (chart) chart.DrawType=this.KLineDrawType;

            this.CancelAutoUpdate();    //先停止定时器
            this.AutoUpdateEvent(false,'KLineChartContainer::ChangeKLineDrawType');

            if (ChartData.IsDayPeriod(this.Period,true))
            {
                this.ResetOverlaySymbolStatus();
                this.RequestHistoryData();                  //请求日线数据
            }
            else if (ChartData.IsMinutePeriod(this.Period,true) || ChartData.IsSecondPeriod(this.Period))
            {
                this.ResetOverlaySymbolStatus();
                this.ReqeustHistoryMinuteData();            //请求分钟数据
            }

            return;
        }


        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;
        } 

        if (isDraw==false) return;

        this.UpdateFrameMaxMin();          //调整坐标最大 最小值
        this.Frame.SetSizeChage(true);
        this.Draw();
    }

    //修改坐标类型 
    //{ Type:  0=普通坐标  1=百分比坐标 (右边坐标刻度) 2=对数对标 3=等比坐标, IsReverse:是否反转坐标 }
    this.ChangeCoordinateType=function(obj) 
    {
        if (!this.Frame && !this.Frame.SubFrame) return;
        if (!this.Frame.SubFrame.length) return;

        if (IFrameSplitOperator.IsNumber(obj))  //老版本
        {
            var type=obj;
            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 if (type==3)   //对数坐标
            {
                this.Frame.SubFrame[0].Frame.YSplitOperator.CoordinateType=2;
            }
            else
            {
                return;
            }
        }
        else
        {
            if (obj.Type>=0 && obj.Type<=5) this.Frame.SubFrame[0].Frame.YSplitOperator.CoordinateType=obj.Type;
            if (obj.IsReverse===true) this.Frame.SubFrame[0].Frame.CoordinateType=1;
            else if (obj.IsReverse==false) this.Frame.SubFrame[0].Frame.CoordinateType=0;
        }

        this.UpdateFrameMaxMin();          //调整坐标最大 最小值
        this.Frame.SetSizeChage(true);
        this.Draw();
    }

    //设置指标窗口个数
    this.ChangeIndexWindowCount=function(count,option)
    {
        if (count<=0) return;
        if (this.Frame.SubFrame.length==count) return;

        this.Frame.RestoreIndexWindows();
        
        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;
            }

            this.Frame.SetSizeChage(true);
            this.ResetFrameXYSplit();
            this.UpdateFrameMaxMin();          //调整坐标最大 最小值
            this.Draw();
        }
        else
        {
            //创建新的指标窗口
            var pixelRatio=GetDevicePixelRatio();
            for(var i=currentLength;i<count;++i)
            {
                var subFrame=this.CreateSubFrameItem(i);
                subFrame.Frame.ChartBorder.TitleHeight*=pixelRatio;
                this.Frame.SubFrame[i]=subFrame;
                var titlePaint=new DynamicChartTitlePainting();
                titlePaint.Frame=this.Frame.SubFrame[i].Frame;
                titlePaint.Canvas=this.Canvas;
                titlePaint.LanguageID=this.LanguageID;
                titlePaint.GetEventCallback=(id)=> { return this.GetEventCallback(id); }
                this.TitlePaint[i+1]=titlePaint;
            }

            //最后一个显示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.Frame.SetSizeChage(true);
            this.ResetFrameXYSplit();
            this.UpdateFrameMaxMin();          //调整坐标最大 最小值
            this.Draw();

            //创建指标
            var indexName= [ {Index:"RSI"}, {Index:"MACD"}, {Index:"VOL"}, {Index:"UOS"}, {Index:"CHO"}, {Index:"BRAR"} ];  //增加的指标名字
            if (option && option.Windows.length>0)
                indexName=option.Windows;   //外部设置增加窗口的默认指标

            let scriptData = new JSIndexScript();
            for(var i=currentLength;i<count;++i)
            {
                var item=indexName[i%indexName.length];
                var name=item.Index;
                let indexInfo = scriptData.Get(name);
                var args=indexInfo.Args;
                if (item.Args) args=item.Args;
                let indexData = 
                { 
                    Name:indexInfo.Name, Script:indexInfo.Script, Args: args, ID:item.Index,
                    //扩展属性 可以是空
                    KLineType:indexInfo.KLineType,  YSpecificMaxMin:indexInfo.YSpecificMaxMin,  YSplitScale:indexInfo.YSplitScale,
                    FloatPrecision:indexInfo.FloatPrecision, Condition:indexInfo.Condition,
                    OutName:indexInfo.OutName
                };
    
                this.WindowIndex[i]=new ScriptIndex(indexData.Name,indexData.Script,indexData.Args,indexData);    //脚本执行

                var subFrame=this.Frame.SubFrame[i];
                if (item.Modify!=null) this.Frame.SubFrame[i].Frame.ModifyIndex=item.Modify;
                if (item.Change!=null) this.Frame.SubFrame[i].Frame.ChangeIndex=item.Change;
                if (item.Close!=null) this.Frame.SubFrame[i].Frame.CloseIndex=item.Close;
                if (item.Overlay!=null) chart.Frame.SubFrame[i].Frame.OverlayIndex=item.Overlay;
                if (item.IsDrawTitleBG==true)  this.Frame.SubFrame[i].Frame.IsDrawTitleBG=item.IsDrawTitleBG;

                if (IFrameSplitOperator.IsNumber(item.TitleHeight)) this.Frame.SubFrame[i].Frame.ChartBorder.TitleHeight=item.TitleHeight;
                else item.TitleHeight=this.Frame.SubFrame[i].Frame.ChartBorder.TitleHeight;
                if (item.IsShowTitleArraw==false) this.Frame.SubFrame[i].Frame.IsShowTitleArraw=false;
                if (item.IsShowIndexName==false) this.Frame.SubFrame[i].Frame.IsShowIndexName=false;
                if (item.IsShowOverlayIndexName==false) this.Frame.SubFrame[i].Frame.IsShowOverlayIndexName=false;
                if (IFrameSplitOperator.IsNumber(item.IndexParamSpace)) this.Frame.SubFrame[i].Frame.IndexParamSpace=item.IndexParamSpace;
                if (IFrameSplitOperator.IsNumber(item.IndexTitleSpace)) this.Frame.SubFrame[i].Frame.IndexTitleSpace=item.IndexTitleSpace;
                
                if (item.IsShowXLine==false) this.Frame.SubFrame[i].Frame.IsShowXLine=false;
                if (item.IsShowYLine==false) this.Frame.SubFrame[i].Frame.IsShowYLine=false;
                if (IFrameSplitOperator.IsBool(item.IsShowIndexTitle)) this.Frame.SubFrame[i].Frame.IsShowIndexTitle=item.IsShowIndexTitle;

                if (IFrameSplitOperator.IsBool(item.IsShowLeftText)) 
                {
                    subFrame.Frame.IsShowYText[0]=item.IsShowLeftText;
                    subFrame.Frame.YSplitOperator.IsShowLeftText=item.IsShowLeftText;            //显示左边刻度
                }
                if (IFrameSplitOperator.IsBool(item.IsShowRightText)) 
                {
                    subFrame.Frame.IsShowYText[1]=item.IsShowRightText;
                    subFrame.Frame.YSplitOperator.IsShowRightText=item.IsShowRightText;         //显示右边刻度
                }

                if (item.OverlayIndexType)
                {
                    if (IFrameSplitOperator.IsNumber(item.OverlayIndexType.Position)) subFrame.Frame.OverlayIndexType.Position=item.OverlayIndexType.Position;
                    if (IFrameSplitOperator.IsNumber(item.OverlayIndexType.LineSpace)) subFrame.Frame.OverlayIndexType.LineSpace=item.OverlayIndexType.LineSpace;
                }

                var bindData=this.ChartPaint[0].Data;
                this.BindIndexData(i,bindData);   //执行脚本
            }

            //this.UpdataDataoffset();           //更新数据偏移
        }
    }

    this.ChangeIndexTemplate=function(option)   //切换指标模板 可以设置指标窗口个数 每个窗口的指标
    {
        if (!option.Windows) return;
        var count=option.Windows.length;
        if (count<=0) return;
        var currentLength=this.Frame.SubFrame.length;

        var period=null, right=null;
        if (option.KLine)
        {
            if (IFrameSplitOperator.IsNumber(option.KLine.Period) && option.KLine.Period!=this.Period) period=option.KLine.Period;  //周期
            if (IFrameSplitOperator.IsNumber(option.KLine.Right) && option.KLine.Right!=this.Right) right=option.KLine.Right;       //复权
        }

        var bRefreshData= (period!=null || right!=null);

        //清空所有的指标图型
        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;
                titlePaint.GetEventCallback=(id)=> { return this.GetEventCallback(id); }
                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 item=option.Windows[i];
            var frameItem=null;
            if(option.Frame && option.Frame.length>i) frameItem=option.Frame[i];
            var titleIndex=windowIndex+1;
            this.TitlePaint[titleIndex].Data=[];
            this.TitlePaint[titleIndex].Title=null;

            if (item.Script)    //自定义X轴绘制事件
            {
                this.WindowIndex[i]=new ScriptIndex(item.Name,item.Script,item.Args,item);    //脚本执行
                if (!bRefreshData) this.BindIndexData(windowIndex,bindData);   //执行脚本
            }
            else
            {
                var indexID=item.Index;
                var indexItem=JSIndexMap.Get(indexID);
                if (indexItem)
                {
                    this.WindowIndex[i]=indexItem.Create();
                    this.CreateWindowIndex(windowIndex);
                    if (!bRefreshData) 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,
                            OutName:indexInfo.OutName
                        };
                        if (item.TitleFont) indexData.TitleFont=item.TitleFont;
    
                        this.WindowIndex[i]=new ScriptIndex(indexData.Name,indexData.Script,indexData.Args,indexData);    //脚本执行
                        if (!bRefreshData) this.BindIndexData(windowIndex,bindData);   //执行脚本
                    }
                }
            }

            if (item.Modify!=null) this.Frame.SubFrame[i].Frame.ModifyIndex=item.Modify;
            if (item.Change!=null) this.Frame.SubFrame[i].Frame.ChangeIndex=item.Change;
            if (item.Close!=null) this.Frame.SubFrame[i].Frame.CloseIndex=item.Close;
            if (item.Overlay!=null) chart.Frame.SubFrame[i].Frame.OverlayIndex=item.Overlay;
            if (item.IsDrawTitleBG==true)  this.Frame.SubFrame[i].Frame.IsDrawTitleBG=item.IsDrawTitleBG;
            

            if (IFrameSplitOperator.IsNumber(item.TitleHeight)) this.Frame.SubFrame[i].Frame.ChartBorder.TitleHeight=item.TitleHeight;
            else item.TitleHeight=this.Frame.SubFrame[i].Frame.ChartBorder.TitleHeight;
            if (item.IsShowTitleArraw==false) this.Frame.SubFrame[i].Frame.IsShowTitleArraw=false;
            if (item.IsShowIndexName==false) this.Frame.SubFrame[i].Frame.IsShowIndexName=false;
            if (IFrameSplitOperator.IsNumber(item.IndexParamSpace)) this.Frame.SubFrame[i].Frame.IndexParamSpace=item.IndexParamSpace;
            if (IFrameSplitOperator.IsNumber(item.IndexTitleSpace)) this.Frame.SubFrame[i].Frame.IndexTitleSpace=item.IndexTitleSpace;
            
            if (frameItem)
            {
                if (frameItem.SplitCount) this.Frame.SubFrame[i].Frame.YSplitOperator.SplitCount=frameItem.SplitCount;
                if (frameItem.IsShowXLine===false || frameItem.IsShowXLine===true) this.Frame.SubFrame[i].Frame.IsShowXLine=frameItem.IsShowXLine;
                if (frameItem.IsShowYLine===false || frameItem.IsShowYLine===true) this.Frame.SubFrame[i].Frame.IsShowYLine=frameItem.IsShowYLine;

                if (frameItem.IsShowLeftText===false || frameItem.IsShowLeftText===true) 
                {
                    this.Frame.SubFrame[i].Frame.IsShowYText[0]=frameItem.IsShowLeftText;
                    this.Frame.SubFrame[i].Frame.YSplitOperator.IsShowLeftText=frameItem.IsShowLeftText;            //显示左边刻度
                }
                if (frameItem.IsShowRightText===false || frameItem.IsShowRightText===true) 
                {
                    this.Frame.SubFrame[i].Frame.IsShowYText[1]=frameItem.IsShowRightText;
                    this.Frame.SubFrame[i].Frame.YSplitOperator.IsShowRightText=frameItem.IsShowRightText;         //显示右边刻度
                }
            }

        }

        //最后一个显示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;
        }

        if (!bRefreshData)
        {
            this.UpdataDataoffset();           //更新数据偏移
            this.Frame.SetSizeChage(true);
            this.ResetFrameXYSplit();
            this.UpdateFrameMaxMin();          //调整坐标最大 最小值
            this.Draw();
        }
        else
        {
            this.Frame.SetSizeChage(true);
            if (period!=null) this.ChangePeriod(period, option);
            else if (right!=null) this.ChangeRight(right);
        }
       
    }

    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;

        this.Frame.RestoreIndexWindows();

        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;
            if (item.Arguments) //参数
            {
                info.Args=[];
                for(var i in item.Arguments)
                {
                    var argItem=item.Arguments[i];
                    info.Args.push( {Name:argItem.Name, Value:argItem.Value} );
                }
            }

            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;
            case "深度图":
                chart=new DepthMapPaint();
                chart.Canvas=this.Canvas;
                chart.ChartBorder=this.Frame.ChartBorder;
                chart.ChartFrame=this.Frame;
                chart.HQChart=this;
                chart.SetOption(option);
                this.ExtendChartPaint.push(chart);
                return chart;
            case '背景图':
                chart=new BackgroundPaint();
                chart.Canvas=this.Canvas;
                chart.ChartBorder=this.Frame.ChartBorder;
                chart.ChartFrame=this.Frame;
                chart.HQChart=this;
                chart.SetOption(option);
                this.ExtendChartPaint.push(chart);
                return chart;
            case "FrameSplitPaint": //框架分割
                chart=new FrameSplitPaint();
                chart.Canvas=this.Canvas;
                chart.ChartBorder=this.Frame.ChartBorder;
                chart.ChartFrame=this.Frame;
                chart.HQChart=this;
                chart.SetOption(option);
                this.ExtendChartPaint.push(chart);
                return chart;

            default:
                chart=g_ExtendChartPaintFactory.Create(name);
                if (!chart) return null;

                chart.Canvas=this.Canvas;
                chart.ChartBorder=this.Frame.ChartBorder;
                chart.ChartFrame=this.Frame;
                chart.HQChart=this;
                chart.SetOption(option);
                this.ExtendChartPaint.push(chart);
                return chart;
        }
    }

    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();
            }
        }
    }

    //锁|解锁指标 { 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.SetSizeChange=function(bChanged)
    {
        this.Frame.SetSizeChage(bChanged);
        for(var i in this.ExtendChartPaint)
        {
            var item=this.ExtendChartPaint[i];
            item.SizeChange=bChanged;
        }
    }
    this.SetSizeChage=this.SetSizeChange;   //单词拼错了， 还没替换完

    this.Update=function(option) //option: { UpdateCursorIndexType:更新十字光标方式 }
    {
        if (!this.SourceData) return;
        if (this.BeforeBindMainData) this.BeforeBindMainData('Update');

        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.GetRightData(bindData.Right, { AlgorithmType: this.RightFormula });
            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);
        if (this.AfterBindMainData) this.AfterBindMainData("Update");

        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];
            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, this.IsApiPeriod);      //和主图数据拟合以后的数据
                bindData.Data=aryOverlayData;

                if (ChartData.IsMinutePeriod(bindData.Period,false) && !this.IsApiPeriod)   //周期数据
                {
                    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.GetRightData(bindData.Right,{ AlgorithmType: this.RightFormula });
                    bindData.Data=rightData;
                }

                var aryOverlayData=this.SourceData.GetOverlayData(bindData.Data, this.IsApiPeriod);      //和主图数据拟合以后的数据
                bindData.Data=aryOverlayData;

                if (ChartData.IsDayPeriod(bindData.Period,false) && !this.IsApiPeriod)   //周期数据
                {
                    var periodData=bindData.GetPeriodData(bindData.Period);
                    bindData.Data=periodData;
                }

                item.Data=bindData;
            }
        }

        this.ReqeustKLineInfoData( {FunctionName:"Update"} );
        
        this.CreateChartDrawPictureByStorage(); //创建画图工具
        
        //刷新画图
        this.UpdataDataoffset();           //更新数据偏移
        if (option && option.UpdateCursorIndexType>0) this.UpdatePointByCursorIndex(option.UpdateCursorIndexType);
        else 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, option)
    {
        this.CancelAutoUpdate();    //先停止定时器
        this.AutoUpdateEvent(false,'KLineChartContainer::ChangeSymbol');
        this.ClearRectSelect(true);
        this.ClearCustomKLine();
        this.Symbol=symbol;
        if (!symbol)
        {
            this.DrawEmpty();
            return;
        }

        if (option)
        {
            if (option.KLine)
            {
                var item=option.KLine;
                if (IFrameSplitOperator.IsNumber(item.Right)) this.Right=item.Right;
                if (IFrameSplitOperator.IsNumber(item.Period)) this.Period=item.Period;
            }
        }
       
        if (MARKET_SUFFIX_NAME.IsSHSZIndex(symbol)) this.Right=0;    //指数没有复权

        this.ClearIndexPaint(); //清空指标
        
        if (option)
        {
            if (option.Windows && Array.isArray(option.Windows) && option.Windows.length>0)
            {
                var windows=option.Windows;
                var systemScript = new JSIndexScript();
                for(var i in windows)
                {
                    if (i>=this.WindowIndex.length) break; //暂时不支持 动态增加/减少
                    var item=windows[i];
                    if (!item) continue;

                    if (item.Script)
                    {
                        this.WindowIndex[i]=new ScriptIndex(item.Name,item.Script,item.Args,item);    //脚本执行
                    }
                    else if (item.API)
                    {
                        var apiItem=item.API;
                        this.WindowIndex[i]=new APIScriptIndex(apiItem.Name,apiItem.Script,apiItem.Args,item);
                    }
                    else
                    {
                        var indexID=item.Index;
                        var indexInfo = systemScript.Get(indexID);
                        if (indexInfo)
                        {
                            var args=indexInfo.Args;
                            if (item.Args) indexInfo.Args=item.Args;
                            indexInfo.ID=indexID;
                            this.WindowIndex[i]=new ScriptIndex(indexInfo.Name,indexInfo.Script,indexInfo.Args,indexInfo);    //脚本执行
                        }
                    }
                }
            }
        }

        this.ReloadChartDrawPicture();
        this.Frame.ClearUpDonwFrameYData();
        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(obj)
    {
        if (obj && obj.FunctionName=="RecvDragDayData") //增量更新
        {
            obj.Update=true;
        }
        else
        {
            if (this.ChartPaint.length>0)
            {
                var klinePaint=this.ChartPaint[0];
                klinePaint.InfoData=new Map();
            }
            obj.Update=false;
        }

        //信息地雷信息
        for(var i in this.ChartInfo)
        {
            this.ChartInfo[i].RequestData(this,obj);
        }
    }

    //设置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({ FunctionName:"SetKLineInfo" });
    }

    //添加信息地雷
    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) && !this.IsApiPeriod)    //复权数据 ,A股才有有复权
        {
            var rightData=bindData.GetRightData(bindData.Right,{ AlgorithmType: this.RightFormula });
            bindData.Data=rightData;
        }

        var aryOverlayData=this.SourceData.GetOverlayData(bindData.Data, this.IsApiPeriod);      //和主图数据拟合以后的数据
        bindData.Data=aryOverlayData;

        if (ChartData.IsDayPeriod(bindData.Period,false) && !this.IsApiPeriod)   //周期数据
        {
            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, this.IsApiPeriod);      //和主图数据拟合以后的数据
        bindData.Data=aryOverlayData;

        if (ChartData.IsMinutePeriod(bindData.Period,false) && !this.IsApiPeriod)   //周期数据, API周期数据不用计算
        {
            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;

        var upperSymbol=this.Symbol.toUpperCase();

        var bNeedDonloadData=true;
        if (MARKET_SUFFIX_NAME.IsBIT(upperSymbol) || MARKET_SUFFIX_NAME.IsFutures(upperSymbol)) //数字货币, 期货 不需要下载流通股本
            bNeedDonloadData=false;

        if (this.EnableFlowCapital) //强制下载流通股
        {
            if (MARKET_SUFFIX_NAME.IsBIT(upperSymbol)) 
            {
                if (this.EnableFlowCapital.BIT==true) bNeedDonloadData=true;
            }
        }

        if (!bNeedDonloadData)
        {
            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 (this.IsApiPeriod)
        {
            var klineData=this.ChartPaint[0].Data;
            var aryFixedData=null;
            if (ChartData.IsMinutePeriod(this.Period,true)) //分钟数据
            {
                aryFixedData=klineData.GetMinuteFittingFinanceData(aryData);
            }
            else if (ChartData.IsDayPeriod(this.Period,true)) //日线数据
            {
                aryFixedData=klineData.GetFittingFinanceData(aryData);
            }

            if (aryFixedData && klineData.Data && aryFixedData.length==klineData.Data.length)
            {
                for(var i in klineData.Data)
                {
                    var item=klineData.Data[i];
                    if (aryFixedData[i] && IFrameSplitOperator.IsNumber(aryFixedData[i].Value))
                        item.FlowCapital=aryFixedData[i].Value;
                }
            }
        }
        else
        {
            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];
                    if (aryFixedData[i] && IFrameSplitOperator.IsNumber(aryFixedData[i].Value))
                        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];
                    if (aryFixedData[i] && IFrameSplitOperator.IsNumber(aryFixedData[i].Value))
                        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.GetRightData(bindData.Right, { AlgorithmType: this.RightFormula });
                    newBindData.Data=rightData;
                }

                if (ChartData.IsDayPeriod(bindData.Period,false)) //周期数据
                {
                    var periodData=newBindData.GetPeriodData(bindData.Period);  
                    newBindData.Data=periodData;
                }

                bindData.Data=newBindData.Data;
            }
        }

        this.FlowCapitalReady=true;
        var bDraw=false;
        for(var i in this.ExtendChartPaint)
        {
            var item=this.ExtendChartPaint[i];
            if (item.ClassName=='StockChip')
            {
                bDraw=true;
                break;
            }
        }

        if (bDraw) this.Draw();
    }

    //创建画图工具
    this.CreateChartDrawPicture=function(name, option, callback)
    {
        var drawPicture=null;
        var item=IChartDrawPicture.GetDrawPictureByName(name);
        if (item)
        {
            drawPicture=item.Create();
            if (drawPicture.ClassName=='ChartDrawPictureText') drawPicture.HQChart=this;
        }

        if (!drawPicture)    //iconfont图标
        {
            if (IChartDrawPicture.MapIonFont.has(name))
            {
                var iconItem=IChartDrawPicture.MapIonFont.get(name);
                drawPicture=new ChartDrawPictureIconFont();
                drawPicture.FontOption.Family=iconItem.Family
                drawPicture.Text=iconItem.Text;
                if (iconItem.Color) drawPicture.LineColor=iconItem.Color;
            }
        }

        if (!drawPicture) return false;
        
        drawPicture.Canvas=this.Canvas;
        drawPicture.Status=0;
        drawPicture.Symbol=this.Symbol;
        drawPicture.Period=this.Period;
        drawPicture.Right=this.Right;
        drawPicture.Option=this.ChartDrawOption;
        
        if (callback) drawPicture.FinishedCallback=callback;    //完成通知上层回调
        if (option) drawPicture.SetOption(option);
        var self=this;
        drawPicture.Update=function()   //更新回调函数
        {
            self.DrawDynamicInfo();
        };
        drawPicture.GetActiveDrawPicture=function() { return self.GetActiveDrawPicture(); }
        this.CurrentChartDrawPicture=drawPicture;
        //JSConsole.Chart.Log("[KLineChartContainer::CreateChartDrawPicture] ", name,this.CurrentChartDrawPicture);
        return true;
    }

    this.AddChartDrawPicture=function(obj)
    {
        if (!obj) return null;
        if (obj.FrameID<0 || obj.FrameID>=this.Frame.SubFrame.length) return null;

        var item=IChartDrawPicture.GetDrawPictureByClassName(obj.ClassName);
        if (!item) return null;
        var drawPicture=item.Create();

        drawPicture.Canvas=this.Canvas;
        drawPicture.Status=10;
        drawPicture.Frame=this.Frame.SubFrame[obj.FrameID].Frame;  //绑定框架坐标
        drawPicture.Symbol=this.Symbol;
        drawPicture.Period=this.Period;
        drawPicture.Right=this.Right;
        if (obj.Value) drawPicture.Value=obj.Value;

        if (drawPicture.ImportStorageData) drawPicture.ImportStorageData(obj);
        drawPicture.SetOption(obj);

        if (obj.EnableUpdateXValue) drawPicture.UpdateXValue();
        drawPicture.ValueToPoint();

        if (drawPicture.ClassName==='ChartDrawPictureText') drawPicture.IsInitialized=true;
        this.ChartDrawPicture.push(drawPicture);

        this.DrawDynamicInfo();

        return drawPicture;
    }

    //xStep,yStep 移动的偏移量
    this.MoveChartDrawPicture=function(x,y,isPhone)
    {
        var drawPicture=this.CurrentChartDrawPicture;
        if (!drawPicture) return false;

        var pixelTatio = GetDevicePixelRatio(); //x,y 需要乘以放大倍速
        if (isPhone) pixelTatio=1;
        var xStep=x*pixelTatio;
        var yStep=y*pixelTatio;
        //JSConsole.Chart.Log("xStep="+xStep+" yStep="+yStep);
        drawPicture.Move(xStep,yStep);

        return true;
    }


    //数据长度变化 需要更新画图工具X轴索引
    this.UpdateChartDrawXValue=function()
    {
        for(var i in this.ChartDrawPicture)
        {
            var item=this.ChartDrawPicture[i];
            item.UpdateXValue();
        }
    }


    //注册鼠标右键事件
    this.OnRightMenu=function(x,y,e)
    {
        var pixelTatio = GetDevicePixelRatio(); //x,y 需要乘以放大倍速
        if (this.RightMenu)
        {
            var frameId=this.Frame.PtInFrame(x*pixelTatio,y*pixelTatio);
            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*pixelTatio,y*pixelTatio);
            var data={ X:x, Y:y, Event:e, FrameID:frameId };
            event.Callback(event,data,this);
        }
    }

    //重新加载画图工具(切换股票|周期)
    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.CreateChartDrawPicture(item);
            if (!drawPicture) continue;

            drawPicture.Canvas=this.Canvas;
            drawPicture.Status=10;
            drawPicture.Frame=this.Frame.SubFrame[item.FrameID].Frame;  //绑定框架坐标
            
            if (drawPicture.ImportStorageData) drawPicture.ImportStorageData(item);
            drawPicture.UpdateXValue();
            drawPicture.ValueToPoint();

            var self=this;
            drawPicture.GetActiveDrawPicture=function() { return self.GetActiveDrawPicture(); }

            if (drawPicture.ClassName==='ChartDrawPictureText') drawPicture.IsInitialized=true;

            this.ChartDrawPicture.push(drawPicture);
        }

        this.ChartDrawStorageCache=null;    //清空缓存
    }

    //形态匹配
    // 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;
            if (hisData && hisData.Data && hisData.Data.length>0)
            {
                var fristKItem=hisData.Data[0];
                var aryInfo=[];
                for(var i in this.ChartInfo)
                {
                    var infoItem=this.ChartInfo[i];
                    for(var j in infoItem.Data)
                    {
                        var item=infoItem.Data[j];
                        if (item.Date>=fristKItem.Date) //在K线范围内的才显示
                            aryInfo.push(item);
                    }
                }
                aryInfo.sort(function(a,b) { return a.Date-b.Date });   //排序

                for(var i=0;i<hisData.Data.length;)
                {
                    var kItem=hisData.Data[i];  //K线数据

                    if (aryInfo.length<=0) 
                        break;

                    var infoItem=aryInfo[0];
                    if (kItem.Date<infoItem.Date) 
                    {
                        ++i;
                        continue;
                    }
                    
                    if (mapInfoData.has(kItem.Date.toString())) //信息地雷日期<K线上的日期 就是属于这个K线上的
                    {
                        mapInfoData.get(kItem.Date.toString()).Data.push(infoItem);
                    }
                    else
                    {
                        mapInfoData.set(kItem.Date.toString(),{Data:new Array(infoItem)});
                    }

                    aryInfo.shift();
                    //JSConsole.Chart.Log('[KLineChartContainer::UpdataChartInfo]',item);
                }
            }
        }
            
        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 (this.IsApiPeriod)
        {

        }
        else
        {
            if (bindData.Right>0)    //复权
            {
                var rightData=bindData.GetRightData(bindData.Right, { AlgorithmType: this.RightFormula });
                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.GetOverlayIndexByIdentify=function(identify)
    {
        for(var i=0; i<this.Frame.SubFrame.length; ++i)
        {
            var item=this.Frame.SubFrame[i];
            if (!IFrameSplitOperator.IsNonEmptyArray(item.OverlayIndex)) continue;

            for(var j=0; j<item.OverlayIndex.length; ++j)
            {
                var overlayItem=item.OverlayIndex[j];
                if (overlayItem.Identify===identify)
                    return { OverlayItem:overlayItem, WindowIndex:i };
            }
        }

        return null;
    }

    //更新叠加指标
    this.UpdateOverlayIndex=function(identify)
    {
        var overlayIndex=this.GetOverlayIndexByIdentify(identify)

        if (overlayIndex==null) 
        {
            console.warn(`[KLineChartContainer::UpdateOverlayIndex] can't find overlay index. [identify=${identify}]`);
            return;
        }

        if (!this.ChartPaint[0]) return;
        var kData=this.ChartPaint[0].Data;
        if (!kData) return;

        this.BindOverlayIndexData(overlayIndex.OverlayItem, overlayIndex.WindowIndex, kData);
    }

    //修改参数指标
    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)
    {
        if (this.EnableYDrag && (this.EnableYDrag.Left || this.EnableYDrag.Right) && this.Frame && this.Frame.PtInFrameY)
        {
            var pixelTatio = GetDevicePixelRatio();
            var x = (e.clientX-this.UIElement.getBoundingClientRect().left)*pixelTatio;
            var y = (e.clientY-this.UIElement.getBoundingClientRect().top)*pixelTatio;
            var dragY=this.Frame.PtInFrameY(x,y);
            if (dragY && dragY.Index>=0)
            {
                this.CancelZoomUpDownFrameY(dragY);
            }
        }

        if (this.EnableZoomIndexWindow)
        {
            var frameId=this.Frame.PtInFrame(x,y);
            JSConsole.Chart.Log("[KLineChartContainer::OnDoubleClick] frameId",frameId);
            if (frameId>=this.Frame.ZoomStartWindowIndex)
            {
                if (this.ZoomIndexWindow(frameId, {X:x, Y:y}))
                {
                    this.Frame.SetSizeChage(true);
                    this.Draw();
                    return true;
                }
            }
        }
        
        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();
        if (!this.PtInChartPaintTooltip(x,y,tooltip)) return;
        if (!tooltip.Data) return;

        if (event)
        {
            if (this.ClickChartTimer!=null) //清空单击定时器
            {
                clearTimeout(this.ClickChartTimer);
                this.ClickChartTimer=null;
            }
            
            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.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) || ChartData.IsSecondPeriod(this.Period)) //下载分钟/秒数据
        {
            JSConsole.Chart.Log(`[KLineChartContainer.DragDownloadData] Minute:[Enable=${this.DragDownload.Minute.Enable}, IsEnd=${this.DragDownload.Minute.IsEnd}, Status=${this.DragDownload.Minute.Status}, Period=${this.Period}]`);
            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();
        }
        else if(ChartData.IsTickPeriod(this.Period))
        {
            JSConsole.Chart.Log(`[KLineChartContainer.DragDownloadData] Tick:[Enable=${this.DragDownload.Tick.Enable}, IsEnd=${this.DragDownload.Tick.IsEnd}, Status=${this.DragDownload.Tick.Status}]`);
            if (!this.DragDownload.Tick.Enable) return;
            if (this.DragDownload.Tick.IsEnd) return; //全部下载完了
            if (this.DragDownload.Tick.Status!=0) return;
            this.RequestDragTickData(); 
        }
    }

    //TODO: 
    this.RequestDragTickData=function()
    {
        JSConsole.Chart.Log(`[KLineChartContainer.RequestDragTickData] not finished.`);
    }

    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:'拖拽分钟|秒K线数据下载',
                Request:{ Url:this.DragMinuteKLineApiUrl,  Type:'POST' , Data: postData, Period:this.Period, Right:this.Right  }, 
                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);
        if (!aryDayData || aryDayData.length<=0)
        {
            this.DragDownload.Minute.IsEnd=true; 
            return;
        }

        var lastDataCount=this.GetHistoryDataCount();   //保存下上一次的数据个数

        var firstData=this.SourceData.Data[0];
        var endIndex=null;
        for(var i=aryDayData.length-1;i>=0;--i)
        {
            var item=aryDayData[i];
            if (firstData.Date>item.Date || (firstData.Date==item.Date && firstData.Time>item.Time)) 
            {
                endIndex=i;
                break;
            }
            else if (firstData.Date==item.Date && firstData.Time==item.Time)
            {
                firstData.YClose=item.YClose;
                endIndex=i-1;
                break;
            }
        }

        if (endIndex==null && endIndex<0) return;
        
        for(var i=0;i<aryDayData.length && i<=endIndex;++i)    //数据往前插
        {
            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 (!this.IsApiPeriod)
        {
            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.UpdateChartDrawXValue();      //更新画图工具X轴索引
        this.Draw();

        //叠加指标计算
        this.BindAllOverlayIndexData(bindData);
    }

    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, Period:this.Period, Right:this.Right }, 
                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 || aryDayData.length<=0)
        {
            this.DragDownload.Day.IsEnd=true;   //下完了
            return;
        }
        var lastDataCount=this.GetHistoryDataCount();   //保存下上一次的数据个数

        var firstData=this.SourceData.Data[0];
        var endIndex=null;
        for(var i=aryDayData.length-1;i>=0;--i)
        {
            var item=aryDayData[i];
            if (firstData.Date>item.Date) 
            {
                endIndex=i;
                break;
            }
            else if (firstData.Date==item.Date)
            {
                firstData.YClose=item.YClose;
                endIndex=i-1;
                break;
            }
        }
        if (endIndex==null && endIndex<0) return;
        
        for(var i=0; i<aryDayData.length && i<=endIndex;++i)    //数据往前插
        {
            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 (!this.IsApiPeriod)
        {
            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.UpdateChartDrawXValue();       //更新画图工具X轴索引
        this.Draw();   
        
        //更新信息地雷
        this.ReqeustKLineInfoData( { FunctionName:"RecvDragDayData", StartDate:firstData.Date } );

        //叠加指标计算
        this.BindAllOverlayIndexData(bindData);
    }

    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;
    }

    this.OnSize=function()
    {
        if (!this.Frame) return;
        if (!this.Frame.OnSize) return;

        //this.Frame.CalculateChartBorder();
        var obj=this.Frame.OnSize();
        this.Frame.SetSizeChage(true);
        if (obj.Changed)
        {
            this.UpdataDataoffset();
            this.UpdatePointByCursorIndex(2);
            this.UpdateFrameMaxMin();
        }

        this.Draw();
    }

}

//API 返回数据 转化为array[]
KLineChartContainer.JsonDataToHistoryData=function(data)
{
    var aryDayData=[];
    if (!data.data) return aryDayData;

    var upperSymbol=null;
    if (data.symbol) upperSymbol=data.symbol.toUpperCase();
    var isFutures=false;    //是否是期货
    if (upperSymbol) isFutures=MARKET_SUFFIX_NAME.IsFutures(upperSymbol);

    var list = data.data;
    var date = 0, yclose = 1, open = 2, high = 3, low = 4, close = 5, vol = 6, amount = 7, position=8;
    var fclose=9, yfclose=10;   //结算价, 前结算价
    var bfactor=11, afactor=12; //前, 后复权因子
    var orderFlow=20;
    for (var i = 0; i < list.length; ++i)
    {
        var item = new HistoryData();
        var jsData=list[i];

        item.Date = jsData[date];
        item.Open = jsData[open];
        item.YClose = jsData[yclose];
        item.Close = jsData[close];
        item.High = jsData[high];
        item.Low = jsData[low];
        item.Vol = jsData[vol];    //原始单位股
        item.Amount = jsData[amount];
        if (IFrameSplitOperator.IsNumber(jsData[position])) item.Position=jsData[position];//期货持仓
        if (IFrameSplitOperator.IsNumber(jsData[fclose])) item.FClose=jsData[fclose];       //期货结算价
        if (IFrameSplitOperator.IsNumber(jsData[yfclose])) item.YFClose=jsData[yfclose];    //期货前结算价

        if (IFrameSplitOperator.IsNumber(jsData[bfactor])) item.BFactor=jsData[bfactor];    //前复权因子
        if (IFrameSplitOperator.IsNumber(jsData[afactor])) item.AFactor=jsData[afactor];    //后复权因子

        if (!IFrameSplitOperator.IsNumber(item.Open)) continue;

        if (jsData[orderFlow]) item.OrderFlow=jsData[orderFlow];

        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;
    item.Vol=stock.vol; //股
    item.Amount=stock.amount;
    item.Close=stock.price;
    if (IFrameSplitOperator.IsNumber(stock.position)) item.Position=stock.position; //持仓量

    if (IFrameSplitOperator.IsNumber(stock.bfactor)) item.BFactor=stock.bfactor;    //前复权因子
    if (IFrameSplitOperator.IsNumber(stock.afactor)) item.AFactor=stock.afactor;    //后复权因子
    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.IsFutures(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;
        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 (IFrameSplitOperator.IsNumber(jsData.position)) item.Position=jsData.position; //持仓量

        if (!IFrameSplitOperator.IsNumber(item.Close)) //当前没有价格 使用上一个价格填充
        {
            item.Close=preClose;
            item.Open=item.High=item.Low=item.Close;
        }

        //价格是0的 都用空
        if (!IFrameSplitOperator.IsNumber(item.Open)) item.Open=null;
        if (!IFrameSplitOperator.IsNumber(item.Close)) item.Close=null;
        if (!IFrameSplitOperator.IsNumber(item.High)) item.High=null;
        if (!IFrameSplitOperator.IsNumber(item.Low)) item.Low=null;

        //上次价格
        if (IFrameSplitOperator.IsNumber(jsData.price)) preClose=jsData.price;

        aryMinuteData[i]=item;
    }

    return aryMinuteData;
}

//分钟K线叠加数据增量更新v2版本
KLineChartContainer.JsonDataToMinuteRealtimeDataV2=function(data,symbol)
{
    if (!data || !data.overlay || !symbol) return null;

    var overlayData=null;
    for(var i=0;i<data.overlay.length;++i) //overlay={ symbol:, name:, data:[] }
    {
        var item=data.overlay[i];
        if (item.symbol==symbol)
        {
            overlayData=item;
            break;
        }
    }

    if (!overlayData) return null;

    var upperSymbol=symbol.toUpperCase();
    var isSHSZ=MARKET_SUFFIX_NAME.IsSHSZ(upperSymbol);
    var isFutures=MARKET_SUFFIX_NAME.IsFutures(upperSymbol);    //是否是期货

    var date = 0, yclose = 1, open = 2, high = 3, low = 4, close = 5, vol = 6, amount = 7, time = 8, position=9, orderFlow=20;
    var yClose=null; 
    
    for (var i = 0; i < overlayData.data.length; ++i)
    {
        var item = new HistoryData();
        var jsData=overlayData.data[i];
        item.Date = jsData[date];
        item.Open = jsData[open];
        item.YClose = jsData[yclose];
        item.Close = jsData[close];
        item.High = jsData[high];
        item.Low = jsData[low];
        item.Vol = jsData[vol];    //股
        item.Amount = jsData[amount];
        item.Time=jsData[time];
        if (IFrameSplitOperator.IsNumber(jsData[position])) item.Position=jsData[position]; //期货持仓

        if (!IFrameSplitOperator.IsNumber(item.YClose))
        {
            if (IFrameSplitOperator.IsNumber(yClose)) item.YClose=yClose;
        }

        if (IFrameSplitOperator.IsNumber(item.Close)) yClose=item.Close;

        if (jsData[orderFlow]) item.OrderFlow=jsData[orderFlow];

        aryMinuteData.push(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 isFutures=false;    //是否是期货
    if (upperSymbol) isFutures=MARKET_SUFFIX_NAME.IsFutures(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, position=9, orderFlow=20;
    var yClose=null; 
    for (var i = 0; i < list.length; ++i)
    {
        var item = new HistoryData();
        var jsData=list[i];
        item.Date = jsData[date];
        item.Open = jsData[open];
        item.YClose = jsData[yclose];
        item.Close = jsData[close];
        item.High = jsData[high];
        item.Low = jsData[low];
        item.Vol = jsData[vol];    //股
        item.Amount = jsData[amount];
        item.Time=jsData[time];
        if (IFrameSplitOperator.IsNumber(jsData[position])) item.Position=jsData[position]; //期货持仓

        if (!IFrameSplitOperator.IsNumber(item.YClose))
        {
            if (IFrameSplitOperator.IsNumber(yClose)) item.YClose=yClose;
        }

        if (IFrameSplitOperator.IsNumber(item.Close)) yClose=item.Close;

        if (jsData[orderFlow]) item.OrderFlow=jsData[orderFlow];

        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.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 (!IFrameSplitOperator.IsNumber(item.Open)) continue; //停牌的数据剔除

       //yClose=item.Close;
       aryDayData.push(item);
   }

   return aryDayData;
}

KLineChartContainer.JsonDataToTickDataV2=function(data)
{
   var aryDayData=[];
   if (!IFrameSplitOperator.IsNonEmptyArray(data.data)) return aryDayData;

   for(var i=0;i<data.data.length;++i)
   {
       var item = new HistoryData();
       var tick=data.data[i];   //[ date, time, yClose, price, extendData]
       if (!tick) continue;

       item.Date = tick[0];
       item.Time=tick[1];
       item.YClose = tick[2];
       item.Low=item.High=item.Close=item.Open = tick[3];
       aryDayData.push(item);

       if (tick[4]) item.ExtendData=tick[4];
   }

   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.IndexBindData;                       //计算指标需要绑定的分钟数据
    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.BeforeOpenData=null;                 //盘前集合竞价数据
    this.IsBeforeData=false;                  //是否支持显示盘前集合竞价数据

    this.IsShowAfterData=false;               //收盘集合竞价
    this.AfterCloseData=null;                 //收盘集合竞价数据
    this.IsAfterData=false;                   //是否支持显示收盘集合竞价数据
    this.ExtendWidth={ Left: 120, Right:120 } ;      //单日分时图 左右扩展图形宽度
    
    this.IsShowLead=true;                     //指数是否显示领先指标

    this.IsShowMultiDayBeforeData=false;             //多日分时图 是否显示盘前集合竞价
    this.MultiDayBeforeOpenData=null;                //多日分时图 盘前集合竞价数据 
    this.IsShowMultiDayAfterData=false;             //多日分时图 是否显示收盘集合竞价
    this.MultiDayAfterCloseData=null;                //多日分时图 收盘集合竞价数据

    this.MultiDayExtendWidth={ Left:20, Right:20 };   //多日分时图 左右扩展图形宽度

    this.ChartDrawStorage=new ChartDrawStorage();
    this.ChartDrawStorageCache=null;         //首次需要创建的画图工具数据

    this.MinuteApiUrl=g_JSChartResource.Domain+"/API/Stock";
    this.HistoryMinuteApiUrl=g_JSChartResource.Domain+'/API/StockMinuteData';  //历史分钟数据

    this.ColorLineData;    //主图价格线颜色自定义配置
    this.EnableSelectRect=false;    //是否可以区间选择
    this.SelectRectDialog=null;     //区间选择对话框

    //集合竞价设置 obj={ Left:true/false, Right:true/false, MultiDay:{Left:, Right:} }
    this.SetCallCationDataBorder=function(obj)
    {
        if (!obj) return;

        var extendWidth=
        {
            Left: obj.Left?this.ExtendWidth.Left:0,
            Right: obj.Right?this.ExtendWidth.Right:0
        };

        this.Frame.SetExtendWidth(extendWidth);

        if (obj.MultiDay)
        {
            var item=obj.MultiDay;
            var DayMinuteWidth=
            {
                Left:item.Left? this.MultiDayExtendWidth.Left:0,
                Right:item.Right? this.MultiDayExtendWidth.Right:0
            };

            this.Frame.SetMultiDayMinuteWidth(DayMinuteWidth);
        }
    }

    this.ReloadChartPaint=function(resource)
    {
        for(var i=0; i<this.ChartPaint.length; ++i)
        {
            var item=this.ChartPaint[i];
            if (!item) continue;
            if (item.ReloadResource) item.ReloadResource(resource);

            if (i==0)
            {
                if (item.Name=="Minute-Line")
                {
                    item.Color=g_JSChartResource.Minute.PriceColor;
                    item.AreaColor=g_JSChartResource.Minute.AreaPriceColor;
                }
            }
            else if (i==1)
            {
                if (item.Name=="Minute-Average-Line")
                {
                    item.Color=g_JSChartResource.Minute.AvPriceColor;
                }
            }
            else if (i==2)
            {
                if (item.Name=="Minute-Vol-Bar")
                {
                    item.Color=g_JSChartResource.Minute.VolBarColor;
                }
            }
        }
    }

    this.StopAutoUpdate=function()
    {
        this.CancelAutoUpdate();
        if (!this.IsAutoUpdate) return;
        this.IsAutoUpdate=false;
    }

    this.ClickFrameButton=function(button)
    {
        if (button.ID==JSCHART_BUTTON_ID.CLOSE_BEFOREOPEN_ID)
            this.ShowCallAuctionData({ Left:false, Right:false, MultiDay:{ Left:false, Right:false } });
    }

    //左右拖拽
    this.OnDragMode_One=function(moveData, e)
    {
        var drag=this.MouseDrag;
        var moveSetp=moveData.X;
        var yMoveSetp=moveData.Y;

        if (this.RectSelectDrag && this.RectSelectDrag.Index>=0)    //区间选择
        {
            if (moveSetp<5) return;
            var obj={ X:e.clientX, Y:e.clientY, PointIndex:this.RectSelectDrag.Index, Name:"MoveRectSelectLine" };
            if (this.MoveRectSelectPoint(obj))
            {
                drag.LastMove.X=e.clientX;
                this.Draw();
            }
        }
        else
        {
            if (moveSetp<5 && yMoveSetp<5) return;
            if (!this.EnableSelectRect) return;

            this.UIElement.style.cursor="default";
            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.OnMinuteSelectRectMouseUp=function(e)
    {
        var drag=this.MouseDrag;
        drag.LastMove.X=e.clientX;
        drag.LastMove.Y=e.clientY;

        var selectData=new SelectRectData();
        var pixelTatio = GetDevicePixelRatio();
        //区间起始位置 结束位子
        selectData.XStart=(drag.Click.X-uielement.getBoundingClientRect().left)*pixelTatio;
        selectData.YStart=(drag.Click.Y-uielement.getBoundingClientRect().top)*pixelTatio;
        selectData.XEnd=(drag.LastMove.X-uielement.getBoundingClientRect().left)*pixelTatio;
        selectData.YEnd=(drag.LastMove.Y-uielement.getBoundingClientRect().top)*pixelTatio;
        selectData.JSChartContainer=this;
        selectData.Stock={Symbol:this.Symbol, Name:this.Name};

        if (this.EnableSelectRect && !this.BorderDrag && this.GetSelectRectData(selectData))
        {
            var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_SELECT_RECT);
            var paint=this.GetRectSelectPaint();
            var isShowDialog=true;  //是否显示内置区间选择框
            if (event && event.Callback)
            {
                var data=
                { 
                    X:drag.LastMove.X-uielement.getBoundingClientRect().left,
                    Y:drag.LastMove.Y-uielement.getBoundingClientRect().top,
                    SelectData:selectData,   //区间选择的数据
                    RectSelectPaint:paint    //区间选择背景
                };
                event.Callback(event,data,this);
                isShowDialog=false; //外部调用了区间选择事件，不弹框
            }

            if (isShowDialog && this.SelectRectDialog)
            {
                e.data=
                {
                    Chart:this,
                    X:drag.LastMove.X-uielement.getBoundingClientRect().left,
                    Y:drag.LastMove.Y-uielement.getBoundingClientRect().top,
                    SelectData:selectData,          //区间选择的数据
                    RectSelectPaint:paint           //区间选择背景
                };

                this.SelectRectDialog.DoModal(e);
            }
            else
            {
                this.HideSelectRect();
                this.UpdateSelectRect(selectData.Start,selectData.End);
            }
        }
        else
        {
            this.TryClickPaintEvent(JSCHART_EVENT_ID.ON_CLICKUP_CHART_PAINT,this.ClickDownPoint,e);
            this.ClickEvent(e);
        }
    }

    this.OnDragSelectRectMouseUp=function(e)
    {
        var paint=this.GetRectSelectPaint();
        if (!paint) return;
        
        var selectData=paint.GetSelectRectData();
        if (!selectData) return;

        var pixelTatio = GetDevicePixelRatio();
        var corssCursor=this.ChartCorssCursor;  //十字光标
        var x=corssCursor.LastPoint.X/pixelTatio;
        var y=corssCursor.LastPoint.Y/pixelTatio;

        var isShowDialog=true;  //是否显示内置区间选择框
        var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_DRAG_SELECT_RECT_MOUSEUP);
        if (event)
        {
            var data=
            { 
                X:x,
                Y:y,
                SelectData:selectData,   //区间选择的数据
                RectSelectPaint:paint    //区间选择背景
            };
            event.Callback(event,data,this);
            isShowDialog=false;
        }

        if (isShowDialog && this.SelectRectDialog)
        {
            e.data=
            {
                Chart:this,
                X:x,
                Y:y,
                SelectData:selectData,          //区间选择的数据
                RectSelectPaint:paint           //区间选择背景
            };

            this.SelectRectDialog.DoModal(e);
        }
            
    }

    this.UpdateSelectRect=function(start,end)
    {
        if (!this.SourceData || !this.SourceData.Data) return;
        var paint=this.GetRectSelectPaint();
        if (!paint) return;

        var data=this.SourceData;
        if (!data || !IFrameSplitOperator.IsNonEmptyArray(data.Data)) return;
        var count=data.Data.length;
        var startItem=data.Data[start];
        if (end>=count) end=count-1;
        var endItem=data.Data[end];

        JSConsole.Chart.Log('[MinuteChartContainer::UpdateSelectRect]',startItem,endItem);
        paint.SetPoint(startItem, { Index:0 });
        paint.SetPoint(endItem, { Index:1 });

        this.Draw();
    }

    this.MoveRectSelectPoint=function(obj)
    {
        var paint=this.GetRectSelectPaint();
        if (!paint) return false;

        if (!this.SourceData || !this.SourceData.Data) return false;
        var kData=this.SourceData;

        if (!this.Frame.SubFrame[0]) return false;
        var subFrame=this.Frame.SubFrame[0].Frame;
        if (!subFrame) false;

        var pixelTatio = GetDevicePixelRatio();
        var x=(obj.X-uielement.getBoundingClientRect().left)*pixelTatio;
        var index=subFrame.GetXData(x);
        index=parseInt(index.toFixed(0));
        var dataIndex=index+kData.DataOffset;
        if (dataIndex>=kData.Data.length) dataIndex=kData.Data.length-1;

        var item = kData.Data[dataIndex];
        JSConsole.Chart.Log("[MinuteChartContainer::MoveRectSelectPoint] point, item", obj.PointIndex, item);

        if (!paint.SetPoint(item,{ Index: obj.PointIndex })) return false;

        var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_DRAG_SELECT_RECT);
        if (event)
        {
            var selectData=paint.GetSelectRectData();
            var data={ X:obj.X, Y:obj.Y, SelectData:selectData, RectSelectPaint:paint };
            event.Callback(event,data,this);
        }

        return true;
    }


    //手势
    this.OnTouchStart=function(e)
    {
        if(this.DragMode==0) return;
        if (this.ChartSplashPaint && this.ChartSplashPaint.IsEnableSplash == true) 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.ChartDrawOption.IsLockScreen)
            {
                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,true);
                    else
                    {
                        this.SetChartDrawPictureFirstPoint(drag.Click.X,drag.Click.Y,true);
                        //只有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;
                    }
                }
            }
            else
            {
                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.PhoneTouchInfo={ Start:{X:touches[0].clientX, Y:touches[0].clientY }, End:{ X:touches[0].clientX, Y:touches[0].clientY } };
                this.SelectChartDrawPicture=null;
    
                if (this.EnableScrollUpDown==false)
                    T_ShowCorssCursor();    //移动十字光标
            }

            if (this.EnableZoomIndexWindow)
            {
                this.PhoneDBClick.AddTouchStart(touches[0].clientX, touches[0].clientY, Date.now());
                JSConsole.Chart.Log("[MinuteChartContainer::OnTouchStart] PhoneDBClick ", this.PhoneDBClick);
            }

            this.TouchEvent({ EventID:JSCHART_EVENT_ID.ON_PHONE_TOUCH, FunctionName:"OnTouchStart"}, e);
        }
    }

    this.OnTouchMove=function(e)
    {
        if (this.ChartSplashPaint && this.ChartSplashPaint.IsEnableSplash == true) return;

        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 (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,true))
                        {
                            this.DrawDynamicInfo();
                        }
                    }
                    else if (drawPicture.Status==3)
                    {
                        if(this.SetChartDrawPictureThirdPoint(touches[0].clientX,touches[0].clientY,true))
                        {
                            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,true))
                        {
                            this.DrawDynamicInfo();
                        }
                    }

                    drag.LastMove.X=touches[0].clientX;
                    drag.LastMove.Y=touches[0].clientY;
                }
                else
                {
                    //上下滚动
                    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.PhoneTouchInfo)
            {
                this.PhoneTouchInfo.End.X=touches[0].clientX;
                this.PhoneTouchInfo.End.Y=touches[0].clientY;
            }
        }

        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);
        if (this.ChartSplashPaint && this.ChartSplashPaint.IsEnableSplash == true) return;

        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();
            }
        }

        if (this.EnableZoomIndexWindow)
        {
            var time=Date.now();
            this.PhoneDBClick.AddTouchEnd(time);
            if (this.PhoneDBClick.IsVaildDBClick())
            {
                this.OnTouchDBClick(this.PhoneDBClick.Start);
                this.PhoneDBClick.Clear();
            }
        }

        this.IsOnTouch = false;
        this.StopDragTimer();
        this.TouchEvent({ EventID:JSCHART_EVENT_ID.ON_PHONE_TOUCH, FunctionName:"OnTouchEnd"}, e);
        this.OnTouchFinished();
        this.TouchDrawCount=0;
    }

    
    //键盘左右移动十字光标
    this.OnKeyDown=function(e)
    {
        if (this.ChartSplashPaint && this.ChartSplashPaint.IsEnableSplash == true) return;

        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;
            case 46:    //del
                if (!this.SelectChartDrawPicture) break;
                var drawPicture=this.SelectChartDrawPicture;
                JSConsole.Chart.Log(drawPicture,"drawPicturedrawPicturedrawPicture")
                this.SelectChartDrawPicture=null;
                this.ClearChartDrawPicture(drawPicture);    //删除选中的画图工具
                break;
            case 32:    //space
                this.OnMarkRectSelect(e);
                break;
            default:
                return;
        }

        //不让滚动条滚动
        if(e.preventDefault) e.preventDefault();
        else e.returnValue = false;
    }

    this.OnMarkRectSelect=function(e)
    {
        var corssCursor=this.ChartCorssCursor;  //十字光标
        if (!corssCursor || corssCursor.Status==0) return;
        if (!IFrameSplitOperator.IsNumber(corssCursor.CursorIndex)) return;
        if (!this.SourceData || !this.SourceData.Data) return;
        var paint=this.GetRectSelectPaint();
        if (!paint) return;

        var cursorIndex=corssCursor.CursorIndex;
        JSConsole.Chart.Log("[MinuteChartContainer::OnMarkRectSelect] dataIndex", cursorIndex);

        var kData=this.SourceData;
        cursorIndex=parseInt(cursorIndex.toFixed(0));
        var index=cursorIndex+kData.DataOffset;
        if (index>=kData.Data.length) index=kData.Data.length-1;

        var item = kData.Data[index];

        JSConsole.Chart.Log("[MinuteChartContainer::OnMarkRectSelect] item", item);

        if (!this.SetRectSelectData(item)) return;

        if (paint.GetPointCount()==2)
        {
            var selectData=paint.GetSelectRectData();
            var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_KEYDOWN_SELECT_RECT);
            var pixelTatio = GetDevicePixelRatio();
            if (event && event.Callback)
            {
                var data=
                { 
                    X:corssCursor.LastPoint.X/pixelTatio,
                    Y:corssCursor.LastPoint.Y/pixelTatio,
                    SelectData:selectData,   //区间选择的数据
                    RectSelectPaint:paint    //区间选择背景
                };
                event.Callback(event,data,this);
            }

            if (this.SelectRectDialog)
            {
                e.data=
                {
                    Chart:this,
                    X:corssCursor.LastPoint.X/pixelTatio,
                    Y:corssCursor.LastPoint.Y/pixelTatio,
                    SelectData:selectData,          //区间选择的数据
                    RectSelectPaint:paint           //区间选择背景
                };
                this.SelectRectDialog.DoModal(e);
            }
        }
        
        this.Draw();
    }

    //注册鼠标右键事件
    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.OnWheel=function(e)
    {
        JSConsole.Chart.Log('[MinuteChartContainer::OnWheel]',e);
    }

    this.OnDoubleClick=function(x,y,e)
    {
        JSConsole.Chart.Log("[MinuteChartContainer::OnDoubleClick]", e);

        if (this.ClickChartTimer!=null)
        {
            clearTimeout(this.ClickChartTimer);
            this.ClickChartTimer=null;
        }

        this.DBClickEvent(e);

        if (this.EnableZoomIndexWindow)
        {
            var frameId=this.Frame.PtInFrame(x,y);
            JSConsole.Chart.Log("[MinuteChartContainer::OnDoubleClick] frameId",frameId);
            if (frameId>=this.Frame.ZoomStartWindowIndex)
            {
                if (this.ZoomIndexWindow(frameId, {X:x, Y:y}))
                {
                    this.Frame.SetSizeChage(true);
                    this.Draw();
                }
            }
        }
    }

    this.DBClickEvent=function(e)
    {
        var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_DBCLICK);
        if (!event || !event.Callback) return false;

        var pixelTatio = GetDevicePixelRatio();
        var x=(e.clientX-uielement.getBoundingClientRect().left)*pixelTatio;
        var y=(e.clientY-uielement.getBoundingClientRect().top)*pixelTatio;
        var data= { X:e.clientX, Y:e.clientY, FrameID:-1 , ClientPos:-1 };

        var clientPos=this.PtInClient(x,y);
        data.ClientPos=clientPos;

        if (clientPos>0)
        {
            var yValueExtend={};
            var yValue=this.Frame.GetYData(y,yValueExtend);

            if (IFrameSplitOperator.IsNumber(yValueExtend.FrameID) && yValueExtend.FrameID>=0)
            {
                var xValue=this.Frame.GetXData(x);
                data.FrameID=yValueExtend.FrameID;
                data.Data={ X:xValue, Y:yValue } ;
            }
        }

        event.Callback(event, data, this);
        return true;
    }

    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,option)
    {
        this.UIElement.JSChartContainer=this;

        //创建十字光标
        this.ChartCorssCursor=new ChartCorssCursor();
        this.ChartCorssCursor.PtInClient=(x,y)=>{ return this.PtInClient(x,y); }
        this.ChartCorssCursor.Canvas=this.Canvas;
        this.ChartCorssCursor.StringFormatX=new HQMinuteTimeStringFormat();
        this.ChartCorssCursor.StringFormatY=new HQPriceStringFormat();
        this.ChartCorssCursor.StringFormatY.LanguageID=this.LanguageID;
        this.ChartCorssCursor.CallAcutionXOperator=new CallAcutionXOperator();

        //创建等待提示
        this.ChartSplashPaint = new ChartSplashPaint();
        this.ChartSplashPaint.Canvas = this.Canvas;
        this.ChartSplashPaint.HQChart=this;

        //创建框架容器
        this.Frame=new HQTradeFrame();
        this.Frame.ChartBorder=new ChartBorder();
        this.Frame.ChartBorder.UIElement=this.UIElement;
        this.Frame.ChartBorder.Top=25;
        this.Frame.ChartBorder.TitleHeight=0;
        this.Frame.ChartBorder.Left=50;
        this.Frame.ChartBorder.Bottom=20;
        this.Frame.Canvas=this.Canvas;
        this.Frame.GetExtendChartRightWidth=()=> { return this.GetExtendChartRightWidth() }
        this.Frame.ZoomStartWindowIndex=2;
        this.ChartCorssCursor.Frame=this.Frame; //十字光标绑定框架
        this.ChartSplashPaint.Frame = this.Frame;

        this.CreateChildWindow(windowCount);
        this.CreateMainKLine();
        this.CreateExtendChart("RectSelectPaint");  //区间统计

        //子窗口动态标题
        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;
            titlePaint.GetEventCallback=(id)=> { return this.GetEventCallback(id); }
            this.TitlePaint.push(titlePaint);
        }

        this.ChartCorssCursor.StringFormatX.Frame=this.Frame.SubFrame[0].Frame;
        this.ChartCorssCursor.StringFormatY.Frame=this.Frame;
        if (this.ChartCorssCursor.CallAcutionXOperator)
            this.ChartCorssCursor.CallAcutionXOperator.Frame=this.Frame.SubFrame[0].Frame;

        var bRegisterKeydown=true;
        var bRegisterWheel=true;

        if (option)
        {
            if (option.KeyDown===false) 
            {
                bRegisterKeydown=false;
                JSConsole.Chart.Log('[MinuteChartContainer::Create] not register keydown event.');
            }

            if (option.Wheel===false) 
            {
                bRegisterWheel=false;
                JSConsole.Chart.Log('[MinuteChartContainer::Create] not register wheel event.');
            }
        }

        if (bRegisterKeydown) this.UIElement.addEventListener("keydown", (e)=>{ this.OnKeyDown(e);} , true);              //键盘消息
        if (bRegisterWheel) 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 MinuteFrame();
            frame.Canvas=this.Canvas;
            frame.ChartBorder=border;
            frame.Identify=i;
            if (i<2) frame.ChartBorder.TitleHeight=0;
            frame.XPointCount=243;

            if (i>=2)
            {
                if (this.ModifyIndexDialog) frame.ModifyIndexEvent=this.ModifyIndexDialog.DoModal;        //绑定菜单事件
                if (this.ChangeIndexDialog) frame.ChangeIndexEvent=this.ChangeIndexDialog.DoModal;
            }

            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');
                frame.YSplitOperator.GetEventCallback=(id)=> { return this.GetEventCallback(id); }
            }
            else
            {
                frame.YSplitOperator=new FrameSplitY();
                frame.YSplitOperator.LanguageID=this.LanguageID;
                frame.YSplitOperator.FrameSplitData=this.FrameSplitData.get('double');
                frame.YSplitOperator.GetEventCallback=(id)=> { return this.GetEventCallback(id); }
            }

            frame.YSplitOperator.Frame=frame;
            frame.YSplitOperator.ChartBorder=border;
            frame.XSplitOperator=new FrameSplitMinuteX();
            frame.XSplitOperator.Frame=frame;
            frame.XSplitOperator.ChartBorder=border;
            frame.XSplitOperator.GetEventCallback=(id)=> { return this.GetEventCallback(id); }
            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;
        

        if (id>=2)
        {
            if (this.ModifyIndexDialog) frame.ModifyIndexEvent=this.ModifyIndexDialog.DoModal;        //绑定菜单事件
            if (this.ChangeIndexDialog) frame.ChangeIndexEvent=this.ChangeIndexDialog.DoModal;
        }

        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;
        frame.XSplitOperator.GetEventCallback=(id)=> { return this.GetEventCallback(id); }
        frame.YSplitOperator.GetEventCallback=(id)=> { return this.GetEventCallback(id); }
        frame.XSplitOperator.Symbol=this.Symbol;

        if (this.DayCount>1)
        {
            frame.XSplitOperator.DayCount=this.DayData.length;
            frame.XSplitOperator.DayData=this.DayData;
            frame.DayCount=this.DayData.length;
        }
        

        //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.UpdateXShowText=function()
    {
        var bLastFrame=true;
        for(var i=this.Frame.SubFrame.length-1;i>=0;--i)
        {
            var item=this.Frame.SubFrame[i].Frame;
            var subFrame=this.Frame.SubFrame[i];

            if (bLastFrame)
            {
                item.XSplitOperator.ShowText=true;
                if (subFrame.Height>0) bLastFrame=false;
            }
            else
            {
                item.XSplitOperator.ShowText=false;
            }
        }
    }

    //删除某一个窗口的指标
    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;
        minuteLine.GetEventCallback=(id)=>{ return this.GetEventCallback(id); };

        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.TitlePaint[0].CallAcutionXOperator=new CallAcutionXOperator();
        this.TitlePaint[0].CallAcutionXOperator.Frame=this.Frame.SubFrame[0].Frame;
    }

    //切换成 脚本指标
    this.ChangeScriptIndex=function(windowIndex,indexData,option)
    {
        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,
            OutName:indexInfo.OutName
        };

        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,option);
    }

    //设置指标窗口个数
    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;
                titlePaint.GetEventCallback=(id)=> { return this.GetEventCallback(id); }
                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.UpdateXShowText();
        this.Frame.SetSizeChage(true);
        this.ResetFrameXYSplit();
        this.UpdateFrameMaxMin();          //调整坐标最大 最小值
        this.Draw();
    }

    this.RemoveIndexWindow=function(id)
    {
        JSConsole.Chart.Log('[MinuteChartContainer::RemoveIndexWindow] remove id', id);
        if (id<2) 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.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, DayCount:this.DayCount }, Explain: explain };
        if (bStart) 
        {
            data.Callback=function(data) //数据到达更新回调
            { 
                self.RecvMinuteData(data); 
            }
        }
        event.Callback(event,data,this);
    }

    //切换股票代码
    this.ChangeSymbol=function(symbol)
    {
        this.CancelAutoUpdate();
        this.AutoUpdateEvent(false, "MinuteChartContainer::ChangeSymbol");
        this.Symbol=symbol;
        this.ResetOverlaySymbolStatus();
        this.ReloadChartDrawPicture();

        if (symbol) 
        {
            this.ChartSplashPaint.SetTitle(this.LoadDataSplashTitle);
            this.ChartSplashPaint.EnableSplash(true);    //增加下载动画
            this.Draw();
            this.RequestData();
        }
        else
        {
            this.DrawEmpty();
        }
    }

    this.ChangeDayCount=function(count)
    {
        if (count<0 || count>10) return;

        this.CancelAutoUpdate();
        this.AutoUpdateEvent(false, "MinuteChartContainer::ChangeDayCount");
        this.DayCount=count;
        
        if (this.DayCount>1)
        {
            this.ChartDrawPicture=[];
        }
        else
        {
            this.ReloadChartDrawPicture();
        }

        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, option)
    {
        this.ShowCallAuctionData({Left:isShow}, option);
    }

    //集合竞价设置 obj={ Left:, Right: }
    this.ShowCallAuctionData=function(obj, option)
    {
        if (!obj) return;

        var optionChanged=false;    //配置修改
        if (IFrameSplitOperator.IsBool(obj.Left) && this.IsShowBeforeData!=obj.Left) 
        {
            this.IsShowBeforeData=obj.Left;
            optionChanged=true;
        }

        if (IFrameSplitOperator.IsBool(obj.Right) && this.IsShowAfterData!=obj.Right) 
        {
            this.IsShowAfterData=obj.Right;
            optionChanged=true;
        }

        if (obj.MultiDay)
        {
            var item=obj.MultiDay;
            if (IFrameSplitOperator.IsBool(item.Left) && this.IsShowMultiDayBeforeData!=item.Left)
            {
                this.IsShowMultiDayBeforeData=item.Left;
                optionChanged=true;
            }

            if (IFrameSplitOperator.IsBool(item.Right) && this.IsShowMultiDayAfterData!=item.Right) 
            {
                this.IsShowMultiDayAfterData=item.Right;
                optionChanged=true;
            }
        }

        if (option)
        {
            if (option.BeforeOpen)
            {
                var item=option.BeforeOpen;
                if (IFrameSplitOperator.IsNumber(item.Left) && this.ExtendWidth.Left!=item.Left)
                {
                    this.ExtendWidth.Left=item.Left;
                    optionChanged=true;
                }
            }

            if (option.AfterClose)
            {
                var item=option.AfterClose;
                if (IFrameSplitOperator.IsNumber(item.Right) && this.ExtendWidth.Right!=item.Right)
                {
                    this.ExtendWidth.Right=item.Right;
                    optionChanged=true;
                }
            }

            if (option.MultiDay)
            {
                var item=option.MultiDay;
                if (IFrameSplitOperator.IsNumber(item.Left) && this.MultiDayExtendWidth.Left!=item.Left)
                {
                    this.MultiDayExtendWidth.Left=item.Left;
                    optionChanged=true;
                }

                if (IFrameSplitOperator.IsNumber(item.Right)&& this.MultiDayExtendWidth.Right!=item.Right)
                {
                    this.MultiDayExtendWidth.Right=item.Right;
                    optionChanged=true;
                }
            }
        }

        if (optionChanged) 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.IsAfterData=false;
        this.ChartSplashPaint.SetTitle(this.LoadDataSplashTitle);
        this.ChartSplashPaint.EnableSplash(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.EnableSplash(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.EnableSplash(false);
                self.RecvHistoryMinuteData(data);
            }
        });
    }

    this.RecvHistoryMinuteData=function(data)
    {
        this.DayData=MinuteChartContainer.JsonDataToMinuteDataArray(data);
        this.ColorLineData=MinuteChartContainer.JsonDataToHistoryMinuteLineColorData(data);
        this.MultiDayBeforeOpenData=MinuteChartContainer.JosnDataToBeforeOpenDataArray(data);
        this.MultiDayAfterCloseData=MinuteChartContainer.JosnDataToAfterCloseDataArray(data);
        var updateTime=MinuteChartContainer.JsonDataToHistoryMinuteLastUpdateTime(data);
        this.CaclutateCallCationYRange();
        this.Symbol=data.symbol;
        this.Name=data.name;
        this.SetCallCationDataBorder( 
        { 
            Left:false, Right:false, 
            MultiDay:{ Left:this.IsShowMultiDayBeforeData, Right:this.IsShowMultiDayAfterData } 
        } );
        this.CaclutateLimitPrice(this.DayData[0].YClose, data.data[0].limitprice); //计算涨停价格
        this.UpdateHistoryMinuteUI(updateTime);
        this.RecvMinuteDataEvent();
        this.RequestOverlayHistoryMinuteData();

        this.BindAllOverlayIndexData(this.SourceData);

        this.AutoUpdateEvent(true, "MinuteChartContainer::RequestHistoryMinuteData");
        this.AutoUpdate();
    }

    this.CaclutateCallCationYRange=function()
    {
        //多日集合竞价Y轴统一成交量
        if (IFrameSplitOperator.IsNonEmptyArray(this.MultiDayAfterCloseData))
        {
            var range={ Max:null, Min:null };
            for(var i in this.MultiDayAfterCloseData)
            {
                var item=this.MultiDayAfterCloseData[i];
                if (range.Max==null) range.Max=item.VolMax;
                else if (range.Max<item.VolMax) range.Max=item.VolMax;

                if (range.Min==null) range.Min=item.VolMin;
                else if (range.Min>item.VolMin) range.Min=item.VolMin;
            }

            for(var i in this.MultiDayAfterCloseData)
            {
                var item=this.MultiDayAfterCloseData[i];
                item.VolMax=range.Max;
                item.VolMin=range.Min;
            }
        }

        if (IFrameSplitOperator.IsNonEmptyArray(this.MultiDayBeforeOpenData))
        {
            var range={ Max:null, Min:null };
            for(var i in this.MultiDayBeforeOpenData)
            {
                var item=this.MultiDayBeforeOpenData[i];
                if (range.Max==null) range.Max=item.VolMax;
                else if (range.Max<item.VolMax) range.Max=item.VolMax;

                if (range.Min==null) range.Min=item.VolMin;
                else if (range.Min>item.VolMin) range.Min=item.VolMin;
            }

            for(var i in this.MultiDayBeforeOpenData)
            {
                var item=this.MultiDayBeforeOpenData[i];
                item.VolMax=range.Max;
                item.VolMin=range.Min;
            }
        }
    }

    this.UpdateHistoryMinuteUI=function(updateTime)
    {
        var allMinuteData=this.HistoryMinuteDataToArray(this.DayData);

        //原始数据
        var sourceData=new ChartData();
        sourceData.Data=allMinuteData;
        sourceData.UpdateTime=updateTime;

        this.SourceData=sourceData;
        this.TradeDate=this.DayData[0].Date;
        this.Frame.SetDayCount(this.DayData.length);
        var upperSymbol=this.Symbol.toUpperCase();

        var yClose=this.DayData[0].YClose;
        var isFutures=MARKET_SUFFIX_NAME.IsFutures(upperSymbol);
        if (IFrameSplitOperator.IsNumber(this.DayData[0].YClearing) && isFutures) yClose=this.DayData[0].YClearing; //期货使用前结算价
        this.BindMainData(sourceData,yClose);
        
         //外汇 均线暂时不用
        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.XSplitOperator.IsAfterData=this.IsAfterData;
            item.Frame.YSplitOperator.Symbol=this.Symbol;
            item.Frame.YSplitOperator.IsBeforeData=this.IsBeforeData;
            item.Frame.YSplitOperator.IsAfterData=this.IsAfterData;

            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.ChartCorssCursor.StringFormatX.IsAfterData=this.IsAfterData;
        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.IsFutures(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');
        }

        this.IsAfterData=false;
        if (this.IsShowAfterData && this.DayCount===1 && MARKET_SUFFIX_NAME.IsSHSZStockA(self.Symbol))
        {
            this.IsAfterData=true;
        }

        if (this.NetworkFilter)
        {
            var callCation=
            { 
                Before:(this.IsShowBeforeData && this.DayCount===1), 
                After:(this.IsShowAfterData && this.DayCount===1)
            }   //集合竞价
            var obj=
            {
                Name:'MinuteChartContainer::RequestMinuteData', //类名::函数名
                Explain:'最新分时数据',
                Request:{ Url:self.MinuteApiUrl, Data:{field:fields, symbol:[self.Symbol], callcation:callCation }, Type:'POST' }, 
                Self:this,
                PreventDefault:false
            };
            this.NetworkFilter(obj, function(data) 
            { 
                self.ChartSplashPaint.EnableSplash(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.EnableSplash(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.UpdateLineColorData=function(data, date)
    {
        if (!this.ColorLineData) 
        {
            this.ColorLineData=data;
            return;
        }


        //移除当前的
        var aryColorLineData=this.ColorLineData.filter(function(item, index, arr)
        {
            return item.Date!=date;
        });

        if (IFrameSplitOperator.IsNonEmptyArray(data))
        {
            for(var i in data)
            {
                aryColorLineData.push(data[i]);
            }
        }


        this.ColorLineData=aryColorLineData;
    }

    this.UpdateCallCationData=function(beforeOpenData,afterCloseData)
    {
        if (beforeOpenData && IFrameSplitOperator.IsNonEmptyArray(this.MultiDayBeforeOpenData))
        {
            var lastItem=this.MultiDayBeforeOpenData[this.MultiDayBeforeOpenData.length-1];
            if (lastItem.Date==beforeOpenData.Date)
                this.MultiDayBeforeOpenData[this.MultiDayBeforeOpenData.length-1]=beforeOpenData;
        }

        if (afterCloseData && IFrameSplitOperator.IsNonEmptyArray(this.MultiDayAfterCloseData))
        {
            var lastItem=this.MultiDayAfterCloseData[this.MultiDayBeforeOpenData.length-1];
            if (lastItem.Date==afterCloseData.Date)
                this.MultiDayAfterCloseData[this.MultiDayAfterCloseData.length-1]=afterCloseData;
        }

        this.CaclutateCallCationYRange();
    }

    this.RecvMinuteData=function(data)
    {
        if (!data) 
        {
            JSConsole.Chart.Warn("[MinuteChartContainer::RecvMinuteData] recv data is null");
            return;
        }

        var aryMinuteData=MinuteChartContainer.JsonDataToMinuteData(data);
        var aryColorData=MinuteChartContainer.JsonDataToMinuteLineColorData(data);
        this.BeforeOpenData=null;
        this.AfterCloseData=null;
        var beforeOpenData=MinuteChartContainer.JsonDataToBeforeOpenData(data);
        var afterCloseData=MinuteChartContainer.JsonDataToAfterCloseData(data);
        var updateTime=MinuteChartContainer.JsonDataToMinuteLastUpdateTime(data);   //数据最后的更新时间

        if (this.IsBeforeData) this.BeforeOpenData=beforeOpenData;
        if (this.IsAfterData) this.AfterCloseData=afterCloseData;
            
        if (this.DayCount>1)    //多日走势图
        {
            this.UpdateCallCationData(beforeOpenData,afterCloseData);
            this.UpdateLineColorData(aryColorData,data.stock[0].date);
            this.UpdateLatestMinuteData(aryMinuteData,data.stock[0].date);
            this.UpdateHistoryMinuteUI(updateTime);
            this.RecvMinuteDataEvent();
            this.RequestOverlayMinuteData();    //请求叠加数据 (主数据下载完再下载)
            this.BindAllOverlayIndexData(this.SourceData);
            this.AutoUpdateEvent(true, "MinuteChartContainer::RecvMinuteData");
            this.AutoUpdate();
            return;
        }

        //原始数据
        var sourceData=new ChartData();
        sourceData.Data=aryMinuteData;
        sourceData.UpdateTime=updateTime;

        this.ColorLineData=aryColorData;

        this.TradeDate=data.stock[0].date;
        this.Frame.SetDayCount(1);  //单日数据

        this.SourceData=sourceData;
        this.Symbol=data.stock[0].symbol;
        this.Name=data.stock[0].name;

        this.SetCallCationDataBorder( { Left:this.IsBeforeData, Right:this.IsAfterData , MultiDay:{ Left:false, Right:false }} );

        var yClose=data.stock[0].yclose;
        var upperSymbol=this.Symbol.toUpperCase();
        var isFutures=MARKET_SUFFIX_NAME.IsFutures(upperSymbol);
        if (data.stock[0].yclearing>0 && isFutures) yClose=data.stock[0].yclearing; //期货使用前结算价
        this.CaclutateLimitPrice(yClose, data.stock[0].limitprice); //计算涨停价格
        var extendData=null;
        if (data.stock[0].high>0 && data.stock[0].low>0) 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.YSplitOperator.Symbol=this.Symbol;

            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;

        if (MARKET_SUFFIX_NAME.IsSHSZ(upperSymbol)) this.TitlePaint[0].IsShowDate=false;

        if (data.stock[0].IsHistoryMinute==true) this.TitlePaint[0].IsShowDate=true;

        var chartInfo=this.GetChartMinuteInfo();
        if (chartInfo) chartInfo.SourceData=this.SourceData;    //数据绑定到信息地雷上

        this.RecvMinuteDataEvent();
        this.RequestMinuteInfoData();
        this.RequestOverlayMinuteData();//请求叠加数据 (主数据下载完再下载)
        this.CreateChartDrawPictureByStorage(); //创建画图工具

        this.UpdateFrameMaxMin();          //调整坐标最大 最小值
        this.Frame.SetSizeChage(true);
        this.Draw();

        this.BindAllOverlayIndexData(this.SourceData);
        
        this.AutoUpdateEvent(true, "MinuteChartContainer::RecvMinuteData");
        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 multiBeforeOpenData=this.IsShowMultiDayBeforeData?this.MultiDayBeforeOpenData:null;
        var multiAfterCloseData=this.IsShowMultiDayAfterData?this.MultiDayAfterCloseData:null;

        //分钟数据
        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].IsShowLead=false;
        this.ChartPaint[0].LeadData=null;
        this.ChartPaint[0].BeforeOpenData=this.BeforeOpenData;
        this.ChartPaint[0].AfterCloseData=this.AfterCloseData;
        this.ChartPaint[0].MultiDayBeforeOpenData=multiBeforeOpenData;
        this.ChartPaint[0].MultiDayAfterCloseData=multiAfterCloseData;
        this.ChartPaint[0].ColorLineData=this.ColorLineData;    //自定义分段颜色
        this.ChartPaint[0].Source=minuteData;

        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;
        }

        var firstFrame=this.Frame.SubFrame[0].Frame;
       
        firstFrame.YSplitOperator.YClose=yClose;
        firstFrame.YSplitOperator.Data=bindData;
        this.Frame.Data=this.ChartPaint[0].Data;
        this.Frame.SourceData=minuteData;

        for(var i in this.Frame.SubFrame)
        {
            var item=this.Frame.SubFrame[i].Frame;
            item.Data=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;
        else if (MARKET_SUFFIX_NAME.IsShowAvPrice && !MARKET_SUFFIX_NAME.IsShowAvPrice(upperSymbol))    //外部控制是否显示均线
            this.ChartPaint[1].Data=null;

        firstFrame.YSplitOperator.AverageData=bindData;
        firstFrame.YSplitOperator.OverlayChartPaint=this.OverlayChartPaint;
        firstFrame.YSplitOperator.LimitPrice=this.LimitPrice;
        firstFrame.YSplitOperator.MultiDayBeforeOpenData=multiBeforeOpenData;
        firstFrame.YSplitOperator.MultiDayAfterCloseData=multiAfterCloseData;
        if (extendData)
        {
            firstFrame.YSplitOperator.High=extendData.High;
            firstFrame.YSplitOperator.Low=extendData.Low;
        }
        else
        {
            firstFrame.YSplitOperator.High=null;
            firstFrame.YSplitOperator.Low=null;
        }

        //成交量
        this.ChartPaint[2].Data=minuteData;
        this.ChartPaint[2].YClose=yClose;
        this.ChartPaint[2].Symbol=this.Symbol;
        this.ChartPaint[2].BeforeOpenData=this.BeforeOpenData;
        this.ChartPaint[2].AfterCloseData=this.AfterCloseData;
        this.ChartPaint[2].MultiDayBeforeOpenData=multiBeforeOpenData;
        this.ChartPaint[2].MultiDayAfterCloseData=multiAfterCloseData;

        for(var i in this.Frame.SubFrame)
        {
            var item=this.Frame.SubFrame[i];

            item.Frame.YSplitOperator.BeforeOpenData=this.BeforeOpenData;
            item.Frame.YSplitOperator.IsBeforeData=this.IsBeforeData;
            item.Frame.YSplitOperator.AfterCloseData=this.AfterCloseData;
            item.Frame.YSplitOperator.IsAfterData=this.IsAfterData;
            item.Frame.YSplitOperator.MultiDayBeforeOpenData=multiBeforeOpenData;
            item.Frame.YSplitOperator.MultiDayAfterCloseData=multiAfterCloseData;
        }

        if(MARKET_SUFFIX_NAME.IsShowMinutePostionLine(upperSymbol))  
            this.BindOverlayPositionData(minuteData,yClose);    //期货,期权 持仓量
        else 
            this.ClearBindOverlayPositionData();

        this.TitlePaint[0].Data=this.SourceData;                    //动态标题
        this.TitlePaint[0].Symbol=this.Symbol;
        this.TitlePaint[0].Name=this.Name;
        this.TitlePaint[0].YClose=yClose;
        this.TitlePaint[0].BeforeOpenData=this.BeforeOpenData;
        this.TitlePaint[0].AfterCloseData=this.AfterCloseData;
        this.TitlePaint[0].MultiDayBeforeOpenData=this.IsShowMultiDayBeforeData?this.MultiDayBeforeOpenData:null;
        this.TitlePaint[0].MultiDayAfterCloseData=this.IsShowMultiDayAfterData?this.MultiDayAfterCloseData:null;
        if (this.TitlePaint[0].CallAcutionXOperator)
        {
            this.TitlePaint[0].CallAcutionXOperator.BeforeOpenData=this.BeforeOpenData;
            this.TitlePaint[0].CallAcutionXOperator.AfterCloseData=this.AfterCloseData;
            this.TitlePaint[0].CallAcutionXOperator.MultiDayBeforeOpenData=multiBeforeOpenData;
            this.TitlePaint[0].CallAcutionXOperator.MultiDayAfterCloseData=multiAfterCloseData;
        }

        if (this.ChartCorssCursor && this.ChartCorssCursor.StringFormatY)
        {
            this.ChartCorssCursor.StringFormatY.YClose=yClose;
            this.ChartCorssCursor.StringFormatY.BeforeOpenData=this.BeforeOpenData;
            this.ChartCorssCursor.StringFormatY.AfterCloseData=this.AfterCloseData;
            this.ChartCorssCursor.StringFormatY.MultiDayBeforeOpenData=multiBeforeOpenData;
            this.ChartCorssCursor.StringFormatY.MultiDayAfterCloseData=multiAfterCloseData;

            this.ChartCorssCursor.StringFormatX.Data=this.ChartPaint[0].Data;       //十字光标
            this.ChartCorssCursor.StringFormatX.BeforeOpenData=this.BeforeOpenData;
            this.ChartCorssCursor.StringFormatX.AfterCloseData=this.AfterCloseData;

            this.ChartCorssCursor.StringFormatX.MultiDayBeforeOpenData=multiBeforeOpenData;
            this.ChartCorssCursor.StringFormatX.MultiDayAfterCloseData=multiAfterCloseData;

            if (this.ChartCorssCursor.CallAcutionXOperator)
            {
                this.ChartCorssCursor.CallAcutionXOperator.BeforeOpenData=this.BeforeOpenData;
                this.ChartCorssCursor.CallAcutionXOperator.AfterCloseData=this.AfterCloseData;
                this.ChartCorssCursor.CallAcutionXOperator.MultiDayBeforeOpenData=multiBeforeOpenData;
                this.ChartCorssCursor.CallAcutionXOperator.MultiDayAfterCloseData=multiAfterCloseData;
            }
        }
           
        if (this.ExtendChartPaint[0])
        {
            this.ExtendChartPaint[0].Symbol=this.Symbol;
            this.ExtendChartPaint[0].Name=this.Name;
        }

        for(var i in this.OverlayChartPaint)
        {
            var item=this.OverlayChartPaint[i];
            item.MainData=this.ChartPaint[0].Data;         //叠加股票
            item.MainYClose=yClose;
        }
    }

    //绑定分钟叠加指标数据(持仓量)
    this.BindOverlayPositionData=function(minuteData,yClose)
    {
        if (this.Frame.SubFrame.length<2) return;

        var chart=null;
        var frame=null;
        var subFrame=this.Frame.SubFrame[1];    //第2个窗口
        var overlayFrame=null;
        for(var i in subFrame.OverlayIndex)
        {
            var item=subFrame.OverlayIndex[i];
            if (item.Identify=='Position_Line_Frame')
            {
                overlayFrame=item;
                break;
            }
        }

        if (!overlayFrame)
        {
            overlayFrame=new OverlayIndexItem();
            overlayFrame.Identify='Position_Line_Frame';

            if (this.ClassName=="MinuteChartContainer") frame=new OverlayMinuteFrame();
            else frame=new OverlayMinuteHScreenFrame();

            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=overlayFrame.ChartPaint[0];
            frame=overlayFrame.Frame;
        }

        var xPointCouont=this.Frame.SubFrame[0].Frame.XPointCount;
        frame.XPointCount=xPointCouont;
        subFrame.Frame.IsShowPositionTitle=true;

        var bindData=new ChartData();
        bindData.Data=minuteData.GetPosition();
        chart.Data=bindData;
    }

    this.ClearBindOverlayPositionData=function()
    {
        if (this.Frame.SubFrame.length<2) return;
        var subFrame=this.Frame.SubFrame[1];        //第2个窗口
        subFrame.Frame.RightFrame=null;
        subFrame.Frame.IsShowPositionTitle=false;
        for(var i in subFrame.OverlayIndex)
        {
            var item=subFrame.OverlayIndex[i];
            if (item.Identify=='Position_Line_Frame')
            {
                subFrame.OverlayIndex.splice(i,1);
                break;
            }
        }
    }

    //添加叠加指标
    this.AddOverlayIndex=function(obj) 
    {
        var overlay=this.CreateOverlayWindowsIndex(obj);
        if (!overlay) return;

        var bindData=this.SourceData;
        this.BindOverlayIndexData(overlay,obj.WindowIndex,bindData);
        this.UpdataDataoffset();           //更新数据偏移
        this.UpdateFrameMaxMin();          //调整坐标最大 最小值
        this.Draw();
    }

    //创建一个叠加指标
    this.CreateOverlayWindowsIndex=function(obj) //{WindowIndex:, IndexName:, Identify:, ShowRightText:, API:}
    {
        let indexName=obj.IndexName;
        let windowIndex=obj.WindowIndex;
        var apiItem=null, indexInfo=null, indexCustom=null;
        if (obj.API)
        {
            apiItem=obj.API;
        }
        else if (obj.Script)    //动态执行脚本
        {
            indexInfo={ Script:obj.Script, ID:obj.indexName, Name:obj.indexName};
            if (obj.Name) indexInfo.Name=obj.Name;
        }
        else
        {
            let scriptData = new JSIndexScript();
            indexInfo = scriptData.Get(indexName);  //系统指标
            if (!indexInfo) 
            {
                indexCustom=JSIndexMap.Get(indexName);  //定制指标
                if (!indexCustom)
                {
                    console.warn(`[MinuteChartContainer::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=null;
        if (this.ClassName=="MinuteChartContainer") frame=new OverlayMinuteFrame();
        else frame=new OverlayMinuteHScreenFrame();
        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;
        if (obj.IsShareY===true) frame.IsShareY=true;
        if (IFrameSplitOperator.IsBool(obj.IsCalculateYMaxMin)) frame.IsCalculateYMaxMin=obj.IsCalculateYMaxMin;   //是否计算Y最大最小值

        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 (apiItem)
        {
            var apiIndex=new APIScriptIndex(apiItem.Name,apiItem.Script,apiItem.Args,obj, true);
            apiIndex.OverlayIndex={ IsOverlay:true, Identify:overlayFrame.Identify, WindowIndex:windowIndex, Frame:overlayFrame };    //叠加指标信息
            overlayFrame.Script=apiIndex;
        }
        else if (indexInfo)
        {
            let indexData = indexInfo;
            if (obj.Args) indexData.Args=obj.Args;  //外部可以设置参数

            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) //删除叠加指标
    {
        if (!this.DeleteOverlayIndex(identify, null)) return;

        this.Frame.ResetXYSplit(true);
        this.Draw();
    }

    //计算叠加指标
    this.BindAllOverlayIndexData=function(hisData)
    {
        if (!this.Frame || !this.Frame.SubFrame) return;

        //叠加指标
        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,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);
    }

    //获取子窗口的所有画法
    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':
                if (option.Create && typeof(option.Create)=='function') chart=option.Create();
                else 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;
            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;
            default:
                chart=g_ExtendChartPaintFactory.Create(name);
                if (!chart) return null;

                chart.Canvas=this.Canvas;
                chart.ChartBorder=this.Frame.ChartBorder;
                chart.ChartFrame=this.Frame;
                chart.HQChart=this;
                chart.SetOption(option);
                this.ExtendChartPaint.push(chart);
                return chart;
        }
    }

    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;
    }

    this.UpdateWindowIndex=function(index)
    {
        if (index<2) return;

        var bindData=this.SourceData;
        this.BindIndexData(index,bindData)
        this.UpdataDataoffset();           //更新数据偏移
        this.UpdateFrameMaxMin();          //调整坐标最大 最小值
        this.Draw();
    }

    this.CreateChartDrawPicture=function(name, option, callback)
    {
        var drawPicture=null;
        var item=IChartDrawPicture.GetDrawPictureByName(name);
        if (item)
        {
            drawPicture=item.Create();
            if (drawPicture.ClassName=='ChartDrawPictureText') drawPicture.HQChart=this;
        }

        if (!drawPicture)    //iconfont图标
        {
            if (IChartDrawPicture.MapIonFont.has(name))
            {
                var iconItem=IChartDrawPicture.MapIonFont.get(name);
                drawPicture=new ChartDrawPictureIconFont();
                drawPicture.FontOption.Family=iconItem.Family
                drawPicture.Text=iconItem.Text;
                if (iconItem.Color) drawPicture.LineColor=iconItem.Color;
            }
        }

        if (!drawPicture) return false;

        drawPicture.Canvas=this.Canvas;
        drawPicture.Status=0;
        drawPicture.Symbol=this.Symbol;
        drawPicture.Period=888888888;
        drawPicture.Option=this.ChartDrawOption;
        
        if (callback) drawPicture.FinishedCallback=callback;    //完成通知上层回调
        if (option) drawPicture.SetOption(option);
        var self=this;
        drawPicture.Update=function()   //更新回调函数
        {
            self.DrawDynamicInfo();
        };
        drawPicture.GetActiveDrawPicture=function() { return self.GetActiveDrawPicture(); }
        this.CurrentChartDrawPicture=drawPicture;
        JSConsole.Chart.Log("[MinuteChartContainer::CreateChartDrawPicture] ", name,this.CurrentChartDrawPicture);
        return true;
    }

    this.ReloadChartDrawPicture=function()
    {
        this.ChartDrawPicture=[];
        this.ChartDrawStorageCache;
        if (this.ChartDrawStorage)
        {
            this.ChartDrawStorageCache=this.ChartDrawStorage.GetDrawData( { Symbol:this.Symbol, Period:888888888 } );
        }
    }

    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.CreateChartDrawPicture(item);
            if (!drawPicture) continue;

            drawPicture.Canvas=this.Canvas;
            drawPicture.Status=10;
            drawPicture.Frame=this.Frame.SubFrame[item.FrameID].Frame;  //绑定框架坐标
            drawPicture.UpdateXValue();
            drawPicture.ValueToPoint();

            if (drawPicture.ClassName==='ChartDrawPictureText') drawPicture.IsInitialized=true;

            this.ChartDrawPicture.push(drawPicture);
        }

        this.ChartDrawStorageCache=null;    //清空缓存
    }

    this.SetSizeChange=function(bChanged)
    {
        this.Frame.SetSizeChage(bChanged);
        for(var i in this.ExtendChartPaint)
        {
            var item=this.ExtendChartPaint[i];
            item.SizeChange=bChanged;
        }
    }
    this.SetSizeChage=this.SetSizeChange;

    //根据X坐标获取数据索引
    this.GetDataIndexByPoint=function(x)
    {
        var frame=this.Frame;
        if (this.Frame.SubFrame && this.Frame.SubFrame.length>0) frame=this.Frame.SubFrame[0].Frame;
        if (!frame) return;

        var value=frame.GetXData(x);
        var index=parseInt(value.toFixed(0));

        return index;
    }

    //获取主数据
    this.GetSelectRectData=function(selectData)
    {
        if (Math.abs(selectData.XStart-selectData.XEnd)<5) return false;

        var startClientPos=this.PtInClient(selectData.XStart, selectData.YStart);
        var endClientPos=this.PtInClient(selectData.XEnd, selectData.YEnd);

        selectData.StartClientPos=startClientPos;
        selectData.EndClientPos=endClientPos;
        
        var data=this.SourceData;
        if (!data) return false;
        if (!IFrameSplitOperator.IsNonEmptyArray(data.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;
        }

        var count=data.Data.length;
        if (selectData.End>=count) selectData.End=count-1;

        return true;
    }

    this.Super_UpdateFrameMaxMin=this.UpdateFrameMaxMin;
    this.UpdateFrameMaxMin=function()
    {
        this.Super_UpdateFrameMaxMin();

        if (this.DayCount==1)   //集合竞价多坐标,Y轴强制都计算
        {
            var subFrame=this.Frame.SubFrame[1];
            if (subFrame.Frame) subFrame.Frame.XYSplit=true;
        }
    }
}

//盘前数据
MinuteChartContainer.JsonDataToBeforeOpenData=function(data)
{
    var preClose=data.stock[0].yclose;      //前一个数据价格
    var stockData=data.stock[0];
    var date=stockData.date;                //日期
    var beforeOpenData={ Data:[], TotalCount:15, Ver:1.0, Date:date };
    if (stockData.beforeinfo)
    {
        if (IFrameSplitOperator.IsNumber(stockData.beforeinfo.totalcount)) beforeOpenData.TotalCount=stockData.beforeinfo.totalcount;
        if (IFrameSplitOperator.IsNumber(stockData.beforeinfo.ver)) beforeOpenData.Ver=stockData.beforeinfo.ver;
    }
    if (beforeOpenData.Ver==1.0)
    {
        for(var i in stockData.before)
        {
            var item=new BeforeOpenData();
            var jsData=stockData.before[i];
            item.Time=jsData[0];
            item.Date=date;
            item.Price=jsData[1];
            if (!item.Price) item.Price=preClose;
            else preClose=item.Price;
            item.Vol[0]=jsData[2]/100;  //沪深股票原始单位股
            item.Amount=jsData[3];
            item.DateTime=date.toString()+" "+item.Time.toString();
    
            beforeOpenData.Data.push(item);
        }
    }
    else if (beforeOpenData.Ver==2.0)
    {
        var max=0;
        for(var i in stockData.before)
        {
            var item=new BeforeOpenData();
            var jsData=stockData.before[i];
            item.Time=jsData[0];
            item.Date=date;
            item.Price=jsData[1];
            item.Vol[0]=jsData[2];  //匹配量
            item.Vol[1]=jsData[3];  //未匹配量
            item.ColorID=jsData[4]; //柱子颜色ID
            item.DateTime=date.toString()+" "+item.Time.toString();

            var totalVol=item.Vol[0]+item.Vol[1];
            if (IFrameSplitOperator.IsNumber(jsData[5])) totalVol=jsData[5];
            if (totalVol>max) max=totalVol;
    
            beforeOpenData.Data.push(item);
        }

        beforeOpenData.VolMax=max;
        beforeOpenData.VolMin=0;
    }
    else if (beforeOpenData.Ver==3.0)
    {
        var max=0;
        for(var i in stockData.before)
        {
            var item=new BeforeOpenData();
            var jsData=stockData.before[i];
            item.Time=jsData[0];
            item.Date=date;
            item.Price=jsData[1];
            item.AvPrice=jsData[2]; //均价
            item.Vol[0]=jsData[3];  //匹配量
            item.ColorID=jsData[4]; //柱子颜色ID
            item.DateTime=date.toString()+" "+item.Time.toString();

            var totalVol=item.Vol[0];
            if (IFrameSplitOperator.IsNumber(jsData[5])) totalVol=jsData[5];
            if (totalVol>max) max=totalVol;
    
            beforeOpenData.Data.push(item);
        }

        beforeOpenData.VolMax=max;
        beforeOpenData.VolMin=0;
    }
    
    return beforeOpenData;
}

//收盘集合竞价
MinuteChartContainer.JsonDataToAfterCloseData=function(data)
{
    var preClose=data.stock[0].yclose;      //前一个数据价格
    var stockData=data.stock[0];
    var date=stockData.date;                //日期
    if (!stockData.afterinfo) return null;

    var afterCloseData={ Data:[], TotalCount:3*60, Ver:2.0, Date:date };
    var item=stockData.afterinfo;
    if (IFrameSplitOperator.IsNumber(item.totalcount)) afterCloseData.TotalCount=item.totalcount;
    if (IFrameSplitOperator.IsNumber(item.ver)) afterCloseData.Ver=item.ver;
    
    if (afterCloseData.Ver==2.0)
    {
        var max=0;
        for(var i in stockData.after)
        {
            var item=new AfterCloseData();
            var jsData=stockData.after[i];
            item.Time=jsData[0];
            item.Date=date;
            item.Price=jsData[1];
            item.Vol[0]=jsData[2];  //匹配量
            item.Vol[1]=jsData[3];  //未匹配量
            item.ColorID=jsData[4]; //柱子颜色ID
            item.DateTime=date.toString()+" "+item.Time.toString();

            var totalVol=item.Vol[0]+item.Vol[1];
            if (IFrameSplitOperator.IsNumber(jsData[5])) totalVol=jsData[5];
            if (totalVol>max) max=totalVol;
    
            afterCloseData.Data.push(item);
        }

        afterCloseData.VolMax=max;
        afterCloseData.VolMin=0;
    }
    else if (afterCloseData.Ver==3.0)
    {
        var max=0;
        for(var i in stockData.after)
        {
            var item=new AfterCloseData();
            var jsData=stockData.after[i];
            item.Time=jsData[0];
            item.Date=date;
            item.Price=jsData[1];
            item.AvPrice=jsData[2]; //均价
            item.Vol[0]=jsData[3];  //匹配量
            item.ColorID=jsData[4]; //柱子颜色ID
            item.DateTime=date.toString()+" "+item.Time.toString();

            var totalVol=item.Vol[0];
            if (IFrameSplitOperator.IsNumber(jsData[5])) totalVol=jsData[5];
            if (totalVol>max) max=totalVol;
    
            afterCloseData.Data.push(item);
        }

        afterCloseData.VolMax=max;
        afterCloseData.VolMin=0;
    }
    
    return afterCloseData;
}

//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.IsFutures(upperSymbol);    //国内期货, 纽约期货交易所
    var isSHO=MARKET_SUFFIX_NAME.IsSHO(upperSymbol);            //上海股票期权
    var isSZO=MARKET_SUFFIX_NAME.IsSZO(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 || isSHO || isSZO) item.Position=jsData.position;  //期货 期权有持仓
        if (8<jsData.length && jsData[8]>0) 
        {
            item.Date=jsData[8];    //日期
            item.DateTime=item.Date.toString()+" "+jsData[0].toString();
        }
        
        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;
}

MinuteChartContainer.JsonDataToMinuteLineColorData=function(data)
{
    if (!data || !data.stock[0]) return null;
    var stockItem=data.stock[0];
    if (!stockItem.linecolor || !IFrameSplitOperator.IsNonEmptyArray(stockItem.linecolor.data)) return null;

    var aryLineColor=[];
    for(var i in stockItem.linecolor.data)
    {
        var item=stockItem.linecolor.data[i];
        if (!IFrameSplitOperator.IsNumber(item.type) || !IFrameSplitOperator.IsNumber(item.date) || !IFrameSplitOperator.IsNumber(item.start) ||
            !IFrameSplitOperator.IsNumber(item.end) || !item.color) continue;
        
        if (item.start>=item.end) continue;

        var newItem={ Type:item.type, Date:item.date, Start:item.start, End:item.end, Color:item.color };
        if (IFrameSplitOperator.IsPlusNumber(item.linewidth)) newItem.LineWidth=item.linewidth;

        aryLineColor.push(newItem);
    }

    return aryLineColor;
}

//获取最后的数据更新时间
MinuteChartContainer.JsonDataToMinuteLastUpdateTime=function(data)
{
    if (!data || !data.stock[0]) return null;
    var stock=data.stock[0];
    if (!IFrameSplitOperator.IsNumber(stock.date) || !IFrameSplitOperator.IsNumber(stock.time)) return null;
    return { Date:stock.date, Time:stock.time };
}

MinuteChartContainer.JsonDataToHistoryMinuteLastUpdateTime=function(data)
{
    if (!data || !data.updatetime) return null;
    var item=data.updatetime;

    if (!IFrameSplitOperator.IsNumber(item.date) || !IFrameSplitOperator.IsNumber(item.time)) return null;

    return { Date:item.date, Time:item.time };
}

//多日日线数据API 转化成array[];
MinuteChartContainer.JsonDataToMinuteDataArray=function(data)
{
    var symbol=data.symbol;
    var upperSymbol=symbol.toUpperCase();
    var isSHSZ=MARKET_SUFFIX_NAME.IsSHSZ(upperSymbol);
    var isSHO=MARKET_SUFFIX_NAME.IsSHO(upperSymbol);    //上海股票期权
    var isSZO=MARKET_SUFFIX_NAME.IsSZO(upperSymbol);            //深证股票期权
    var isFutures=MARKET_SUFFIX_NAME.IsFutures(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 yClearing=dayData.yclearing;    //昨结算价

        //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];    //日期
                item.DateTime=item.Date.toString()+" "+jsData[0].toString();
            }
            if ((isFutures || isSHO || isSZO) && 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;

            //价格是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;
        if (IFrameSplitOperator.IsNumber(yClearing)) newData.YClearing=yClearing;

        result.push(newData);
    }

    return result;
}

MinuteChartContainer.JsonDataToHistoryMinuteLineColorData=function(data)
{
    if (!data) return null;

    var aryLineColor=[];
    for(var i in data.data)
    {
        var dayData=data.data[i];
        if (!dayData.linecolor) continue;

        for(var j in dayData.linecolor.data)
        {
            var item=dayData.linecolor.data[j];

            if (!IFrameSplitOperator.IsNumber(item.type) || !IFrameSplitOperator.IsNumber(item.date) || !IFrameSplitOperator.IsNumber(item.start) ||
            !IFrameSplitOperator.IsNumber(item.end) || !item.color) continue;
        
            if (item.start>=item.end) continue;

            var newItem={ Type:item.type, Date:item.date, Start:item.start, End:item.end, Color:item.color };
            if (IFrameSplitOperator.IsPlusNumber(item.linewidth)) newItem.LineWidth=item.linewidth;

            aryLineColor.push(newItem);
        }
    }

    return aryLineColor.length>0? aryLineColor : null;
}


MinuteChartContainer.JsonDataToCallAuctionItem=function(data, callAuctionData, isBeforeOpen)
{
    var date=callAuctionData.Date;

    if (callAuctionData.Ver==1.0)
    {
        for(var i in data)
        {
            var item=isBeforeOpen? new BeforeOpenData() : new AfterCloseData();
            var jsData=data[i];
            item.Time=jsData[0];
            item.Date=date;
            item.Price=jsData[1];
            if (!item.Price) item.Price=preClose;
            else preClose=item.Price;
            item.Vol[0]=jsData[2]/100;  //沪深股票原始单位股
            item.Amount=jsData[3];
            item.DateTime=date.toString()+" "+item.Time.toString();
    
            callAuctionData.Data.push(item);
        }
    }
    else if (callAuctionData.Ver==2.0)
    {
        var max=0;
        for(var i in data)
        {
            var item=isBeforeOpen? new BeforeOpenData() : new AfterCloseData();
            var jsData=data[i];
            item.Time=jsData[0];
            item.Date=date;
            item.Price=jsData[1];
            item.Vol[0]=jsData[2];  //匹配量
            item.Vol[1]=jsData[3];  //未匹配量
            item.ColorID=jsData[4]; //柱子颜色ID
            item.DateTime=date.toString()+" "+item.Time.toString();

            var totalVol=item.Vol[0]+item.Vol[1];
            if (IFrameSplitOperator.IsNumber(jsData[5])) totalVol=jsData[5];
            if (totalVol>max) max=totalVol;
    
            callAuctionData.Data.push(item);
        }

        callAuctionData.VolMax=max;
        callAuctionData.VolMin=0;
    }
    else if (beforeOpenData.Ver==3.0)
    {
        var max=0;
        for(var i in data)
        {
            var item=isBeforeOpen? new BeforeOpenData() : new AfterCloseData();
            var jsData=data[i];
            item.Time=jsData[0];
            item.Date=date;
            item.Price=jsData[1];
            item.AvPrice=jsData[2]; //均价
            item.Vol[0]=jsData[3];  //匹配量
            item.ColorID=jsData[4]; //柱子颜色ID
            item.DateTime=date.toString()+" "+item.Time.toString();

            var totalVol=item.Vol[0];
            if (IFrameSplitOperator.IsNumber(jsData[5])) totalVol=jsData[5];
            if (totalVol>max) max=totalVol;
    
            callAuctionData.Data.push(item);
        }

        callAuctionData.VolMax=max;
        callAuctionData.VolMin=0;
    }
}

MinuteChartContainer.JosnDataToBeforeOpenDataArray=function(data)
{
    if (!data || !data.data) return null;

    var aryDay=[];
    for(var i in data.data)
    {
        var dayItem=data.data[i];
        var beforeOpenData={ Data:[], TotalCount:15, Ver:1.0, Date:dayItem.date };
        if (dayItem.beforeinfo)
        {
            if (IFrameSplitOperator.IsNumber(dayItem.beforeinfo.totalcount)) beforeOpenData.TotalCount=dayItem.beforeinfo.totalcount;
            if (IFrameSplitOperator.IsNumber(dayItem.beforeinfo.ver)) beforeOpenData.Ver=dayItem.beforeinfo.ver;
        }

        MinuteChartContainer.JsonDataToCallAuctionItem(dayItem.before, beforeOpenData, true);

        aryDay.push(beforeOpenData);
    }

    aryDay.sort((left, right)=>{return left.Date - right.Date}); 

    return aryDay;
}

MinuteChartContainer.JosnDataToAfterCloseDataArray=function(data)
{
    if (!data || !data.data) return null;

    var aryDay=[];
    for(var i in data.data)
    {
        var dayItem=data.data[i];
        var afterCloseData={ Data:[], TotalCount:15, Ver:1.0, Date:dayItem.date };

        if (dayItem.afterinfo)
        {
            if (IFrameSplitOperator.IsNumber(dayItem.afterinfo.totalcount)) afterCloseData.TotalCount=dayItem.afterinfo.totalcount;
            if (IFrameSplitOperator.IsNumber(dayItem.afterinfo.ver)) afterCloseData.Ver=dayItem.afterinfo.ver;
        }

        MinuteChartContainer.JsonDataToCallAuctionItem(dayItem.after, afterCloseData, false);

        aryDay.push(afterCloseData);
    }

    aryDay.sort((left, right)=>{return left.Date - right.Date}); 

    return aryDay;
}

/*
    历史分钟走势图
*/
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.EnableSplash(false);
                self.RecvHistoryMinuteData(data);
            },
            error:function(reqeust)
            {
                self.ChartSplashPaint.EnableSplash(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.SetTitle(this.LoadDataSplashTitle);
        this.ChartSplashPaint.EnableSplash(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.EnableSplash(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.GetRightData(bindData.Right, { AlgorithmType: this.RightFormula });
            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.TrainStartDate;        //训练开始日期时间 { Date:, Time: }
    this.AutoRunTimer=null;     //K线自动前进定时器
    this.BuySellData=[];        //模拟买卖数据 {Buy:{Price:价格,Date:日期, Time:时间} , Sell:{Price:价格,Date:日期, Time:时间} 
    this.TrainCallback;         //训练回调 (K线每前进一次就调用一次)
    this.DragMode=1;
    this.IsAutoUpdate=false;

    this.KLineSourceData;       //原始K线数据 对应 SourceData
    this.TrainInfo={ Start:{ }, End:{ } }; // Index:数据索引, Date:日期  Time:时间

    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.GetKDataIndexByDateTime=function(kData, dateTime)
    {
        if (!dateTime || !kData) return -1;

        for(var i in kData)
        {
            var item=kData[i];
            if (ChartData.IsMinutePeriod(this.Period, true))
            {
                if (IFrameSplitOperator.IsNumber(this.TrainStartDate.Time))
                {
                    if (item.Date>=this.TrainStartDate.Date && item.Time>=this.TrainStartDate.Time)
                        return parseInt(i);
                }
                else
                {
                    if (item.Date>=this.TrainStartDate.Date)
                        return parseInt(i);
                }
            }
            else if (ChartData.IsDayPeriod(this.Period, true) || ChartData.IsTickPeriod(this.Period))
            {
                if (item.Date>=this.TrainStartDate.Date)
                    return parseInt(i);
            }
        }

        return -1;
    }

    this.AfterBindMainData=function(funcName)
    {
        if (!this.ChartPaintEx[0]) this.CreateBuySellPaint();

        var hisData=this.ChartPaint[0].Data;
        this.ChartPaintEx[0].Data=hisData;

        var showItem=hisData.Data[hisData.Data.length-1];

        //最后一个显示数据
        this.TrainInfo.LastShowData=showItem;
        this.TrainInfo.LastData = this.SourceData.Data[this.SourceData.Data.length - 1];

        if (funcName!='Update')
            this.UpdateTrainUICallback("开始");
    }

    this.BeforeBindMainData=function(funcName)
    {
        if (funcName=="Update") return;

        //全量数据 需要过滤
        this.KLineSourceData=new ChartData();
        this.KLineSourceData.Data=this.SourceData.Data.slice(0);
        var count=this.SourceData.Data.length;
        var lEnd=count-this.TrainDataCount-20;
        var findIndex=this.GetKDataIndexByDateTime(this.SourceData.Data, this.TrainStartDate);
        if (findIndex>=0)
        {
            lEnd=findIndex+1;
            if (count-lEnd<this.TrainDataCount) this.TrainDataCount=count-lEnd;
        }
        
        //训练起始日期
        var index=lEnd-1;
        var kItem=this.SourceData.Data[index];
        this.TrainInfo.Start.Index=index;
        this.TrainInfo.Start.Date=kItem.Date;
        this.TrainInfo.Start.Time=kItem.Time;

        //训练结束日期
        this.TrainInfo.End.Index=index;
        this.TrainInfo.End.Date=kItem.Date;
        this.TrainInfo.End.Time=kItem.Time;
        
        //最后一个数据
        this.TrainInfo.LastData=kItem;

        //修改数据个数
        this.SourceData.Data.length=lEnd;
    }

    this.Run=function(option)
    {
        if (this.AutoRunTimer) return;
        if (this.TrainDataCount<=0) return;

        var self=this;
        this.AutoRunTimer=setInterval(function()
        {
            if (!self.MoveNextKLineData(option)) clearInterval(self.AutoRunTimer);
        }, 1000);
    }

    this.MoveNextKLineData=function(option) //{PageSize:, Step:}
    {
        if (this.TrainDataCount<=0) return false;

        var step=1;
        if (option && option.Step>1) step=option.Step;

        var moveStep=0;
        for(var i=0; i<step; ++i)
        {
            var index=this.TrainInfo.End.Index+1;
            if (index>=this.KLineSourceData.Data.length) break;
    
            var kItem=this.KLineSourceData.Data[index];
            this.SourceData.Data.push(kItem);
    
            this.TrainInfo.End.Index=index;
            this.TrainInfo.End.Date=kItem.Date;
            this.TrainInfo.End.Time=kItem.Time;
            --this.TrainDataCount;
            ++moveStep;

            if (this.TrainDataCount<=0) break;
        }

        if (moveStep==0) return false;

        //使用当前页数据个数移动K线
        var pageSize=this.Frame.GetCurrentPageSize();
        if (IFrameSplitOperator.IsNumber(pageSize))
            this.PageSize=pageSize-this.RightSpaceCount;

        if (option && option.PageSize>0) this.PageSize=option.PageSize;

        this.Update();

        if (this.TrainDataCount<=0) 
        {
            this.FinishTrainData();
            this.UpdateTrainUICallback("结束");
            return false;
        }

        this.UpdateTrainUICallback("训练中");
        return true;
    }

    this.UpdateTrainUICallback=function(description)
    {
        //新的监听事件
        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;

        var data=
        { 
            TrainDataCount:this.TrainDataCount,
            BuySellData:this.BuySellData, 
            KLine:
            { 
                Start: { Index: this.TrainInfo.Start.Index, Date:this.TrainInfo.Start.Date },
                End:{ Index: this.TrainInfo.End.Index, Date:this.TrainInfo.End.Date }
            },
            LastData:this.TrainInfo.LastData,
            LastShowData:this.TrainInfo.LastShowData
        };  
        if (IFrameSplitOperator.IsNumber(this.TrainInfo.Start.Time)) data.KLine.Start.Time=this.TrainInfo.Start.Time;
        if (IFrameSplitOperator.IsNumber(this.TrainInfo.End.Time)) data.KLine.End.Time=this.TrainInfo.End.Time;
        if (description) data.Description=description

        if (this.TrainDataCount<=0)
        {
            data.Symbol=this.Symbol;
            data.Name=this.Name;
        }

        item.Callback(item,data,this);
    }

    this.FinishTrainData=function()
    {
        JSConsole.Chart.Log('[KLineTrainChartContainer::FinishTrainData] trian end ');
    }

    this.Stop=function()
    {
        if (this.AutoRunTimer!=null) clearInterval(this.AutoRunTimer);
        this.AutoRunTimer=null;
    }

    this.BuyOrSell=function(obj, bDraw)  //{ Price:价格, Vol:数量, Op: 买/卖 0=buy 1=sell, ID:单号 } bDraw是否立即绘制图标
    {
        var kItem=this.TrainInfo.LastShowData;
        if (!kItem) return false;
        
        var buySellPaint=this.ChartPaintEx[0];
        if (!buySellPaint) return false;

        var hisData=this.ChartPaint[0].Data;
        if (!hisData || hisData.Data.length<=0) return false;

        var index=hisData.Data.length-1;  //数据索引
        var buyItem={ Date:this.TrainInfo.End.Date, Time:this.TrainInfo.End.Time, Price:obj.Price, Vol:obj.Vol, Op:0, ID:obj.ID };
        if (obj.Op==1) buyItem.Op=1;
        var key=index;
        buyItem.Key=key;

        this.BuySellData.push(buyItem);
        buySellPaint.AddTradeItem(buyItem);

        if (bDraw==true) this.Draw();
    }

    this.RestartTrain=function(option)  // { Symbol:, Period:周期, Right:复权, Train:{ DataCount:, DateTime: } }
    {
        JSConsole.Chart.Log('[KLineTrainChartContainer::RestartTrain] option ', option);

        this.TrainInfo={ Start:{ }, End:{ } };
        this.BuySellData=[];
        this.KLineSourceData=null;

        var buySellPaint=this.ChartPaintEx[0];
        if (buySellPaint)
        {
            buySellPaint.Data=null;
            buySellPaint.ClearTradeData();
        }

        if (option.Symbol) this.Symbol=option.Symbol;
        if (IFrameSplitOperator.IsNumber(option.Period)) this.Period=option.Period;
        if (IFrameSplitOperator.IsNumber(option.Right)) this.Right=option.Right;
        if (option.Train)
        {
            if (option.Train.DataCount>1) this.TrainDataCount=option.Train.DataCount;
            if (option.Train.DateTime) this.TrainStartDate=option.Train.DateTime;
        }

        var symbol=this.Symbol;
        this.ChangeSymbol(symbol);
    }

    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];
                if (!aryFixedData[i]) continue;
                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;

            var aryFixedData=this.KLineSourceData.GetMinuteFittingFinanceData(aryData); //数据添加到备份数据中
            for(let i in this.KLineSourceData.Data)
            {
                var item=this.KLineSourceData.Data[i];
                if (!aryFixedData[i]) continue;
                item.FlowCapital=aryFixedData[i].Value;
            }
        }
        else
        {
            var aryFixedData=this.SourceData.GetFittingFinanceData(aryData);
            for(let i in this.SourceData.Data)
            {
                var item=this.SourceData.Data[i];
                if (!aryFixedData[i]) continue;
                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.GetRightData(bindData.Right, { AlgorithmType: this.RightFormula });
                newBindData.Data=rightData;
            }

            if (ChartData.IsDayPeriod(bindData.Period,false)) //周期数据
            {
                var periodData=newBindData.GetPeriodData(bindData.Period);  
                newBindData.Data=periodData;
            }

            bindData.Data=newBindData.Data;

            var aryFixedData=this.KLineSourceData.GetFittingFinanceData(aryData);   //数据添加到备份数据中
            for(let i in this.KLineSourceData.Data)
            {
                var item=this.KLineSourceData.Data[i];
                if (!aryFixedData[i]) continue;
                item.FlowCapital=aryFixedData[i].Value;
            }
        }

        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.AutoUpdate()
    {

    }
}

////////////////////////////////////////////////////////////////////////////////
//  K线横屏显示
//
function KLineChartHScreenContainer(uielement)
{
    this.newMethod=KLineChartContainer;   //派生
    this.newMethod(uielement);
    delete this.newMethod;

    this.ClassName='KLineChartHScreenContainer';

    this.OnMouseMove=function(x,y,e,isPhone)
    {
        this.LastPoint.X=x;
        this.LastPoint.Y=y;
        this.CursorIndex=this.Frame.GetXData(y);

        var option={ ParentFunction:'OnMouseMove', Point:{X:x, Y:y}, IsPhone:isPhone===true };

        this.DrawDynamicInfo(option);
    }

    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 oneStepWidth=this.JSChartContainer.GetMoveOneStepWidth();
                if (moveSetp<oneStepWidth) 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)
    {
        if (this.ChartSplashPaint && this.ChartSplashPaint.IsEnableSplash == true) return;

        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,true);
                else
                {
                    this.SetChartDrawPictureFirstPoint(drag.Click.X,drag.Click.Y,true);
                    //只有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 (this.ChartSplashPaint && this.ChartSplashPaint.IsEnableSplash == true) return;

        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,true))
                        {
                            this.DrawDynamicInfo();
                        }
                    }
                    else if (drawPicture.Status==3)
                    {
                        if(this.SetChartDrawPictureThirdPoint(touches[0].clientX,touches[0].clientY,true))
                        {
                            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,true))
                        {
                            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 oneStepWidth=this.GetMoveOneStepWidth();
                    if (moveSetp<oneStepWidth) 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);
        if (this.ChartSplashPaint && this.ChartSplashPaint.IsEnableSplash == true) return;

        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=g_DivTooltipDataForamt.Create("CorssCursor_XStringFormat");
        this.ChartCorssCursor.StringFormatX.LanguageID=this.LanguageID;
        this.ChartCorssCursor.StringFormatY=g_DivTooltipDataForamt.Create("CorssCursor_YStringFormat");
        this.ChartCorssCursor.StringFormatY.LanguageID=this.LanguageID;
        this.ChartCorssCursor.StringFormatY.ExtendChartPaint=this.ExtendChartPaint;

        //创建等待提示
        this.ChartSplashPaint = new ChartSplashPaint();
        this.ChartSplashPaint.Canvas = this.Canvas;
        this.ChartSplashPaint.HQChart=this;

        //创建框架容器
        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;
            titlePaint.GetEventCallback=(id)=> { return this.GetEventCallback(id); }
            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;                   //窗口序号
            frame.RightSpaceCount=this.RightSpaceCount; //右边

            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');
                frame.YSplitOperator.GetEventCallback=(id)=> { return this.GetEventCallback(id); }
                //主图上下间距
                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;
            frame.XSplitOperator.GetEventCallback=(id)=> { return this.GetEventCallback(id); }

            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,isPhone)
    {
        this.LastPoint.X=x;
        this.LastPoint.Y=y;
        this.CursorIndex=this.Frame.GetXData(y);

        var clientPos=this.PtInClient(x,y);
        var option={ ParentFunction:'OnMouseMove', Point:{X:x, Y:y}, IsPhone:isPhone===true,ClientPos:clientPos };
        this.DrawDynamicInfo(option);
    }

     //创建
    //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.CallAcutionXOperator=new CallAcutionXOperator();

         //创建等待提示
         this.ChartSplashPaint = new ChartSplashPaint();
         this.ChartSplashPaint.Canvas = this.Canvas;
         this.ChartSplashPaint.HQChart=this;

        //创建框架容器
        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;
            titlePaint.GetEventCallback=(id)=> { return this.GetEventCallback(id); }
            this.TitlePaint.push(titlePaint);
        }
        
        this.ChartCorssCursor.StringFormatX.Frame=this.Frame.SubFrame[0].Frame;
        this.ChartCorssCursor.StringFormatY.Frame=this.Frame;
        this.ChartCorssCursor.CallAcutionXOperator.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;
            frame.Identify=i;
            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');
                frame.YSplitOperator.GetEventCallback=(id)=> { return this.GetEventCallback(id); }
            }
            else
            {
                frame.YSplitOperator=new FrameSplitY();
                frame.YSplitOperator.LanguageID=this.LanguageID;
                frame.YSplitOperator.FrameSplitData=this.FrameSplitData.get('double');
                frame.YSplitOperator.GetEventCallback=(id)=> { return this.GetEventCallback(id); }
            }

            frame.YSplitOperator.Frame=frame;
            frame.YSplitOperator.ChartBorder=border;
            frame.XSplitOperator=new FrameSplitMinuteX();
            frame.XSplitOperator.Frame=frame;
            frame.XSplitOperator.ChartBorder=border;
            frame.XSplitOperator.GetEventCallback=(id)=> { return this.GetEventCallback(id); }
            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 DepthChartContainer(uielement)
{
    this.newMethod=JSChartContainer;   //派生
    this.newMethod(uielement);
    delete this.newMethod;

    this.ClassName="DepthChartContainer";
    this.Symbol;
    
    //数据
    this.MapAsk=new Map();
    this.MapBid=new Map();

    this.IsAutoUpdate=false;                    //是否自动更新行情数据
    this.AutoUpdateFrequency=30000;             //30秒更新一次数据
    this.AutoUpdateTimer;

    this.DefaultZoom=0.8;       //默认显示80%的盘口 (0 - 1)
    this.MaxVolRate=1.1;

    this.Create=function(option)
    {
        this.UIElement.JSChartContainer=this;

        //创建十字光标
        this.ChartCorssCursor=new DepthChartCorssCursor();
        this.ChartCorssCursor.Canvas=this.Canvas;
        this.ChartCorssCursor.HQChart=this;
        //this.ChartCorssCursor.StringFormatX=g_DivTooltipDataForamt.Create("CorssCursor_XStringFormat");
        //this.ChartCorssCursor.StringFormatX.LanguageID=this.LanguageID;
        //this.ChartCorssCursor.StringFormatY=g_DivTooltipDataForamt.Create("CorssCursor_YStringFormat");
        //this.ChartCorssCursor.StringFormatY.LanguageID=this.LanguageID;


        //创建等待提示
        this.ChartSplashPaint = new ChartSplashPaint();
        this.ChartSplashPaint.Canvas = this.Canvas;
        this.ChartSplashPaint.SetTitle(this.LoadDataSplashTitle);

        //创建框架
        this.Frame=new DepthChartFrame();
        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.ChartBorder.TitleHeight=0;
        this.Frame.Canvas=this.Canvas;

        var ySplitOper=new FrameSplitY();
        ySplitOper.FrameSplitData=this.FrameSplitData.get('double');
        ySplitOper.LanguageID=this.LanguageID;
        ySplitOper.Frame=this.Frame;
        ySplitOper.SplitCount=5;
        ySplitOper.LineType=3;
        ySplitOper.IgnoreYValue=[0];
        //ySplitOper.SplitType=2;
        ySplitOper.ChartBorder=this.Frame.ChartBorder;
        this.Frame.YSplitOperator=ySplitOper;

        var xSplitOper=new FrameSplitXDepth();
        xSplitOper.Frame=this.Frame;;
        xSplitOper.ChartBorder=this.Frame.ChartBorder;;
        xSplitOper.LanguageID=this.LanguageID;
        xSplitOper.LineType=3;
        this.Frame.XSplitOperator=xSplitOper

        if (this.ChartCorssCursor) this.ChartCorssCursor.Frame=this.Frame; //十字光标绑定框架
        this.ChartSplashPaint.Frame = this.Frame;

        var chartItem=new ChartOrderbookDepth();
        chartItem.Canvas=this.Canvas;
        chartItem.ChartBorder=this.Frame.ChartBorder;
        chartItem.ChartFrame=this.Frame;
        chartItem.Name="深度图"
        this.ChartPaint.push(chartItem);

        var bRegisterKeydown=true;
        var bRegisterWheel=true;
        if (option)
        {
            if (option.Wheel===false) 
            {
                bRegisterWheel=false;
                JSConsole.Chart.Log('[DepthChartContainer::Create] not register wheel event.');
            }
        }

        if (bRegisterKeydown) this.UIElement.addEventListener("keydown", (e)=>{ this.OnKeyDown(e); }, true);            //键盘消息
        if (bRegisterWheel) this.UIElement.addEventListener("wheel", (e)=>{ this.OnWheel(e); }, true);                //上下滚动消息
    }

    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);

        var wheelValue=e.wheelDelta;
        if (!IFrameSplitOperator.IsObjectExist(e.wheelDelta))
            wheelValue=e.deltaY* -0.01;
        
        var enableZoomUpDown=true;  //是否允许缩放
        if (this.EnableZoomUpDown && this.EnableZoomUpDown.Wheel===false) enableZoomUpDown=false;
        
        if (isInClient && wheelValue<0 && enableZoomUpDown)       //缩小
        {
            if (this.Frame.ZoomDown())
            {
                this.UpdateFrameMaxMin();
                this.Draw();
            }
        }
        else if (isInClient && wheelValue>0 && enableZoomUpDown)  //放大
        {
            if (this.Frame.ZoomUp())
            {
                this.UpdateFrameMaxMin();
                this.Draw();
            }
        }

        if(e.preventDefault) e.preventDefault();
        else e.returnValue = false;
    }

    this.UIOnMouseDown=function(e)
    {
    }

    this.OnTouchStart=function(e)
    {
        if (this.ChartSplashPaint && this.ChartSplashPaint.IsEnableSplash == true) return;

        this.IsOnTouch=true;
        this.TouchDrawCount=0;
        this.PhonePinch=null;

        var isSingleTouch=this.IsSingleTouch(e);
        if (this.EnableScrollUpDown==false || !isSingleTouch) //多点触屏 
        {
            if (e.cancelable) e.preventDefault();
        }

        if (this.IsPhoneDragging(e))
        {
            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;

            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.OnTouchMove=function(e)
    {
        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-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 ) 
                {
                    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);
            }
        }
        else if (this.IsPhonePinching(e))
        {
            this.PreventTouchEvent(e);
            var phonePinch=this.PhonePinch;
            if (!phonePinch) return;

            if (this.EnableZoomUpDown && this.EnableZoomUpDown.Touch===false) 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)    //放大
            {
                if (!this.Frame.ZoomUp()) return;
                this.UpdateFrameMaxMin();
                this.Draw();
            }
            else        //缩小
            {
                if (!this.Frame.ZoomDown()) return;
                this.UpdateFrameMaxMin();
                this.Draw();
            }

            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('[DepthChartContainer::OnTouchEnd]',e);
        this.IsOnTouch = false;
        this.OnTouchFinished();
        this.TouchDrawCount=0;
    }

    this.OnTouchFinished=function()
    {
        if (this.CorssCursorTouchEnd===true)    //手势离开十字光标消失
        {
            this.DrawDynamicInfo();
            return;
        }
    }

    this.ChangeSymbol=function(symbol)
    {
        this.CancelAutoUpdate();    //先停止定时器
        this.Symbol=symbol;
        this.MapBid=new Map();
        this.MapAsk=new Map();
        this.Frame.VerticalRange.Differ=null;

        this.ChartSplashPaint.SetTitle(this.LoadDataSplashTitle);
        this.ChartSplashPaint.EnableSplash(true);
        this.Draw();

        this.RequestDepthData();
    }

    this.RequestDepthData=function()  //全量历史数据
    {
        var self=this;
        if (this.NetworkFilter)
        {
            var obj=
            {
                Name:'DepthChartContainer::RequestDepthData', //类名::
                Explain:'深度图数据',
                Request:{ Data: { symbol:self.Symbol } }, 
                Self:this,
                PreventDefault:false
            };
            this.NetworkFilter(obj, function(data) 
            { 
                self.ChartSplashPaint.EnableSplash(false);
                self.RecvDepthData(data);
                self.AutoUpdate();
            });

            if (obj.PreventDefault==true) return;   //已被上层替换,不调用默认的网络请求
        }
    }

    this.RecvDepthData=function(data)
    {
        this.UpdateAskAndBid(data);

        var aryAsk=Array.from(this.MapAsk.values());    //卖    右边
        aryAsk.sort((a,b)=> { return a.Price-b.Price; });
        var sumVol=0;
        for(var i in aryAsk)
        {
            var item=aryAsk[i];
            sumVol+=item.Vol;

            aryAsk[i]={Price:item.Price, Vol:sumVol };
        }

        var aryBid=Array.from(this.MapBid.values());    //买    左边
        aryBid.sort((a,b)=> { return b.Price-a.Price; });
        var sumVol=0;
        for(var i in aryBid)
        {
            var item=aryBid[i];
            sumVol+=item.Vol;

            aryBid[i]={Price:item.Price, Vol:sumVol };
        }

        var drawData={ Asks:aryAsk, Bids:aryBid };
        var chart=this.ChartPaint[0];
        chart.Data=drawData;

        this.Frame.XSplitOperator.Symbol=this.Symbol;
        this.ChartCorssCursor.Data=drawData;
        this.ChartCorssCursor.Symbol=this.Symbol;

        this.UpdateFramePriceList();
        this.UpdateFrameMaxMin();

        this.Draw();
    }

    this.UpdateAskAndBid=function(data) //更新数据
    {
        if(data.datatype=="snapshot") //全量数据
        {
            this.MapBid=new Map();
            this.MapAsk=new Map();
        }

        for(var i in data.asks)
        {
            var item=data.asks[i];
            var price=parseFloat(item[0]);
            var vol=parseFloat(item[1]);

            if (this.MapAsk.has(price))
            {
                var value=this.MapAsk.get(price);
                if (vol<=0) this.MapAsk.delete(price);
                else value.Vol=vol;
            }
            else
            {
                if (vol>0) this.MapAsk.set(price, { Price:price, Vol:vol});
            }
        }

        for(var i in data.bids)
        {
            var item=data.bids[i];
            var price=parseFloat(item[0]);
            var vol=parseFloat(item[1]);

            if (this.MapBid.has(price))
            {
                var value=this.MapBid.get(price);
                if (vol<=0) this.MapBid.delete(price);
                else value.Vol=vol;
            }
            else
            {
                if (vol>0) this.MapBid.set(price, { Price:price, Vol:vol});
            }
        }
    }

    this.UpdateFramePriceList=function()
    {
        var aryAskPrice=Array.from(this.MapAsk.keys());
        var aryBidPrice=Array.from(this.MapBid.keys());

        aryAskPrice.sort((a,b)=> { return a-b; });
        aryBidPrice.sort((a,b)=> { return a-b; });

        var range={ Max:88, Min:8 };
        if (aryAskPrice.length>1 && aryBidPrice.length>1)
        {
            var askMin=aryAskPrice[0], askMax=aryAskPrice[aryAskPrice.length-1];
            var bidMin=aryBidPrice[0], bidMax=aryBidPrice[aryBidPrice.length-1];
            var askDifference=askMax-askMin;    //卖差值
            var bidDifference=bidMax-bidMin;    //买差值
            var difference=Math.max(askDifference, bidDifference);   //取最大的差值,2边调整

            var ask={Min:askMin, Max:askMin+difference};
            var bid={Max:bidMax, Min:bidMax-difference};
            range={ Max:ask.Max, Min:bid.Min };
        }

        this.Frame.SetPriceList(aryAskPrice,aryBidPrice);
        var xRange=this.Frame.VerticalRange;
        xRange.Max=range.Max;
        xRange.Center=range.Min+(range.Max-range.Min)/2;
        xRange.Min=range.Min;
        xRange.MaxDiffer=difference;        //差值
        xRange.Ask=ask;
        xRange.Bid=bid;
        if (!IFrameSplitOperator.IsNumber(xRange.Differ)) 
            xRange.Differ=difference*this.DefaultZoom;
        
        xRange.Min=xRange.Center-xRange.Differ;
        xRange.Max=xRange.Center+xRange.Differ;
    }

    this.UpdateFrameMaxMin=function()
    {
        var range=this.ChartPaint[0].GetMaxMin();

        this.Frame.HorizontalMax=range.Max*this.MaxVolRate;
        this.Frame.HorizontalMin=0;
        this.Frame.XYSplit=true;
    }

    this.CancelAutoUpdate=function()    //关闭停止更新
    {
        if (typeof (this.AutoUpdateTimer) == 'number') 
        {
            clearTimeout(this.AutoUpdateTimer);
            this.AutoUpdateTimer = undefined;
        }
    }

    this.StopAutoUpdate=function()
    {
        this.CancelAutoUpdate();
        if (!this.IsAutoUpdate) return;
        this.IsAutoUpdate=false;
    }

    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.RequestDepthData();
            },frequency);
        }
    }
}


////////////////////////////////////////////////////////////////////////////////
//  简单的图形框架
//
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.ClassName="BaseIndex";
    
    this.OverlayIndex=null; //叠加指标{ IsOverlay:true, Identify:overlayFrame.Identify, WindowIndex:windowIndex, Frame:overlayFrame }
    this.GetEventCallback;  //事件回调函数
    this.Status=0;  //0=空闲 1=计算

    //默认创建都是线段
    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 JSIndex_CJL()
{
    this.newMethod=BaseIndex;   //派生
    this.newMethod('CJL');
    delete this.newMethod;

    this.Index=new Array(
        new IndexInfo("VOL",null),
        new IndexInfo("OPID",null),
    );

    this.Index[0].LineColor=g_JSChartResource.Index.LineColor[0];
    this.Index[1].LineColor=g_JSChartResource.Index.LineColor[1];

    this.CreateChart=function(id) 
    {
        if (id==0)
        {
            var chart=new ChartVolStick();
            return chart;
        }
        else if (id==1)
        {
            var chart = new ChartSubLine();
            chart.LineWidth = 1*GetDevicePixelRatio();
            return chart;
        }
    }

    //请求数据
    this.RequestData=function(hqChart,windowIndex,hisData)
    {
        this.BindData(hqChart,windowIndex,hisData);

        hqChart.UpdataDataoffset();           //更新数据偏移
        hqChart.UpdateFrameMaxMin();          //调整坐标最大 最小值
        hqChart.Draw();

        return true;
    }

    
    this.BindData=function(hqChart,windowIndex,hisData)
    {
        var paint=this.CreatePaints(hqChart,windowIndex);
        var isOverlay=this.IsOverlay();
        if (paint.length!=this.Index.length) return false;

        var vol=hisData.GetVol();
        var position=hisData.GetPosition();

        paint[0].HistoryData=hisData;
        paint[0].Data.Data=vol;
        paint[1].Data.Data=position;

        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);
                titlePaint.OverlayIndex.get(this.OverlayIndex.Identify).Data[i]=titleData;
            }
        }
        else  
        {
            hqChart.TitlePaint[titleIndex].Data[0]=new DynamicTitleData(paint[0].Data,this.Index[0].Name,this.Index[0].LineColor);
            hqChart.TitlePaint[titleIndex].Data[1]=new DynamicTitleData(paint[1].Data,this.Index[1].Name,this.Index[1].LineColor);
            hqChart.TitlePaint[titleIndex].Title = this.Name;
        }

        return true;
    }
}

//市场多空
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.GetIconLibrary=function(index)
{
    var iconLib=g_JSChartResource.KLine.Info.IconLibrary;
    if (!iconLib || !iconLib.Icon) return g_JSChartResource.KLine.Info.Announcement.IconFont;

    if (index>=0 && index<iconLib.Icon.length)
    {
        var item=iconLib.Icon[index];
        var obj={ Text:item.Text, HScreenText:item.HScreenText, Color:item.Color, Family:iconLib.Family };
        return obj;
    }

    return g_JSChartResource.KLine.Info.Announcement.IconFont;
}

JSKLineInfoMap.GetIconFont=function(type)
{
    //公告扩展数据
    if (type>=KLINE_INFO_TYPE.ANNOUNCEMENT_EX_START && type<=KLINE_INFO_TYPE.ANNOUNCEMENT_EX_END)
    {
        var index=type-KLINE_INFO_TYPE.ANNOUNCEMENT_EX_START;
        return JSKLineInfoMap.GetIconLibrary(index);
    }

    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.Explain="IKLineInfo";

    this.GetToday=function()
    {
        var date=new Date();
        var today=date.getFullYear()*10000+(date.getMonth()+1)*100+date.getDate();
        return today;
    }

    this.GetRequestData=function(hqChart)
    {
        var obj=
        { 
            Symbol:hqChart.Symbol ,
            MaxReqeustDataCount: hqChart.MaxReqeustDataCount,            //日线数据个数
            MaxRequestMinuteDayCount:hqChart.MaxRequestMinuteDayCount,    //分钟数据请求的天数
            Period:hqChart.Period       //周期
        };
        
        return obj;
    }

    this.NetworkFilter=function(hqChart,callInfo)
    {
        if (!hqChart.NetworkFilter) return false;

        var self=this;

        var param=
        {
            HQChart:hqChart,
        };

        var obj=
        {
            Name:`${this.ClassName}::RequestData`, //类名::函数
            Explain:this.Explain,
            Request:this.GetRequestData(hqChart), 
            Self:this,
            HQChart:hqChart,
            PreventDefault:false
        };

        if (callInfo) 
        {
            if (callInfo.Update==true) 
            {
                obj.Update={ Start:{ Date: callInfo.StartDate } };
                param.Update={ Start:{ Date: callInfo.StartDate } };
            }

            obj.CallFunctionName=callInfo.FunctionName; //内部调用函数名
        }

        hqChart.NetworkFilter(obj, function(data) 
        { 
            self.RecvData(data,param);
        });

        if (obj.PreventDefault==true) return true;   //已被上层替换,不调用默认的网络请求
        
        return false;
    }
}



//互动易
function InvestorInfo()
{
    this.newMethod=IKLineInfo;   //派生
    this.newMethod();
    delete this.newMethod;

    this.ClassName='InvestorInfo';
    this.Explain='互动易'
    this.RequestData=function(hqChart, obj)
    {
        var self = this;
        var param=
        {
            HQChart:hqChart,
        };

        this.Data=[];
        if (this.NetworkFilter(hqChart,obj)) return; //已被上层替换,不调用默认的网络请求

        var postData=
        {
            filed: ["question","answerdate","symbol","id"],
            symbol: [param.HQChart.Symbol],
            querydate:{"StartDate":this.StartDate,"EndDate":this.GetToday()},
            start:0,
            end:this.MaxReqeustDataCount,
        };

        //请求数据
        var url=g_JSChartResource.Domain+g_JSChartResource.KLine.Info.Investor.ApiUrl;
        JSNetwork.HttpRequest({
            url: url,
            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.Explain='公告';
    this.ApiType=1; //0=读API 1=读OSS缓存文件

    this.RequestData=function(hqChart,obj)
    {
        var self = this;
        var param=
        {
            HQChart:hqChart,
        };

        if (obj && obj.Update===true)   //更新模式 不清内存数据
        {

        }
        else
        {
            this.Data=[];
        }

        if (this.NetworkFilter(hqChart, obj)) return; //已被上层替换,不调用默认的网络请求

        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
        {
            //请求数据
            var url=g_JSChartResource.Domain+g_JSChartResource.KLine.Info.Announcement.ApiUrl;
            JSNetwork.HttpRequest({
                url: url,
                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;

        var aryReport=[];
        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;
                }
            }

            //目前只支持1个类型
            for(var j in item.typeex)
            {
                var id=item.typeex[j];
                infoData.InfoType=KLINE_INFO_TYPE.ANNOUNCEMENT_EX_START+id;
                break;
            }

            aryReport.push(infoData);
        }

        if (recvData.Update===true && this.Data.length>0)
        {
            this.UpdateData(aryReport);
        }
        else
        {
            this.Data=aryReport;
        }

        param.HQChart.UpdataChartInfo();
        param.HQChart.Draw();
    }


    this.UpdateData=function(aryData)
    {
        if (!aryData || aryData.length<=0) return;

        var setKeys=new Set();  //通过 日期+类型+标题去重
        for(var i in this.Data)
        {
            var item=this.Data[i];
            var strKey=`${item.Date}-${item.InfoType}-${item.Title}`;
            setKeys.add(strKey);
        }

        var count=0;
        for(var i in aryData)
        {
            var item=aryData[i];
            var strKey=`${item.Date}-${item.InfoType}-${item.Title}`;
            if (setKeys.has(strKey)) continue;

            this.Data.push(item);
            ++count;
        }

        JSConsole.Chart.Log(`[AnnouncementInfo::UpdateData] add new count=${count}`);
    }

    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,obj)
    {
        var self = this;
        var param=
        {
            HQChart:hqChart,
        };

        this.Data=[];

        var url=g_JSChartResource.Domain+g_JSChartResource.KLine.Info.Pforecast.ApiUrl;
        //请求数据
        JSNetwork.HttpRequest({
            url: url,
            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,obj)
    {
        var self = this;
        var param=
        {
            HQChart:hqChart
        };

        this.Data=[];
        var url=g_JSChartResource.Domain+g_JSChartResource.KLine.Info.Research.ApiUrl;
        //请求数据
        JSNetwork.HttpRequest({
            url: url,
            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,obj)
    {
        var self = this;
        var param=
        {
            HQChart:hqChart
        };

        this.Data=[];
        var url=g_JSChartResource.Domain+g_JSChartResource.KLine.Info.BlockTrading.ApiUrl;

        //请求数据
        JSNetwork.HttpRequest({
            url: url,
            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, obj)
    {
        var self = this;
        var param=
        {
            HQChart:hqChart
        };

        this.Data=[];
        var url=g_JSChartResource.Domain+g_JSChartResource.KLine.Info.TradeDetail.ApiUrl;

        //请求数据
        JSNetwork.HttpRequest({
            url: url,
            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;
                    if (item.Content) info.Content=item.Content;
                    if (item.Link) info.Link=item.Link;
                    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)
    {
        var cssData={display:'block'};
        if (IFrameSplitOperator.IsNumber(left)) cssData.left=left+'px';
        if (IFrameSplitOperator.IsNumber(top)) cssData.top=top+'px';
        if (IFrameSplitOperator.IsNumber(width)) cssData.width=width+'px';
        if (IFrameSplitOperator.IsNumber(height)) cssData.height=height+'px';

        $("#"+this.ID).css(cssData);
    }
}


//修改指标
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属性值，转化为整型
                    if (!IFrameSplitOperator.IsNumber(value)) 
                    {
                        alert("参数不能为空");
                        return;
                    }
                    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属性值，转化为整型
                    if (!IFrameSplitOperator.IsNumber(value)) 
                    {
                        alert("参数不能为空");
                        return;
                    }
                    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();  //绑定取消和关闭事件

        dialog.Show();//显示, 在css里调整居中
    }
}

//换指标
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($("#" + this.ID + " .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) {
            $(".target-left ul").html('');
            $.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);
        dialog.Show();
    }
}

//信息地理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+="&nbsp;四周后涨幅:<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/>&nbsp;&nbsp;<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+"&nbsp;&nbsp;"+year+reportType+item.Title+"&nbsp;"+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'>证券代表&nbsp;&nbsp;&nbsp;</i>";
                        }else if(levels[j]==1){
                            recPerson+="<i>董秘&nbsp;&nbsp;&nbsp;</i>";
                        }else if(levels[j]==2){
                            recPerson+="<i style='color:#00a0e9'>总经理&nbsp;&nbsp;&nbsp;</i>";
                        }else if(levels[j]==3){
                            recPerson+="<i style='color:#00a0e9'>董事长&nbsp;&nbsp;&nbsp;</i>";
                        }
                    }
                }
                var strDate=item.Date.toString();
                var strNew=strDate.substring(0,4)+"-"+strDate.substring(4,6)+"-"+strDate.substring(6,8);  //转换时间格式
                strText+="<span>"+strNew+"&nbsp;&nbsp;&nbsp;接待:&nbsp;&nbsp;&nbsp;"+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>&nbsp;&nbsp;<i class='tipBoxTitle'>成交价:&nbsp;"+showPriceInfo.Price.toFixed(2)+"</i><i class='tipBoxTitle'>收盘价:&nbsp;"+showPriceInfo.ClosePrice.toFixed(2)+
                    "</i><br/><i class='rate-discount tipBoxTitle'>溢折价率:&nbsp;<strong style='color:"+ this.GetColor(showPriceInfo.Premium.toFixed(2))+"'>"+
                    showPriceInfo.Premium.toFixed(2)+"%</strong></i><i class='tipBoxTitle'>成交量(万股):&nbsp;"+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+"&nbsp;&nbsp;&nbsp;上榜原因:&nbsp;&nbsp;</i><i class='reason-list'>"+reasons+"</i><br/><i class='trade-detall'>一周后涨幅:&nbsp;<strong style='color:"+
                    this.GetColor(item.ExtendData.FWeek.Week1.toFixed(2))+"'>"+ item.ExtendData.FWeek.Week1.toFixed(2)+
                    "%</strong>&nbsp;&nbsp;&nbsp;四周后涨幅:&nbsp;<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+"&nbsp;&nbsp;&nbsp;"+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.Show=function(left,top,width,height)
    {
        var div=document.getElementById(this.ID);
        if (!div) return false;

        var findDiv=div.getElementsByClassName("minute-hqchart");
        if (!findDiv || findDiv.length!=1) return false;
        var klineDiv=findDiv[0];

        if (IFrameSplitOperator.IsNumber(width)) div.style.width=width+"px";
        if (IFrameSplitOperator.IsNumber(height)) div.style.height=height+"px";
        if (IFrameSplitOperator.IsNumber(left)) div.style.left=left+"px";
        if (IFrameSplitOperator.IsNumber(top)) div.style.top=top+"px";

        div.style.display='block';

        var klineWdith=klineDiv.offsetWidth;
        var klineTop=klineDiv.offsetTop;
        klineDiv.style.width=klineWdith+"px";
        klineDiv.style.height=(height-klineTop-5)+"px";
    }

    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;

        var pixelTatio=GetDevicePixelRatio();
        dialog.Show(500/pixelTatio,100/pixelTatio,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>&nbsp;"+
            "<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 MinuteSelectRectDialog(divElement)
{
    this.newMethod=IDivDialog;   //派生
    this.newMethod(divElement);
    delete this.newMethod;

    this.SelectData;
    this.Dialog;
    this.HQChart;
    this.RectSelectPaint;

    //隐藏窗口
    this.Close=function()
    {
        if (this.Dialog) 
        {
            this.DivElement.removeChild(this.Dialog);
            this.Dialog=null;
            this.ID=null;
        }

        if (this.RectSelectPaint) this.RectSelectPaint.PreventClose=false;
    }

    //创建
    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>\
        </div>\
        </div>";

        this.DivElement.appendChild(div);
        this.Dialog=div;

        //关闭按钮
        $("#"+this.ID+" #close").click(
            {
                divBox:this,
            },
            function(event)
            {
                event.data.divBox.Close();
            });
    }

    this.BindData=function()
    {
        var hqData=this.SelectData.Data;
        var start=this.SelectData.Start;
        var end=this.SelectData.End;
        this.HQChart.UpdateSelectRect(start,end);
        if (this.RectSelectPaint) this.RectSelectPaint.PreventClose=true;

        var showData=
        { 
            Open:0,Close:0,High:0,Low:0,  //起始价格, 结束价格, 最高, 最低
            Vol:0, Amount:0, 
            Date:
            { 
                Start:{Time:null, Date:null },
                End:{ Time:null, Date:null }
            }, 
            Count:0,
        }

        for(var i=start; i<=end && i<hqData.Data.length; ++i)
        {
            var item=hqData.Data[i];
            if (i==start) 
            {
                showData.Date.Start.Date=item.Date;
                showData.Date.Start.Time=item.Time;
                showData.Open=item.Close;
                showData.High=item.High;
                showData.Low=item.Low;
            }

            showData.Date.End.Date=item.Date;
            showData.Date.End.Time=item.Time;
            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 (showData.Vol>0) showData.AvPrice=showData.Amount/showData.Vol;  //均价
        if (item.Open>0)
        {
            showData.Increase = (showData.Close - showData.Open) / showData.Open *100;   //区间涨幅
            showData.Amplitude = (showData.High - showData.Low) / showData.Open * 100;   //区间振幅
        }

        // JSConsole.Chart.Log('[KLineSelectRectDialog::BindData]', showData);
        var defaultfloatPrecision=GetfloatPrecision(this.SelectData.Symbol);
        var startDate=IFrameSplitOperator.FormatDateString(showData.Date.Start.Date);
        var endDate=IFrameSplitOperator.FormatDateString(showData.Date.End.Date);
        startDate+=' '+IFrameSplitOperator.FormatTimeString(showData.Date.Start.Time,"HH:MM");
        endDate+=" "+IFrameSplitOperator.FormatTimeString(showData.Date.End.Time,"HH:MM");
       
        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.Open.toFixed(defaultfloatPrecision) +'</span></td>' +
            '               <td><strong>终止价: </strong><span>'+ showData.Close.toFixed(defaultfloatPrecision) +'</span></td>' +
            '               <td><strong>均价: </strong><span>'+ (IFrameSplitOperator.IsNumber(showData.AvPrice) ? 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' +
            '        </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.RectSelectPaint=event.data.RectSelectPaint;
        this.HQChart=chart;
        this.HQChart.HideSelectRect();
        this.BindData();

        this.Show();      //通过CSS居中显示
    }


}

//区间统计
function KLineSelectRectDialog(divElement)
{
    this.newMethod=IDivDialog;   //派生
    this.newMethod(divElement);
    delete this.newMethod;

    this.SelectData;
    this.Dialog;
    this.HQChart;
    this.RectSelectPaint;

    //隐藏窗口
    this.Close=function()
    {
        if (this.Dialog) 
        {
            this.DivElement.removeChild(this.Dialog);
            this.Dialog=null;
        }

        if (this.RectSelectPaint) this.RectSelectPaint.PreventClose=false;
    }

    //创建
    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;
        this.HQChart.UpdateSelectRect(start,end);
        if (this.RectSelectPaint) this.RectSelectPaint.PreventClose=true;

        var showData=
        { 
            Open:0,Close:0,High:0,Low:0, YClose:0,
            Vol:0, Amount:0, 
            Date:
            { 
                Start:{Time:null, Date:null },
                End:{ Time:null, Date:null }
            }, 
            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.Date=item.Date;
                showData.Date.Start.Time=item.Time;
                showData.Open=item.Open;
                showData.High=item.High;
                showData.Low=item.Low;
                showData.YClose=item.YClose;
            }

            showData.Date.End.Date=item.Date;
            showData.Date.End.Time=item.Time;
            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=IFrameSplitOperator.FormatDateString(showData.Date.Start.Date);
        var endDate=IFrameSplitOperator.FormatDateString(showData.Date.End.Date);
        if (ChartData.IsMinutePeriod(this.HQChart.Period))
        {
            startDate+=' '+IFrameSplitOperator.FormatTimeString(showData.Date.Start.Time,"HH:MM");
            endDate+=" "+IFrameSplitOperator.FormatTimeString(showData.Date.End.Time,"HH:MM");
        }
        else if (ChartData.IsSecondPeriod(this.HQChart.Period) || ChartData.IsTickPeriod(this.HQChart.Period))
        {
            startDate+=' '+IFrameSplitOperator.FormatTimeString(showData.Date.Start.Time,"HH:MM:SS");
            endDate+=" "+IFrameSplitOperator.FormatTimeString(showData.Date.End.Time,"HH:MM:SS");
        }
       
        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>'+ (IFrameSplitOperator.IsNumber(showData.AvPrice) ? 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.RectSelectPaint=event.data.RectSelectPaint;
        this.HQChart=chart;
        this.HQChart.HideSelectRect();
        this.BindData();

        this.Show();      //通过CSS居中显示
    }

    //形态匹配
    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;
        if (typeof($)=="undefined") return;
        $("#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();
            }
        }).contextmenu(function()
        {
            return false;   //屏蔽系统右键菜单
        });


        $childMenu.mouseenter(function () {
            $(this).attr("data-isShow", "1");
        }).mouseleave(function () {
            $(this).attr("data-isShow", "0");
        }).contextmenu(function()
        {
            return false;   //屏蔽系统右键菜单
        });

        $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:22,
                click: function () { chart.ChangePeriod(22); }
            },
            {
                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( {Type:0} ); }
            },
            {
                text: "百分比坐标",
                click: function () { chart.ChangeCoordinateType( {Type:1} ); }
            },
            {
                text: "反转坐标",
                click: function () { chart.ChangeCoordinateType( { IsReverse:true } ); }
            },
            {
                text: "对数坐标",
                click: function () { chart.ChangeCoordinateType( {Type:2} ); }
            },
            {
                text: "等比坐标",
                click: function () { chart.ChangeCoordinateType( {Type:3} ); }
            },
            {
                text: "等分坐标",
                click: function () { chart.ChangeCoordinateType( {Type:4} ); }
            },
            {
                text: "黄金分割",
                click: function () { chart.ChangeCoordinateType( {Type:5} ); }
            }
        ];

        if (chart.Frame && chart.Frame.SubFrame && chart.Frame.SubFrame.length>0) 
        {
            if (chart.Frame.SubFrame[0].Frame.CoordinateType==1) 
            {
                data[2].selected=true;
                data[2].click=function() { chart.ChangeCoordinateType( { IsReverse:false } ); } //取消反转
            }

            if (chart.Frame.SubFrame[0].Frame.YSplitOperator.CoordinateType==1) data[1].selected=true;  //百分比
            else if (chart.Frame.SubFrame[0].Frame.YSplitOperator.CoordinateType==0) data[0].selected=true; //普通坐标
            else if (chart.Frame.SubFrame[0].Frame.YSplitOperator.CoordinateType==2) data[3].selected=true; //对数
            else if (chart.Frame.SubFrame[0].Frame.YSplitOperator.CoordinateType==3) data[4].selected=true; //等比坐标
            else if (chart.Frame.SubFrame[0].Frame.YSplitOperator.CoordinateType==4) data[5].selected=true; //等分坐标
            else if (chart.Frame.SubFrame[0].Frame.YSplitOperator.CoordinateType==5) data[6].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.SetSizeChange(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.SetSizeChange(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.SetSizeChange(true);
                        chart.Draw();
                    }
                    
                }
            );
        }
        else
        {
            data.push(
                {
                    text: "移动筹码",
                    click: function () {  
                        var option={Name:'筹码分布', ShowType:1, Width:230 };
                        var extendChart=chart.CreateExtendChart(option.Name, option);   //创建扩展图形
                        chart.SetSizeChange(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 || windowsIndex<0) 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] 区间统计');
                    rightMenu.Hide();
                    var dialog=new KLineSelectRectDialog(divElement);
                    dialog.DoModal(event);
                }
            },
            {
                text:'区间放大',
                click:function()
                {
                    JSConsole.Chart.Log('[KLineSelectRightMenu::click] 区间放大');
                    var chart=event.data.Chart;
                    chart.ShowSelectData(event.data.SelectData);
                }
            }
        ];

        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();
        //判断下如果DOM没了需要重新创建
        var divIdName='topMenu_'+_self.ID;
        var divDom=document.getElementById(divIdName);
        if (!divDom) _self.Create();

        var $topMenu = $("#topMenu_"+_self.ID),
            topWidth = $topMenu.outerWidth(),
            topHeight = $topMenu.outerHeight();

        $topMenu.contextmenu(function()
        {
            return false;   //屏蔽系统右键菜单
        });

        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)
            },
            {
                text:"区间选择",
                children:this.GetSelectRect(chart)
            },
            
        ];

        var symbol=chart.Symbol;
        if (MARKET_SUFFIX_NAME.IsSHSZStockA(symbol))
        {
            dataList.push({text:'集合竞价',children: this.GetShowBeforeData(chart)});
        }

        dataList.push({text:"工具", children:this.GetTools(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.ShowCallAuctionData( { Left:false, MultiDay:{ Left:false }} ); },
                }
            ];
            
            return data;
        }
        else
        {
            var data=
            [
                {
                    text: "显示",
                    click: function () { chart.ShowCallAuctionData({Left:true, MultiDay:{ Left:true }}); },
                }
            ];

            return data;
        }
    }

    this.GetSelectRect=function(chart)  //区间选择
    {
        if (chart.EnableSelectRect)
        {
            var data=
            [
                {
                    text: "禁用区间选择",
                    click: function () { chart.EnableSelectRect=false; },
                }
            ];
            
            return data;
        }
        else
        {
            var data=
            [
                {
                    text: "启动区间选择",
                    click: function () { chart.EnableSelectRect=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;
    }

    //工具
    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);
                        chart.DeleteExtendChart(drawTools); 
                        chart.Frame.ChartBorder.Right-=toolsWidth;
                        chart.SetSizeChange(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.SetSizeChange(true);
                        chart.Draw();
                    }
                }
            );
        }

        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 pixelTatio = GetDevicePixelRatio();
        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 lineColor=this.ChartPicture.LineColor;
        if (lineColor.indexOf("rgb(")==0 || lineColor.indexOf("RGB(")==0)
            lineColor=IChartDrawPicture.RGBToHex(lineColor.toLowerCase());
        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="'+ 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="'+ lineColor +'"></p>\n' +
            '        <p class="subtool-del"><i class="iconfont icon-recycle_bin"></i></p>';
        }

        
        this.SubToolsDiv.style.right = right/pixelTatio + "px";
        this.SubToolsDiv.style.top = top/pixelTatio + "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 pixelTatio = GetDevicePixelRatio();
        var DoModalStr = titleContainerStr+contentContainerStr+btnContainer;
        this.SettingDiv.style.left = this.Position.Left/pixelTatio + "px";
        this.SettingDiv.style.top = this.Position.Top/pixelTatio + "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',
    SHSZ_C_Index:'.CI',     //自定义指数
    BJ:".BJ",               //北交所 BeiJing stock exchange

    SHO:'.SHO',          //上海交易所 股票期权
    SZO:".SZO",          //深证交易所 股票期权
    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)

    NYMEX:'.NYMEX',      //纽约商品期货交易所(New York Mercantile Exchange)
    COMEX:".COMEX",      //纽约商品期货交易所(New York Mercantile Exchange)
    NYBOT:".NYBOT",      //美國紐約商品交易所
    CBOT:".CBOT",        //芝商所

    LME:".LME",          //伦敦金属交易所
    TOCOM:".TOCOM",      //东京商品交易所（TOCOM）
    IPE:".IPE",          //美国洲际交易所 （ICE EUROPE）

    ET:'.ET',            //其他未知的品种

    IsET:function(upperSymbol)
    {
        if (!upperSymbol) return false;
        return upperSymbol.indexOf(this.ET) > 0;
    },

    IsETShowAvPrice:function(upperSymbol)   //是否显示均价
    {
        return false;
    },

    IsNYMEX:function(upperSymbol)
    {
        if (!upperSymbol) return false;
        return upperSymbol.indexOf(this.NYMEX)>0;
    },

    IsCOMEX:function(upperSymbol)
    {
        if (!upperSymbol) return false;
        return upperSymbol.indexOf(this.COMEX)>0;
    },

    IsNYBOT:function(upperSymbol)
    {
        if (!upperSymbol) return false;
        return upperSymbol.indexOf(this.NYBOT)>0;
    },

    IsCBOT:function(upperSymbol)
    {
        if (!upperSymbol) return false;
        return upperSymbol.indexOf(this.CBOT)>0;
    },

    IsLME:function(upperSymbol)
    {
        if (!upperSymbol) return false;
        return upperSymbol.indexOf(this.LME)>0;
    },

    IsTOCOM:function(upperSymbol)
    {
        if (!upperSymbol) return false;
        return upperSymbol.indexOf(this.TOCOM)>0;
    },

    IsIPE:function(upperSymbol)
    {
        if (!upperSymbol) return false;
        return upperSymbol.indexOf(this.IPE)>0;
    },

    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;
    },

    IsBJ:function(upperSymbol)
    {
        var pos = upperSymbol.length - this.BJ.length;
        var find = upperSymbol.indexOf(this.BJ);
        return find == pos;
    },

    //自定义指数
    IsSHSZCustomIndex:function(upperSymbol)
    {
        var pos = upperSymbol.length - this.SHSZ_C_Index.length;
        var find = upperSymbol.indexOf(this.SHSZ_C_Index);
        return find == pos;
    },

    IsSHO: function(upperSymbol)
    {
        var pos = upperSymbol.length - this.SHO.length;
        var find = upperSymbol.indexOf(this.SHO);
        return find == pos;
    },

    IsSZO: function(upperSymbol)
    {
        var pos = upperSymbol.length - this.SZO.length;
        var find = upperSymbol.indexOf(this.SZO);
        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) 
    {
        if (!upperSymbol) return false;
        if (upperSymbol.indexOf(this.CFFEX) > 0) return true;
        
        return false;
    },

    IsDCE: function (upperSymbol) 
    {
        if (!upperSymbol) return false;
        return upperSymbol.indexOf(this.DCE) > 0;
    },

    IsCZCE: function (upperSymbol) 
    {
        if (!upperSymbol) return false;
        return upperSymbol.indexOf(this.CZCE) > 0;
    },

    IsChinaFutures:function(upperSymbol)   //是否是国内期货 /期权
    {
        return this.IsSHO(upperSymbol) || this.IsSZO(upperSymbol) || this.IsCFFEX(upperSymbol) || this.IsCZCE(upperSymbol) || this.IsDCE(upperSymbol) || this.IsSHFE(upperSymbol);
    },

    IsFutures:function(upperSymbol) //是否是期货 包含国外的
    {
        return this.IsChinaFutures(upperSymbol) || 
            this.IsNYMEX(upperSymbol) || this.IsCOMEX(upperSymbol) || this.IsNYBOT(upperSymbol) || this.IsCBOT(upperSymbol) ||
            this.IsLME(upperSymbol) || this.IsTOCOM(upperSymbol);
    },

    IsSHSZ:function(upperSymbol)            //是否是沪深的股票
    {
        return this.IsSZ(upperSymbol)|| this.IsSH(upperSymbol) || this.IsSHSZCustomIndex(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 (this.IsSHSZCustomIndex(upperSymbol))  //自定义指数
        {
            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(2)=='2') return true;  //002 中小板
                if (upperSymbol.charAt(1)!='7' && upperSymbol.charAt(1)!='8') return true;
            } 
            else if (upperSymbol.charAt(0)=='3')
            {
                if (upperSymbol.charAt(1)=='0' && upperSymbol.charAt(2)=='0') return true;    //创业板 300XXX.sz
            }
        }

        return false;
    },

    IsBJStock:function(symbol)  //北交所股票
    {
        if (!symbol) return false;
        var upperSymbol=symbol.toUpperCase();
        if (!this.IsBJ(upperSymbol)) return false;

        var value=upperSymbol.charAt(0);

        if (value=='4' || value=='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 if (this.IsHK(upperSymbol))    //港股
        {
            if(day == 6 || day== 0) return 0;   //周末
            if(time>1630) return 3;
            if(time<925) return 1;
            return 2;   
        }
        else if (this.IsNYMEX(upperSymbol))
        {
            return this.GetNYMEXMarketStatus(upperSymbol);
        }
        else if (this.IsCOMEX(upperSymbol))
        {
            return this.GetCOMEXMarketStatus(upperSymbol);
        }
        else if (this.IsNYBOT(upperSymbol))
        {
            return this.GetNYBOTMarketStatus(upperSymbol);
        }
        else if (this.IsCBOT(upperSymbol))
        {
            return this.GetCBOTMarketStatus(upperSymbol);
        }
        else if (this.IsLME(upperSymbol))
        {
            return this.GetLMEMarketStatus(upperSymbol);
        }
        else if (this.IsTOCOM(upperSymbol))
        {
            return this.GetTOCOMMarketStatus(upperSymbol);
        }
        else if (this.IsChinaFutures(upperSymbol))  //国内期货
        {
            if(day == 6 || day== 0) return 0;   //周末

            //21:00-2:30
            if(time>=2100) return 2;
            if (time<=240) return 2;

            //8:55-11:30, 13:00-15:00
            if(time>=830 && time<=1510) return 2;

            return 1;
        }
        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%]
    },

    GetDefaultDecimal:function(symbol)  //默认小数位数
    {
        return 2;
    },

    GetFHKDecimal:function(symbol)  //港股指数期货 小数位数
    {
        return 0;
    },

    GetFTSEDecimal:function(symbol) //富时中国A50期货 小数位数
    {
        return 0;
    },

    GetBITDecimal:function(symbol)
    {
        return 2;
    },

    GetSHODecimal:function(symbol)
    {
        return 4;
    },

    GetETDecimal:function(symbol)
    {
        return 2;
    },

    GetForeignExchangeDecimal:function(symbol)
    {
        return 4;
    },

    GetNYMEXDecimal:function(symbol)    //纽约期货交易所
    {
        return g_NYMEXTimeData.GetDecimal(symbol);
    },

    GetCOMEXDecimal:function(symbol)
    {
        return g_COMEXTimeData.GetDecimal(symbol);
    },

    GetNYBOTDecimal:function(symbol)
    {
        return g_NYBOTTimeData.GetDecimal(symbol);
    },

    GetCBOTDecimal:function(symbol)
    {
        return g_CBOTTimeData.GetDecimal(symbol);
    },

    GetLMEDecimal:function(symbol)
    {
        return g_LMETimeData.GetDecimal(symbol);
    },

    GetTOCOMDecimal:function(symbol)
    {
        return g_TOCOMTimeData.GetDecimal(symbol);
    },

    GetIPEDecimal:function(symbol)
    {
        return g_IPETimeData.GetDecimal(symbol);
    },

    GetETMarketStatus:function(symbol)  
    {
        // 0=闭市 1=盘前 2=盘中 3=盘后
        return 2;
    },

    GetNYMEXMarketStatus:function(symbol)
    {
        return g_NYMEXTimeData.GetMarketStatus(symbol);
    },

    GetCOMEXMarketStatus:function(symbol)
    {
        return g_COMEXTimeData.GetMarketStatus(symbol);
    },

    GetNYBOTMarketStatus:function(symbol)
    {
        return g_NYBOTTimeData.GetMarketStatus(symbol);
    },

    GetCBOTMarketStatus:function(symbol)
    {
        return g_CBOTTimeData.GetMarketStatus(symbol);
    },

    GetLMEMarketStatus:function(symbol)
    {
        return g_LMETimeData.GetMarketStatus(symbol);
    },

    GetTOCOMMarketStatus:function(symbol)
    {
        return g_TOCOMTimeData.GetMarketStatus(symbol);
    },

    GetIPEMarketStatus:function(symbol)
    {
        return g_IPETimeData.GetMarketStatus(symbol);
    },

    IsShowMinuteVolTitle:function(symbol)   //是否画走势图成交量标题
    {
        if (!symbol) return false;
        var upperSymbol=symbol.toUpperCase();
        //if (this.IsChinaFutures(upperSymbol)) return true;

        return false;
    },

    IsShowMinutePostionLine:function(upperSymbol)    //分时图 成交量图中是否显示持仓线
    {
        if(MARKET_SUFFIX_NAME.IsFutures(upperSymbol) || MARKET_SUFFIX_NAME.IsSHO(upperSymbol) || MARKET_SUFFIX_NAME.IsSZO(upperSymbol))  return true;

        return false;
    },

    IsShowMinuteColorVolBar:function(symobl)        //是否分时图成绩量柱子使用彩色柱
    {
        if (g_JSChartResource.Minute.VolBarColor) return true;

        return false;
    },

    IsEnableRight:function(period, symbol)    //是否支持复权
    {
        if (!MARKET_SUFFIX_NAME.IsSHSZStockA(symbol) && !MARKET_SUFFIX_NAME.IsBJStock(symbol)) return false;
        if (ChartData.IsTickPeriod(period)) return false;                    //分笔没有复权
        if (ChartData.IsMinutePeriod(period,true)) return false;             //内置分钟K线不支持复权

        return true;
    }
}


//走势图分钟数据对应的时间
function MinuteTimeStringData() 
{
    this.SHSZ = null;       //上海深证交易所时间
    this.BJ=null;
    this.SHO=null;          //上海股票期权交易时间
    this.HK = null;         //香港交易所时间
    this.Futures=new Map(); //期货交易时间 key=时间名称 Value=数据
    this.USA = null;        //美股交易时间
    this.FTSE=null;         //富时中国
    this.FHK=null;          //港股指数期货
    this.ForeEx=null;       //外汇
    this.BIT=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(upperSymbol) //动态创建
    {
        if (!this.SHSZ) this.SHSZ=this.CreateSHSZData();
        return this.SHSZ;
    }

    this.GetBJ=function(upperSymbol)
    {
        if (!this.BJ) this.BJ=this.CreateBJData();
        return this.BJ;
    }

    this.GetSHO=function()
    {
        if (!this.SHO) this.SHO=this.CreateSHOData();
        return this.SHO;
    }

    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.GetBIT=function(upperSymbol)
    {
        if (!this.BIT) this.BIT=this.CreateBITData();
        return this.BIT;
    }

    this.CreateSHSZData = function () 
    {
        const TIME_SPLIT =
            [
                { Start: 925, End: 925 },
                { Start: 930, End: 1130 },
                { Start: 1300, End: 1500 }
            ];

        return this.CreateTimeData(TIME_SPLIT);
    }

    this.CreateBJData=function()
    {
        const TIME_SPLIT =
            [
                { Start: 925, End: 925 },
                { Start: 930, End: 1130 },
                { Start: 1300, End: 1500 }
            ];

        return this.CreateTimeData(TIME_SPLIT);
    }

    this.CreateSHOData=function()
    {
        const TIME_SPLIT =
        [
            { Start: 930, End: 1129 },
            { 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.CreateBITData=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(upperSymbol);
        if (MARKET_SUFFIX_NAME.IsBJ(upperSymbol)) return this.GetBJ(upperSymbol);
        if (MARKET_SUFFIX_NAME.IsSHO(upperSymbol) || MARKET_SUFFIX_NAME.IsSZO(upperSymbol)) return this.GetSHO();
        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);
        if (MARKET_SUFFIX_NAME.IsBIT(upperSymbol)) return this.GetBIT(upperSymbol);

        if (MARKET_SUFFIX_NAME.IsNYMEX(upperSymbol))    //纽约期货交易所
        {
            var splitData = g_NYMEXTimeData.GetSplitData(upperSymbol);
            if (!splitData) return null;
            return this.GetFutures(splitData);
        }

        if (MARKET_SUFFIX_NAME.IsCOMEX(upperSymbol))    //纽约期货交易所
        {
            var splitData = g_COMEXTimeData.GetSplitData(upperSymbol);
            if (!splitData) return null;
            return this.GetFutures(splitData);
        }

        if (MARKET_SUFFIX_NAME.IsNYBOT(upperSymbol))    //纽约期货交易所
        {
            var splitData = g_NYBOTTimeData.GetSplitData(upperSymbol);
            if (!splitData) return null;
            return this.GetFutures(splitData);
        }

        if (MARKET_SUFFIX_NAME.IsCBOT(upperSymbol))    //芝商所
        {
            var splitData = g_CBOTTimeData.GetSplitData(upperSymbol);
            if (!splitData) return null;
            return this.GetFutures(splitData);
        }

        if (MARKET_SUFFIX_NAME.IsLME(upperSymbol))    //伦敦LME
        {
            var splitData = g_LMETimeData.GetSplitData(upperSymbol);
            if (!splitData) return null;
            return this.GetFutures(splitData);
        }

        if (MARKET_SUFFIX_NAME.IsTOCOM(upperSymbol))    //东京商品交易所（TOCOM）
        {
            var splitData = g_TOCOMTimeData.GetSplitData(upperSymbol);
            if (!splitData) return null;
            return this.GetFutures(splitData);
        }

        if (MARKET_SUFFIX_NAME.IsIPE(upperSymbol))    //东京商品交易所（TOCOM）
        {
            var splitData = g_IPETimeData.GetSplitData(upperSymbol);
            if (!splitData) return null;
            return this.GetFutures(splitData);
        }
    }
}

//走势图刻度分钟线
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 SHO_MINUTE_X_COORDINATE =
        {
            Full:   //完整模式
            [
                [0, 0, "rgb(200,200,200)", "09:30"],
                [30, 0, "RGB(200,200,200)", "10:00"],
                [60, 0, "RGB(200,200,200)", "10:30"],
                [90, 0, "RGB(200,200,200)", "11:00"],
                [120, 1, "RGB(200,200,200)", "13:00"],
                [150, 0, "RGB(200,200,200)", "13:30"],
                [180, 0, "RGB(200,200,200)", "14:00"],
                [210, 0, "RGB(200,200,200)", "14:30"],
                [240, 1, "RGB(200,200,200)", "15:00"], // 15:00
            ],
            Simple: //简洁模式
            [
                [0, 0, "rgb(200,200,200)", "09:30"],
                [60, 0, "RGB(200,200,200)", "10:30"],
                [120, 1, "RGB(200,200,200)", "13:00"],
                [180, 0, "RGB(200,200,200)", "14:00"],
                [240, 1, "RGB(200,200,200)", "15:00"]
            ],
            Min:   //最小模式     
            [
                [0, 0, "rgb(200,200,200)", "09:30"],
                [120, 1, "RGB(200,200,200)", "13:00"],
                [240, 1, "RGB(200,200,200)", "15:00"]
            ],

            Count: 241,
            MiddleCount: 120,

            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.IsBJ(upperSymbol))
                data=this.GetBJData(upperSymbol,width);
            else if (MARKET_SUFFIX_NAME.IsSHO(upperSymbol) || MARKET_SUFFIX_NAME.IsSZO(upperSymbol))
                data=this.GetSHOData(upperSymbol,width);
            else if (MARKET_SUFFIX_NAME.IsHK(upperSymbol))
                data=this.GetHKData(upperSymbol,width);
            else if (MARKET_SUFFIX_NAME.IsCFFEX(upperSymbol) || MARKET_SUFFIX_NAME.IsCZCE(upperSymbol) || MARKET_SUFFIX_NAME.IsDCE(upperSymbol) || MARKET_SUFFIX_NAME.IsSHFE(upperSymbol))
                return this.GetChinatFuturesData(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);
            else if ((MARKET_SUFFIX_NAME.IsBIT(upperSymbol,width)))
                data=this.GetBITData(upperSymbol,width);
            else if (MARKET_SUFFIX_NAME.IsET(upperSymbol))
                data=this.GetETData(upperSymbol,width);
            else if (MARKET_SUFFIX_NAME.IsNYMEX(upperSymbol))
               return  data=this.GetNYMEXData(upperSymbol,width);
            else if (MARKET_SUFFIX_NAME.IsCOMEX(upperSymbol))
               return  data=this.GetCOMEXData(upperSymbol,width);
            else if (MARKET_SUFFIX_NAME.IsNYBOT(upperSymbol))
               return  data=this.GetNYBOTData(upperSymbol,width);
            else if (MARKET_SUFFIX_NAME.IsCBOT(upperSymbol))
               return  data=this.GetCBOTData(upperSymbol,width);
            else if (MARKET_SUFFIX_NAME.IsLME(upperSymbol))
               return  data=this.GetLMEData(upperSymbol,width);
            else if (MARKET_SUFFIX_NAME.IsTOCOM(upperSymbol))
                return  data=this.GetTOCOMData(upperSymbol,width);
            else if (MARKET_SUFFIX_NAME.IsIPE(upperSymbol))
                return  data=this.GetIPEData(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.GetBJData=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.GetHKData=function(upperSymbol,width)
    {
        var result=HK_MINUTE_X_COORDINATE;
        return result;
    }

    this.GetSHOData=function(upperSymbol,width)
    {
        var result=SHO_MINUTE_X_COORDINATE;
        return result;
    }

    this.GetFuturesData = function (upperSymbol,width,timeData)
    {
        var splitData = timeData.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.GetChinatFuturesData=function(upperSymbol,width)
    {
        return this.GetFuturesData(upperSymbol,width, g_FuturesTimeData);
    }

    this.GetNYMEXData=function(upperSymbol,width)
    {
        return this.GetFuturesData(upperSymbol,width, g_NYMEXTimeData);
    }

    this.GetCOMEXData=function(upperSymbol,width)
    {
        return this.GetFuturesData(upperSymbol,width, g_COMEXTimeData);
    }

    this.GetNYBOTData=function(upperSymbol,width)
    {
        return this.GetFuturesData(upperSymbol,width, g_NYBOTTimeData);
    }

    this.GetCBOTData=function(upperSymbol,width)
    {
        return this.GetFuturesData(upperSymbol,width, g_CBOTTimeData);
    }

    this.GetLMEData=function(upperSymbol,width)
    {
        return this.GetFuturesData(upperSymbol,width, g_LMETimeData);
    }

    this.GetTOCOMData=function(upperSymbol,width)
    {
        return this.GetFuturesData(upperSymbol,width, g_TOCOMTimeData);
    }

    this.GetIPEData=function(upperSymbol,width)
    {
        return this.GetFuturesData(upperSymbol,width, g_IPETimeData);
    }

    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.GetBITData=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()
{
    this.TIME_SPLIT=
    [
        //ID=0 9:00-10:15,10:31-11:30,13:31-15:00
        {
            Name:'9:00-10:15,10:31-11:30,13:31-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' },
                ]
            }
        },
        //ID=1 9:30-11:30,13:01-15:15
        {

            Name:'9:30-11:30,13:01-15:15',
            Data:
            [
                { Start: 930, 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' },
                ]
            }
        },
        //ID=2 '9:30-11:30,13:01-15:00'
        {
            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' },
                ]
            }
        },

        //ID=4 21:00-1:00,9:01-10:15,10:31-11:30,13:31-15:00
        {
            Name:'21:00-1:00,9:01-10:15,10:31-11:30,13:31-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' },
                ]
            }
        },

        //ID=5 21:00-2:30,9:01-10:15,10:31-11:30,13:31-15:00
        {
            Name:'21:00-2:30,9:01-10:15,10:31-11:30,13:31-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' },
                ]
            }
        },

        //ID:6 21:00-23:00,9:01-10:15,10:30-11:30,13:31-15:00
        {
            Name:'21:00-23:00,9:01-10:15,10:30-11:30,13:31-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' },
                ]
            }
        },
        {

            Name:'9:00-11:30,13:00-15:00',
            Data:
            [
                { Start: 900, End: 1130 },
                { Start: 1300, End: 1500 }
            ],
            Coordinate:
            {
                Full://完整模式
                [
                    { Value: 900, Text: '9:00' },
                    { 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: 900, Text: '9:00' },
                    { Value: 1000, Text: '10:00' },
                    { Value: 1300, Text: '13:00' },
                    { Value: 1400, Text: '14:00' },
                    { Value: 1500, Text: '15:00' },
                ],
                Min:   //最小模式  
                [
                    { Value: 900, Text: '9:00' },
                    { Value: 1300, Text: '13: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: 900, End: 1015 },
                { Start: 1030, End: 1130 },
                { Start: 1330, 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' },
                ]
            }
        },

        //ID=9 9:01-10:15,10:31-11:30,13:31-15:00
        {
            Name:'9:01-10:15,10:31-11:30,13:31-15:00',
            Data:
            [
                //9:01-10:15,10:31-11:30,13:31-15:00
                { Start: 901, End: 1015 },
                { Start: 1031, End: 1130 },
                { Start: 1331, End: 1500 }
            ],
            Coordinate:
            {
                Full://完整模式
                [
                    { Value: 901, 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: 901, 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: 901, Text: '9:00' },
                    { Value: 1330, Text: '13:30' },
                    { Value: 1500, Text: '15:00' },
                ]
            }
        },

        //ID=10 21:00-1:00,9:01-10:15,10:31-11:30,13:31-15:00
        {
            Name:'21:01-1:00,9:01-10:15,10:31-11:30,13:31-15:00',
            Data:
            [   
                { Start: 2101, End: 2359 },
                { Start: 0, End: 100 },
                { Start: 901, End: 1015 },
                { Start: 1031, End: 1130 },
                { Start: 1331, End: 1500 }
            ],
            Coordinate:
            {
                Full://完整模式
                [
                    { Value: 2101, 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: 2101, 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: 2101, Text: '21:00' },
                    { Value: 901, Text: '9:00' },
                    { Value: 1500, Text: '15:00' },
                ]
            }
        },

        //ID:11 21:01-23:00,9:01-10:15,10:30-11:30,13:31-15:00
        {
            Name:'21:01-23:00,9:01-10:15,10:30-11:30,13:31-15:00',
            Data:
            [
                { Start: 2101, End: 2300 },
                { Start: 901, End: 1015 },
                { Start: 1031, End: 1130 },
                { Start: 1331, End: 1500 }
            ],
            Coordinate:
            {
                Full://完整模式
                [
                    { Value: 2101, 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: 2101, Text: '21:00' },
                    { Value: 2300, Text: '23:00' },
                    { Value: 1331, Text: '13:30' },
                    { Value: 1500, Text: '15:00' },
                ],
                Min:   //最小模式  
                [
                    { Value: 2101, Text: '21:00' },
                    { Value: 2300, Text: '23:00' },
                    { Value: 1500, Text: '15:00' },
                ]
            }
        },

        //ID=12 21:01-2:30,9:01-10:15,10:31-11:30,13:31-15:00
        {
            Name:'21:01-2:30,9:01-10:15,10:31-11:30,13:31-15:00',
            Data:
            [
                { Start: 2101, End: 2359 },
                { Start: 0, End: 230 },
                { Start: 901, End: 1015 },
                { Start: 1031, End: 1130 },
                { Start: 1331, End: 1500 }
            ],
            Coordinate:
            {
                Full://完整模式
                [
                    { Value: 2101, 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: 2101, 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: 2101, Text: '21:00' },
                    { Value: 901, Text: '9:00' },
                    { Value: 1500, Text: '15:00' },
                ]
            }
        },

        //ID=13 9:31-11:30,13:01-15:15
        {

            Name:'9:30-11:30,13:01-15:15',
            Data:
            [
                { Start: 931, End: 1130 },
                { Start: 1301, End: 1515 }
            ],
            Coordinate:
            {
                Full://完整模式
                [
                    { Value: 931, Text: '9:30' },
                    { Value: 1000, Text: '10:00' },
                    { Value: 1030, Text: '10:30' },
                    { Value: 1100, Text: '11:00' },
                    { Value: 1301, 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: 931, Text: '9:30' },
                    { Value: 1030, Text: '10:30' },
                    { Value: 1301, Text: '13:00' },
                    { Value: 1400, Text: '14:00' },
                    { Value: 1515, Text: '15:15' },
                ],
                Min:   //最小模式  
                [
                    { Value: 931, Text: '9:30' },
                    { Value: 1301, Text: '13:00' },
                    { Value: 1515, Text: '15:15' },
                ]
            }
        },

         //ID=14 '9:31-11:30,13:01-15:00'
        {
            Name:'9:31-11:30,13:01-15:00',
            Data:
            [
                { Start: 931, End: 1130 },
                { Start: 1301, End: 1500 }
            ],
            Coordinate:
            {
                Full://完整模式
                [
                    { Value: 931, Text: '9:30' },
                    { Value: 1000, Text: '10:00' },
                    { Value: 1030, Text: '10:30' },
                    { Value: 1100, Text: '11:00' },
                    { Value: 1301, 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: 931, Text: '9:30' },
                    { Value: 1030, Text: '10:30' },
                    { Value: 1301, Text: '13:00' },
                    { Value: 1400, Text: '14:00' },
                    { Value: 1500, Text: '15:00' },
                ],
                Min:   //最小模式  
                [
                    { Value: 931, Text: '9:30' },
                    { Value: 1301, Text: '13:00' },
                    { Value: 1500, Text: '15:00' },
                ]
            }
        },
    ];

    this.MAP_TWOWORDS=new Map([
        //大连商品交易所
        [MARKET_SUFFIX_NAME.DCE + '-JD', {Time:0,Decimal:0,Name:"鸡蛋"}],
        [MARKET_SUFFIX_NAME.DCE + '-FB', {Time:0,Decimal:2,Name:"纤板"}],
        [MARKET_SUFFIX_NAME.DCE + '-BB', {Time:0,Decimal:2,Name:"胶板"}],
        [MARKET_SUFFIX_NAME.DCE + '-PP', {Time:6,Decimal:0,Name:"丙烯"}],
        [MARKET_SUFFIX_NAME.DCE + '-JM', {Time:6,Decimal:1,Name:'焦煤'}],
        [MARKET_SUFFIX_NAME.DCE + '-EG', {Time:6,Decimal:0,Name:'乙二醇'}],
        [MARKET_SUFFIX_NAME.DCE + '-EB', {Time:6,Decimal:0,Name:'苯乙烯'}],
        [MARKET_SUFFIX_NAME.DCE + '-CS', {Time:6,Decimal:0,Name:'淀粉'}],
        [MARKET_SUFFIX_NAME.DCE + '-PG', {Time:6,Decimal:0,Name:'液化气'}],
        [MARKET_SUFFIX_NAME.DCE + '-RR', {Time:6,Decimal:0,Name:'梗米'}],
        [MARKET_SUFFIX_NAME.DCE + '-LH', {Time:0,Decimal:0,Name:'生猪'}],

        //上期所
        [MARKET_SUFFIX_NAME.SHFE + '-CU', {Time:4,Decimal:0,Name:"铜"}],
        [MARKET_SUFFIX_NAME.SHFE + '-AL', {Time:4,Decimal:0,Name:"铝"}],
        [MARKET_SUFFIX_NAME.SHFE + '-NI', {Time:4,Decimal:0,Name:"镍"}],
        [MARKET_SUFFIX_NAME.SHFE + '-SN', {Time:4,Decimal:0,Name:'沪锡'}],
        [MARKET_SUFFIX_NAME.SHFE + '-ZN', {Time:4,Decimal:0,Name:"沪锌"}],
        [MARKET_SUFFIX_NAME.SHFE + '-PB', {Time:4,Decimal:0,Name:'沪铅'}],
        [MARKET_SUFFIX_NAME.SHFE + '-RU', {Time:6,Decimal:0,Name:"天然橡胶"}],
        [MARKET_SUFFIX_NAME.SHFE + '-FU', {Time:6,Decimal:0,Name:"燃料油"}],
        [MARKET_SUFFIX_NAME.SHFE + '-RB', {Time:6,Decimal:0,Name:"螺纹钢"}],
        [MARKET_SUFFIX_NAME.SHFE + '-BU', {Time:6,Decimal:0,Name:'石油沥青'}],
        [MARKET_SUFFIX_NAME.SHFE + '-HC', {Time:6,Decimal:0,Name:"热轧卷板"}],
        [MARKET_SUFFIX_NAME.SHFE + '-SP', {Time:6,Decimal:0,Name:"纸浆"}],
        [MARKET_SUFFIX_NAME.SHFE + '-WR', {Time:0,Decimal:0,Name:"线材"}],
        [MARKET_SUFFIX_NAME.SHFE + '-AG', {Time:5,Decimal:0,Name:"白银"}],
        [MARKET_SUFFIX_NAME.SHFE + '-AU', {Time:5,Decimal:2,Name:"黄金"}],
        [MARKET_SUFFIX_NAME.SHFE + '-SS', {Time:4,Decimal:0,Name:'不锈钢'}],

        //上期所-能源
        [MARKET_SUFFIX_NAME.SHFE + '-NR', {Time:6,Decimal:1,Name:'20号胶'}],
        [MARKET_SUFFIX_NAME.SHFE + '-SC', {Time:5,Decimal:1,Name:'原油'}],
        [MARKET_SUFFIX_NAME.SHFE + '-LU', {Time:6,Decimal:0,Name:'低硫燃油'}],
        [MARKET_SUFFIX_NAME.SHFE + '-BC', {Time:4,Decimal:0,Name:'国际铜'}],
       
        //郑州期货交易所
        [MARKET_SUFFIX_NAME.CZCE + '-CF', {Time:6,Decimal:0,Name:"棉花"}],
        [MARKET_SUFFIX_NAME.CZCE + '-SR', {Time:6,Decimal:0,Name:"白糖"}],
        [MARKET_SUFFIX_NAME.CZCE + '-MA', {Time:6,Decimal:0,Name:"甲醇"}],
        [MARKET_SUFFIX_NAME.CZCE + '-ZC', {Time:6,Decimal:1,Name:'动力煤'}],
        [MARKET_SUFFIX_NAME.CZCE + '-TA', {Time:6,Decimal:0,Name:"精对苯二甲酸(PTA)"}],
        [MARKET_SUFFIX_NAME.CZCE + '-RM', {Time:6,Decimal:0,Name:'菜籽粕'}],
        [MARKET_SUFFIX_NAME.CZCE + '-OI', {Time:6,Decimal:0,Name:"菜籽油"}],
        [MARKET_SUFFIX_NAME.CZCE + '-ME', {Time:3,Decimal:0,Name:"甲醇(老)"}],
        [MARKET_SUFFIX_NAME.CZCE + '-FG', {Time:6,Decimal:0,Name:'平板玻璃'}],
        [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,Name:"菜籽"}],
        [MARKET_SUFFIX_NAME.CZCE + '-ER', {Time:0,Decimal:0}],
        [MARKET_SUFFIX_NAME.CZCE + '-RI', {Time:0,Decimal:0,Name:"早籼稻"}],
        [MARKET_SUFFIX_NAME.CZCE + '-WH', {Time:0,Decimal:0,Name:"强麦"}],
        [MARKET_SUFFIX_NAME.CZCE + '-AP', {Time:0,Decimal:0,Name:"苹果"}],
        [MARKET_SUFFIX_NAME.CZCE + '-PM', {Time:0,Decimal:0,Name:"普麦"}],
        [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,Name:"粳稻"}],
        [MARKET_SUFFIX_NAME.CZCE + '-LR', {Time:0,Decimal:0,Name:"晚籼稻"}],
        [MARKET_SUFFIX_NAME.CZCE + '-SF', {Time:0,Decimal:0,Name:"硅铁"}],
        [MARKET_SUFFIX_NAME.CZCE + '-SM', {Time:0,Decimal:0,Name:"锰硅"}],
        [MARKET_SUFFIX_NAME.CZCE + '-CJ', {Time:0,Decimal:2, Name:"红枣"}],
        [MARKET_SUFFIX_NAME.CZCE + '-CY', {Time:6,Decimal:0, Name:"棉纱"}],
        [MARKET_SUFFIX_NAME.CZCE + '-UR', {Time:0,Decimal:0, Name:"尿素"}],
        [MARKET_SUFFIX_NAME.CZCE + '-SA', {Time:6,Decimal:0, Name:"纯碱"}],
        [MARKET_SUFFIX_NAME.CZCE + '-PF', {Time:6,Decimal:0, Name:"短纤"}],
        [MARKET_SUFFIX_NAME.CZCE + '-PK', {Time:0,Decimal:0, Name:"花生"}],


        //中期所 
        [MARKET_SUFFIX_NAME.CFFEX + '-TF', {Time:1,Decimal:3,Name:"二债"}],
        [MARKET_SUFFIX_NAME.CFFEX + '-TS', {Time:1,Decimal:3,Name:"五债"}],
        [MARKET_SUFFIX_NAME.CFFEX + '-IH', {Time:2,Decimal:1,Name:'上证股指期货'}],
        [MARKET_SUFFIX_NAME.CFFEX + '-IC', {Time:2,Decimal:1,Name:'中证股指期货'}],
        [MARKET_SUFFIX_NAME.CFFEX + '-IF', {Time:2,Decimal:1,Name:'沪深股指期货'}],
    ]);

    this.MAP_ONEWORD=new Map([
        //大连商品交易所
        [MARKET_SUFFIX_NAME.DCE + '-C', {Time:6,Decimal:0,Name:"玉米"}],
        [MARKET_SUFFIX_NAME.DCE + '-L', {Time:6,Decimal:0,Name:"乙烯"}],
        [MARKET_SUFFIX_NAME.DCE + '-V', {Time:6,Decimal:0,Name:"PVC"}],
        [MARKET_SUFFIX_NAME.DCE + '-A', {Time:6,Decimal:0,Name:"豆一"}],
        [MARKET_SUFFIX_NAME.DCE + '-B', {Time:6,Decimal:0,Name:"豆二"}],
        [MARKET_SUFFIX_NAME.DCE + '-M', {Time:6,Decimal:0,Name:"豆粕"}],
        [MARKET_SUFFIX_NAME.DCE + '-Y', {Time:6,Decimal:0,Name:"豆油"}],
        [MARKET_SUFFIX_NAME.DCE + '-P', {Time:6,Decimal:0,Name:"棕榈"}],
        [MARKET_SUFFIX_NAME.DCE + '-J', {Time:6,Decimal:1,Name:'焦炭'}],
        [MARKET_SUFFIX_NAME.DCE + '-I', {Time:6,Decimal:1,Name:"铁矿"}],
        //中期所 
        [MARKET_SUFFIX_NAME.CFFEX + '-T', {Time:1,Decimal:3,Name:"十债"}],
    ]);

    //添加新品种
    this.AddNewFutures=function(obj)    //{ Suffix:后缀, Symbol:品种代码, Time:交易时间段, Decimal:小数位数, Name:名字 }
    {
        if (!obj) return;

        var key=obj.Suffix+'-'+obj.Symbol;
        var item={ Time:obj.Time, Decimal:obj.Decimal, Name:obj.Name };
        if (obj.Symbol.length==1)
        {
            this.MAP_ONEWORD.set(key, item);
        }
        else if (obj.Symbol.length==2)
        {
            this.MAP_TWOWORDS.set(key, item);
        }
    }

    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 (this.MAP_TWOWORDS.has(twoWordsName))
        {
            return this.MAP_TWOWORDS.get(twoWordsName);
        }

        if (this.MAP_ONEWORD.has(oneWordName))
        {
            return this.MAP_ONEWORD.get(oneWordName);
        }

        return null;
    }

    this.GetSplitData = function (upperSymbol)
    {
        var data=this.GetData(upperSymbol);
        if (!data) return null;

        return this.TIME_SPLIT[data.Time];
    }

    this.GetDecimal=function(upperSymbol)
    {
        var data=this.GetData(upperSymbol);
        if (!data) return 2;

        return data.Decimal;
    }
}


//纽约商业交易所 交易时间数据 
function NYMEXTimeData()
{
    //美国标准时间
    this.TIME_SPLIT=
    [
        {
            Name:'6:00-5:00',
            Data:
            [
                //6:00 - 5:00
                { Start: 600, End: 2359 },
                { Start: 0, End: 500 },
            ],
            Coordinate:
            {
                Full://完整模式
                [
                    { Value: 600, Text: '6:00' },
                    { Value: 800, Text: '8:00' },
                    { Value: 1000, Text: '10:00' },
                    { Value: 1200, Text: '12:00' },
                    { Value: 1400, Text: '14:00' },
                    { Value: 1600, Text: '16:00' },
                    { Value: 1800, Text: '18:00' },
                    { Value: 2000, Text: '20:00' },
                    { Value: 2200, Text: '22:00' },
                    { Value: 0, Text: '0:00' },
                    { Value: 200, Text: '2:00' },
                    { Value: 400, Text: '4:00' },
                ],
                Simple: //简洁模式
                [
                    { Value: 600, Text: '6:00' },
                    //{ Value: 800, Text: '8:00' },
                    { Value: 1000, Text: '10:00' },
                    //{ Value: 1200, Text: '12:00' },
                    { Value: 1400, Text: '14:00' },
                    //{ Value: 1600, Text: '16:00' },
                    { Value: 1800, Text: '18:00' },
                    //{ Value: 2000, Text: '20:00' },
                    { Value: 2200, Text: '22:00' },
                    //{ Value: 0, Text: '0:00' },
                    { Value: 200, Text: '2:00' }
                    //{ Value: 400, Text: '4:00' },
                ],
                Min:   //最小模式  
                [
                    { Value: 600, Text: '6:00' },
                    { Value: 1800, Text: '18:00' },
                    { Value: 500, Text: '5:00' }
                ]
            }
        }
    ]

    //美国夏时令
    this.TIME_SPLIT2=
    [
        {
            Name:'7:00-6:00',
            Data:
            [
                //6:00 - 5:00
                { Start: 700, End: 2359 },
                { Start: 0, End: 600 },
            ],
            Coordinate:
            {
                Full://完整模式
                [
                    { Value: 700, Text: '7:00' },
                    { Value: 900, Text: '9:00' },
                    { Value: 1100, Text: '11:00' },
                    { Value: 1300, Text: '13:00' },
                    { Value: 1500, Text: '15:00' },
                    { Value: 1700, Text: '17:00' },
                    { Value: 1900, Text: '19:00' },
                    { Value: 2100, Text: '21:00' },
                    { Value: 2300, Text: '23:00' },
                    { Value: 1, Text: '1:00' },
                    { Value: 300, Text: '3:00' },
                    { Value: 500, Text: '5:00' }
                ],
                Simple: //简洁模式
                [
                    { Value: 700, Text: '7:00' },
                    //{ Value: 900, Text: '9:00' },
                    { Value: 1100, Text: '11:00' },
                    //{ Value: 1300, Text: '13:00' },
                    { Value: 1500, Text: '15:00' },
                    //{ Value: 1700, Text: '17:00' },
                    { Value: 1900, Text: '19:00' },
                    //{ Value: 2100, Text: '21:00' },
                    { Value: 2300, Text: '23:00' },
                    //{ Value: 1, Text: '1:00' },
                    { Value: 300, Text: '3:00' }
                    //{ Value: 500, Text: '5:00' }
                ],
                Min:   //最小模式  
                [
                    { Value: 700, Text: '7:00' },
                    { Value: 1900, Text: '19:00' },
                    { Value: 500, Text: '5:00' }
                ]
            }
        }
    ]

    this.FUTURES_LIST=
    [
        { Symbol:"CL", Decimal:2, Time:0, Name:"原油"}, //原油
        { Symbol:"NG", Decimal:3, Time:0, Name:"天然气" }, //天然气
        { Symbol:"RB", Decimal:4, Time:0, Name:"汽油" }, //汽油
        { Symbol:"PL", Decimal:1, Time:0, Name:"铂金" }, //铂金
        { Symbol:"PA", Decimal:2, Time:0, Name:"钯金" }, //钯金
        { Symbol:"HR", Decimal:0, Time:0, Name:"热轧钢卷" }, //热轧钢卷
        { Symbol:"QM", Decimal:3, Time:0, Name:"迷你原油" }, //迷你原油
        { Symbol:"HO", Decimal:4, Time:0, Name:"燃油"}, //燃油
    ]

    this.MarketSuffix=".NYMEX";
    this.TimeType=0; // 0=标准时间 1=夏令时间 2=美国时间

    this.GetFuturesInfo=function(upperSymbol)
    {
        if (upperSymbol.indexOf(this.MarketSuffix)<=0) return null;

        for(var i in this.FUTURES_LIST)
        {
            var item=this.FUTURES_LIST[i];
            if (upperSymbol.indexOf(item.Symbol)==0)
            {
                return item;
            }
        }

        return null;
    }

    this.GetSplitData=function(upperSymbol)
    {
        //夏令和标准时间切换
        var timeSplit=this.TimeType==0 ? this.TIME_SPLIT : this.TIME_SPLIT2;
        var find=this.GetFuturesInfo(upperSymbol);
        if (find) return timeSplit[find.Time];

        return timeSplit[0];
    }

    this.GetDecimal=function(upperSymbol)
    {
        var find=this.GetFuturesInfo(upperSymbol);
        if (find) return find.Decimal;

        return 3;
    }

    this.GetMarketStatus=function(upperSymbol) // 0=闭市 1=盘前 2=盘中 3=盘后
    {
        var usaDate=GetLocalTime(-4);   //需要转成美国时间的 周6 周日
        var nowDate= new Date();
        var day = usaDate.getDay();
        var time = nowDate.getHours() * 100 + nowDate.getMinutes();
        if(day == 6 || day== 0) return 0;   //周末
        if(time>430 && time<730) return 1;

        return 2;   
    }

    this.AddNewFutures=function(obj) //{ Symbol:品种代码, Time:时间id, Decimal:小数位数, Name:名字 }
    {
        if (!obj) return;

        var newItem={ Symbol:obj.Symbol, Time:obj.Time, Decimal:obj.Decimal, Name:obj.Name };
        for(var i=0;i<this.FUTURES_LIST.length;++i)
        {
            var item=this.FUTURES_LIST[i];
            if (item.Symbol==newItem.Symbol) 
            {
                this.FUTURES_LIST[i]=newItem;
                return;
            }
        }
        
        this.FUTURES_LIST.push(newItem);
    }
}

//纽约金属交易所（COMEX）
function COMEXTimeData()
{
    this.newMethod=NYMEXTimeData;   //派生
    this.newMethod();
    delete this.newMethod;

    this.FUTURES_LIST=
    [
        { Symbol:"GC", Decimal:1, Time:0, Name:"COMEX黄金"}, //COMEX黄金
        { Symbol:"QO", Decimal:2, Time:0, Name:"迷你黄金" }, //迷你黄金
        { Symbol:"MG", Decimal:1, Time:0, Name:"微型黄金" }, //微型黄金
        { Symbol:"QI", Decimal:4, Time:0, Name:"迷你白银" }, //迷你白银
        { Symbol:"SI", Decimal:3, Time:0, Name:"COMEX白银" }, //COMEX白银
        { Symbol:"HG", Decimal:4, Time:0, Name:"COMEX铜" }  //COMEX铜
    ]

    this.MarketSuffix=".COMEX";
}

//纽约期货交易所（ICEUS-NYBOT）
function NYBOTTimeData()
{
    this.newMethod=NYMEXTimeData;   //派生
    this.newMethod();
    delete this.newMethod;

    //美国标准时间
    this.TIME_SPLIT=
    [
        {
            Name:'9:00-2:20',
            Data:
            [
                //9:00-2:20
                { Start: 900, End: 2359 },
                { Start: 0, End: 220 },
            ],
            Coordinate:
            {
                Full://完整模式
                [
                    { Value: 900, Text: '9:00' },
                    { Value: 1100, Text: '11:00' },
                    { Value: 1300, Text: '13:00' },
                    { Value: 1500, Text: '15:00' },
                    { Value: 1700, Text: '17:00' },
                    { Value: 1900, Text: '19:00' },
                    { Value: 2100, Text: '21:00' },
                    { Value: 2300, Text: '23:00' },
                    { Value: 100, Text: '1:00' }
                ],
                Simple: //简洁模式
                [
                    { Value: 900, Text: '9:00' },
                    //{ Value: 1100, Text: '11:00' },
                    { Value: 1300, Text: '13:00' },
                    //{ Value: 1500, Text: '15:00' },
                    { Value: 1700, Text: '17:00' },
                    //{ Value: 1900, Text: '19:00' },
                    { Value: 2100, Text: '21:00' },
                    //{ Value: 2300, Text: '23:00' },
                    { Value: 100, Text: '1:00' }
                ],
                Min:   //最小模式  
                [
                    { Value: 900, Text: '9:00' },
                    { Value: 1700, Text: '17:00' },
                    { Value: 100, Text: '1:00' }
                ]
            }
        },
        {
            Name:'15:30-1:00',
            Data:
            [
                //9:00-2:20
                { Start: 1530, End: 2359 },
                { Start: 0, End: 100 },
            ],
            Coordinate:
            {
                Full://完整模式
                [
                    { Value: 1600, Text: '16:00' },
                    { Value: 1700, Text: '17:00' },
                    { Value: 1800, Text: '18:00' },
                    { Value: 1900, Text: '19:00' },
                    { Value: 2000, Text: '20:00' },
                    { Value: 2100, Text: '21:00' },
                    { Value: 2200, Text: '22:00' },
                    { Value: 2300, Text: '23:00' },
                    { Value: 0, Text: '0:00' },
                    { Value: 100, Text: '1:00' }
                ],
                Simple: //简洁模式
                [
                    { Value: 1600, Text: '16:00' },
                    //{ Value: 1600, Text: '17:00' },
                    { Value: 1800, Text: '18:00' },
                    //{ Value: 1900, Text: '19:00' },
                    { Value: 2000, Text: '20:00' },
                    //{ Value: 2100, Text: '21:00' },
                    { Value: 2200, Text: '22:00' },
                    //{ Value: 2300, Text: '23:00' },
                    { Value: 0, Text: '0:00' },
                    //{ Value: 100, Text: '1:00' }
                ],
                Min:   //最小模式  
                [
                    { Value: 1600, Text: '16:00' },
                    { Value: 2100, Text: '21:00' },
                    { Value: 100, Text: '1:00' }
                ]
            }
        }
    ]

    //美国夏时令
    this.TIME_SPLIT2=
    [
        {
            Name:'10:00-3:20',
            Data:
            [
                //9:00-2:20
                { Start: 1000, End: 2359 },
                { Start: 0, End: 320 },
            ],
            Coordinate:
            {
                Full://完整模式
                [
                    { Value: 1000, Text: '10:00' },
                    { Value: 1200, Text: '12:00' },
                    { Value: 1400, Text: '14:00' },
                    { Value: 1600, Text: '16:00' },
                    { Value: 1800, Text: '18:00' },
                    { Value: 2000, Text: '20:00' },
                    { Value: 2200, Text: '22:00' },
                    { Value: 0, Text: '0:00' },
                    { Value: 200, Text: '2:00' }
                ],
                Simple: //简洁模式
                [
                    { Value: 1000, Text: '10:00' },
                    //{ Value: 1200, Text: '12:00' },
                    { Value: 1400, Text: '14:00' },
                    //{ Value: 1600, Text: '16:00' },
                    { Value: 1800, Text: '18:00' },
                    //{ Value: 2000, Text: '20:00' },
                    { Value: 2200, Text: '22:00' },
                    //{ Value: 0, Text: '0:00' },
                    { Value: 200, Text: '2:00' }
                ],
                Min:   //最小模式  
                [
                    { Value: 1000, Text: '10:00' },
                    { Value: 1800, Text: '18:00' },
                    { Value: 200, Text: '2:00' }
                ]
            }
        },
        {
            Name:'16:30-2:00',
            Data:
            [
                { Start: 1630, End: 2359 },
                { Start: 0, End: 200 },
            ],
            Coordinate:
            {
                Full://完整模式
                [
                    { Value: 1700, Text: '17:00' },
                    { Value: 1800, Text: '18:00' },
                    { Value: 1900, Text: '19:00' },
                    { Value: 2000, Text: '20:00' },
                    { Value: 2100, Text: '21:00' },
                    { Value: 2200, Text: '22:00' },
                    { Value: 2300, Text: '23:00' },
                    { Value: 0, Text: '0:00' },
                    { Value: 100, Text: '1:00' },
                    { Value: 200, Text: '2:00' }
                ],
                Simple: //简洁模式
                [
                    { Value: 1700, Text: '17:00' },
                    //{ Value: 1800, Text: '18:00' },
                    { Value: 1900, Text: '19:00' },
                    //{ Value: 2000, Text: '20:00' },
                    { Value: 2100, Text: '21:00' },
                    //{ Value: 2200, Text: '22:00' },
                    { Value: 2300, Text: '23:00' },
                    //{ Value: 0, Text: '0:00' },
                    { Value: 100, Text: '1:00' }
                    //{ Value: 200, Text: '2:00' }
                ],
                Min:   //最小模式  
                [
                    { Value: 1700, Text: '17:00' },
                    { Value: 2100, Text: '21:00' },
                    { Value: 200, Text: '2:00' }
                ]
            }
        }
    ]

    this.FUTURES_LIST=
    [
        { Symbol:"SB", Decimal:2, Time:1 }, //11号白糖
        { Symbol:"CT", Decimal:2, Time:0 }, //棉花
        //{ Symbol:"KC", Decimal:2, Time:0 }, //咖啡
        //{ Symbol:"DX", Decimal:2, Time:0 }, //美元指数
        //{ Symbol:"CC", Decimal:2, Time:0 }  //可可
    ]

    this.MarketSuffix=".NYBOT";

    this.GetMarketStatus=function(upperSymbol) // 0=闭市 1=盘前 2=盘中 3=盘后
    {
        var usaDate=GetLocalTime(-4);   //需要转成美国时间的 周6 周日
        var day = usaDate.getDay();
        var time = usaDate.getHours() * 100 + usaDate.getMinutes();
        if(day == 6 || day== 0) return 0;   //周末

        var find=this.GetFuturesInfo(upperSymbol);
        if (!find) return 2;
        
        if (find.Symbol=="SB")  //Sugar No. 11 Futures 03:30 - 13:00
        {
            if (time>300 && time<1400) return 2;
        }
        else if (find.Symbol=="CT") //美棉 21:00-14:20 
        {
            if( (time>=0 && time<=1500 ) || (time>=2000 && time<=2359) ) return 2;
            return 1;
        }

        return 0;   
    }
}

//芝加哥期货交易所
function CBOTTimeData()
{
    this.newMethod=NYMEXTimeData;   //派生
    this.newMethod();
    delete this.newMethod;

    //标准时间
    this.TIME_SPLIT=
    [
        //ID=0 8:00-2:20
        {
            Name:'8:00-2:20',
            Data:
            [
                //6:00 - 5:00
                { Start: 800, End: 2359 },
                { Start: 0, End: 220 },
            ],
            Coordinate:
            {
                Full://完整模式
                [
                    { Value: 800, Text: '8:00' },
                    { Value: 1000, Text: '10:00' },
                    { Value: 1200, Text: '12:00' },
                    { Value: 1400, Text: '14:00' },
                    { Value: 1600, Text: '16:00' },
                    { Value: 1800, Text: '18:00' },
                    { Value: 2000, Text: '20:00' },
                    { Value: 2200, Text: '22:00' },
                    { Value: 0, Text: '0:00' },
                    { Value: 200, Text: '2:00' }
                ],
                Simple: //简洁模式
                [
                    { Value: 800, Text: '8:00' },
                    //{ Value: 1000, Text: '10:00' },
                    { Value: 1200, Text: '12:00' },
                    //{ Value: 1400, Text: '14:00' },
                    { Value: 1600, Text: '16:00' },
                    //{ Value: 1800, Text: '18:00' },
                    { Value: 2000, Text: '20:00' },
                    //{ Value: 2200, Text: '22:00' },
                    { Value: 0, Text: '0:00' }
                    //{ Value: 200, Text: '2:00' }
                ],
                Min:   //最小模式  
                [
                    { Value: 800, Text: '8:00' },
                    { Value: 1800, Text: '18:00' },
                    { Value: 200, Text: '2:00' }
                ]
            }
        },
        //ID=1 8:00-2:45
        {
            Name:'8:00-2:45',
            Data:
            [
                //6:00 - 5:00
                { Start: 800, End: 2359 },
                { Start: 0, End: 245 },
            ],
            Coordinate:
            {
                Full://完整模式
                [
                    { Value: 800, Text: '8:00' },
                    { Value: 1000, Text: '10:00' },
                    { Value: 1200, Text: '12:00' },
                    { Value: 1400, Text: '14:00' },
                    { Value: 1600, Text: '16:00' },
                    { Value: 1800, Text: '18:00' },
                    { Value: 2000, Text: '20:00' },
                    { Value: 2200, Text: '22:00' },
                    { Value: 0, Text: '0:00' },
                    { Value: 200, Text: '2:00' }
                ],
                Simple: //简洁模式
                [
                    { Value: 800, Text: '8:00' },
                    //{ Value: 1000, Text: '10:00' },
                    { Value: 1200, Text: '12:00' },
                    //{ Value: 1400, Text: '14:00' },
                    { Value: 1600, Text: '16:00' },
                    //{ Value: 1800, Text: '18:00' },
                    { Value: 2000, Text: '20:00' },
                    //{ Value: 2200, Text: '22:00' },
                    { Value: 0, Text: '0:00' }
                    //{ Value: 200, Text: '2:00' }
                ],
                Min:   //最小模式  
                [
                    { Value: 800, Text: '8:00' },
                    { Value: 1800, Text: '18:00' },
                    { Value: 200, Text: '2:00' }
                ]
            }
        },
        //ID=2 6:00-5:00
        {
            Name:'6:00-5:00',
            Data:
            [
                //6:00 - 5:00
                { Start: 600, End: 2359 },
                { Start: 0, End: 500 },
            ],
            Coordinate:
            {
                Full://完整模式
                [
                    { Value: 600, Text: '6:00' },
                    { Value: 800, Text: '8:00' },
                    { Value: 1000, Text: '10:00' },
                    { Value: 1200, Text: '12:00' },
                    { Value: 1400, Text: '14:00' },
                    { Value: 1600, Text: '16:00' },
                    { Value: 1800, Text: '18:00' },
                    { Value: 2000, Text: '20:00' },
                    { Value: 2200, Text: '22:00' },
                    { Value: 0, Text: '0:00' },
                    { Value: 200, Text: '2:00' },
                    { Value: 400, Text: '4:00' },
                ],
                Simple: //简洁模式
                [
                    { Value: 600, Text: '6:00' },
                    //{ Value: 800, Text: '8:00' },
                    { Value: 1000, Text: '10:00' },
                    //{ Value: 1200, Text: '12:00' },
                    { Value: 1400, Text: '14:00' },
                    //{ Value: 1600, Text: '16:00' },
                    { Value: 1800, Text: '18:00' },
                    //{ Value: 2000, Text: '20:00' },
                    { Value: 2200, Text: '22:00' },
                    //{ Value: 0, Text: '0:00' },
                    { Value: 200, Text: '2:00' }
                    //{ Value: 400, Text: '4:00' },
                ],
                Min:   //最小模式  
                [
                    { Value: 600, Text: '6:00' },
                    { Value: 1800, Text: '18:00' },
                    { Value: 500, Text: '5:00' }
                ]
            }
        },

        //ID=3 08:00-20:45 21:31-02:20
        {
            Name:'08:00-20:45 21:31-02:20',
            Data:
            [
                { Start: 800, End: 2045 },
                { Start: 2131, End: 2359 },
                { Start: 0, End: 220 },
            ],
            Coordinate:
            {
                Full://完整模式
                [
                    { Value: 800, Text: '8:00' },
                    { Value: 1000, Text: '10:00' },
                    { Value: 1200, Text: '12:00' },
                    { Value: 1400, Text: '14:00' },
                    { Value: 1600, Text: '16:00' },
                    { Value: 1800, Text: '18:00' },
                    { Value: 2000, Text: '20:00' },
                    { Value: 2200, Text: '22:00' },
                    { Value: 0, Text: '0:00' },
                    { Value: 200, Text: '2:00' }
                ],
                Simple: //简洁模式
                [
                    { Value: 800, Text: '8:00' },
                    //{ Value: 1000, Text: '10:00' },
                    { Value: 1200, Text: '12:00' },
                    //{ Value: 1400, Text: '14:00' },
                    { Value: 1600, Text: '16:00' },
                    //{ Value: 1800, Text: '18:00' },
                    { Value: 2000, Text: '20:00' },
                    //{ Value: 2200, Text: '22:00' },
                    { Value: 0, Text: '0:00' }
                    //{ Value: 200, Text: '2:00' }
                ],
                Min:   //最小模式  
                [
                    { Value: 800, Text: '8:00' },
                    { Value: 1800, Text: '18:00' },
                    { Value: 200, Text: '2:00' }
                ]
            }
        },

        //ID=4 8:00-20:45 21:31-2:45
        {
            Name:'8:00-2:45',
            Data:
            [
                { Start: 800, End: 2045 },
                { Start: 2131, End: 2359 },
                { Start: 0, End: 245 },
            ],
            Coordinate:
            {
                Full://完整模式
                [
                    { Value: 800, Text: '8:00' },
                    { Value: 1000, Text: '10:00' },
                    { Value: 1200, Text: '12:00' },
                    { Value: 1400, Text: '14:00' },
                    { Value: 1600, Text: '16:00' },
                    { Value: 1800, Text: '18:00' },
                    { Value: 2000, Text: '20:00' },
                    { Value: 2200, Text: '22:00' },
                    { Value: 0, Text: '0:00' },
                    { Value: 200, Text: '2:00' }
                ],
                Simple: //简洁模式
                [
                    { Value: 800, Text: '8:00' },
                    //{ Value: 1000, Text: '10:00' },
                    { Value: 1200, Text: '12:00' },
                    //{ Value: 1400, Text: '14:00' },
                    { Value: 1600, Text: '16:00' },
                    //{ Value: 1800, Text: '18:00' },
                    { Value: 2000, Text: '20:00' },
                    //{ Value: 2200, Text: '22:00' },
                    { Value: 0, Text: '0:00' }
                    //{ Value: 200, Text: '2:00' }
                ],
                Min:   //最小模式  
                [
                    { Value: 800, Text: '8:00' },
                    { Value: 1800, Text: '18:00' },
                    { Value: 200, Text: '2:00' }
                ]
            }
        },

        //ID=5 06:00-04:15 04:31-05:00
        {
            Name:'06:00-04:15 04:31-05:00',
            Data:
            [
                { Start: 600, End: 2359 },
                { Start: 0, End: 415 },
                { Start: 431, End: 500 },
            ],
            Coordinate:
            {
                Full://完整模式
                [
                    { Value: 600, Text: '6:00' },
                    { Value: 800, Text: '8:00' },
                    { Value: 1000, Text: '10:00' },
                    { Value: 1200, Text: '12:00' },
                    { Value: 1400, Text: '14:00' },
                    { Value: 1600, Text: '16:00' },
                    { Value: 1800, Text: '18:00' },
                    { Value: 2000, Text: '20:00' },
                    { Value: 2200, Text: '22:00' },
                    { Value: 0, Text: '0:00' },
                    { Value: 200, Text: '2:00' },
                    { Value: 400, Text: '4:00' },
                ],
                Simple: //简洁模式
                [
                    { Value: 600, Text: '6:00' },
                    //{ Value: 800, Text: '8:00' },
                    { Value: 1000, Text: '10:00' },
                    //{ Value: 1200, Text: '12:00' },
                    { Value: 1400, Text: '14:00' },
                    //{ Value: 1600, Text: '16:00' },
                    { Value: 1800, Text: '18:00' },
                    //{ Value: 2000, Text: '20:00' },
                    { Value: 2200, Text: '22:00' },
                    //{ Value: 0, Text: '0:00' },
                    { Value: 200, Text: '2:00' }
                    //{ Value: 400, Text: '4:00' },
                ],
                Min:   //最小模式  
                [
                    { Value: 600, Text: '6:00' },
                    { Value: 1800, Text: '18:00' },
                    { Value: 500, Text: '5:00' }
                ]
            }
        }
    ]

    //夏令时间
    this.TIME_SPLIT2=
    [
        //ID=0 9:00-3:20
        {
            Name:'9:00-3:20',
            Data:
            [
                { Start: 900, End: 2359 },
                { Start: 0, End: 320 },
            ],
            Coordinate:
            {
                Full://完整模式
                [
                    { Value: 900, Text: '9:00' },
                    { Value: 1100, Text: '11:00' },
                    { Value: 1300, Text: '13:00' },
                    { Value: 1500, Text: '15:00' },
                    { Value: 1700, Text: '17:00' },
                    { Value: 1900, Text: '19:00' },
                    { Value: 2100, Text: '21:00' },
                    { Value: 2300, Text: '23:00' },
                    { Value: 1, Text: '1:00' },
                    { Value: 300, Text: '3:00' }
                ],
                Simple: //简洁模式
                [
                    { Value: 900, Text: '9:00' },
                    //{ Value: 1100, Text: '11:00' },
                    { Value: 1300, Text: '13:00' },
                    //{ Value: 1500, Text: '15:00' },
                    { Value: 1700, Text: '17:00' },
                    //{ Value: 1900, Text: '19:00' },
                    { Value: 2100, Text: '21:00' },
                    //{ Value: 2300, Text: '23:00' },
                    { Value: 1, Text: '1:00' }
                    //{ Value: 300, Text: '3:00' }
                ],
                Min:   //最小模式  
                [
                    { Value: 900, Text: '9:00' },
                    { Value: 1900, Text: '19:00' },
                    { Value: 300, Text: '3:00' }
                ]
            }
        },
        //ID=1 9:00-3:45
        {
            Name:'9:00-3:45',
            Data:
            [
                { Start: 900, End: 2359 },
                { Start: 0, End: 345 },
            ],
            Coordinate:
            {
                Full://完整模式
                [
                    { Value: 900, Text: '9:00' },
                    { Value: 1100, Text: '11:00' },
                    { Value: 1300, Text: '13:00' },
                    { Value: 1500, Text: '15:00' },
                    { Value: 1700, Text: '17:00' },
                    { Value: 1900, Text: '19:00' },
                    { Value: 2100, Text: '21:00' },
                    { Value: 2300, Text: '23:00' },
                    { Value: 1, Text: '1:00' },
                    { Value: 300, Text: '3:00' }
                ],
                Simple: //简洁模式
                [
                    { Value: 900, Text: '9:00' },
                    //{ Value: 1100, Text: '11:00' },
                    { Value: 1300, Text: '13:00' },
                    //{ Value: 1500, Text: '15:00' },
                    { Value: 1700, Text: '17:00' },
                    //{ Value: 1900, Text: '19:00' },
                    { Value: 2100, Text: '21:00' },
                    //{ Value: 2300, Text: '23:00' },
                    { Value: 1, Text: '1:00' }
                    //{ Value: 300, Text: '3:00' }
                ],
                Min:   //最小模式  
                [
                    { Value: 900, Text: '9:00' },
                    { Value: 1900, Text: '19:00' },
                    { Value: 300, Text: '3:00' }
                ]
            }
        },
        //ID=2 7:00-6:00
        {
            Name:'7:00-6:00',
            Data:
            [
                { Start: 700, End: 2359 },
                { Start: 0, End: 600 },
            ],
            Coordinate:
            {
                Full://完整模式
                [
                    { Value: 700, Text: '7:00' },
                    { Value: 900, Text: '9:00' },
                    { Value: 1100, Text: '11:00' },
                    { Value: 1300, Text: '13:00' },
                    { Value: 1500, Text: '15:00' },
                    { Value: 1700, Text: '17:00' },
                    { Value: 1900, Text: '19:00' },
                    { Value: 2100, Text: '21:00' },
                    { Value: 2300, Text: '23:00' },
                    { Value: 1, Text: '1:00' },
                    { Value: 300, Text: '3:00' },
                    { Value: 500, Text: '5:00' }
                ],
                Simple: //简洁模式
                [
                    { Value: 700, Text: '7:00' },
                    //{ Value: 900, Text: '9:00' },
                    { Value: 1100, Text: '11:00' },
                    //{ Value: 1300, Text: '13:00' },
                    { Value: 1500, Text: '15:00' },
                    //{ Value: 1700, Text: '17:00' },
                    { Value: 1900, Text: '19:00' },
                    //{ Value: 2100, Text: '21:00' },
                    { Value: 2300, Text: '23:00' },
                    //{ Value: 1, Text: '1:00' },
                    { Value: 300, Text: '3:00' }
                    //{ Value: 500, Text: '5:00' }
                ],
                Min:   //最小模式  
                [
                    { Value: 700, Text: '7:00' },
                    { Value: 1800, Text: '18:00' },
                    { Value: 500, Text: '5:00' }
                ]
            }
        },

        //ID=3 09:00-21:45 22:31-03:20
        {
            Name:'09:00-21:45 22:31-03:20',
            Data:
            [
                { Start: 900, End: 2145 },
                { Start: 2231, End: 2359 },
                { Start: 0, End: 320 },
            ],
            Coordinate:
            {
                Full://完整模式
                [
                    { Value: 900, Text: '9:00' },
                    { Value: 1100, Text: '11:00' },
                    { Value: 1300, Text: '13:00' },
                    { Value: 1500, Text: '15:00' },
                    { Value: 1700, Text: '17:00' },
                    { Value: 1900, Text: '19:00' },
                    { Value: 2100, Text: '21:00' },
                    { Value: 2300, Text: '23:00' },
                    { Value: 1, Text: '1:00' },
                    { Value: 300, Text: '3:00' }
                ],
                Simple: //简洁模式
                [
                    { Value: 900, Text: '9:00' },
                    //{ Value: 1100, Text: '11:00' },
                    { Value: 1300, Text: '13:00' },
                    //{ Value: 1500, Text: '15:00' },
                    { Value: 1700, Text: '17:00' },
                    //{ Value: 1900, Text: '19:00' },
                    { Value: 2100, Text: '21:00' },
                    //{ Value: 2300, Text: '23:00' },
                    { Value: 1, Text: '1:00' }
                    //{ Value: 300, Text: '3:00' }
                ],
                Min:   //最小模式  
                [
                    { Value: 900, Text: '9:00' },
                    { Value: 1900, Text: '19:00' },
                    { Value: 300, Text: '3:00' }
                ]
            }
        },

        //ID=4 09:00-21:45 22:31-03:45
        {
            Name:'09:00-21:45 22:31-03:45',
            Data:
            [
                { Start: 900, End: 2145 },
                { Start: 2231, End: 2359 },
                { Start: 0, End: 345 },
            ],
            Coordinate:
            {
                Full://完整模式
                [
                    { Value: 900, Text: '9:00' },
                    { Value: 1100, Text: '11:00' },
                    { Value: 1300, Text: '13:00' },
                    { Value: 1500, Text: '15:00' },
                    { Value: 1700, Text: '17:00' },
                    { Value: 1900, Text: '19:00' },
                    { Value: 2100, Text: '21:00' },
                    { Value: 2300, Text: '23:00' },
                    { Value: 1, Text: '1:00' },
                    { Value: 300, Text: '3:00' }
                ],
                Simple: //简洁模式
                [
                    { Value: 900, Text: '9:00' },
                    //{ Value: 1100, Text: '11:00' },
                    { Value: 1300, Text: '13:00' },
                    //{ Value: 1500, Text: '15:00' },
                    { Value: 1700, Text: '17:00' },
                    //{ Value: 1900, Text: '19:00' },
                    { Value: 2100, Text: '21:00' },
                    //{ Value: 2300, Text: '23:00' },
                    { Value: 1, Text: '1:00' }
                    //{ Value: 300, Text: '3:00' }
                ],
                Min:   //最小模式  
                [
                    { Value: 900, Text: '9:00' },
                    { Value: 1900, Text: '19:00' },
                    { Value: 300, Text: '3:00' }
                ]
            }
        },

        //ID=5 07:00-05:15 05:31-06:00
        {
            Name:'07:00-05:15 05:31-06:00',
            Data:
            [
                { Start: 700, End: 2359 },
                { Start: 0, End: 515 },
                { Start: 531, End: 600 },
            ],
            Coordinate:
            {
                Full://完整模式
                [
                    { Value: 700, Text: '7:00' },
                    { Value: 900, Text: '9:00' },
                    { Value: 1100, Text: '11:00' },
                    { Value: 1300, Text: '13:00' },
                    { Value: 1500, Text: '15:00' },
                    { Value: 1700, Text: '17:00' },
                    { Value: 1900, Text: '19:00' },
                    { Value: 2100, Text: '21:00' },
                    { Value: 2300, Text: '23:00' },
                    { Value: 1, Text: '1:00' },
                    { Value: 300, Text: '3:00' },
                    { Value: 500, Text: '5:00' }
                ],
                Simple: //简洁模式
                [
                    { Value: 700, Text: '7:00' },
                    //{ Value: 900, Text: '9:00' },
                    { Value: 1100, Text: '11:00' },
                    //{ Value: 1300, Text: '13:00' },
                    { Value: 1500, Text: '15:00' },
                    //{ Value: 1700, Text: '17:00' },
                    { Value: 1900, Text: '19:00' },
                    //{ Value: 2100, Text: '21:00' },
                    { Value: 2300, Text: '23:00' },
                    //{ Value: 1, Text: '1:00' },
                    { Value: 300, Text: '3:00' }
                    //{ Value: 500, Text: '5:00' }
                ],
                Min:   //最小模式  
                [
                    { Value: 700, Text: '7:00' },
                    { Value: 1800, Text: '18:00' },
                    { Value: 500, Text: '5:00' }
                ]
            }
        }
    ]

    this.FUTURES_LIST=
    [
        { Symbol:"ZC", Decimal:2, Time:0, Name:"玉米" }, //玉米
        { Symbol:"XC", Decimal:2, Time:1, Name:"迷你玉米" }, //迷你玉米
        { Symbol:"ZS", Decimal:2, Time:0, Name:'大豆' }, //大豆
        { Symbol:"XK", Decimal:2, Time:1, Name:"迷你大豆" }, //迷你大豆
        { Symbol:"ZL", Decimal:2, Time:0, Name:"豆油"}, //豆油
        { Symbol:"ZR", Decimal:2, Time:0, Name:"稻谷" }, //稻谷
        { Symbol:"ZO", Decimal:2, Time:0, Name:"燕麦" }, //燕麦
        { Symbol:"ZW", Decimal:2, Time:0, Name:'小麦'}, //小麦
        { Symbol:"XW", Decimal:2, Time:1, Name:"迷你小麦" }, //迷你小麦
        { Symbol:"ZM", Decimal:1, Time:0, Name:"豆粕" }, //豆粕

        { Symbol:"EH", Decimal:3, Time:2 }, //乙醇

        { Symbol:"YM", Decimal:0, Time:2, Name:"小型道指"}, //小型道指
        { Symbol:"ES", Decimal:2, Time:2, Name:"小型标普" }, //小型标普
        { Symbol:"NQ", Decimal:2, Time:2, Name:"小型纳指" }, //小型纳指

        { Symbol:"TY", Decimal:4, Time:2, Name:"10年美国债" }, //10年美国债
        { Symbol:"TU", Decimal:4, Time:2, Name:"2年美国债" }, //2年美国债
        { Symbol:"FV", Decimal:4, Time:2, Name:"5年美国债" }, //5年美国债
        { Symbol:"US", Decimal:4, Time:2, Name:"30年美国债" }, //30年美国债
        { Symbol:"UL", Decimal:4, Time:2, Name:"超国债" }, //超国债
    ]

    this.MarketSuffix=".CBOT";
}

//伦敦金属交易所 LME
function LMETimeData()
{
    this.newMethod=NYMEXTimeData;   //派生
    this.newMethod();
    delete this.newMethod;

    //标准时间
    this.TIME_SPLIT=
    [
        {
            Name:'LME 9:00-3:00',
            Data:
            [
                { Start: 900, End: 2359 },
                { Start: 0, End: 300 },
            ],
            Coordinate:
            {
                Full://完整模式
                [
                    { Value: 900, Text: '9:00' },
                    { Value: 1100, Text: '11:00' },
                    { Value: 1300, Text: '13:00' },
                    { Value: 1500, Text: '15:00' },
                    { Value: 1700, Text: '17:00' },
                    { Value: 1900, Text: '19:00' },
                    { Value: 2100, Text: '21:00' },
                    { Value: 2300, Text: '23:00' },
                    { Value: 100, Text: '1:00' },
                    { Value: 300, Text: '3:00' }
                ],
                Simple: //简洁模式
                [
                    { Value: 900, Text: '9:00' },
                    //{ Value: 1100, Text: '11:00' },
                    { Value: 1300, Text: '13:00' },
                    //{ Value: 1500, Text: '15:00' },
                    { Value: 1700, Text: '17:00' },
                    //{ Value: 1900, Text: '19:00' },
                    { Value: 2100, Text: '21:00' },
                    //{ Value: 2300, Text: '23:00' },
                    { Value: 100, Text: '1:00' }
                   // { Value: 300, Text: '3:00' }
                ],
                Min:   //最小模式  
                [
                    { Value: 900, Text: '9:00' },
                    { Value: 1800, Text: '18:00' },
                    { Value: 300, Text: '3:00' }
                ]
            }
        }
    ]

    //夏令
    this.TIME_SPLIT=
    [
        {
            Name:'LME 8:00-2:00',
            Data:
            [
                { Start: 800, End: 2359 },
                { Start: 0, End: 200 },
            ],
            Coordinate:
            {
                Full://完整模式
                [
                    { Value: 800, Text: '8:00' },
                    { Value: 1000, Text: '10:00' },
                    { Value: 1200, Text: '12:00' },
                    { Value: 1400, Text: '14:00' },
                    { Value: 1600, Text: '16:00' },
                    { Value: 1800, Text: '18:00' },
                    { Value: 2000, Text: '20:00' },
                    { Value: 2200, Text: '22:00' },
                    { Value: 0, Text: '0:00' },
                    { Value: 200, Text: '2:00' }
                ],
                Simple: //简洁模式
                [
                    { Value: 800, Text: '8:00' },
                    //{ Value: 1000, Text: '10:00' },
                    { Value: 1200, Text: '12:00' },
                    //{ Value: 1400, Text: '14:00' },
                    { Value: 1600, Text: '16:00' },
                    //{ Value: 1800, Text: '18:00' },
                    { Value: 2000, Text: '20:00' },
                    //{ Value: 2200, Text: '22:00' },
                    { Value: 0, Text: '0:00' }
                    //{ Value: 200, Text: '2:00' }
                ],
                Min:   //最小模式  
                [
                    { Value: 800, Text: '8:00' },
                    { Value: 1800, Text: '18:00' },
                    { Value: 200, Text: '2:00' }
                ]
            }
        }
    ]

    this.FUTURES_LIST=
    [
        { Symbol:"SN", Decimal:0, Time:0, Name:"LME锡" }, //综合锡03
        { Symbol:"AH", Decimal:2, Time:0, Name:"LME铝" }, //综合铝03
        { Symbol:"PB", Decimal:2, Time:0, Name:"LME铅" }, //综合铅03
        { Symbol:"ZS", Decimal:2, Time:0, Name:"LME锌" }, //综合锌03
        { Symbol:"CA", Decimal:2, Time:0, Name:"LME铜" }, //综合铜03
        { Symbol:"NI", Decimal:0, Time:0, Name:"LME镍" }, //综合镍03
    ]

    this.MarketSuffix=".LME";
}

//东京商品交易所（TOCOM）
function TOCOMTimeData()
{
    this.newMethod=NYMEXTimeData;   //派生
    this.newMethod();
    delete this.newMethod;

    this.TimeType=0;

    this.TIME_SPLIT=
    [
        //ID=0 15:30-04:30 07:46-14:15
        {
            Name:'15:30-04:30 07:46-14:15',
            Data:
            [
                { Start: 1530,  End: 2359},
                { Start: 0,     End: 430 },
                { Start: 746,   End: 1415 },
            ],
            Coordinate:
            {
                Full://完整模式
                [
                    { Value: 1530, Text: '15:30' },
                    { Value: 1700, Text: '17:00' },
                    { Value: 1900, Text: '19:00' },
                    { Value: 2100, Text: '21:00' },
                    { Value: 2300, Text: '23:00' },
                    { Value: 100, Text: '1:00' },
                    { Value: 300, Text: '3:00' },
                    { Value: 430, Text: '4:30' },
                    { Value: 900, Text: '9:00' },
                    { Value: 1100, Text: '11:00' },
                    { Value: 1300, Text: '13:00' },
                    { Value: 1415, Text: '14:15' }
                ],
                Simple: //简洁模式
                [
                    { Value: 1530, Text: '15:30' },
                    { Value: 1900, Text: '19:00' },
                    { Value: 2300, Text: '23:00' },
                    { Value: 100, Text: '1:00' },
                    { Value: 430, Text: '4:30' },
                    { Value: 1100, Text: '11:00' },
                    { Value: 1415, Text: '14:15' }
                ],
                Min:   //最小模式  
                [
                    { Value: 1530, Text: '15:30' },
                    { Value: 100, Text: '1:00' },
                    { Value: 1415, Text: '14:15' }
                ]
            }
        }
    ];

    this.FUTURES_LIST=
    [
        { Symbol:"JRV", Decimal:0, Time:0, Name:"东京TSR20橡胶" }, 
        { Symbol:"JPL", Decimal:0, Time:0, Name:"东京铂金" }, 
        { Symbol:"JAU", Decimal:0, Time:0, Name:"东京黄金" }, 
        { Symbol:"JCO", Decimal:0, Time:0, Name:"中东原油" }, 
        { Symbol:"JRU", Decimal:1, Time:0, Name:"东京RSS3橡胶橡胶" }, 
        { Symbol:"JAG", Decimal:1, Time:0, Name:"日白银" } ,
        { Symbol:"JPA", Decimal:1, Time:0, Name:"日钯金" } 
    ]

    this.MarketSuffix=".TOCOM";
}

//美国洲际交易所（ICE EUROPE）
function IPETimeData()
{
    this.newMethod=NYMEXTimeData;   //派生
    this.newMethod();
    delete this.newMethod;

    this.MarketSuffix=".IPE";

     //美国标准时间
    this.TIME_SPLIT=
    [
        //ID=0 8:00-6:00
        {
            Name:'8:00-6:00',
            Data:
            [
                { Start: 800, End: 2359 },
                { Start: 0, End: 600 },
            ],
            Coordinate:
            {
                Full://完整模式
                [
                    { Value: 800, Text: '8:00' },
                    { Value: 1000, Text: '10:00' },
                    { Value: 1200, Text: '12:00' },
                    { Value: 1400, Text: '14:00' },
                    { Value: 1600, Text: '16:00' },
                    { Value: 1800, Text: '18:00' },
                    { Value: 2000, Text: '20:00' },
                    { Value: 2200, Text: '22:00' },
                    { Value: 0, Text: '0:00' },
                    { Value: 200, Text: '2:00' },
                    { Value: 400, Text: '4:00' },
                    { Value: 600, Text: '6:00' },
                ],
                Simple: //简洁模式
                [
                    { Value: 800, Text: '8:00' },
                    { Value: 1200, Text: '12:00' },
                    { Value: 1600, Text: '16:00' },
                    { Value: 2000, Text: '20:00' },
                    { Value: 0, Text: '0:00' },
                    { Value: 400, Text: '4:00' },
                    { Value: 600, Text: '6:00' },
                ],
                Min:   //最小模式  
                [
                    { Value: 800, Text: '8:00' },
                    { Value: 2000, Text: '20:00' },
                    { Value: 600, Text: '6:00' }
                ]
            }
        }
    ]
 
    //美国夏时令
    this.TIME_SPLIT2=
    [
        //ID=0 09:00-07:00
        {
            Name:'09:00-07:00',
            Data:
            [
                { Start: 900, End: 2359 },
                { Start: 0, End: 700 },
            ],
            Coordinate:
            {
                Full://完整模式
                [
                    { Value: 900, Text: '9:00' },
                    { Value: 1100, Text: '11:00' },
                    { Value: 1300, Text: '13:00' },
                    { Value: 1500, Text: '15:00' },
                    { Value: 1700, Text: '17:00' },
                    { Value: 1900, Text: '19:00' },
                    { Value: 2100, Text: '21:00' },
                    { Value: 2300, Text: '23:00' },
                    { Value: 1, Text: '1:00' },
                    { Value: 300, Text: '3:00' },
                    { Value: 500, Text: '5:00' },
                    { Value: 700, Text: '7:00' }
                ],
                Simple: //简洁模式
                [
                    { Value: 900, Text: '9:00' },
                    { Value: 1300, Text: '13:00' },
                    { Value: 1700, Text: '17:00' },
                    { Value: 2100, Text: '21:00' },
                    { Value: 1, Text: '1:00' },
                    { Value: 500, Text: '5:00' },
                    { Value: 700, Text: '7:00' }
                ],
                Min:   //最小模式  
                [
                    { Value: 900, Text: '9:00' },
                    { Value: 2100, Text: '21:00' },
                    { Value: 700, Text: '7:00' }
                ]
            }
        }
    ]

    this.FUTURES_LIST=
    [
        { Symbol:"RC", Decimal:2, Time:0, Name:"罗布斯塔咖啡" }, 
        { Symbol:"W", Decimal:2, Time:0, Name:"白糖" }, 
        { Symbol:"C", Decimal:2, Time:0, Name:"伦敦可可" }, 
        { Symbol:"R", Decimal:2, Time:0, Name:"长期英国国债" }, 
        { Symbol:"L", Decimal:2, Time:0, Name:"3个月英镑利率" },
        { Symbol:"T", Decimal:2, Time:0, Name:"WTI原油" },
        { Symbol:"G", Decimal:2, Time:0, Name:"低硫柴油" },
        { Symbol:"B", Decimal:2, Time:0, Name:"布伦特原油" }  
    ]
}

var g_MinuteTimeStringData = new MinuteTimeStringData();
var g_MinuteCoordinateData = new MinuteCoordinateData();
var g_FuturesTimeData = new FuturesTimeData();
var g_NYMEXTimeData=new NYMEXTimeData();
var g_COMEXTimeData=new COMEXTimeData();
var g_NYBOTTimeData=new NYBOTTimeData();
var g_CBOTTimeData=new CBOTTimeData();
var g_LMETimeData=new LMETimeData();
var g_TOCOMTimeData=new TOCOMTimeData();
var g_IPETimeData=new IPETimeData();


function GetfloatPrecision(symbol)  //获取小数位数
{
    var defaultfloatPrecision=2;    //默认2位
    if (!symbol) return defaultfloatPrecision;
    var upperSymbol=symbol.toUpperCase();

    //全部由外部控制
    if (typeof(MARKET_SUFFIX_NAME.GetCustomDecimal)=='function') return MARKET_SUFFIX_NAME.GetCustomDecimal(upperSymbol);

    if (MARKET_SUFFIX_NAME.IsSHSZFund(upperSymbol)) defaultfloatPrecision=3;    //基金3位小数
    else if (MARKET_SUFFIX_NAME.IsSHO(upperSymbol) || MARKET_SUFFIX_NAME.IsSZO(upperSymbol)) defaultfloatPrecision=MARKET_SUFFIX_NAME.GetSHODecimal(upperSymbol);
    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);
    else if (MARKET_SUFFIX_NAME.IsNYMEX(upperSymbol)) defaultfloatPrecision=g_NYMEXTimeData.GetDecimal(upperSymbol);
    else if (MARKET_SUFFIX_NAME.IsCOMEX(upperSymbol)) defaultfloatPrecision=g_COMEXTimeData.GetDecimal(upperSymbol);
    else if (MARKET_SUFFIX_NAME.IsNYBOT(upperSymbol)) defaultfloatPrecision=g_NYBOTTimeData.GetDecimal(upperSymbol);
    else if (MARKET_SUFFIX_NAME.IsCBOT(upperSymbol)) defaultfloatPrecision=g_CBOTTimeData.GetDecimal(upperSymbol);
    else if (MARKET_SUFFIX_NAME.IsLME(upperSymbol)) defaultfloatPrecision=g_LMETimeData.GetDecimal(upperSymbol);
    else if (MARKET_SUFFIX_NAME.IsTOCOM(upperSymbol)) defaultfloatPrecision=g_TOCOMTimeData.GetDecimal(upperSymbol);
    else if (MARKET_SUFFIX_NAME.IsIPE(upperSymbol)) defaultfloatPrecision=g_IPETimeData.GetDecimal(upperSymbol);
    else defaultfloatPrecision=MARKET_SUFFIX_NAME.GetDefaultDecimal(upperSymbol);

    return defaultfloatPrecision;
}

//把不连续的分时数据转成连续的分时数据
function GenerateMinuteStockJsonData(data)
{
    var stock =
    { 
        symbol:data.symbol, name:data.name,time:data.time, date:data.date,
        price:data.price, open:data.open, yclose:data.yclose, high:data.high, low:data.low, vol:data.vol,amount:data.amount,
        minute:[]
    };

    var mapMinute=new Map();
    for(var i in data.minute)
    {
        var item=data.minute[i];
        mapMinute.set(item.time,item);
    }

    var timeData=g_MinuteTimeStringData.GetTimeData(stock.symbol);
    for(var i in timeData)  //根据交易时间产生数据
    {
        var time=timeData[i];
        var minuteItem={ time:time, vaild:false };
        if (mapMinute.has(time))
        {
            var find=mapMinute.get(time);
            minuteItem.vaild=true;
            minuteItem.price=find.price;
            minuteItem.open=find.open;
            minuteItem.high=find.high;
            minuteItem.low=find.low;
            minuteItem.avprice=find.avprice;
            minuteItem.vol=find.vol;
            minuteItem.amount=find.amount;
            if (IFrameSplitOperator.IsNumber(find.increase)) minuteItem.increase=find.increase;
            if (IFrameSplitOperator.IsNumber(find.risefall)) minuteItem.risefall=find.risefall;
            if (IFrameSplitOperator.IsNumber(find.position)) minuteItem.position=find.position;
        }
        stock.minute.push(minuteItem);
    }

    var vaildCount=0;
    for(var i=stock.minute.length-1;i>=0;--i)
    {
        vaildCount=i+1;
        var item=stock.minute[i];
        if (item.vaild==true) break;
    }

    stock.minute=stock.minute.slice(0,vaildCount);  //去掉最后无用的数据

    return stock;
}

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, Warn:console.warn },      //图形日志
        Complier:{ Log:console.log, Warn:console.warn }    //编译器日志
    };
}

//API默认地址
var g_JSComplierResource=
{
    Domain : "https://opensource.zealink.com",               //API域名
    CacheDomain : "https://opensourcecache.zealink.com",      //缓存域名

    DrawIcon:
    {  
        Family:'iconfont', 
        Data:new Map([
            [1, { Text:'\ue660', Color:'rgb(243,28,15)'}],    //向上箭头
            [2, { Text:'\ue661', Color:'rgb(87,247,41)'}],    //向下箭头
            [3, { Text:'\ue662', Color:'rgb(237,153,0)'}],
            [4, { Text:'\ue663', Color:'rgb(237,153,0)'}],  
            [5, { Text:'\ue664', Color:'rgb(237,153,0)'}],  
            [6, { Text:'\ue665', Color:'rgb(140,57,208)'}],  
            [7, { Text:'\ue666', Color:'rgb(246,135,37)'}],  
            [8, { Text:'\ue667', Color:'rgb(85,231,56)'}],  
            [9, { Text:'\ue668', Color:'rgb(227,61,41)'}], 

            [10, { Text:'\ue669', Color:'rgb(216,78,48)'}], 
            [11, { Text:'\ue66a', Color:'rgb(249,187,0)'}],    //点赞
            [12, { Text:'\ue66b', Color:'rgb(249,187,0)'}], 
            [13, { Text:'\ue66c', Color:'rgb(216,42,0)'}], 
            [14, { Text:'\ue66d', Color:'rgb(58,90,236)'}], 
            [15, { Text:'\ue66e', Color:'rgb(227,149,0)'}], 
            [16, { Text:'\ue66f', Color:'rgb(208,82,78)'}], 
            [17, { Text:'\ue670', Color:'rgb(234,114,26)'}], 
            [18, { Text:'\ue671', Color:'rgb(116,25,255)'}], 
            [19, { Text:'\ue672', Color:'rgb(102,9,11)'}], 

            [20, { Text:'\ue673', Color:'rgb(127,125,137)'}],
            [21, { Text:'\ue674', Color:'rgb(110,188,255)'}],
            [22, { Text:'\ue675', Color:'rgb(238,79,51)'}],
            [23, { Text:'\ue676', Color:'rgb(244,71,0)'}],
            [24, { Text:'\ue677', Color:'rgb(102,183,248)'}],
            [25, { Text:'\ue678', Color:'rgb(234,88,231)'}],
            [26, { Text:'\ue679', Color:'rgb(242,171,0)'}],
            [27, { Text:'\ue67a', Color:'rgb(87,247,168)'}],
            [28, { Text:'\ue67b', Color:'rgb(97,204,113)'}],
            [29, { Text:'\ue67c', Color:'rgb(84,115,193)'}],

            [30, { Text:'\ue67d', Color:'rgb(141,51,255)'}],
            [31, { Text:'\ue67e', Color:'rgb(200,126,24)'}],
            [32, { Text:'\ue67f', Color:'rgb(195,41,32)'}],
            [33, { Text:'\ue68f', Color:'rgb(215,85,194)'}],
            [34, { Text:'\ue690', Color:'rgb(250,222,105)'}],
            [35, { Text:'\ue691', Color:'rgb(112,249,224)'}],
            [36, { Text:'\ue692', Color:'rgb(217,107,98)'}],
            [37, { Text:'\ue693', Color:'rgb(114,231,17)'}],
            [38, { Text:'\ue694', Color:'rgb(238,31,25)'}],
            [39, { Text:'\ue695', Color:'rgb(92,247,113)'}],

            [40, { Text:'\ue696', Color:'rgb(175,175,175)'}],
            [41, { Text:'\ue697', Color:'rgb(252,228,23)'}],
            [42, { Text:'\ue698', Color:'rgb(88,195,235)'}],
            [43, { Text:'\ue699', Color:'rgb(55,74,94)'}],
            [44, { Text:'\ue69a', Color:'rgb(248,175,33)'}],
            [45, { Text:'\ue69b', Color:'rgb(194,180,112)'}],
            [46, { Text:'\ue69c', Color:'rgb(50,153,28)'}],
            [47, { Text:'\ue69d', Color:'rgb(17,65,152)'}],
            [48, { Text:'\ue69e', Color:'rgb(194,55,26)'}],
            [49, { Text:'\ue69f', Color:'rgb(243,0,0)'}],

            /*
            [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: }   //svg
                        //value={ ID:1, Symbol:'↑', Color:'rgb(238,44,44)' } //文字
    },

    CustomFunction: //定制函数
    {
        Data:new Map()  //自定义函数 key=函数名, Value:{ID:函数名, Callback: }
    },

    CustomVariant:  //自定义变量
    {
        Data:new Map()  //自定义函数 key=变量名, Value:{ Name:变量名, Description:描述信息 }
    },

    GetDrawIcon:function(id)
    {
        var icon;
        if (g_JSComplierResource.CustomDrawIcon.Data.has(id))
        {
            const iconfont=g_JSComplierResource.CustomDrawIcon.Data.get(id);
            if (iconfont.Symbol)    //文字
                icon={ Symbol:iconfont.Symbol, Color:iconfont.Color, IconFont:false, ID:id };
            else    //SVG图标
                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;
    },

    GetDrawTextIcon:function(id)
    {
        //图标对应的字符代码
        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:'🏅'}]
        ]);

        var icon=mapIcon.get(id);
        return icon;
    },

    IsCustomFunction:function(name)
    {
        if (g_JSComplierResource.CustomFunction.Data.has(name)) return true;
        return false;
    },

    IsCustomVariant:function(name)
    {
        if (g_JSComplierResource.CustomVariant.Data.has(name)) return true;
        return false;
    }
}

var Messages = {
    BadGetterArity: 'Getter must not have any formal parameters',
    BadSetterArity: 'Setter must have exactly one formal parameter',
    BadSetterRestParameter: 'Setter function argument must not be a rest parameter',
    ConstructorIsAsync: 'Class constructor may not be an async method',
    ConstructorSpecialMethod: 'Class constructor may not be an accessor',
    DeclarationMissingInitializer: 'Missing initializer in %0 declaration',
    DefaultRestParameter: 'Unexpected token =',
    DuplicateBinding: 'Duplicate binding %0',
    DuplicateConstructor: 'A class may only have one constructor',
    DuplicateProtoProperty: 'Duplicate __proto__ fields are not allowed in object literals',
    ForInOfLoopInitializer: '%0 loop variable declaration may not have an initializer',
    GeneratorInLegacyContext: 'Generator declarations are not allowed in legacy contexts',
    IllegalBreak: 'Illegal break statement',
    IllegalContinue: 'Illegal continue statement',
    IllegalExportDeclaration: 'Unexpected token',
    IllegalImportDeclaration: 'Unexpected token',
    IllegalLanguageModeDirective: 'Illegal \'use strict\' directive in function with non-simple parameter list',
    IllegalReturn: 'Illegal return statement',
    InvalidEscapedReservedWord: 'Keyword must not contain escaped characters',
    InvalidHexEscapeSequence: 'Invalid hexadecimal escape sequence',
    InvalidLHSInAssignment: 'Invalid left-hand side in assignment',
    InvalidLHSInForIn: 'Invalid left-hand side in for-in',
    InvalidLHSInForLoop: 'Invalid left-hand side in for-loop',
    InvalidModuleSpecifier: 'Unexpected token',
    InvalidRegExp: 'Invalid regular expression',
    LetInLexicalBinding: 'let is disallowed as a lexically bound name',
    MissingFromClause: 'Unexpected token',
    MultipleDefaultsInSwitch: 'More than one default clause in switch statement',
    NewlineAfterThrow: 'Illegal newline after throw',
    NoAsAfterImportNamespace: 'Unexpected token',
    NoCatchOrFinally: 'Missing catch or finally after try',
    ParameterAfterRestParameter: 'Rest parameter must be last formal parameter',
    Redeclaration: '%0 \'%1\' has already been declared',
    StaticPrototype: 'Classes may not have static property named prototype',
    StrictCatchVariable: 'Catch variable may not be eval or arguments in strict mode',
    StrictDelete: 'Delete of an unqualified identifier in strict mode.',
    StrictFunction: 'In strict mode code, functions can only be declared at top level or inside a block',
    StrictFunctionName: 'Function name may not be eval or arguments in strict mode',
    StrictLHSAssignment: 'Assignment to eval or arguments is not allowed in strict mode',
    StrictLHSPostfix: 'Postfix increment/decrement may not have eval or arguments operand in strict mode',
    StrictLHSPrefix: 'Prefix increment/decrement may not have eval or arguments operand in strict mode',
    StrictModeWith: 'Strict mode code may not include a with statement',
    StrictOctalLiteral: 'Octal literals are not allowed in strict mode.',
    StrictParamDupe: 'Strict mode function may not have duplicate parameter names',
    StrictParamName: 'Parameter name eval or arguments is not allowed in strict mode',
    StrictReservedWord: 'Use of future reserved word in strict mode',
    StrictVarName: 'Variable name may not be eval or arguments in strict mode',
    TemplateOctalLiteral: 'Octal literals are not allowed in template strings.',
    UnexpectedEOS: 'Unexpected end of input',
    UnexpectedIdentifier: 'Unexpected identifier',
    UnexpectedNumber: 'Unexpected number',
    UnexpectedReserved: 'Unexpected reserved word',
    UnexpectedString: 'Unexpected string',
    UnexpectedTemplate: 'Unexpected quasi %0',
    UnexpectedToken: 'Unexpected token %0',
    UnexpectedTokenIllegal: 'Unexpected token ILLEGAL',
    UnknownLabel: 'Undefined label \'%0\'',
    UnterminatedRegExp: 'Invalid regular expression: missing /'
};

var Regex = {
    // Unicode v8.0.0 NonAsciiIdentifierStart:
    NonAsciiIdentifierStart: /[\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0-\u08B4\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0AF9\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D\u0C58-\u0C5A\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D5F-\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2118-\u211D\u2124\u2126\u2128\u212A-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303C\u3041-\u3096\u309B-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FD5\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA69D\uA6A0-\uA6EF\uA717-\uA71F\uA722-\uA788\uA78B-\uA7AD\uA7B0-\uA7B7\uA7F7-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA8FD\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uA9E0-\uA9E4\uA9E6-\uA9EF\uA9FA-\uA9FE\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA7E-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB65\uAB70-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDD40-\uDD74\uDE80-\uDE9C\uDEA0-\uDED0\uDF00-\uDF1F\uDF30-\uDF4A\uDF50-\uDF75\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF\uDFD1-\uDFD5]|\uD801[\uDC00-\uDC9D\uDD00-\uDD27\uDD30-\uDD63\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC60-\uDC76\uDC80-\uDC9E\uDCE0-\uDCF2\uDCF4\uDCF5\uDD00-\uDD15\uDD20-\uDD39\uDD80-\uDDB7\uDDBE\uDDBF\uDE00\uDE10-\uDE13\uDE15-\uDE17\uDE19-\uDE33\uDE60-\uDE7C\uDE80-\uDE9C\uDEC0-\uDEC7\uDEC9-\uDEE4\uDF00-\uDF35\uDF40-\uDF55\uDF60-\uDF72\uDF80-\uDF91]|\uD803[\uDC00-\uDC48\uDC80-\uDCB2\uDCC0-\uDCF2]|\uD804[\uDC03-\uDC37\uDC83-\uDCAF\uDCD0-\uDCE8\uDD03-\uDD26\uDD50-\uDD72\uDD76\uDD83-\uDDB2\uDDC1-\uDDC4\uDDDA\uDDDC\uDE00-\uDE11\uDE13-\uDE2B\uDE80-\uDE86\uDE88\uDE8A-\uDE8D\uDE8F-\uDE9D\uDE9F-\uDEA8\uDEB0-\uDEDE\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3D\uDF50\uDF5D-\uDF61]|\uD805[\uDC80-\uDCAF\uDCC4\uDCC5\uDCC7\uDD80-\uDDAE\uDDD8-\uDDDB\uDE00-\uDE2F\uDE44\uDE80-\uDEAA\uDF00-\uDF19]|\uD806[\uDCA0-\uDCDF\uDCFF\uDEC0-\uDEF8]|\uD808[\uDC00-\uDF99]|\uD809[\uDC00-\uDC6E\uDC80-\uDD43]|[\uD80C\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD811[\uDC00-\uDE46]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDED0-\uDEED\uDF00-\uDF2F\uDF40-\uDF43\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDF00-\uDF44\uDF50\uDF93-\uDF9F]|\uD82C[\uDC00\uDC01]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB]|\uD83A[\uDC00-\uDCC4]|\uD83B[\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1]|\uD87E[\uDC00-\uDE1D]/,
    // Unicode v8.0.0 NonAsciiIdentifierPart:
    NonAsciiIdentifierPart: /[\xAA\xB5\xB7\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0300-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u0483-\u0487\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u05D0-\u05EA\u05F0-\u05F2\u0610-\u061A\u0620-\u0669\u066E-\u06D3\u06D5-\u06DC\u06DF-\u06E8\u06EA-\u06FC\u06FF\u0710-\u074A\u074D-\u07B1\u07C0-\u07F5\u07FA\u0800-\u082D\u0840-\u085B\u08A0-\u08B4\u08E3-\u0963\u0966-\u096F\u0971-\u0983\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BC-\u09C4\u09C7\u09C8\u09CB-\u09CE\u09D7\u09DC\u09DD\u09DF-\u09E3\u09E6-\u09F1\u0A01-\u0A03\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A3C\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A59-\u0A5C\u0A5E\u0A66-\u0A75\u0A81-\u0A83\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABC-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0AD0\u0AE0-\u0AE3\u0AE6-\u0AEF\u0AF9\u0B01-\u0B03\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3C-\u0B44\u0B47\u0B48\u0B4B-\u0B4D\u0B56\u0B57\u0B5C\u0B5D\u0B5F-\u0B63\u0B66-\u0B6F\u0B71\u0B82\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD0\u0BD7\u0BE6-\u0BEF\u0C00-\u0C03\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C58-\u0C5A\u0C60-\u0C63\u0C66-\u0C6F\u0C81-\u0C83\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBC-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5\u0CD6\u0CDE\u0CE0-\u0CE3\u0CE6-\u0CEF\u0CF1\u0CF2\u0D01-\u0D03\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D-\u0D44\u0D46-\u0D48\u0D4A-\u0D4E\u0D57\u0D5F-\u0D63\u0D66-\u0D6F\u0D7A-\u0D7F\u0D82\u0D83\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0DCA\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DE6-\u0DEF\u0DF2\u0DF3\u0E01-\u0E3A\u0E40-\u0E4E\u0E50-\u0E59\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB9\u0EBB-\u0EBD\u0EC0-\u0EC4\u0EC6\u0EC8-\u0ECD\u0ED0-\u0ED9\u0EDC-\u0EDF\u0F00\u0F18\u0F19\u0F20-\u0F29\u0F35\u0F37\u0F39\u0F3E-\u0F47\u0F49-\u0F6C\u0F71-\u0F84\u0F86-\u0F97\u0F99-\u0FBC\u0FC6\u1000-\u1049\u1050-\u109D\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u135D-\u135F\u1369-\u1371\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1714\u1720-\u1734\u1740-\u1753\u1760-\u176C\u176E-\u1770\u1772\u1773\u1780-\u17D3\u17D7\u17DC\u17DD\u17E0-\u17E9\u180B-\u180D\u1810-\u1819\u1820-\u1877\u1880-\u18AA\u18B0-\u18F5\u1900-\u191E\u1920-\u192B\u1930-\u193B\u1946-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u19D0-\u19DA\u1A00-\u1A1B\u1A20-\u1A5E\u1A60-\u1A7C\u1A7F-\u1A89\u1A90-\u1A99\u1AA7\u1AB0-\u1ABD\u1B00-\u1B4B\u1B50-\u1B59\u1B6B-\u1B73\u1B80-\u1BF3\u1C00-\u1C37\u1C40-\u1C49\u1C4D-\u1C7D\u1CD0-\u1CD2\u1CD4-\u1CF6\u1CF8\u1CF9\u1D00-\u1DF5\u1DFC-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u200C\u200D\u203F\u2040\u2054\u2071\u207F\u2090-\u209C\u20D0-\u20DC\u20E1\u20E5-\u20F0\u2102\u2107\u210A-\u2113\u2115\u2118-\u211D\u2124\u2126\u2128\u212A-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D7F-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2DE0-\u2DFF\u3005-\u3007\u3021-\u302F\u3031-\u3035\u3038-\u303C\u3041-\u3096\u3099-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FD5\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA62B\uA640-\uA66F\uA674-\uA67D\uA67F-\uA6F1\uA717-\uA71F\uA722-\uA788\uA78B-\uA7AD\uA7B0-\uA7B7\uA7F7-\uA827\uA840-\uA873\uA880-\uA8C4\uA8D0-\uA8D9\uA8E0-\uA8F7\uA8FB\uA8FD\uA900-\uA92D\uA930-\uA953\uA960-\uA97C\uA980-\uA9C0\uA9CF-\uA9D9\uA9E0-\uA9FE\uAA00-\uAA36\uAA40-\uAA4D\uAA50-\uAA59\uAA60-\uAA76\uAA7A-\uAAC2\uAADB-\uAADD\uAAE0-\uAAEF\uAAF2-\uAAF6\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB65\uAB70-\uABEA\uABEC\uABED\uABF0-\uABF9\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE00-\uFE0F\uFE20-\uFE2F\uFE33\uFE34\uFE4D-\uFE4F\uFE70-\uFE74\uFE76-\uFEFC\uFF10-\uFF19\uFF21-\uFF3A\uFF3F\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDD40-\uDD74\uDDFD\uDE80-\uDE9C\uDEA0-\uDED0\uDEE0\uDF00-\uDF1F\uDF30-\uDF4A\uDF50-\uDF7A\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF\uDFD1-\uDFD5]|\uD801[\uDC00-\uDC9D\uDCA0-\uDCA9\uDD00-\uDD27\uDD30-\uDD63\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC60-\uDC76\uDC80-\uDC9E\uDCE0-\uDCF2\uDCF4\uDCF5\uDD00-\uDD15\uDD20-\uDD39\uDD80-\uDDB7\uDDBE\uDDBF\uDE00-\uDE03\uDE05\uDE06\uDE0C-\uDE13\uDE15-\uDE17\uDE19-\uDE33\uDE38-\uDE3A\uDE3F\uDE60-\uDE7C\uDE80-\uDE9C\uDEC0-\uDEC7\uDEC9-\uDEE6\uDF00-\uDF35\uDF40-\uDF55\uDF60-\uDF72\uDF80-\uDF91]|\uD803[\uDC00-\uDC48\uDC80-\uDCB2\uDCC0-\uDCF2]|\uD804[\uDC00-\uDC46\uDC66-\uDC6F\uDC7F-\uDCBA\uDCD0-\uDCE8\uDCF0-\uDCF9\uDD00-\uDD34\uDD36-\uDD3F\uDD50-\uDD73\uDD76\uDD80-\uDDC4\uDDCA-\uDDCC\uDDD0-\uDDDA\uDDDC\uDE00-\uDE11\uDE13-\uDE37\uDE80-\uDE86\uDE88\uDE8A-\uDE8D\uDE8F-\uDE9D\uDE9F-\uDEA8\uDEB0-\uDEEA\uDEF0-\uDEF9\uDF00-\uDF03\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3C-\uDF44\uDF47\uDF48\uDF4B-\uDF4D\uDF50\uDF57\uDF5D-\uDF63\uDF66-\uDF6C\uDF70-\uDF74]|\uD805[\uDC80-\uDCC5\uDCC7\uDCD0-\uDCD9\uDD80-\uDDB5\uDDB8-\uDDC0\uDDD8-\uDDDD\uDE00-\uDE40\uDE44\uDE50-\uDE59\uDE80-\uDEB7\uDEC0-\uDEC9\uDF00-\uDF19\uDF1D-\uDF2B\uDF30-\uDF39]|\uD806[\uDCA0-\uDCE9\uDCFF\uDEC0-\uDEF8]|\uD808[\uDC00-\uDF99]|\uD809[\uDC00-\uDC6E\uDC80-\uDD43]|[\uD80C\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD811[\uDC00-\uDE46]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDE60-\uDE69\uDED0-\uDEED\uDEF0-\uDEF4\uDF00-\uDF36\uDF40-\uDF43\uDF50-\uDF59\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDF00-\uDF44\uDF50-\uDF7E\uDF8F-\uDF9F]|\uD82C[\uDC00\uDC01]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99\uDC9D\uDC9E]|\uD834[\uDD65-\uDD69\uDD6D-\uDD72\uDD7B-\uDD82\uDD85-\uDD8B\uDDAA-\uDDAD\uDE42-\uDE44]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB\uDFCE-\uDFFF]|\uD836[\uDE00-\uDE36\uDE3B-\uDE6C\uDE75\uDE84\uDE9B-\uDE9F\uDEA1-\uDEAF]|\uD83A[\uDC00-\uDCC4\uDCD0-\uDCD6]|\uD83B[\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1]|\uD87E[\uDC00-\uDE1D]|\uDB40[\uDD00-\uDDEF]/
}

var Character =
{
    FromCodePoint: function (cp) {
        return (cp < 0x10000) ? String.fromCharCode(cp) :
            String.fromCharCode(0xD800 + ((cp - 0x10000) >> 10)) +
                String.fromCharCode(0xDC00 + ((cp - 0x10000) & 1023));
    },

    //是否是空格 https://tc39.github.io/ecma262/#sec-white-space
    IsWhiteSpace:function(cp)
    {
        return (cp === 0x20) || (cp === 0x09) || (cp === 0x0B) || (cp === 0x0C) || (cp === 0xA0) ||
            (cp >= 0x1680 && [0x1680, 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, 0x2007, 0x2008, 0x2009, 0x200A, 0x202F, 0x205F, 0x3000, 0xFEFF].indexOf(cp) >= 0);
    },

    //是否换行 https://tc39.github.io/ecma262/#sec-line-terminators
    IsLineTerminator:function(cp)
    {
        return (cp === 0x0A) || (cp === 0x0D) || (cp === 0x2028) || (cp === 0x2029);
    },

    // https://tc39.github.io/ecma262/#sec-names-and-keywords
    IsIdentifierStart:function(cp)
    {
        return (cp === 0x24) || (cp === 0x5F) ||
            (cp >= 0x41 && cp <= 0x5A) ||
            (cp >= 0x61 && cp <= 0x7A) ||
            (cp === 0x5C) ||
            //【】▲▼
            (cp===0x3010 || cp===0x3011 || cp===0x25B2 || cp===0x25BC) ||
            ((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===0x23) ||
            //【】▲▼
            (cp===0x3010 || cp===0x3011 || cp===0x25B2 || cp===0x25BC) ||
            ((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 JSComplierHelper()
{
    
}

JSComplierHelper.GetPeriodInfo=function(obj)
{
    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:'MULTIDAY',    Period:40002, Order:1002},
        {Name:'DAY2',    Period:40002, Order:1002},
        {Name:'DAY3',    Period:40003, Order:1003},
        {Name:'DAY4',    Period:40004, Order:1004},
        {Name:'DAY5',    Period:40005, Order:1005},
        {Name:'WEEK',   Period:1, Order:1005},

        {Name:'DAY6',    Period:40006, Order:1006},
        {Name:'DAY7',    Period:40007, Order:1007},
        {Name:'DAY8',    Period:40008, Order:1008},
        {Name:'DAY9',    Period:40009, Order:1009},
        {Name:'DAY10',   Period:40009, Order:1010},
        {Name:"WEEK2",   Period:21,    Order:1010},

        {Name:'DAY11',    Period:40011, Order:1011},
        {Name:'DAY12',    Period:40012, Order:1012},
        {Name:'DAY13',    Period:40013, Order:1013},
        {Name:'DAY14',    Period:40014, Order:1014},

        {Name:'MONTH',  Period:2, Order:1030},
        {Name:"SEASON", Period:9, Order:1090},
        {Name:"HALFYEAR", Period:22, Order:1180},
        {Name:"YEAR",   Period:3, Order:1365}
    ];

    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;
}

JSComplierHelper.GetConvertValueName=function(funcName)
{
    var valueName;
    if (funcName=='COVER_C') valueName='CLOSE';
    else if (funcName=='COVER_O') valueName="OPEN";
    else if (funcName=='COVER_H') valueName="HIGH";
    else if (funcName=='COVER_L') valueName="LOW";
    else if (funcName=='COVER_A') valueName="AMOUNT";
    else if (funcName=='COVER_V') valueName="VOL";

    return valueName;
}
        


//编译异常, 错误类
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, word)
    {
        let msg='Line ' + line + ': ' + description;
        let error=this.ConstructError(msg,col);
        error.Index=index;
        error.LineNumber=line;
        error.Description=description;
        error.Word=word;    //错误单词
        return error;
    }

    this.ThrowError=function(index, line, col, description, word)
    {
        let error=this.CreateError(index,line,col,description,word);
        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;
            case '.':
                ++this.Index;
                /*if (this.Source[this.Index] === '.' && this.Source[this.Index + 1] === '.') 
                {
                    //Spread operator: ...
                    this.Index += 2;
                    str = '...';
                }
                */
                break;
            default:
                str=this.Source.substr(this.Index,3);
                if (str=='AND') 
                {
                    this.Index+=3;
                }
                else
                {
                    str = this.Source.substr(this.Index, 2);
                    if (str === '&&' || str === '||' || str === '==' || str === '!=' || str === '<=' || str === '>=' || str === '=>' || str==':=' || str=='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,word)
    {
        if (!message) message = Messages.UnexpectedTokenIllegal;
	    return this.ErrorHandler.ThrowError(this.Index, this.LineNumber, this.Index - this.LineStart + 1, message, word);
    }

}

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(ErrorHandler)
{
    this.IsNeedIndexData=false;         //是否需要大盘数据
    this.IsNeedLatestIndexData=false;   //是否需要下载最新大盘数据
    this.IsNeedSymbolData=false;        //是否需要下载股票数据
    this.IsNeedMarginData=new Set();
    this.IsNeedNewsAnalysisData=new Set();      //新闻统计数据
    this.NeedBlockIncreaseData=[];              //是否需要市场涨跌股票数据统计
    this.IsNeedSymbolExData=new Set();          //下载股票行情的其他数据
    this.NeedHK2SHSZData=[];                    //下载北上资金数据
    this.IsNeedSectionFinance=new Map();        //下载截面财务数据 { key= 报告期 , Set() 字段}

    this.FunctionData=[];                       //{ID:,  Args:,  FunctionName: }
                                                //FINVALUE(ID),FINONE(ID,Y,MMDD)
    this.Dynainfo=[];   //最新的个股行情数据 {ID:,  Args:,  FunctionName: }

    this.IsAPIData=[]       //加载API数据

    this.ExecuteIndex=[];       //执行调用指标
    this.OtherSymbolData=[];    //其他股票数据 key=股票代码(小写)
    this.PeriodSymbolData=[];   //跨周期数据 { Period:, VarName: }

    this.ErrorHandler=ErrorHandler;

    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.IsNeedLatestIndexData) jobs.push({ID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_LATEST_INDEX_DATA});

        //最新的个股行情数据
        for(var i=0;i<this.Dynainfo.length;++i)
        {
            var item=this.Dynainfo[i];
            jobs.push(item);
        }

        //涨跌停家数统计
        for(var i in this.NeedBlockIncreaseData)    
        {
            jobs.push(this.NeedBlockIncreaseData[i]);
        }

        //加载融资融券
        for(var jobID of this.IsNeedMarginData)
        {
            jobs.push({ID:jobID});
        }

        //加载北上资金
        for(var i in this.NeedHK2SHSZData)
        {
            jobs.push(this.NeedHK2SHSZData[i]);
        }

        //加载新闻统计
        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.IsAPIData)
        {
            var item=this.IsAPIData[i];
            jobs.push(item);
        }

        for(var i in this.ExecuteIndex)
        {
            var item=this.ExecuteIndex[i];
            jobs.push(item);
        }

        for(var i in this.OtherSymbolData)
        {
            var item=this.OtherSymbolData[i];
            jobs.push(item);
        }

        for(var i in this.PeriodSymbolData)
        {
            var item=this.PeriodSymbolData[i];
            jobs.push(item);
        }

        for(var i in this.FunctionData)
        {
            var item=this.FunctionData[i];
            jobs.push(item);
        }

        return jobs;
    }

    this.VerifySymbolVariable=function(varName, token)
    {
        let setIndexName=new Set(['INDEXA','INDEXC','INDEXH','INDEXL',"INDEXO","INDEXV",'INDEXDEC','INDEXADV']);
        if (setIndexName.has(varName)) 
        {
            this.IsNeedIndexData=true;
            return;
        }

        let setSymbolDataName=new Set(['CLOSE','C','VOL','V','OPEN','O','HIGH','H','LOW','L','AMOUNT','AMO','VOLINSTK']);
        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);
        }

        //CAPITAL流通股本(手), EXCHANGE 换手率, TOTALCAPITAL 总股本(手)
        let setVariantName=new Set(
        [
            "CAPITAL","TOTALCAPITAL","EXCHANGE",
            "HYBLOCK","DYBLOCK","GNBLOCK","FGBLOCK","ZSBLOCK","ZHBLOCK","ZDBLOCK","HYZSCODE",
            "GNBLOCKNUM","FGBLOCKNUM","ZSBLOCKNUM","ZHBLOCKNUM","ZDBLOCKNUM",
            "HYSYL","HYSJL"
        ]);

        if (setVariantName.has(varName))
        {
            var item={ ID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_VARIANT, VariantName:varName };
            if (token) item.Token={ Index:token.Start, Line:token.LineNumber };
            this.FunctionData.push(item);
            return;
        }

        if (varName=='FROMOPEN')
        {
            this.IsNeedLatestIndexData=true;
            return;
        }

        if (varName=='ADVANCE' || varName=="DECLINE")
        {
            var item={ ID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_INDEX_INCREASE_DATA, IsSelfSymbol:true, FunctionName:varName };
            if (token) item.Token={ Index:token.Start, Line:token.LineNumber };
            this.NeedBlockIncreaseData.push(item);  
            return;
        }

        if (varName.indexOf('#')>0)
        {
            var aryWrods = varName.split('#');
            if (aryWrods.length!=2)
            {
                var errorMessage=`${varName}, 跨周期语法错误, 变量名#周期`;
                this.ThrowUnexpectedToken(token,errorMessage);
            }
            else
            {
                const VAR_NAME=["C", "CLOSE", "O","OPEN", "H","HIGH", "L", "LOW", "AMOUNT", "AMO", "VOL", "V" , "VOLINSTK"];
                if (VAR_NAME.indexOf(aryWrods[0])<0)
                {
                    var errorMessage=`${varName}, 跨周期语法错误, 数据只支持'OPEN,HIGH,LOW,CLOSE,VOL,AMOUNT,VOLINSTK'`;
                    this.ThrowUnexpectedToken(token,errorMessage);
                }

                const VAR_PERIOD_NAME=
                [
                    "MIN1","MIN5","MIN15","MIN30","MIN60","DAY","WEEK","MONTH","SEASON","YEAR","HALFYEAR","WEEK2",
                    "MULTIDAY","DAY2","DAY3","DAY4","DAY5","DAY6","DAY7","DAY8","DAY9","DAY10",
                    "DAY11","DAY12","DAY13","DAY14","DAY15"
                ];
                if (VAR_PERIOD_NAME.indexOf(aryWrods[1])<0)
                {
                    var errorMessage=`${varName}, 跨周期语法错误， 周期只支持'MIN1,MIN5,MIN15,MIN30,MIN60,DAY,WEEK,MONTH,SEASON,YEAR'`;
                    this.ThrowUnexpectedToken(token,errorMessage);
                }

                var item={ID: JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SYMBOL_PERIOD_DATA, VarName:varName, ValueName:aryWrods[0], PeriodName:aryWrods[1] };
                if (token) item.Token={ Index:token.Start, Line:token.LineNumber };
                this.PeriodSymbolData.push(item);
            }

            return;
        }

        if (g_JSComplierResource.IsCustomVariant(varName)) //自定义函数
        {
            var item={ VariantName:varName, ID:JS_EXECUTE_JOB_ID.JOB_CUSTOM_VARIANT_DATA };
            if (token) item.Token={ Index:token.Start, Line:token.LineNumber };
            this.FunctionData.push(item);
            return;
        }
    }

    this.VerifySymbolLiteral=function(value,token)
    {
        if (IFrameSplitOperator.IsString(value))
        {
            if (value.indexOf('$')>0)
            {
                var aryValue=value.split('$');
                if (aryValue.length!=2) return;

                var item= { Literal:value, ID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_OTHER_SYMBOL_DATA };
                if (token) item.Token={ Index:token.Start, Line:token.LineNumber };
    
                this.OtherSymbolData.push(item);
            }
        }
    }

    this.VerifySymbolFunction=function(callee,args, token)
    {
        //自定义函数 可以覆盖系统内置函数
        if (g_JSComplierResource.IsCustomFunction(callee.Name)) 
        {
            var item={FunctionName:callee.Name, ID:JS_EXECUTE_JOB_ID.JOB_CUSTOM_FUNCTION_DATA, Args:args}
            if (token) item.Token={ Index:token.Start, Line:token.LineNumber};
            this.FunctionData.push(item);
            return;
        }

        if (callee.Name=='DYNAINFO') 
        {
            var item={ ID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SYMBOL_LATEST_DATA, Args:args,  FunctionName:callee.Name };
            this.Dynainfo.push(item);
            return;
        }

        //财务函数
        if (callee.Name=='FINANCE')
        {
            var item={ ID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_FINANCE, Args:args,  FunctionName:callee.Name };
            if (token) item.Token={ Index:token.Start, Line:token.LineNumber };
            this.FunctionData.push(item);
            return;
        }

        if (callee.Name=="FINVALUE")
        {
            var item={ ID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_FINVALUE, Args:args,  FunctionName:callee.Name };
            if (token) item.Token={ Index:token.Start, Line:token.LineNumber };
            this.FunctionData.push(item);
            return;
        }

        if (callee.Name=="FINONE")
        {
            var item={ ID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_FINONE, Args:args,  FunctionName:callee.Name };
            if (token) item.Token={ Index:token.Start, Line:token.LineNumber };
            this.FunctionData.push(item);
            return;
        }

        if (callee.Name=='GPJYVALUE')
        {
            var item={ ID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_GPJYVALUE, Args:args,  FunctionName:callee.Name };
            if (token) item.Token={ Index:token.Start, Line:token.LineNumber };
            this.FunctionData.push(item);
            return;
        }

        if (callee.Name=="SCJYVALUE")
        {
            var item={ ID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SCJYVALUE, Args:args,  FunctionName:callee.Name };
            if (token) item.Token={ Index:token.Start, Line:token.LineNumber };
            this.FunctionData.push(item);
            return;
        }

        if (callee.Name==='MARGIN')
        {
            let jobID=JS_EXECUTE_JOB_ID.GetMarginJobID(args[0].Value);
            if (jobID && !this.IsNeedMarginData.has(jobID))  this.IsNeedMarginData.add(jobID);
            return;
        }

        if (callee.Name==='NEWS')
        {
            let jobID=JS_EXECUTE_JOB_ID.GetNewsAnalysisID(args[0].Value);
            if (jobID && !this.IsNeedNewsAnalysisData.has(jobID))  this.IsNeedNewsAnalysisData.add(jobID);
            return;
        }

        if (callee.Name==='HK2SHSZ')    //北上资金
        {
            var item={ ID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_HK_TO_SHSZ, Args:args,  FunctionName:callee.Name };
            if (token) item.Token={ Index:token.Start, Line:token.LineNumber };
            this.NeedHK2SHSZData.push(item);
            return;
        }

        if (callee.Name=='COST' || callee.Name=='WINNER' || callee.Name=='PPART' || callee.Name=='COSTEX' ||
            callee.Name=='LWINNER' || callee.Name=='PWINNER')   //需要流通股
        {
            //下载流通股
            var item={ ID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_FINANCE, Args:[7],  FunctionName:"FINANCE", FunctionName2:callee.Name };
            if (token) item.Token={ Index:token.Start, Line:token.LineNumber };
            this.FunctionData.push(item);
            return;
        }

        if (callee.Name=="INBLOCK")
        {
            var item={ ID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_VARIANT, VariantName:"INBLOCK" }; //下载所有板块
            if (token) item.Token={ Index:token.Start, Line:token.LineNumber };
            this.FunctionData.push(item);
            return;
        }

        if (callee.Name==='BETA')    //beta需要下载上证指数
        {
            this.IsNeedIndexData=true;
            return;
        }

        if (callee.Name=='UPCOUNT' || callee.Name=='DOWNCOUNT')    //上涨下跌个数
        {
            var item={ ID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_INDEX_INCREASE_DATA, Args:args, FunctionName:callee.Name };
            if (token) item.Token={ Index:token.Start, Line:token.LineNumber };
            this.NeedBlockIncreaseData.push(item);  
            return;
        }

        if (callee.Name=='STKINDI') //指标调用
        {
            var item={ ID:JS_EXECUTE_JOB_ID.JOB_EXECUTE_INDEX, Args:args,  FunctionName:callee.Name };
            if (token) item.Token={ Index:token.Start, Line:token.LineNumber };
            this.ExecuteIndex.push(item);
            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;
            const VAR_PERIOD_NAME=["MIN1","MIN5","MIN15","MIN30","MIN60","DAY","WEEK","MONTH","SEASON","YEAR"];
            if (VAR_PERIOD_NAME.indexOf(periodName)<0)
            {
                var errorMessage=`${callee.Name}, 跨周期函数错误， 周期只支持'MIN1,MIN5,MIN15,MIN30,MIN60,DAY,WEEK,MONTH,SEASON,YEAR'`;
                this.ThrowUnexpectedToken(token,errorMessage);
            }

            var valueName=JSComplierHelper.GetConvertValueName(callee.Name);
            var item={ID: JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SYMBOL_PERIOD_DATA, FunctionName:callee.Name, ValueName:valueName, PeriodName:periodName };
            if (token) item.Token={ Index:token.Start, Line:token.LineNumber };
            this.PeriodSymbolData.push(item);
            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 (callee.Name=="LOADAPIDATA") //加载API数据
        {
            var item= { Name:callee.Name, ID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_CUSTOM_API_DATA,Args:args };
            if (token) item.Token={ Index:token.Start, Line:token.LineNumber};

            this.IsAPIData.push(item);
            return;
        }

        let setStockDataName=new Set(['CLOSE',"C",'VOL','V','OPEN','O','HIGH','H','LOW','L','AMOUNT','AMO','VOLINSTK']);
        if (setStockDataName.has(callee.Name)) 
        {
            var item= { Name:callee.Name, ID:JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_OTHER_SYMBOL_DATA,Args:args };
            if (token) item.Token={ Index:token.Start, Line:token.LineNumber};

            this.OtherSymbolData.push(item);
            return;
        }

    }

    this.VerifyMemberVariable=function(object,property,token)
    {
        var item={ ID:JS_EXECUTE_JOB_ID.JOB_EXECUTE_INDEX,  Member:{Object:object, Property:property} };
        if (token) item.Token={ Index:token.Start, Line:token.LineNumber };
        this.ExecuteIndex.push(item);
        return;
    }

    this.ExpressionStatement=function(expression)
    {
        return { Type:Syntax.ExpressionStatement, Expression:expression };
    }

    this.Script=function(body)
    {
        return {Type:Syntax.Program, Body:body, SourceType:'通达信脚本' };
    } 

    this.SequenceExpression=function(expression)
    {
        return {Type:Syntax.SequenceExpression, Expression:expression };
    }

    this.BinaryExpression=function(operator, left, right) 
    {
        let logical = (operator === '||' || operator === '&&' || operator=='AND' || operator=='OR');
        let type = logical ? Syntax.LogicalExpression : Syntax.BinaryExpression;

        return { Type:type, Operator:operator, Left:left, Right:right };
    }

    this.Literal=function(value,raw,token)
    {
        this.VerifySymbolLiteral(value, token);
        return { Type:Syntax.Literal, Value:value, Raw:raw };
    }

    this.Identifier=function(name, token)
    {
        this.VerifySymbolVariable(name, token);

        return { Type:Syntax.Identifier, Name:name};
    }

    //成员变量, 不需要检测
    this.MemberIdentifier=function(name, token)
    {
        return { Type:Syntax.Identifier, Name:name};
    }

    this.AssignmentExpression=function (operator, left, right) 
    {
        return { Type:Syntax.AssignmentExpression, Operator:operator, Left:left, Right:right };
    }

    this.UnaryExpression=function(operator, argument) 
    {
        return { Type:Syntax.UnaryExpression, Operator:operator, Argument:argument, Prefix:true };
    }

    this.EmptyStatement=function() 
    {
        return { Type:Syntax.EmptyStatement };
    }

    this.CallExpression=function(callee, args, token) 
    {
        this.VerifySymbolFunction(callee, args, token);

        return { Type:Syntax.CallExpression, Callee:callee, Arguments:args };
    }

    this.StaticMemberExpression=function(object, property,token)
    {
        this.VerifyMemberVariable(object,property, token);
        return { Type:Syntax.MemberExpression, Computed:false, Object:object, Property:property };
    }

    this. Directive=function(expression, directive)
    {
        return { Type:Syntax.ExpressionStatement, Expression : expression, Directive: directive };
    }

    ////////////////////////////////////////////////////////////////
    this.ThrowUnexpectedToken=function(token,message)
    {
        throw this.UnexpectedTokenError(token,message);
    }

    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 column=-1
            return this.ErrorHandler.CreateError(index,line,column,msg);
        }
    }
}



function JSParser(code)
{
    this.ErrorHandler=new ErrorHandler();
    this.Scanner=new Scanner(code, this.ErrorHandler);
    this.Node=new Node(this.ErrorHandler);   //节点创建

    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();

        let directive = (expr.Type === Syntax.Literal) ? this.GetTokenRaw(token).slice(1, -1) : null;
        this.ConsumeSemicolon();

        return this.Finalize(node, directive ? this.Node.Directive(expr, directive) : this.Node.ExpressionStatement(expr));
    }

    this.ParseDirectivePrologues=function()
    {
        let firstRestricted=null;
        let body=[];
        while(true)
        {
            let token=this.LookAhead;
            if (token.Type!=8 /*StringLiteral*/) break;

            let statement=this.ParseDirective();
            body.push(statement);
        }

        return body;
    }

    // https://tc39.github.io/ecma262/#sec-block
    this.ParseStatementListItem=function()
    {
        let statement;
        this.Context.IsAssignmentTarget=true;
        this.Context.IsBindingElement=true;
        if (this.LookAhead.Type==4 /*Keyword*/)
        {

        }
        else
        {
            statement=this.ParseStatement();
        }

        return statement;
    }

    // https://tc39.github.io/ecma262/#sec-ecmascript-language-statements-and-declarations
    this.ParseStatement=function()
    {
        let statement;
        switch(this.LookAhead.Type)
        {
            case 1 /* BooleanLiteral */:
            case 5 /* NullLiteral */:
            case 6 /* NumericLiteral */:
            case 8 /* StringLiteral */:
            case 10 /* Template */:
            case 9 /* RegularExpression */:
                statement = this.ParseExpressionStatement();
                break;
            case 7 /* Punctuator */:
                let value = this.LookAhead.Value;
                if (value === '(') statement = this.ParseExpressionStatement();
                else if (value === ';') statement = this.ParseEmptyStatement();
                else statement = this.ParseExpressionStatement();
                break;
            case 3 /* Identifier */:
                statement = this.ParseLabelledStatement();
                break;
            case 4 /* Keyword */:
                break;
            default:
                statement="error";
        }

        return statement;
    }
    
    // https://tc39.github.io/ecma262/#sec-empty-statement
    this.ParseEmptyStatement=function()
    {
        let node=this.CreateNode();
        this.Expect(';');
        return this.Finalize(node, this.Node.EmptyStatement());
    }

    //https://tc39.github.io/ecma262/#sec-labelled-statements
    this.ParseLabelledStatement=function()
    {
        let node=this.CreateNode();
        let expr=this.ParseExpression();
        this.ConsumeSemicolon();
        let statement = new this.Node.ExpressionStatement(expr);

        return this.Finalize(node, statement);
    }

    // https://tc39.github.io/ecma262/#sec-comma-operator
    this.ParseExpression=function()
    {
        let startToken=this.LookAhead;
        let expr=this.IsolateCoverGrammar(this.ParseAssignmentExpression);
        if (this.Match(','))
        {
            let expressions=[];
            expressions.push(expr);
            while(this.LookAhead.Type!=2 /*EOF*/)
            {
                if (!this.Match(',')) break;
                this.NextToken();
                expressions.push(this.IsolateCoverGrammar(this.ParseAssignmentExpression));
            }

            expr=this.Finalize(this.StartNode(startToken),this.Node.SequenceExpression(expressions));
        }

        return expr;
    }

    this.ParseAssignmentExpression=function()
    {
        let expr;

        let startToken=this.LookAhead;
        let token=startToken;
        expr=this.ParseConditionalExpression();

        if (this.MatchAssign())
        {
            if (!this.Context.IsAssignmentTarget) 
            {
                let marker=expr.Marker;
                this.ThrowUnexpectedError(marker.Index,marker.Line,marker.Column,Messages.InvalidLHSInAssignment);
            }

            if (!this.Match('=') && !this.Match(':'))
            {
                this.Context.IsAssignmentTarget=false;
                this.Context.IsBindingElement=false;
            }
            else
            {
                this.ReinterpretExpressionAsPattern(expr);
            }

            token=this.NextToken();
            let operator=token.Value;
            let right=this.IsolateCoverGrammar(this.ParseAssignmentExpression);
            expr=this.Finalize(this.StartNode(startToken), this.Node.AssignmentExpression(operator, expr, right));
            this.Context.FirstCoverInitializedNameError=null;
        }

        return expr;
    }

    this.ParseConditionalExpression=function()
    {
        let startToken=this.LookAhead;
        let expr=this.InheritCoverGrammar(this.ParseBinaryExpression);

        return expr;
    }

    this.ParseBinaryExpression=function()
    {
        let startToken=this.LookAhead;
        let expr=this.InheritCoverGrammar(this.ParseExponentiationExpression);
        let token=this.LookAhead;
        var prec=this.BinaryPrecedence(token);
        if (prec>0)
        {
            this.NextToken();
            this.Context.IsAssignmentTarget=false;
            this.Context.IsBindingElement=false;
            let markers=[startToken,this.LookAhead];
            let left=expr;
            let right=this.IsolateCoverGrammar(this.ParseExponentiationExpression);
            let stack=[left,token.Value,right];
            let precedences = [prec];
            while(true)
            {
                prec=this.BinaryPrecedence(this.LookAhead);
                if (prec<=0) break;

                while(stack.length>2 && prec<=precedences[precedences.length-1])
                {
                    right=stack.pop();
                    let operator=stack.pop();
                    precedences.pop();
                    left=stack.pop();
                    markers.pop();
                    let node=this.StartNode(markers[markers.length - 1]);
                    stack.push(this.Finalize(node, this.Node.BinaryExpression(operator, left, right)));
                }

                //Shift
                stack.push(this.NextToken().Value);
                precedences.push(prec);
                markers.push(this.LookAhead);
                stack.push(this.IsolateCoverGrammar(this.ParseExponentiationExpression));
            }

            let i=stack.length-1;
            expr=stack[i];
            let lastMarker=markers.pop();
            while(i>1)
            {
                let marker=markers.pop();
                let lastLineStart=lastMarker && lastMarker.LineStart;
                let node=this.StartNode(marker, lastLineStart);
                let operator=stack[i-1];
                expr=this.Finalize(node, this.Node.BinaryExpression(operator, stack[i - 2], expr));
                i-=2;
                lastMarker=marker;
            }
        }

        return expr;
    }

    this.ParseExponentiationExpression=function()
    {
        let startToken=this.LookAhead;
        let expr=this.InheritCoverGrammar(this.ParseUnaryExpression);

        return expr;
    }

    this.ParseUnaryExpression=function()
    {
        let expr;
        if (this.Match('+') || this.Match('-'))
        {
            let node=this.StartNode(this.LookAhead);
            let token=this.NextToken();
            expr=this.InheritCoverGrammar(this.ParseUnaryExpression);
            expr=this.Finalize(node, this.Node.UnaryExpression(token.Value, expr));
            this.Context.IsAssignmentTarget=false;
            this.Context.IsBindingElement=false;
        }
        else
        {
            expr=this.ParseUpdateExpression();
        }

        return expr;
    }

    // https://tc39.github.io/ecma262/#sec-update-expressions
    this.ParseUpdateExpression=function()
    {
        let expr;
        let startToken=this.LookAhead;
        expr=this.InheritCoverGrammar(this.ParseLeftHandSideExpressionAllowCall);

        return expr;
    }

    this.ParseLeftHandSideExpressionAllowCall=function()
    {
        let startToken=this.LookAhead;
        let expr;
        expr=this.InheritCoverGrammar(this.ParsePrimaryExpression);

        while(true)
        {
            if (this.Match('.')) 
            {
                this.Context.IsBindingElement = false;
                this.Context.IsAssignmentTarget = true;
                this.Expect('.');
                const property = this.ParseMemberIdentifierName();
                expr = this.Finalize(this.StartNode(startToken), this.Node.StaticMemberExpression(expr, property,startToken));

            }
            else if (this.Match('('))
            {
                this.Context.IsBindingElement=false;
                this.Context.IsAssignmentTarget=false;
                var args=this.ParseArguments(); //解析 调用参数
                expr=this.Finalize(this.StartNode(startToken), this.Node.CallExpression(expr,args,startToken));
            }
            else
            {
                break;
            }
        }

        return expr;
    }

    /*
    BooleanLiteral = 1,
    EOF=2,
    Identifier=3,
    Keyword=4,
    NullLiteral=5,
    NumericLiteral=6,
    Punctuator=7,
    StringLiteral=9,
    RegularExpression=9,
    Template=10
    */
    this.IsIdentifierName=function(token) 
    {
        return token.Type === 3 //Identifier 
            || token.Type === 4 //Keyword 
            || token.Type === 1 //BooleanLiteral 
            || token.Type === 5 ;//NullLiteral;
    }

    this.ParseIdentifierName=function()
    {
        const node = this.CreateNode();
        const token = this.NextToken();
        if (!this.IsIdentifierName(token)) 
        {
            this.ThrowUnexpectedToken(token);
        }

        return this.Finalize(node, this.Node.Identifier(token.Value, token));
    }

    this.ParseMemberIdentifierName=function()
    {
        const node = this.CreateNode();
        const token = this.NextToken();
        if (!this.IsIdentifierName(token)) 
        {
            this.ThrowUnexpectedToken(token);
        }

        return this.Finalize(node, this.Node.MemberIdentifier(token.Value, token));
    }

    // https://tc39.github.io/ecma262/#sec-left-hand-side-expressions
    this.ParseArguments=function()
    {
        this.Expect('(');
        var args=[];
        if (!this.Match(')'))
        {
            while(true)
            {
                let expr=this.IsolateCoverGrammar(this.ParseAssignmentExpression);
                args.push(expr);

                if (this.Match(')')) break;

                this.ExpectCommaSeparator();

                if (this.Match(')')) break;
            }
        }

        this.Expect(')');
        return args;
    }

    // Quietly expect a comma when in tolerant mode, otherwise delegates to expect().
    this.ExpectCommaSeparator=function()
    {
        this.Expect(',');
    }

    // https://tc39.github.io/ecma262/#sec-primary-expression
    this.ParsePrimaryExpression=function()
    {
        let node=this.CreateNode();
        let expr;
        var token, raw;
        switch(this.LookAhead.Type)
        {
            case 3:/* Identifier */
                token=this.NextToken();
                expr=this.Finalize(node, this.Node.Identifier(token.Value, token));
                break;
            case 6:/* NumericLiteral */
            case 8:/* StringLiteral */
                this.Context.IsAssignmentTarget=false;
                this.Context.IsBindingElement=false;
                token=this.NextToken();
                raw=this.GetTokenRaw(token);
                expr=this.Finalize(node, this.Node.Literal(token.Value,raw,token));
                break;
            case 7:/* Punctuator */
                switch(this.LookAhead.Value)
                {
                    case '(':
                        this.Context.IsBindingElement=false;
                        expr=this.InheritCoverGrammar(this.ParseGroupExpression);
                        break;
                    default:
                        expr=this.ThrowUnexpectedToken(this.NextToken())
                }
                break;
            default:
                expr = this.ThrowUnexpectedToken(this.NextToken());
        }

        return expr;
    }

    this.ParseGroupExpression=function()
    {
        let expr;
        this.Expect('(');
        if (this.Match(')'))
        {
            this.NextToken();
        }
        else
        {
            let startToken=this.LookAhead;
            let params=[];
            let arrow=false;
            this.Context.IsBindingElement=true;
            expr=this.InheritCoverGrammar(this.ParseAssignmentExpression);
            if (this.Match(','))
            {
                let expressions=[];
                this.Context.IsAssignmentTarget=false;
                expressions.push(expr);
                while(this.LookAhead.Type!=2 /* EOF */)
                {
                    if (!this.Match(',')) break;

                    this.NextToken();
                    if (this.Match(')'))
                    {

                    }
                }
            }

            if (!arrow)
            {
                this.Expect(')');
                this.Context.IsBindingElement=false;
            }
        }

        return expr;
    }

    // https://tc39.github.io/ecma262/#sec-expression-statement
    this.ParseExpressionStatement=function()
    {
        let node=this.CreateNode();
        let expr=this.ParseExpression();
        this.ConsumeSemicolon();

        return this.Finalize(node,this.Node.ExpressionStatement(expr));
    }

    this.ConsumeSemicolon=function()
    {
        if (this.Match(';')) 
        {
            this.NextToken();
        }
        else if (!this.HasLineTerminator)
        {
            //if (this.LookAhead.Type!=2/*EOF*/ && !this.Match('}'))

            this.LastMarker.Index=this.StartMarker.Index;
            this.LastMarker.Line=this.StartMarker.Line;
            this.LastMarker.Column=this.StartMarker.Column;
        }
    }

    this.ReinterpretExpressionAsPattern=function(expr)
    {
        switch(expr.Type)
        {
            case Syntax.Identifier:
            case Syntax.MemberExpression:
            case Syntax.AssignmentExpression:
                break;
            default:
                break;
        }
    }

    this.Finalize=function(marker,node)
    {
        node.Marker={ Line:marker.Line, Column:marker.Column, Index:marker.Index };
        return node;
    }

    this.BinaryPrecedence = function (token) 
    {
        let op = token.Value;
        let precedence;

        if (token.Type === 7 /* Punctuator */) precedence = this.PeratorPrecedence[op] || 0;
        else precedence = 0;
        
        return precedence;
    };

    this.IsolateCoverGrammar=function(parseFunction)
    {
        let previousIsBindingElement=this.Context.IsBindingElement;
        let previousIsAssignmentTarget=this.Context.IsAssignmentTarget;
        let previousFirstCoverInitializedNameError=this.Context.FirstCoverInitializedNameError;

        this.Context.IsBindingElement=true;
        this.Context.IsAssignmentTarget=true;
        this.Context.FirstCoverInitializedNameError=null;
        let result=parseFunction.call(this);

        if (this.Context.FirstCoverInitializedNameError!=null)
        {
            //错误 this.throwUnexpectedToken(this.context.firstCoverInitializedNameError);
        }

        this.Context.IsBindingElement=previousIsBindingElement;
        this.Context.IsAssignmentTarget=previousIsAssignmentTarget;
        this.Context.FirstCoverInitializedNameError=previousFirstCoverInitializedNameError;

        return result;
    }

    this.InheritCoverGrammar = function (parseFunction) 
    {
        let previousIsBindingElement = this.Context.IsBindingElement;
        let previousIsAssignmentTarget = this.Context.IsAssignmentTarget;
        let previousFirstCoverInitializedNameError = this.Context.FirstCoverInitializedNameError;
        this.Context.IsBindingElement = true;
        this.Context.IsAssignmentTarget = true;
        this.Context.FirstCoverInitializedNameError = null;

        let result = parseFunction.call(this);

        this.Context.IsBindingElement = this.Context.IsBindingElement && previousIsBindingElement;
        this.Context.IsAssignmentTarget = this.Context.IsAssignmentTarget && previousIsAssignmentTarget;
        this.Context.FirstCoverInitializedNameError = previousFirstCoverInitializedNameError || this.Context.FirstCoverInitializedNameError;

        return result;
    };

    this.ThrowUnexpectedToken=function(token,message)
    {
        throw this.UnexpectedTokenError(token,message);
    }

    this.ThrowUnexpectedError=function(index,line,column,message)
    {
        let msg=message || "执行异常";
       
        return this.ErrorHandler.ThrowError(index,line,column,msg);
    }

    this.UnexpectedTokenError=function(token,message)
    {
        let msg=message || Messages.UnexpectedToken;
        let value='ILLEGAL';
        if (token)
        {
            if (!message)
            {

            }
            value=token.Value;
        }

        msg=msg.replace("%0",value);
        if (token && typeof(token.LineNumber)=='number')
        {
            let index=token.Start;
            let line=token.LineNumber;
            let lastMarkerLineStart=this.LastMarker.Index-this.LastMarker.Column;
            let column=token.Start-lastMarkerLineStart+1;
            return this.ErrorHandler.CreateError(index,line,column,msg);
        }
        else
        {
            let index=this.LastMarker.Index;
            let line=this.LastMarker.Line;
            let column=this.LastMarker.Column+1;
            return this.ErrorHandler.CreateError(index,line,column,msg);
        }
    }
}


/*
    算法类
*/
function JSAlgorithm(errorHandler,symbolData)
{
    this.ErrorHandler=errorHandler;
    this.SymbolData=symbolData; //股票数据

    //相加
    this.Add=function(data,data2)
    {
        let isNumber=typeof(data)=='number';
        let isNumber2=typeof(data2)=='number';

        //单数值相加
        if (isNumber && isNumber2) return data+data2;

        //都是数组相加
        let result=[];
        if (!isNumber && !isNumber2)
        {
            let count=Math.max(data.length, data2.length);
            for(let i=0;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=this.IsNumber(data);
        let isNumber2=this.IsNumber(trueData);
        let isNumber3=this.IsNumber(falseData);

        var isArray2=Array.isArray(trueData);
        var isArray3=Array.isArray(falseData);
        
        //单数值
        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 if (isArray2) result[i]=trueData[i];
                else result[i]=null;
            }
            else
            {
                if (isNumber3) result[i]=falseData;
                else if (isArray3) result[i]=falseData[i];
                else result[i]=null;
            }
        }

        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);
    }

    //指标函数 函数名全部大写

    //引用若干周期前的数据(平滑处理).
    //用法: REF(X,A),引用A周期前的X值.A可以是变量.
    //平滑处理:当引用不到数据时进行的操作.此函数中,平滑时使用上一个周期的引用值.
    //例如: REF(CLOSE,BARSCOUNT(C)-1)表示第二根K线的收盘价.
    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);

            //平滑处理
            var firstData=data[0];
            for(let i=0;i<n;++i)
                result.unshift(firstData);
        }
        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; 
    }

    //引用若干周期前的数据(未作平滑处理).
    //用法: REFV(X,A),引用A周期前的X值.A可以是变量.
    //平滑处理:当引用不到数据时进行的操作.
    //例如: REFV(CLOSE,BARSCOUNT(C)-1)表示第二根K线的收盘价.
    this.REFV=function(data,n)
    {
        let result=[];
        if (typeof(n)=='number')
        {
            if (data.length<=0) return result;
            if (n>=data.length) return result;

            result=data.slice(0,data.length-n);

            for(let i=0;i<n;++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];
            }
        }

        return result; 
    }

    //属于未来函数,引用若干周期后的数据(平滑处理).
    //用法: REFX(X,A),引用A周期后的X值.A可以是变量.
    //平滑处理:当引用不到数据时进行的操作.此函数中,平滑时使用上一个周期的引用值.
    //例如: TT:=IF(C>O,1,2);
    //      REFX(CLOSE,TT);表示阳线引用下一周期的收盘价,阴线引用日后第二周期的收盘价.
    this.REFX=function(data,n)
    {
        let result=[];
        if (typeof(n)=='number')
        {
            if (data.length<=0) return result;
            if (n>=data.length) 
            {
                if (data.length>0) return data[data.length-1];  //取最后一个数据

                return result;
            }

            result=data.slice(n,data.length);

            //平滑处理
            var lastData=data[data.length-1];
            for(let i=0;i<n;++i)
                result.push(lastData);
        }
        else    //n 为数组的情况
        {
            var dataCount=data.length;
            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<dataCount) result[i]=data[i+value];
                else if (i) result[i]=result[i-1];
                else result[i]=data[i];
            }
        }

        return result; 
    }

    //属于未来函数,引用若干周期后的数据(未作平滑处理).
    //用法:REFXV(X,A),引用A周期后的X值.A可以是变量.
    //平滑处理:当引用不到数据时进行的操作.
    //例如: REFXV(CLOSE,1)表示下一周期的收盘价,在日线上就是明天收盘价
    this.REFXV=function(data,n)
    {
        let result=[];
        if (typeof(n)=='number')
        {
            if (data.length<=0) return result;
            if (n>=data.length) return result;

            result=data.slice(n,data.length);

            //平滑处理
            for(let i=0;i<n;++i)
                result.push(null);
        }
        else    //n 为数组的情况
        {
            var dataCount=data.length;
            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<dataCount) result[i]=data[i+value];
            }
        }

        return result; 
    }

    //求最大值.
    //用法:MAX(A,B,C,D ..... ) 返回A,B,C,D ..... 中的较大值 
    //例如: MAX(CLOSE-OPEN,0)表示若收盘价大于开盘价返回它们的差值,否则返回0
    this.MAX=function(args, node)
    {
        if (args.length==0) this.ThrowUnexpectedNode(node,'MAX() Error: 参数个数不能为0');
        if (args.length==1) return args[0];

        var aryData=[], aryNumber=[];
        for(var i in args)
        {
            var item=args[i];
            if (IFrameSplitOperator.IsNumber(item)) aryNumber.push(item);
            else if (Array.isArray(item)) aryData.push(item);
        }

        var maxNumber=null;
        if (aryNumber.length>0)
        {
            maxNumber=aryNumber[0];
            for(var i=1; i<aryNumber.length; ++i)
            {
                maxNumber=Math.max(maxNumber,aryNumber[i]);
            }
        }

        var maxAryData=null;
        if (aryData.length>0)
        {
            maxAryData=aryData[0].slice(0);
            for(var i=1;i<aryData.length;++i)
            {
                var dataItem=aryData[i];
                for(var j in dataItem)
                {
                    var maxItem=maxAryData[j];
                    var item=dataItem[j];
                    if (!IFrameSplitOperator.IsNumber(maxItem)) continue;
                    if (!IFrameSplitOperator.IsNumber(item))
                    {
                        maxAryData[j]=null;
                        continue;
                    }
                        
                    maxAryData[j]=Math.max(maxItem,item);
                }
            }
        }

        if (maxAryData==null && maxNumber!=null) return maxNumber;
        if (maxAryData && maxNumber==null) return maxAryData;

        for(var i in maxAryData)
        {
            if (!IFrameSplitOperator.IsNumber(maxAryData[i])) continue;
            maxAryData[i]=Math.max(maxAryData[i],maxNumber);
        }
        
        return maxAryData;
    }

    //求最小值.
    //用法:MIN(A,B, C, D .....)返回A,B, C ,D ......中的较小值
    //例如:MIN(CLOSE,OPEN)返回开盘价和收盘价中的较小值
    this.MIN=function(args, node)
    {
        if (args.length==0) this.ThrowUnexpectedNode(node,'MIN() Error: 参数个数不能为0');
        if (args.length==1) return args[0];

        var aryData=[], aryNumber=[];
        for(var i in args)
        {
            var item=args[i];
            if (IFrameSplitOperator.IsNumber(item)) aryNumber.push(item);
            else if (Array.isArray(item)) aryData.push(item);
        }

        var minNumber=null;
        if (aryNumber.length>0)
        {
            minNumber=aryNumber[0];
            for(var i=1; i<aryNumber.length; ++i)
            {
                minNumber=Math.min(minNumber,aryNumber[i]);
            }
        }

        var minAryData=null;
        if (aryData.length>0)
        {
            minAryData=aryData[0].slice(0);
            for(var i=1;i<aryData.length;++i)
            {
                var dataItem=aryData[i];
                for(var j in dataItem)
                {
                    var minItem=minAryData[j];
                    var item=dataItem[j];
                    if (!IFrameSplitOperator.IsNumber(minItem)) continue;
                    if (!IFrameSplitOperator.IsNumber(item))
                    {
                        minAryData[j]=null;
                        continue;
                    }
                        
                    minAryData[j]=Math.min(minItem,item);
                }
            }
        }

        if (minAryData==null && minNumber!=null) return minNumber;
        if (minAryData && minNumber==null) return minAryData;

        for(var i in minAryData)
        {
            if (!IFrameSplitOperator.IsNumber(minAryData[i])) continue;
            minAryData[i]=Math.min(minAryData[i],minNumber);
        }
        
        return minAryData;
    }

    //取正数
    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 (dayCount<=0) return 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) continue;
                
                var sum=0;
                var count=0;
                for(var j=i, k=0;j>=0 && k<sumCount;--j,++k)
                {
                    sum+=data[j];
                    ++count;
                }
                if (count>0) result[i]=sum/count;
            }
        }

        return result;
    }

    //指数平均数指标 EMA(close,10)
    //N  支持周期数组
    this.EMA=function(data,dayCount)
    {
        var result = [];
        if (data.length<=0) return result;

        if (Array.isArray(dayCount))
        {
            for(var i=0;i<dayCount.length;++i)
            {
                var period=dayCount[i];
                if (!this.IsNumber(period)) continue;
                period=parseInt(period);    //周期用整数
                if (period<=0) continue;

                if (period>i+1) period=i+1;
                //EMA(N) = 2/(N+1)*C + (N-1)/(N+1)*EMA', EMA'为前一天的ema
                var EMAFactor=[ 2/ (period + 1), (period - 1) / (period + 1)];

                var ema=null;
                var lastEMA=null;
                for(var j=0;j<period;++j)
                {
                    var index=i-(period-j-1);
                    var value=data[index];
                    if (!this.IsNumber(value)) coninue;
                    if (lastEMA==null)
                    {
                        ema=value;  //第一个EMA为第一个数据的价格
                        lastEMA=ema;  
                    }
                    else
                    {
                        ema = EMAFactor[0] * value + EMAFactor[1] * lastEMA;
                        lastEMA=ema;
                    } 
                }

                result[i]=ema;
            }

        }
        else
        {
            var offset=0;
            //取首个有效数据
            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;
    }

    this.XMA=function(data,n)
    {
        var result=[];
        var offset=0;
        for(;offset<data.length;++offset)
        {
            if (this.IsNumber(data[offset])) break;
        }

        var p = parseInt((n - 2) / 2);
	    var sum = 0;
        var count = 0, start=0, end = 0;
    
        for(var i=offset, j=0; i<data.length; ++i)
        {
            start = i - p - 1;
            end = i + (n - p) - 1;
            for (j = start; j < end; ++j)
            {
                if (j >= 0 && j<data.length) 
                {
                    if (this.IsNumber(data[j]))
                    {
                        sum += data[j];
                        ++count;
                    }
                }
            }
    
            if (count!=0) result[i]=(sum / count);
            else result[i]=null;

            sum = 0;
            count = 0;
        }

        return result;
    }

    /* 
        SMA 移动平均
        返回移动平均。
        用法：　SMA(X，N，M)　X的N日移动平均，M为权重，如Y=(X*M+Y'*(N-M))/N 
    */
    this.SMA=function(data,n,m)
    {
        var result = [];

        if (Array.isArray(n))
        {
            for( var i=0;i<n.length;++i)
            {
                var period=n[i];
                if (!this.IsNumber(period)) continue;
                period=parseInt(period);
                if (period<=0) continue;
                if (period>i+1) period=i+1;
                
                var lastSMA=null;
                var sma=null;
                for(var j=0;j<period;++j)
                {
                    var index=i-(period-j-1);
                    var item=data[index];
                    if (!this.IsNumber(item)) continue;
                    if (lastSMA==null) 
                    {
                        lastSMA=item;
                        sma=item;
                    }
                    else
                    {
                        sma=(m*item+(period-m)*lastSMA)/period;
                        lastSMA=sma;
                    }
                }

                result[i]=sma;
            }
        }
        else
        {
            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 (Array.isArray(dayCount))
        {
            for(i=0;i<dayCount.length && i<data.length;++i)
            {
                result[i]=null;
                var period=dayCount[i];
                if (period<=0) continue;
                var start=0,value=0, index=0, preValue=0;
                for(var j=0;j<period;++j)
                {
                    index=i-(period-j-1);
                    value=data[index];
                    start=j;
                    if (this.IsNumber(value))
                    {
                        preValue=value;
                        break;
                    }
                }

                if (start>=period) continue;
                var sum=0, count=0;
                for(var j=start, k=1;j<period; ++j, ++k)
                {
                    index=i-(period-j-1);
                    value=data[index];
                    if (this.IsNumber(value))
                        preValue=value;
                    else
                        value=preValue;

                    count += k;
                    sum += value * k;
                }

                result[i] = sum / count;
            }

            return result;
        }
        else
        {
            if (dayCount<=0) return [];
            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)
    {
        if (this.IsNumber(data))
        {
            return 0-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;
    }

    /*
    统计满足条件的周期数.
	用法:COUNT(X, N), 统计N周期中满足X条件的周期数, 若N<0则从第一个有效值开始.
    例如 :COUNT(CLOSE>OPEN, 20)表示统计20周期内收阳的周期数
    N 支持数组
    */
    this.COUNT=function(data,n)
    {
        if (Array.isArray(n))
        {
            var start=null;
            var dataCount=data.length;
            for(var i=0;i<dataCount;++i) 
            {
                if (this.IsNumber(data[i])) 
                {
                    start=i;
                    break;
                }
            }
            if (start==null) return [];

            var result=[];
            var count=0;
            for(var i=0;i<n.length;++i)
            {
                var period=n[i];
                if (!IFrameSplitOperator.IsNumber(period)) continue;
                
                if (period<1) period=i+1;
                count=0;
                for(var j=i, k=0 ;j>=0 && k<period ;--j,++k)    //当前往前period天 统计
                {
                    if (data[j]) ++count;
                }

                result[i]=count;
            }

            return result;
        }
        else
        {
            var period=n;
            var dataCount=data.length;
            var period=period<1?dataCount:period;
    
            var i=0,j=0;
            for(;i<dataCount;++i)   // 取第1个有效数据
            {
                if (this.IsNumber(data[i])) break;
            }
    
            var result=[];
            var days=0;
            for(;i<dataCount && j<period; ++i,++j)
            {
                days=data[i]?days+1:days;
                result[i]=days;
            }
            
            for(;i<dataCount;++i)
            {
                if (data[i-period] && days) days--;
    
                days=data[i] ? days+1 : days;
                result[i]=days;
            }
    
            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 (!IFrameSplitOperator.IsNonEmptyArray(data)) return result;
            if (n<=0) n=data.length;
            else if (n>data.length) n=data.length;

            var nStart=this.GetFirstVaildIndex(data);
            if (nStart>=data.length) return result;

            var nMax=nStart;
            if (nMax<data.length) result[nMax]=data[nMax];
            for(var i=nMax+1,j=2;i<data.length && j<n;++i,++j)
            {
                if (data[i]>=data[nMax]) nMax=i;
                result[i]=data[nMax];
            }

            for(;i<data.length;++i)
            {
                if (i-nMax<n) 
                {
                    nMax=data[i]<data[nMax]?nMax:i;
                }
                else
                {
                    for(j=nMax=(i-n+1);j<=i;++j)
                    {
                        nMax=data[j]<data[nMax]?nMax:j;
                    }
                }

                result[i]=data[nMax];
            }
        }

        return result;
    }

    /*
    HV(X,N)：求X在N个周期内（不包含当前k线）的最高值。

    注：
    1、若N为0则从第一个有效值开始算起(不包含当前K线)；
    2、当N为有效值，但当前的k线数不足N根，按照实际的根数计算，第一根k线返回空值；
    3、N为空值时，返回空值。
    4、N可以是变量。

    例1：
    HH:HV(H,10);//求前10根k线的最高点。
    例2：
    N:=BARSLAST(DATE<>REF(DATE,1))+1;
    ZH:VALUEWHEN(DATE<>REF(DATE,1),HV(H,N));//在分钟周期上，求昨天最高价。
    例3：
    HV(H,5) 和 REF(HHV(H,5),1) 的结果是一样的，用HV编写更加方便。
    */
    this.HV=function(data,n)
    {
        var result=this.HHV(data,n);
        return this.REF(result,1);
    }

    /*
    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 (!IFrameSplitOperator.IsNonEmptyArray(data)) return result;
            if (n<=0) n=data.length;
            else if (n>data.length) n=data.length;

            var nStart=this.GetFirstVaildIndex(data);
            if (nStart>=data.length) return result;

            var nMin=nStart;
            if (nMin<data.length) result[nMin]=data[nMin];
            for(var i=nMin+1,j=2;i<data.length && j<n;++i,++j)
            {
                if (data[i]<=data[nMin]) nMin=i;
                result[i]=data[nMin];
            }

            for(;i<data.length;++i)
            {
                if (i-nMin<n) 
                {
                    nMin=data[i]>data[nMin]?nMin:i;
                }
                else
                {
                    for(j=nMin=(i-n+1);j<=i;++j)
                    {
                        nMin=data[j]>data[nMin]?nMin:j;
                    }
                }

                result[i]=data[nMin];
            }
        }

        return result;
    }

    /*
    LV(X,N) 求X在N个周期内的最小值（不包含当前k线）

    注：
    1、若N为0则从第一个有效值开始算起;
    2、当N为有效值，但当前的k线数不足N根，按照实际的根数计算;
    3、N为空值时，返回空值。
    4、N可以是变量。

    例1：
    LL:LV(L,10);//求前面10根k线的最低点。（不包含当前k线）
    例2：
    N:=BARSLAST(DATE<>REF(DATE,1))+1;//分钟周期，日内k线根数
    ZL:VALUEWHEN(DATE<>REF(DATE,1),LV(L,N));//在分钟周期上，求昨天最低价。
    例3：
    LV(L,5) 和 REF(LLV(L,5),1) 的结果是一样的，用LV编写更加方便。
    */

    this.LV=function(data,n)
    {
        var result=this.LLV(data,n);
        return this.REF(result,1);
    }

    this.STD=function(data,n)
    {
        var result=[];
        
        if (!Array.isArray(data)) return result;
        var nStart=this.GetFirstVaildIndex(data);
        if (!IFrameSplitOperator.IsNumber(n)) return result;
        if(nStart+n>data.length || n<1) return result;

        var i=nStart, j=0, bFirst=true, dTotal=0, dAvg=0;
        for(i+=n-1;i<data.length;++i)
        {
            dTotal = 0;
            if(bFirst)
            {
                bFirst = false;
                for(j=i-n+1;j<=i;++j)
                {
                    dAvg += data[j];
                }
                    
                dAvg /= n;
            }
            else
            {
                dAvg += (data[i]-data[i-n])/n;
            }

            for(j=i-n+1;j<=i;++j)
            {
                dTotal += (data[j]-dAvg)*(data[j]-dAvg);
            }
			

		    result[i] = Math.sqrt(dTotal/(n-1));
        }

        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;
    }

    /*
    CROSSDOWN(A,B)：表示当A从上方向下穿B，成立返回1(Yes)，否则返回0(No)

    注：1、CROSSDOWN(A,B)等同于CROSS(B,A)，CROSSDOWN(A,B)编写更利于理解

    例1：
    MA5:=MA(C,5);
    MA10:=MA(C,10);
    CROSSDOWN(MA5,MA10)//MA5下穿MA10
    */
    this.CROSSDOWN=function(data,data2)
    {
        return this.CROSS(data2,data);
    }

    /*
    CROSSUP(A,B) 表当A从下方向上穿过B，成立返回1(Yes)，否则返回0(No)

    注：
    1、CROSSUP(A,B)等同于CROSS(A,B)，CROSSUP(A,B)编写更利于理解。

    例1：
    MA5:=MA(C,5);
    MA10:=MA(C,10);
    CROSSUP(MA5,MA10),ICON(1,'ICO4');//MA5上穿MA10，标注红箭头。
    //CROSSUP(MA5,MA10),ICON(1,'ICO4'); 与  CROSSUP(MA5,MA10)=1,ICON(1,'ICO4');表达同等意义
    */

    this.CROSSUP=function(data,data2)
    {
        return this.CROSS(data,data2);
    }

    //累乘
    this.MULAR=function(data,n)
    {
        var result=[];
        if (!Array.isArray(n))
        {
            if(data.length<n) return result;
            if (n==0)
            {
                var index=n;
                for(;index<data.length;++index)
                {
                    if (this.IsNumber(data[index]))
                    {
                        result[index]=data[index];
                        break;
                    }
                }

                for(++index;index<data.length;++index)
                {
                    result[index]=result[index-1]*data[index];
                }
            }
            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 (!this.IsNumber(totalCount)) continue;
                totalCount=parseInt(totalCount);
                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;
    }

    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)
    {
        if (this.IsNumber(data) && this.IsNumber(n))
            return 0;

        var result=[];
        if (Array.isArray(data))
        {
            var num = null;
            if (Array.isArray(n))   //取最后一个有效数
            {
               for(var i=n.length-1;i>=0;--i)
               {
                   if (this.IsNumber(n[i]))
                   {
                        num = parseInt(n[i]);
                        break;
                   }
               }
            }
            else
            {
                num = parseInt(n);
            }

            if (!this.IsNumber(num)) return result;
            
            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,x;
        for(j = 0; j < datanum && !this.IsNumber(data[j]); ++j)
        {
            result[j] = null;
        }
        for(i = j+num-1; i < datanum; ++i)
        {
           Ex = Ey = Sxy = Sxx = 0;
           for(j = 0, x=num; j < num && j <= i; ++j, --x)
           {
               Ex += x;
               Ey += data[i - j];
           }
           Ex /= num;
           Ey /= num;
           for(j = 0, x=num; j < num && j <= i; ++j,--x)
           {
               Sxy += (x-Ex)*(data[i-j]-Ey);
               Sxx += (x-Ex)*(x-Ex);
           }
           Slope = Sxy / Sxx;
           Const = Ey - Ex*Slope;
           result[i] = Slope * num + Const;
        }

        return result;
    }

    //TSMA(X,N)：求X在N个周期内的时间序列三角移动平均
    //TSMA(a,n) 算法如下：
    //ysum=a[i]+a[i-1]+...+a[i-n+1]
    //xsum=i+i-1+..+i-n+1
    //xxsum=i*i+(i-1)*(i-1)+...+(i-n+1)*(i-n+1)
    //xysum=i*a[i]+(i-1)*a[i-1]+...+(i-n+1)*a[i-n+1]
    //k=(xysum -(ysum/n)*xsum)/(xxsum- xsum/n * xsum) //斜率
    //b= ysum/n - k*xsum/n
    //forcast[i]=k*i+b //线性回归
    //tsma[i] = forcast[i]+k  //线性回归+斜率
    this.TSMA=function(data,n)
    {
        var result=[];
        if (typeof(n)!='number') n=parseInt(n); //字符串的转成数值型
        var num = n;
        var datanum = data.length;
        if (num < 1 || num >= datanum)
            return result;
        var Ex = 0, Ey = 0, Sxy = 0, Sxx = 0, Const, Slope;
        var i, j,x;
        for(j = 0; j < datanum && !this.IsNumber(data[j]); ++j)
        {
            result[j] = null;
        }
        for(i = j+num-1; i < datanum; ++i)
        {
           Ex = Ey = Sxy = Sxx = 0;
           for(j = 0, x=num; j < num && j <= i; ++j, --x)
           {
               Ex += x;
               Ey += data[i - j];
           }
           Ex /= num;
           Ey /= num;
           for(j = 0, x=num; j < num && j <= i; ++j,--x)
           {
               Sxy += (x-Ex)*(data[i-j]-Ey);
               Sxx += (x-Ex)*(x-Ex);
           }
           Slope = Sxy / Sxx;
           Const = Ey - Ex*Slope;
           result[i] = (Slope * num + Const) + Slope;
        }

        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 (!Array.isArray(data)) return result;
        var nStart=this.GetFirstVaildIndex(data);
        if (!IFrameSplitOperator.IsNumber(n)) return result;
        if(nStart+n>data.length || n<1) return result;

        var i=nStart, j=0, bFirst=true, dTotal=0, dAvg=0;
        for(i+=n-1;i<data.length;++i)
        {
            dTotal = 0;
            if(bFirst)
            {
                bFirst = false;
                for(j=i-n+1;j<=i;++j)
                {
                    dAvg += data[j];
                }
                    
                dAvg /= n;
            }
            else
            {
                dAvg += (data[i]-data[i-n])/n;
            }

            for(j=i-n+1;j<=i;++j)
            {
                dTotal += (data[j]-dAvg)*(data[j]-dAvg);
            }
			

		    result[i] = Math.sqrt(dTotal/n);
        }

        return result;
    }

    //VAR 估算样本方差
    //VAR(X，N)　 返回估算样本方差。
    this.VAR=function(data,n)
    {
        if (this.IsNumber(data) && this.IsNumber(n)) return 0;

        var result=[];
        if (Array.isArray(data) && this.IsNumber(n))
        {
            var num = parseInt(n);
            var datanum = data.length;
            if (num <= 0 || 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);
            }
        }
        else if (Array.isArray(data) && Array.isArray(n))
        {
            var start=this.GetFirstVaildIndex(data);

            for(var i=start; i<data.length; ++i)
            {
                var SigmaPowerX = SigmaX = 0;
                if (!this.IsNumber(n[i])) continue;
                var num=parseInt(n[i]);

                if (num <= 0 || i-(num-1)<0) continue;

                for (var j = 0; j<num; ++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;
    }

    /*
    是否存在.
    例如: EXIST(CLOSE>OPEN,10) 
    表示10日内存在着阳线
    */
    this.EXIST=function(data,n)
    {
        if (typeof(data)=='number') return 0;

        if (Array.isArray(n))
        {
            var result=[];
            if (data.length<=0) return result;

            for( var i in data) //初始化
            {
                result[i]=0;
            }

            for(var i=0;i<n.length && i<data.length;++i)
            {
                var period=n[i];
                if (!this.IsNumber(period)) continue;
                period=parseInt(period);
                if (period<=0) continue;
                if (period>i+1) period=i+1;

                var bExist=false;
                var index=0, value=0;
                for(var j=0;j<period;++j)
                {
                    index=i-(period-j-1);
                    value=data[i];
                    if (this.IsNumber(value) && value>0)
                    {
                        bExist=true;
                        break;
                    }
                }

                result[i]=bExist?1:0;
            }

            return result;
        }
        else
        {
            n=parseInt(n);
            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;
        }
    }

    /*
    过滤连续出现的信号.
    用法:TFILTER(买入条件,卖出条件,N);过滤掉买入(卖出)信号发出后,下一个反向信号发出前的所有买入(卖出)信号.

    N=1表示仅对买入信号过滤;
    N=2表示仅对卖出信号过滤;
    N=0表示对买入和卖出信号都过滤,返回1,2表示买入或卖出条件成立;
    同一K线上只能有一个信号;

    例如:
    ENTERLONG:TFILTER(买入,卖出,1);
    EXITLONG:TFILTER(买入,卖出,2);

    TFILTER(D,K,1) 等价于 D AND COUNT(D, BARSLAST(K)) == 1
    TFILTER(D,K,2) 等价于 K AND COUNT(K, BARSLAST(D)) == 1
    TFILTER(D,K,0) 需要做个判断，如果满足  D AND COUNT(D, BARSLAST(K)) == 1 则返回1，如果满足  K AND COUNT(K, BARSLAST(D)) == 1 则返回2
    */
    this.TFILTER=function(data,data2,n)
    {
        
        if (!this.IsNumber(n)) return [];
        if (n==1)
        {
            return this.And(data,this.EQ(this.COUNT(data,this.BARSLAST(data2)),1));
        }
        else if (n==2)
        {
            return this.And(data2,this.EQ(this.COUNT(data2,this.BARSLAST(data)),1));
        }
        else if (n==0)
        {
            var result=this.And(data2,this.EQ(this.COUNT(data2,this.BARSLAST(data)),1));
            var value=this.And(data2,this.EQ(this.COUNT(data2,this.BARSLAST(data)),1));
            
            for(var i=0; i<result.length; ++i)
            {
                var item=value[i];
                if (item>0) result[i]=2;
            }

            return result;
        }
        
        return [];
    }

    /*
    过滤连续出现的信号.
    用法: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=[];
        if (this.IsNumber(n) && Array.isArray(data))
        {
            var nPeriod=n;
            if (nPeriod<1) nPeriod=data.length;
            var i=this.GetFirstVaildIndex(data);
            if (i>=data.length) return result;
            var j=0;
            if (i <= nPeriod - 1) j = nPeriod - 1;
	        else j = i;

            result[j] = j - i;

            for (; j < data.length; ++j)
            {
                if (this.IsNumber(result[j - 1]))
                {
                    if (result[j - 1] + 1 < nPeriod)
                    {
                        result[j] = result[j - 1] + 1;
                    }
                    else
                    {
                        for (var k = j - nPeriod+1; k <= j; ++k)
                        {
                            if (!(Math.abs(data[k]) < 0.000001))
                            {
                                result[j] = j - k;
                                break;
                            }
                        }
                    }
                }
                else
                {
                    if (!(Math.abs(data[j]) < 0.000001))
                        result[j] = 0;
                }
            }
        }

        return result;
    }

    /*
    第一个条件成立到当前的周期数.
    用法:
    BARSSINCE(X):第一次X不为0到现在的天数
    例如:
    BARSSINCE(HIGH>10)表示股价超过10元时到当前的周期数
    */
    this.BARSSINCE=function(data)
    {
        var result=[];
        var day=null;

        for(let i=0;i<data.length;++i)
        {
            result[i]=null;
            if (day==null)
            {
                if (data[i]) day=0;
            }
            else
            {
                ++day;
            }

            if (day) result[i]=day;
        }

        return result;
    }

    /*三角函数调用 func 三角函数 
    反正切值. 用法: ATAN(X)返回X的反正切值
    余弦值.  用法: COS(X)返回X的余弦值
    正弦值.  用法: SIN(X)返回X的正弦值
    正切值.  用法: TAN(X)返回X的正切值

    求自然对数. 用法: LN(X)以e为底的对数 例如: LN(CLOSE)求收盘价的对数
    求10为底的对数. 用法: LOG(X)取得X的对数 例如: LOG(100)等于2
    指数. 用法: EXP(X)为e的X次幂 例如: EXP(CLOSE)返回e的CLOSE次幂
    开平方. 用法: SQRT(X)为X的平方根 例如: SQRT(CLOSE)收盘价的平方根
    */
    this.Trigonometric=function(data,func)
    {
        if (!Array.isArray(data))
        {
            if (this.IsNumber(data)) return func(data);

            return null;
        }
        else
        {
            var result=[];
            for(let i in data)
            {
                var item=data[i];
                if (this.IsNumber(item)) result[i]=func(item);
                else result[i]=null;
            }

            return result;
        }
    }

    //反正弦值. 用法: ASIN(X)返回X的反正弦值
    this.ASIN=function(data)
    {
        if (!Array.isArray(data))
        {
            if (this.IsNumber(data)) return Math.acos(data);

            return null;
        }
        else
        {
            var result=[];
            for(let i in data)
            {
                var item=data[i];
                result[i]=null;
                if (this.IsNumber(item)) 
                {
                    if (item>=-1 && item<=1) 
                    {
                        result[i]=Math.asin(item);
                    }
                    else if (i-1>=0)
                    {
                        var preItem=result[i-1];
                        if (this.IsNumber(preItem)) result[i]=preItem;
                    }
                }
            }

            return result;
        }
    }


    //反余弦值. 用法: ACOS(X)返回X的反余弦值
    this.ACOS=function(data)
    {
        if (!Array.isArray(data))
        {
            if (this.IsNumber(data)) return Math.acos(data);

            return null;
        }
        else
        {
            var result=[];
            for(let i in data)
            {
                var item=data[i];
                result[i]=null;
                if (this.IsNumber(item)) 
                {
                    if (item>=-1 && item<=1) 
                    {
                        result[i]=Math.acos(item);
                    }
                    else if (i-1>=0)
                    {
                        var preItem=result[i-1];
                        if (this.IsNumber(preItem)) result[i]=preItem;
                    }
                }
            }

            return result;
        }
    }

    /*
    LAST(X,A,B):持续存在.
    用法:
    LAST(CLOSE>OPEN,10,5) 
    表示从前10日到前5日内一直阳线
    若A为0,表示从第一天开始,B为0,表示到最后日止
    */
    this.LAST=function(data,n,n2)
    {
        if (!Array.isArray(data)) return [];
        
        var result=[];
        var lCount=data.length;
        var nStart = n;
        var nEnd = n2, k = 0, i = 0, j = 0, t = 0;
        for (; k < lCount; ++k)
        {
            if (data[k]) break;
        }

        for (i = k, t = k - nEnd + 1; i<lCount; ++i, ++t)
        {
            j = (nStart == 0) ? k : Math.max(k, i - nStart);
            for (; j < t; ++j)
            {
                if (data[j]<=0)
                {
                    break;
                }
            }

            result[i]=(j<t ? 0 : 1);
        }
        
        return result;
    }

    /*
    属于未来函数,之字转向.
    用法: ZIG(K,N),当价格变化量超过N%时转向,K表示0:开盘价,1:最高价,2:最低价,3:收盘价,其余:数组信息
    例如: ZIG(3,5)表示收盘价的5%的ZIG转向
    */
    this.ZIG=function(data,n)
    {
        var hisData=this.SymbolData.Data;
        var result=[];
        if (typeof(data)=='number')
        {
            switch(data)
            {
                case 0:
                    data=hisData.GetOpen();
                    break;
                case 1:
                    data=hisData.GetHigh();
                    break;
                case 2:
                    data=hisData.GetLow();
                    break;
                case 3:
                    data=hisData.GetClose();
                    break;
                default:
                    return result;
            }
        }

        return this.ZIG_Calculate(data,n);
    }

    this.GetFirstVaildIndex=function(data)
    {
        for (var i = 0; i <data.length; ++i)
        {
            if (this.IsNumber(data[i]))
                return i;
        }
    
        return data.length;
    }

    this.ZIG_Calculate=function(data,dRate)
    {
        var dest=[];
        var nDataCount=data.length;
        var m=this.GetFirstVaildIndex(data);
	    var i = 0, lLastPos = 0, lState = 0, j = 0;
        var dif = 0;
        for (i = m + 1, lLastPos = lState = m; i<nDataCount - 1 && lState == m; ++i)
        {
            lState = Math.abs(data[i] - data[m]) * 100 >= dRate*data[m] ? (data[i]>data[m] ? i : -i) : m;
        }

        for (; i<nDataCount - 1; ++i)
        {
            if (data[i] >= data[i - 1] && data[i] >= data[i + 1])
            {
                if (lState<0)
                {
                    if ((data[i] - data[-lState]) * 100<dRate*data[-lState]) continue;
                    else
                    {
                        dif = (data[lLastPos] - data[j = -lState]) / (-lState - lLastPos);
                        dest[j--]=data[-lState];
                        for (; j >= lLastPos; j--)
                            dest[j]=data[-lState] + (-lState - j)*dif;
                        lLastPos = -lState;
                        lState = i;
                    }
                }
                else if (data[i]>data[lState])  lState = i;
            }
            else if (data[i] <= data[i - 1] && data[i] <= data[i + 1])
            {
                if (lState>0)
                {
                    if ((data[lState] - data[i]) * 100<dRate*data[lState]) continue;
                    else
                    {
                        dif = (data[lState] - data[j = lLastPos]) / (lState - lLastPos);
                        dest[j++]=data[lLastPos];
                        for (; j <= lState; ++j)
                            dest[j]=data[lLastPos] + (j - lLastPos)*dif;
                        lLastPos = lState;
                        lState = -i;
                    }
                }
                else if (data[i]<data[-lState]) lState = -i;
            }
        }

        if (Math.abs(lState) >= nDataCount - 2)
        {
            if (lState>0 && data[nDataCount - 1] >= data[lState]) lState = nDataCount - 1;
            if (lState<0 && data[nDataCount - 1] <= data[-lState]) lState = 1 - nDataCount;
        }

        if (lState>0)
        {
            dif = (data[lState] - data[j = lLastPos]) / (lState - lLastPos );
            dest[j++]=data[lLastPos];
            for (; j <= lState; ++j)
                dest[j]=data[lLastPos] + (j - lLastPos)*dif;
        }
        else
        {
            dif = (data[lLastPos] - data[j = -lState]) / (-lState - lLastPos);
            dest[j--]=data[-lState];
            for (; j >= lLastPos; j--)
                dest[j]=(data[-lState] + (-lState - j)*dif);
        }
        if ((lState = Math.abs(lState))<nDataCount - 1)
        {
            if (data[nDataCount - 1] >= data[lState])
            {
                dif = (data[nDataCount - 1] - data[j = lState]) / (nDataCount - lState);
                dest[j++]=(data[lState]);
                for (; j<nDataCount; ++j)
                    dest[j]=(data[lState] + (j - lState)*dif);
            }
            else
            {
                dif = (data[lState] - data[j = nDataCount - 1]) / (nDataCount - lState);
                dest[j--]=(data[nDataCount - 1]);
                for (; j >= lState; j--)
                    dest[j]=(data[nDataCount - 1] + (nDataCount - j)*dif);
            }
        }

        return dest;
    }

    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 dest=[];

        var lEnd =n2;
        if (lEnd<1) return dest;

        var nDataCount = zigData.length;
        var trough = [];
        for(var i=0;i<lEnd;++i) trough[i]=0;
        var lFlag = 0;
        var i = this.GetFirstVaildIndex(zigData) + 1;
        for (lEnd--; i<nDataCount && zigData[i]>zigData[i - 1]; ++i);

        for (; i<nDataCount && zigData[i]<zigData[i - 1]; ++i);

        for (trough[0] = --i; i<nDataCount - 1; ++i)
        {
            if (zigData[i]<zigData[i + 1])
            {
                if (lFlag)
                {
                    if (lEnd)
                    {
                        var tempTrough=trough.slice(0);
                        for(var j=0;j<lEnd;++j)
                        {
                            trough[j+1]=tempTrough[j];
                        }
                    } 
                    trough[lFlag = 0] = i;
                }
            }
            else lFlag = 1;
            if (trough[lEnd]) dest[i]=(i - trough[lEnd]);
        }
        if (trough[lEnd]) dest[i]=(i - trough[lEnd]);

        return dest;
    }

    this.TROUGH=function(data,n,n2)
    {
        var zigData=this.ZIG(data,n);   //计算ZIG
        var dest=[];

        var End=n2;
        if(End<1) return dest;

        var nDataCount = zigData.length;
        var trough=[];
        for(var i=0;i<End;++i) trough[i]=0;
        var i=1,Flag=0;
        var i = this.GetFirstVaildIndex(zigData) + 1;

        for(End--; i<nDataCount && zigData[i]>zigData[i-1]; ++i);

        for(; i<nDataCount && zigData[i]<zigData[i-1]; ++i);

        for(trough[0]=--i;i<nDataCount-1;++i)
        {	
            if(zigData[i]<zigData[i+1])
            {	
                if(Flag) 
                {	
                    if(End) 
                    {
                        var tempTrough=trough.slice(0);
                        for(var j=0;j<End;++j)
                        {
                            trough[j+1]=tempTrough[j];
                        }
                    }
                    trough[Flag=0]=i;
                }
            }
            else Flag=1;
            if(trough[End]) dest[i]=zigData[trough[End]];
        }
        if(trough[End]) dest[i]=zigData[trough[End]];

        return dest;
    }

    /*
    属于未来函数,前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 dest=[];

        var nDataCount = zigData.length;
        var lEnd = n2;
        if (lEnd < 1) return dest;

        var peak = [];
        for(var i=0;i<lEnd;++i) peak[i]=0;
        var lFlag = 0;
        
        var i = this.GetFirstVaildIndex(zigData) + 1;
        for (lEnd--; i<nDataCount && zigData[i]<zigData[i - 1]; ++i);

        for (; i<nDataCount && zigData[i]>zigData[i - 1]; ++i);

        for (peak[0] = --i; i<nDataCount - 1; ++i)
        {
            if (zigData[i]>zigData[i + 1])
            {
                if (lFlag)
                {
                    if (lEnd) 
                    {
                        var tempPeak=peak.slice(0);
                        for(var j=0;j<lEnd;++j)
                        {
                            peak[j+1]=tempPeak[j];
                        }
                    }
                    peak[lFlag = 0] = i;
                }
            }
            else lFlag = 1;
            if (peak[lEnd]) dest[i]=(i - peak[lEnd]);
        }
        if (peak[lEnd])dest[i]=(i - peak[lEnd]);

        return dest;
    }

    this.PEAK=function(data,n,n2)
    {
        var zigData=this.ZIG(data,n);   //计算ZIG
        var dest=[];

        var nDataCount = zigData.length;
        var lEnd = n2;
        if (lEnd < 1) return dest;

        var lFlag = 0;
        var peak = [];
        for(var i=0;i<lEnd;++i) peak[i]=0;
        
        var i = this.GetFirstVaildIndex(zigData) + 1;
        for (lEnd--; i<nDataCount && zigData[i]<zigData[i - 1]; ++i);

        for (; i<nDataCount && zigData[i]>zigData[i - 1]; ++i);

        for (peak[0] = --i; i<nDataCount - 1; ++i)
        {
            if (zigData[i]>zigData[i + 1])
            {
                if (lFlag)
                {
                    if (lEnd) 
                    {
                        var tempPeak=peak.slice(0);
                        for(var j=0;j<lEnd;++j)
                        {
                            peak[j+1]=tempPeak[j];
                        }
                    }
                    peak[lFlag = 0] = i;
                }
            }
            else lFlag = 1;
            if (peak[lEnd]) dest[i]=(zigData[peak[lEnd]]);
        }
        if (peak[lEnd]) dest[i]=(zigData[peak[lEnd]]);
        
        return dest;
    }

    /*
    一直存在.
    例如:
    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, node)
    {
        var result=[];
        var rate=data/100;
        if(rate<0.000001 || rate>1) return result;
    
        var kData=this.SymbolData.Data.Data;
        if (!kData || kData.length<=0) return result;
        var aryCapital=this.SymbolData.GetStockCacheData({ FunctionName:"FINANCE", Args:[7], ArgCount:1, Node:node } ); //流通股本

        var dMaxPrice=kData[0].High,dMinPrice=kData[0].Low;
        for(var i=0;i<kData.length;++i)
        {
            var item=kData[i];
            dMinPrice = Math.min(dMinPrice,item.Low);
            dMaxPrice = Math.max(dMaxPrice,item.High);
        }

        if (dMinPrice > 2000 || dMinPrice < 0 || dMaxPrice>2000 || dMinPrice < 0)
            this.ThrowUnexpectedNode(node,'COST() 历史K线最大最小值错误, 超出(0,1000)范围');

        var lMaxPrice = parseInt(dMaxPrice * 100 + 1);
        var lMinPrice = parseInt(dMinPrice * 100 - 1);
        var lLow = 0, lHigh = 0, lClose = 0;
        //去掉小数
        dMaxPrice = lMaxPrice / 100.0;
        dMinPrice = lMinPrice / 100.0;
        var lSpeed = lMaxPrice - lMinPrice + 1;
        if (lSpeed < 1) return result;
        
        var aryVolPrice=[],aryPerVol=[];
        for(var i=0;i<lSpeed;++i)
        {
            aryVolPrice[i]=0;
            aryPerVol[i]=0;
        }

        var dHSL = 0, dTotalVol = 0, dVol = 0, dCost=0;
        for(var i=0;i<kData.length;++i)
        {
            if (i >= aryCapital.length) continue;
            if (aryCapital[i]>1)
            {
                var kItem=kData[i]
                dHSL = kItem.Vol/aryCapital[i];

                for( var j=0;j<lSpeed;j++) 
                    aryVolPrice[j]*=(1-dHSL);

                lLow=parseInt(Math.min(lMaxPrice,Math.max(lMinPrice,kItem.Low *100)))-lMinPrice;
                lHigh=parseInt(Math.min(lMaxPrice,Math.max(lMinPrice,kItem.High*100)))-lMinPrice;
                lClose=parseInt(Math.min(lMaxPrice,Math.max(lMinPrice,kItem.Close*100)))-lMinPrice;

                for(var j=0;j<lSpeed;++j) aryPerVol[j]=0;

                var lHalf =parseInt((lLow + lHigh + 2 * lClose) / 4);
                if (lHalf == lHigh || lHalf == lLow)
                {
                    aryPerVol[lHalf] += kItem.Vol;
                }
                else
                {
                    var	dVH = kItem.Vol / (lHalf - lLow);
                    for (var k = lLow; k<lHalf; ++k)
                    {
                        aryPerVol[k] += (k - lLow)*(dVH / (lHalf - lLow));
                    }
                    for (k; k <= lHigh; ++k)
                    {
                        aryPerVol[k] += (k - lHigh)*(dVH / (lHalf - lHigh));
                    }
                }

                var dTotalVol = 0;
                for (var j = lLow; j <= lHigh; j++)
                {
                    aryVolPrice[j] += aryPerVol[j];
                }

                for (var j = 0; j < lSpeed; j++)
                {
                    dTotalVol += aryVolPrice[j];
                }

                for(j=0,dCost=dVol=0;j<lSpeed;++j)
                {	
                    dVol+=aryVolPrice[j];
                    if(dVol>=dTotalVol*rate)
                    {	
                        dCost=(dMaxPrice-dMinPrice)*j/lSpeed+dMinPrice;
                        break;
                    }
                }
            }

            result[i]=dCost;
        }

        return result;
    }

    /*
    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, node)
    {
        var result=[];
        var kData=this.SymbolData.Data.Data;
        if (!kData || kData.length<=0) return result;
        var aryCapital=this.SymbolData.GetStockCacheData({ FunctionName:"FINANCE", Args:[7], ArgCount:1, Node:node } ); //流通股本

        var dMaxPrice=kData[0].High,dMinPrice=kData[0].Low;
        for(var i=0;i<kData.length;++i)
        {
            var item=kData[i];
            dMinPrice = Math.min(dMinPrice,item.Low);
            dMaxPrice = Math.max(dMaxPrice,item.High);
        }

        if (dMinPrice > 1000 || dMinPrice < 0 || dMaxPrice>1000 || dMinPrice < 0)
            this.ThrowUnexpectedNode(node,'WINNER() 历史K线最大最小值错误, 超出(0,1000)范围');

        var lMaxPrice = parseInt(dMaxPrice * 100 + 1);
	    var lMinPrice = parseInt(dMinPrice * 100 - 1);
	    var lLow = 0, lHigh = 0, lClose = 0;
        //去掉小数
        dMaxPrice = lMaxPrice / 100.0;
        dMinPrice = lMinPrice / 100.0;
	    var lSpeed = lMaxPrice - lMinPrice + 1;
        if (lSpeed < 1) return result;
        
        var aryVolPrice=[],aryPerVol=[];
        for(var i=0;i<lSpeed;++i)
        {
            aryVolPrice[i]=0;
            aryPerVol[i]=0;
        }

        var dHSL = 0, dTotalVol = 0, dVol = 0;
        for(var i=0;i<kData.length;++i)
        {
            if (i >= aryCapital.length) continue;
            if (!(aryCapital[i]>1)) continue;
            var kItem=kData[i]
            dHSL = kItem.Vol/aryCapital[i];

            for( var j=0;j<lSpeed;j++) 
                aryVolPrice[j]*=(1-dHSL);

            lLow=parseInt(Math.min(lMaxPrice,Math.max(lMinPrice,kItem.Low *100)))-lMinPrice;
            lHigh=parseInt(Math.min(lMaxPrice,Math.max(lMinPrice,kItem.High*100)))-lMinPrice;
            lClose=parseInt(Math.min(lMaxPrice,Math.max(lMinPrice,kItem.Close*100)))-lMinPrice;

            for(var j=0;j<lSpeed;++j) aryPerVol[j]=0;

            var lHalf =parseInt((lLow + lHigh + 2 * lClose) / 4);
            if (lHalf == lHigh || lHalf == lLow)
            {
                aryPerVol[lHalf] += kItem.Vol;
            }
            else
            {
                var	dVH = kItem.Vol / (lHalf - lLow);
                for (var k = lLow; k<lHalf; ++k)
                {
                    aryPerVol[k] += (k - lLow)*(dVH / (lHalf - lLow));
                }
                for (k; k <= lHigh; ++k)
                {
                    aryPerVol[k] += (k - lHigh)*(dVH / (lHalf - lHigh));
                }
            }

            var dTotalVol = 0;
            for (var j = lLow; j <= lHigh; j++)
            {
                aryVolPrice[j] += aryPerVol[j];
            }

            for (var j = 0; j < lSpeed; j++)
            {
                dTotalVol += aryVolPrice[j];
            }

            if (Array.isArray(data))
                lHigh = parseInt(Math.min((data[i] * 100) - lMinPrice, lSpeed - 1));
            else
                lHigh = parseInt(Math.min((data * 100) - lMinPrice, lSpeed - 1));

            for (var j = 0, dVol = 0; j <= lHigh; j++)
            {
                dVol += aryVolPrice[j];
            }

            if (dTotalVol > 0) result[i]=dVol / dTotalVol;
            else if (i - 1 >= 0) result[i] = result[i - 1];
        }
    
        return result;
    }

    /*
    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;
    }
    */

    /*
    区间成本.
    用法:
    例如COSTEX(CLOSE,REF(CLOSE,1)),表示近两日收盘价格间筹码的成本
    该函数仅对日线分析周期有效
    */
    this.COSTEX=function(data, data2, node)
    {
        var result=[];
        var kData=this.SymbolData.Data.Data;
        if (!kData || kData.length<=0) return result;
        var aryCapital=this.SymbolData.GetStockCacheData({ FunctionName:"FINANCE", Args:[7], ArgCount:1, Node:node } ); //流通股本

        var dMaxPrice=kData[0].High,dMinPrice=kData[0].Low;
        for(var i=0;i<kData.length;++i)
        {
            var item=kData[i];
            dMinPrice = Math.min(dMinPrice,item.Low);
            dMaxPrice = Math.max(dMaxPrice,item.High);
        }

        if (dMinPrice > 1000 || dMinPrice < 0 || dMaxPrice>1000 || dMinPrice < 0)
            this.ThrowUnexpectedNode(node,'COSTEX() 历史K线最大最小值错误, 超出(0,1000)范围');

        var lMaxPrice = parseInt(dMaxPrice * 100 + 1);
        var lMinPrice = parseInt(dMinPrice * 100 - 1);
        var lLow = 0, lHigh = 0, lClose = 0;
        //去掉小数
        dMaxPrice = lMaxPrice / 100.0;
        dMinPrice = lMinPrice / 100.0;
        var lSpeed = lMaxPrice - lMinPrice + 1;
        if (lSpeed < 1) return result;
        
        var aryVolPrice=[],aryPerVol=[];
        for(var i=0;i<lSpeed;++i)
        {
            aryVolPrice[i]=0;
            aryPerVol[i]=0;
        }

        var dHSL = 0, dTotalVol = 0, dVol = 0, dVola=0, dPerVola=0, dVolb=0, dPerVolb=0;
        for(var i=0, j=0;i<kData.length;++i)
        {
            if (i >= aryCapital.length) continue;
            if (aryCapital[i]>1)
            {
                var kItem=kData[i]
                dHSL = kItem.Vol/aryCapital[i];

                for( var j=0;j<lSpeed;j++) 
                    aryVolPrice[j]*=(1-dHSL);

                lLow=parseInt(Math.min(lMaxPrice,Math.max(lMinPrice,kItem.Low *100)))-lMinPrice;
                lHigh=parseInt(Math.min(lMaxPrice,Math.max(lMinPrice,kItem.High*100)))-lMinPrice;
                lClose=parseInt(Math.min(lMaxPrice,Math.max(lMinPrice,kItem.Close*100)))-lMinPrice;

                for(var j=0;j<lSpeed;++j) aryPerVol[j]=0;

                var lHalf =parseInt((lLow + lHigh + 2 * lClose) / 4);
                if (lHalf == lHigh || lHalf == lLow)
                {
                    aryPerVol[lHalf] += kItem.Vol;
                }
                else
                {
                    var	dVH = kItem.Vol / (lHalf - lLow);
                    for (var k = lLow; k<lHalf; ++k)
                    {
                        aryPerVol[k] += (k - lLow)*(dVH / (lHalf - lLow));
                    }
                    for (k; k <= lHigh; ++k)
                    {
                        aryPerVol[k] += (k - lHigh)*(dVH / (lHalf - lHigh));
                    }
                }

                dTotalVol = 0;
                for (var j = lLow; j <= lHigh; j++)
                {
                    aryVolPrice[j] += aryPerVol[j];
                }

                for (var j = 0; j < lSpeed; j++)
                {
                    dTotalVol += aryVolPrice[j];
                }

                if (Array.isArray(data)) lHigh = parseInt(Math.min((data[i] * 100) - lMinPrice, lSpeed - 1));
                else lHigh = parseInt(Math.min((data * 100) - lMinPrice, lSpeed - 1));
                for (j = 0, dVola = 0, dPerVola = 0; j <= lHigh; j++)
                {
                    dVola += aryVolPrice[j];
                    dPerVola += (0.01*(j + lMinPrice))*aryVolPrice[j];
                }

                if (Array.isArray(data2)) lHigh = parseInt(Math.min((data2[i] * 100) - lMinPrice, lSpeed - 1));
                else lHigh = parseInt(Math.min((data2 * 100) - lMinPrice, lSpeed - 1));
                for (j = 0,  dVolb = 0, dPerVolb = 0; j <= lHigh; j++)
                {
                    dVolb += aryVolPrice[j];
                    dPerVolb += (0.01*(j + lMinPrice))*aryVolPrice[j];
                }

                dVol = dVola - dVolb;
			    dPerVolRange = dPerVola - dPerVolb;
			    if (Math.abs(dPerVolRange) > 0.001 && dVol!=0 ) result[i]=dPerVolRange / dVol;
			    else if (i-1>=0) result[i] = result[i - 1];
            }
        }

        return result;
    }

    /*
    远期成本分布比例.
    用法:
    PPART(10),表示10前的成本占总成本的比例,0.2表示20%
    */
    this.PPART=function(n,node)
    {
        var result=[];
        var startDay=n;
        if (startDay<0) return result;

        var kData=this.SymbolData.Data.Data;
        if (!kData || kData.length<=0) return result;
        var aryCapital=this.SymbolData.GetStockCacheData({ FunctionName:"FINANCE", Args:[7], ArgCount:1, Node:node } ); //流通股本
        
        for (var i = startDay, j = 0; i < kData.length; ++i)
        {
            var start = i - startDay;
            if (start < 0) continue;
            
            var partVol = 0;
            for (j = 0; j < startDay; ++j)	//前n日成交量和
            {
                var kItem=kData[j + start];
                partVol += kItem.Vol;
            }
    
            if (i < aryCapital.length)
            {
                if (aryCapital[i]>0)
                {
                    var value=1 - (partVol / aryCapital[i]);
                    result[i]=value;
                }
            }
        }

        return result;
    }

    /*
    近期获利盘比例.
    用法: LWINNER(5,CLOSE),表示最近5天的那部分成本以当前收市价卖出的获利盘比例
    例如: 返回0.1表示10%获利盘
    */
    this.LWINNER=function(n, data, node)
    {
        var startDay =n;
        if (startDay<=0) this.ThrowUnexpectedNode(node,'LWINNER() 第1个参数错误');

        var result=[];
        var kData=this.SymbolData.Data.Data;
        if (!kData || kData.length<=0) return result;
        var aryCapital=this.SymbolData.GetStockCacheData({ FunctionName:"FINANCE", Args:[7], ArgCount:1, Node:node } ); //流通股本
        var dTotalVol=0,dVol=0;
        for (var i = startDay-1, j=0, k=0 ; i < kData.length; ++i)
        {
            var index = i - startDay + 1;

            var dMaxPrice=kData[index].High,dMinPrice=kData[index].Low;
            for(var j=0;j<startDay;++j)
            {
                var item=kData[index+j];
                dMinPrice = Math.min(dMinPrice,item.Low);
                dMaxPrice = Math.max(dMaxPrice,item.High);
            }

            if (dMinPrice > 1000 || dMinPrice < 0 || dMaxPrice>1000 || dMinPrice < 0)
                this.ThrowUnexpectedNode(node,'LWINNER() 历史K线最大最小值错误, 超出(0,1000)范围');

            var lMaxPrice = parseInt(dMaxPrice * 100 + 1);
            var lMinPrice = parseInt(dMinPrice * 100 - 1);
            var lLow = 0, lHigh = 0, lClose = 0;
            dMaxPrice = lMaxPrice / 100.0;
            dMinPrice = lMinPrice / 100.0;
            var lSpeed = lMaxPrice - lMinPrice + 1;
            if (lSpeed < 1) return result;
            
            var aryVolPrice=[],aryPerVol=[];
            for(var j=0;j<lSpeed;++j)
            {
                aryVolPrice[j]=0;
                aryPerVol[j]=0;
            }

            for (j = 0; j<startDay; ++j)
		    {
                var capital=aryCapital[index + j];
                if (capital<1) continue;
                
                var kItem=kData[index + j];
                var dHSL = kItem.Vol / capital;
                for (k = 0; k < lSpeed; k++)
                {
                    aryVolPrice[k] *= (1 - dHSL);
                }

                lLow=parseInt(Math.min(lMaxPrice,Math.max(lMinPrice,kItem.Low *100)))-lMinPrice;
                lHigh=parseInt(Math.min(lMaxPrice,Math.max(lMinPrice,kItem.High*100)))-lMinPrice;
                lClose=parseInt(Math.min(lMaxPrice,Math.max(lMinPrice,kItem.Close*100)))-lMinPrice;
    
                for(var k=0;k<lSpeed;++k) aryPerVol[k]=0;

                var lHalf =parseInt((lLow + lHigh + 2 * lClose) / 4);
                if (lHalf == lHigh || lHalf == lLow)
                {
                    aryPerVol[lHalf] += kItem.Vol;
                }
                else
                {
                    var	dVH = kItem.Vol / (lHalf - lLow);
                    for (let k = lLow; k<lHalf; ++k)
                    {
                        aryPerVol[k] += (k - lLow)*(dVH / (lHalf - lLow));
                    }
                    for (let k; k <= lHigh; ++k)
                    {
                        aryPerVol[k] += (k - lHigh)*(dVH / (lHalf - lHigh));
                    }
                }
    
                dTotalVol = 0;
                for (var k = lLow; k <= lHigh; k++)
                {
                    aryVolPrice[k] += aryPerVol[k];
                }
            }

            for (var j = 0; j < lSpeed; j++)
            {
                dTotalVol += aryVolPrice[j];
            }

            if (Array.isArray(data)) 
                lHigh = parseInt(Math.min((data[i] * 100) - lMinPrice, lSpeed - 1));
            else 
                lHigh = parseInt(Math.min((data * 100) - lMinPrice, lSpeed - 1));

            dVol = 0; 
            for (k = 0 ; k <= lHigh; k++)
            {
                dVol += aryVolPrice[k];
            }
            
            if (dTotalVol > 0 && dVol > 0 && dVol <= dTotalVol) result[i]=dVol / dTotalVol;
            else if (i - 1 >= 0) result[i] = result[i - 1];
        }

        return result;
    }

    this.PWINNER=function(n, data, node)
    {
        var result=[];
        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)
    {
        if (this.IsNumber(data) || this.IsNumber(data2)) return 0;

        var result=[];
        if (n<1) n=1;

        if (!Array.isArray(data)|| !Array.isArray(data2)) return result;

        var dataAverage=this.CalculateAverage(data,n);
        var data2Average=this.CalculateAverage(data2,n);

        var count=Math.max(data.length,data2.length);

        var count=Math.max(data.length,data2.length);
        for(let i=0,j=0;i<count;++i)
        {
            result[i]=null;

            if (i>=data.length || i>=data2.length || i>=dataAverage.length || i>=data2Average.length) continue;

            var average=dataAverage[i];
            var average2=data2Average[i];

            var total=0;
            for(j=i-n+1;j<=i;++j)
            {
                total+=(data[j]-average)*(data2[j]-average2);   
            }

            result[i]=(total/n);
        }


        return result;
    }

    /*
    求上一高点到当前的周期数.
    用法:
    HHVBARS(X,N):求N周期内X最高值到当前周期数,N=0表示从第一个有效值开始统计
    例如:
    HHVBARS(HIGH,0)求得历史新高到到当前的周期数
    */
    this.HHVBARS=function(data,n)
    {
        var result=[];
        if (!Array.isArray(data)) return result;
        if (Array.isArray(n))
        {
            for(var i=0;i<n.length;++i)
            {
                result[i]=null;
                var period=n[i];
                if (!this.IsNumber(period)) continue;

                var start=i-period;
                if (start<0) start=0;
                var nMax=null;
                var j=start;
                for(; j<data.length;++j)
                {
                    if (this.IsNumber(data[j]))
                    {
                        nMax=j;
                        break;
                    }
                }

                for(var k=0; j<data.length && k<period;++k, ++j)
                {
                    if (data[j]>=data[nMax]) nMax=j;
                }

                if (nMax!=null)
                    result[i]=(i-nMax);
            }
        }
        else
        {
            if (n<1) n=data.length;

            var nMax=null;  //最大值索引
            for(var i=0;i<data.length;++i)
            {
                result[i]=null;
                if (this.IsNumber(data[i])) 
                {
                    nMax=i;
                    break;
                }
            }

            var j=0;
            for(i=nMax+1;i<data.length && j<n ;++i,++j) //求第1个最大值
            {
                if (data[i]>=data[nMax]) nMax=i;
                if(n==data.length) result[i]=(i-nMax);
            }

            for(;i<data.length;++i)
            {
                if (i-nMax<n)
                {
                    if (data[i]>=data[nMax]) nMax=i;
                }
                else
                {
                    nMax=i-n+1;
                    for(j=nMax;j<=i;++j)    //计算区间最大值
                    {
                        if (data[j]>=data[nMax]) nMax=j;
                    }
                }

                result[i]=i-nMax;
            }
        }

        return result;
    }

    /*
    求上一低点到当前的周期数.
    用法: LLVBARS(X,N):求N周期内X最低值到当前周期数,N=0表示从第一个有效值开始统计
    例如: LLVBARS(HIGH,20)求得20日最低点到当前的周期数
    */
    this.LLVBARS=function(data,n)
    {
        var result=[];
        if (!Array.isArray(data)) return result;

        if (Array.isArray(n))
        {
            for(var i=0;i<n.length;++i)
            {
                result[i]=null;
                var period=n[i];
                if (!this.IsNumber(period)) continue;

                var start=i-period;
                if (start<0) start=0;
                var nMin=null;
                var j=start;
                for(; j<data.length;++j)
                {
                    if (this.IsNumber(data[j]))
                    {
                        nMin=j;
                        break;
                    }
                }

                for(var k=0; j<data.length && k<period;++k, ++j)
                {
                    if (data[j]<=data[nMin]) nMin=j;
                }

                if (nMin!=null)
                    result[i]=(i-nMin);
            }
        }
        else
        {
            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;

        if (Array.isArray(n))
        {
            for(var i=0;i<dataCount;++i)    //初始化0
            {
                result[i]=0;
            }

            for(var i=0;i<dataCount;++i)
            {
                var value=condition[i];
                var period=n[i];
                if (this.IsNumber(value) && value && this.IsNumber(period))
                {
                    for(var j=i,k=0; j>=0 && k<period; --j,++k)
                    {
                        result[j]=1;
                    }
                }
            }
        }
        else
        {
            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=[];
        if (IFrameSplitOperator.IsString(str1) && IFrameSplitOperator.IsString(str2))
            result=str1+str2;
        return result;
    }

    //VARCAT(A,B):将两个字符串A,B相加成一个字符串C.
    //用法: DRAWTEXT(CLOSE>OPEN,LOW,VARCAT('多头',VAR2STR(C,2))) 将两个字符串相加成一个字符串并按条件显示出来
    this.VARCAT=function(data,data2)
    {
        var result=[];
        if (Array.isArray(data) && Array.isArray(data2))
        {
            var nCount=Math.max(data.length, data2.length);
            var strValue="";
            for(var i=0;i<nCount;++i)
            {
                result[i]=null;
                strValue="";
                if (i<data.length)
                {
                    var item=data[i];
                    if (IFrameSplitOperator.IsString(item)) 
                        strValue+=item;
                }

                if (i<data2.length)
                {
                    var item=data2[i];
                    if (IFrameSplitOperator.IsString(item)) 
                        strValue+=item;
                }

                if (strValue!="")
                    result[i]=strValue;
            }
        }
        else if (IFrameSplitOperator.IsString(data) && Array.isArray(data2))
        {
            for(var i=0;i<data2.length;++i)
            {
                result[i]=null;
                var item=data2[i];
                if (IFrameSplitOperator.IsString(item))
                {
                    result[i]=data+item;
                }
            }            
        }
        else if (Array.isArray(data) && IFrameSplitOperator.IsString(data2))
        {
            for(var i=0;i<data.length;++i)
            {
                result[i]=null;
                var item=data[i];
                if (IFrameSplitOperator.IsString(item))
                {
                    result[i]=item+data2;
                }
            }          
        }
        else if (IFrameSplitOperator.IsString(data) && IFrameSplitOperator.IsString(data2))
        {
            result=data+data2;
        }

        return result;
    }

    //FINDSTR(A,B):在字符串A中查找字符串B,如果找到返回1,否则返回0.
    //用法: FINDSTR('多头开仓','开仓')在字符串'多头开仓'中查找字符串'开仓',返回1
    this.FINDSTR=function(data, data2)
    {
        var result=[];
        var str, str2;
        if (IFrameSplitOperator.IsNumber(data)) str=data.toString();
        else str=data;
        if (IFrameSplitOperator.IsNumber(data2)) str2=data2.toString();
        else str2=data2;

        if (IFrameSplitOperator.IsString(str) && IFrameSplitOperator.IsString(str2))
        {
            if (str.indexOf(str2)>=0) return 1;
            else return 0;
        }
        else if (Array.isArray(data) && IFrameSplitOperator.IsString(str2))
        {
            for(var i=0;i<data.length;++i)
            {
                var item=data[i];
                if (IFrameSplitOperator.IsString(item)) 
                {
                    result[i]=item.indexOf(str2)>=0?1:0;
                }
                else if (IFrameSplitOperator.IsNumber(item))
                {
                    str=item.toString();
                    result[i]=str.indexOf(str2)>=0?1:0;
                }
                else
                {
                    result[i]=0;
                }
            }
        }

        return result;
    }

    //STRSPACE(A):字符串附带一空格
    this.STRSPACE=function(data)
    {
        var result=[];
        if (Array.isArray(data))
        {
            for(var i=0;i<data.length;++i)
            {
                result[i]=null;
                var item=data[i];
                if (IFrameSplitOperator.IsString(item))
                    result[i]=item+' ';
            }
        }
        else
        {
            if (IFrameSplitOperator.IsString(data))
                result=data+" ";
        }

        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 (this.IsNumber(item))
                {
                    result=item.toFixed(n);
                    return result;
                }
            }
        }
        else
        {
            if (this.IsNumber(data)) 
                result=data.toFixed(n);
        }

        return result;
    }

    //VAR2STR(A,N):取A的每一个值转为字符串,小数位数N.
    //用法: VAR2STR(C,3)表示取收盘价,以3位小数转为字符串
    this.VAR2STR=function(data,n)
    {
        var result=[];
        if (Array.isArray(data))
        {
            for(var i=0;i<data.length;++i)
            {
                result[i]=null;
                var item=data[i];
                if (this.IsNumber(item))
                    result[i]=item.toFixed(n);
            }
        }
        else
        {
            if (this.IsNumber(data))
                result=data.toFixed(n);
        }

        return result;
    }

    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 (Array.isArray(data) && Array.isArray(n))
        {
            for(var i=0;i<data.length;++i)
            {
                var value=data[i];
                var value2=n[i];
                if (this.IsNumber(value) && this.IsNumber(value2)) result[i]=Math.pow(value,value2);
                else result[i]=null;
            }
        }
        else if (IFrameSplitOperator.IsNumber(data) && Array.isArray(n))
        {
            for(var i=0;i<n.length;++i)
            {
                var item=n[i];
                if (this.IsNumber(item)) result[i]=Math.pow(data,item);
                else result[i]=null;
            }
        }
        else if (IFrameSplitOperator.IsNumber(data) && IFrameSplitOperator.IsNumber(n))
        {
            return Math.pow(data,n);
        }
        else if (Array.isArray(data) && IFrameSplitOperator.IsNumber(n))
        {
            for(var i=0; i<data.length;++i)
            {
                var item=data[i];
                if (this.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 (this.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 (this.IsNumber(item)) result[i]=parseInt((item-1));
            else result[i]=null;
        }

        return result;
    }

    this.ZTPRICE=function(data, rate)
    {
        if (!this.IsNumber(rate)) return null;

        if (Array.isArray(data))
        {
            var result=[];
            for(var i in data)
            {
                var item=data[i];
                if (this.IsNumber(item)) result[i]=(1+rate)*item;
                else result[i]=null;
            }
    
            return result;
        }
        else if (this.IsNumber(data))
        {
            var result=(1+rate)*data;
            return result;
        }
    }

    this.DTPRICE=function(data, rate)
    {
        if (!this.IsNumber(rate)) return null;

        if (Array.isArray(data))
        {
            var result=[];
            for(var i in data)
            {
                var item=data[i];
                if (this.IsNumber(item)) result[i]=(1-rate)*item;
                else result[i]=null;
            }
    
            return result;
        }
        else if (this.IsNumber(data))
        {
            var result=(1-rate)*data;
            return result;
        }
        
    }

    /*
    FRACPART(A)	 取得小数部分
    含义:FRACPART(A)返回数值的小数部分
    阐释:例如FRACPART(12.3)求得0.3,FRACPART(-3.5)求得-0.5
    */
    this.FRACPART=function(data)
    {
        if (Array.isArray(data))
        {
            var result=[];
            var integer=0;
            for(var i in data)
            {
                var item=data[i];
                if (this.IsNumber(item)) 
                {
                    integer=parseInt(item);
                    result[i]=item-integer;
                }
                else result[i]=null;
            }
    
            return result;
        }
        else if (this.IsNumber(data))
        {
            integer=parseInt(data);
            var result=data-integer;
            return result;
        }
    }

    /*
    统计连续满足条件的周期数.
    用法: BARSLASTCOUNT(X),统计连续满足X条件的周期数.
    例如: BARSLASTCOUNT(CLOSE>OPEN)表示统计连续收阳的周期数
    */
    this.BARSLASTCOUNT=function(data)
    {
        var result=null;
        if (Array.isArray(data))
        {
            result=[];
            if (data.length>0)
            {
                var count=0;
                for(var i=data.length-1;i>=0;--i)
                {
                    count=0;
                    for(var j=i;j>=0;--j)
                    {
                        if (data[j]) ++count;
                        else break;
                    }
                    result[i]=count;
                }
            }
        }
        else
        {
            if (data) result=1;
            else result=0;
        }
        return result;
    }

    //取整.
    //用法: INTPART(A)返回沿A绝对值减小方向最接近的整数
    //例如:INTPART(12.3)求得12,INTPART(-3.5)求得-3
    this.INTPART=function(data)
    {
        var result=null;
        if (Array.isArray(data))
        {
            result=[];
            for(var i in data)
            {
                var item=data[i];
                if (this.IsNumber(item)) result[i]=parseInt(item);
                else result[i]=null;
            }
        }
        else if (this.IsNumber(data))
        {
            result=parseInt(data);
        }

        return result;
    }

    //用法:CONST(A),取A最后的值为常量.
    //例如:CONST(INDEXC),表示取大盘现价
    this.CONST=function(data)
    {
        if (Array.isArray(data))
        {
            var count=data.length;
            if (count>0)
                return data[count-1];
            
            return null;
        }
        else
        {
            return data;
        }
    }

    //当前值是近多少周期内的最大值.
    //用法: TOPRANGE(X):X是近多少周期内X的最大值
    //例如: TOPRANGE(HIGH)表示当前最高价是近多少周期内最高价的最大值
    this.TOPRANGE=function(data)
    {
        if (this.IsNumber(data)) return 0;
        
        var result=[];

        if (Array.isArray(data))
        {
            var count=data.length;
            for(var i=count-1; i>=0;--i)
            {
                result[i]=0;
                var item=data[i];
                if (!this.IsNumber(item)) continue;

                var value=0;
                for(var j=i-1;j>=0;--j)
                {
                    if (data[j]>item)
                    {
                        break;
                    }
                    ++value;
                }

                result[i]=value;

            }
        }

        return result;
    }

    //当前值是近多少周期内的最小值.
    //用法:LOWRANGE(X):X是近多少周期内X的最小值
    //例如:LOWRANGE(LOW)表示当前最低价是近多少周期内最低价的最小值
    this.LOWRANGE=function(data)
    {
        if (this.IsNumber(data)) return 0;

        var result=[];

        if (Array.isArray(data))
        {
            var count=data.length;
            for(var i=count-1; i>=0;--i)
            {
                result[i]=0;
                var item=data[i];
                if (!this.IsNumber(item)) continue;

                var value=0;
                for(var j=i-1;j>=0;--j)
                {
                    if (data[j]<item)
                    {
                        break;
                    }
                    ++value;
                }

                result[i]=value;

            }
        }

        return result;
    }

    //N周期前的M周期内的第T个最小值.
    //用法:FINDLOW(VAR,N,M,T):VAR在N日前的M天内第T个最低价
    this.FINDLOW=function(data,n,m,t)
    {
        if (this.IsNumber(data)) return data;
        
        var result=[];
        if (Array.isArray(data))
        {
            var count=data.length;
            for(var i=count-1;i>=0;--i)
            {
                result[i]=null;
                var aryValue=[];
                for(var j=n;j<m;++j)
                {
                    var index=i-j;
                    if (index<0) break;
                    var item=data[index];
                    if (this.IsNumber(item)) aryValue.push(item);
                }

                if (aryValue.length>0)
                {
                    aryValue.sort(function(a,b) { return a-b;});
                    var index=t-1;
                    if (index<0) index=0;
                    else if (index>=aryValue.length) index=aryValue.length-1;
                    result[i]=aryValue[index];
                }
            }
        }

        return result;
    }

    //N周期前的M周期内的第T个最大值.
    //用法:FINDHIGH(VAR,N,M,T):VAR在N日前的M天内第T个最高价
    this.FINDHIGH=function(data,n,m,t)
    {
        if (this.IsNumber(data)) return data;
        
        var result=[];
        if (Array.isArray(data))
        {
            var count=data.length;
            for(var i=count-1;i>=0;--i)
            {
                result[i]=null;
                var aryValue=[];
                for(var j=n;j<m;++j)
                {
                    var index=i-j;
                    if (index<0) break;
                    var item=data[index];
                    if (this.IsNumber(item)) aryValue.push(item);
                }

                if (aryValue.length>0)
                {
                    aryValue.sort(function(a,b) { return b-a;});
                    var index=t-1;
                    if (index<0) index=0;
                    else if (index>=aryValue.length) index=aryValue.length-1;
                    result[i]=aryValue[index];
                }
            }
        }

        return result;
    }

    //N周期前的M周期内的第T个最大值到当前周期的周期数.
    //用法:FINDHIGHBARS(VAR,N,M,T):VAR在N日前的M天内第T个最高价到当前周期的周期数
    this.FINDHIGHBARS=function(data, n, m, t)
    {
        if (this.IsNumber(data)) return (m-n-t);
        
        var result=[];
        if (Array.isArray(data))
        {
            var count=data.length;
            for(var i=count-1;i>=0;--i)
            {
                result[i]=null;
                var aryValue=[];
                for(var j=n;j<m;++j)
                {
                    var index=i-j;
                    if (index<0) break;
                    var item=data[index];
                    if (this.IsNumber(item)) aryValue.push({ Value:item, Period:j });
                }

                if (aryValue.length>0)
                {
                    aryValue.sort(function(a,b) { return b.Value-a.Value;});
                    var index=t-1;
                    if (index<0) index=0;
                    else if (index>=aryValue.length) index=aryValue.length-1;
                    result[i]=aryValue[index].Period;
                }
            }
        }

        return result;
    }

    //N周期前的M周期内的第T个最小值到当前周期的周期数.
    //用法:FINDLOWBARS(VAR,N,M,T):VAR在N日前的M天内第T个最低价到当前周期的周期数.
    this.FINDLOWBARS=function(data, n, m, t)
    {
        if (this.IsNumber(data)) return (m-n-t);
        
        var result=[];
        if (Array.isArray(data))
        {
            var count=data.length;
            for(var i=count-1;i>=0;--i)
            {
                result[i]=null;
                var aryValue=[];
                for(var j=n;j<m;++j)
                {
                    var index=i-j;
                    if (index<0) break;
                    var item=data[index];
                    if (this.IsNumber(item)) aryValue.push({ Value:item, Period:j });
                }

                if (aryValue.length>0)
                {
                    aryValue.sort(function(a,b) { return a.Value-b.Value;});
                    var index=t-1;
                    if (index<0) index=0;
                    else if (index>=aryValue.length) index=aryValue.length-1;
                    result[i]=aryValue[index].Period;
                }
            }
        }

        return result;
    }

    //求高值名次.
    //用法:HOD(X,N):求当前X数据是N周期内的第几个高值,N=0则从第一个有效值开始.
    //例如:HOD(HIGH,20)返回是20日的第几个高价
    this.HOD=function(data, n)
    {
        var result=[];
        if (IFrameSplitOperator.IsNumber(data)) return 1;

        if (Array.isArray(data))
        {
            var count=data.length;
            for(var i=count-1;i>=0;--i)
            {
                var value=data[i];
                if (!IFrameSplitOperator.IsNumber(value)) continue;
                if (Array.isArray(n)) var subCount=parseInt(n[i]);
                else var subCount=parseInt(n);
                if (n<=0) subCount=i;
                var index=1;
                for(var j=i-1, k=1; j>=0 && k<subCount; --j, ++k)
                {
                    var item=data[j];
                    if (IFrameSplitOperator.IsNumber(item) && item>value) ++index;
                }

                result[i]=index;
            }
        }

        return result;
    }

    //求低值名次.
    //用法:LOD(X,N):求当前X数据是N周期内的第几个低值,N=0则从第一个有效值开始.
    //例如:LOD(LOW,20)返回是20日的第几个低价
    this.LOD=function(data, n)
    {
        var result=[];
        if (IFrameSplitOperator.IsNumber(data)) return 1;

        if (Array.isArray(data))
        {
            var count=data.length;
            for(var i=count-1;i>=0;--i)
            {
                var value=data[i];
                if (!IFrameSplitOperator.IsNumber(value)) continue;
                if (Array.isArray(n)) var subCount=parseInt(n[i]);
                else var subCount=parseInt(n);
                if (n<=0) subCount=i;
                var index=1;
                for(var j=i-1, k=1; j>=0 && k<subCount; --j, ++k)
                {
                    var item=data[j];
                    if (IFrameSplitOperator.IsNumber(item) && item<value) ++index;
                }

                result[i]=index;
            }
        }

        return result;
    }

    //属于未来函数,下一次条件成立到当前的周期数.
    //用法:BARSNEXT(X):下一次X不为0到现在的天数
    //例如:BARSNEXT(CLOSE/REF(CLOSE,1)>=1.1)表示下一个涨停板到当前的周期数
    this.BARSNEXT=function(data)
    {
        if (!Array.isArray(data)) return 0;

        var result=[];

        for(var i=0;i<data.length;++i)
        {
            result[i]=0;
            for(var j=i, k=0;j<data.length;++j, ++k)
            {
                var item=data[j];
                if (item>0) 
                {
                    result[i]=k;
                    break;
                }
            }
        }


        return result;
    }

    //取随机数.
    //用法:RAND(N),返回一个范围在1-N的随机整数
    this.RAND=function(n)
    {
        if (Array.isArray(n))
        {
            var result=[];
            for(var i in n)
            {
                result[i]=null;
                var item=n[i];
                var value=parseInt(item);
                if (value<=0) continue;

                result[i]=Math.ceil(Math.random()*value);
            }

            return result;
        }
        else
        {
            var value=parseInt(n);
            if (value<=0) return null;

            var stockData= this.SymbolData.Data;
            var count=stockData.Data.length;
            var result=[];
            for(var i=0;i<count;++i)
            {
                result[i]=Math.ceil(Math.random()*value);
            }
            
            return result;
        }
    }

    //求自适应均线值.
    //用法:AMA(X,A),A为自适应系数,必须小于1.
    //算法:Y=Y'+A*(X-Y').初值为X
    this.AMA=function(data,n)
    {
        var result=[];
        var period;
        if (Array.isArray(n))
        {
            //取最新的一个数据做为自适应系数
            for(var i=data.length-1;i>=0;--i)
            {
                if (this.IsNumber(n[i]))
                {
                    period=n[i];
                    break;
                }
            }
        }
        else 
        {
            period=n;
        }
        
        if (this.IsNumber(period))
        {
            if (period>1) return result;
            var index=0;
            var value=0;
            for(index;index<data.length;++index)
            {
                result[index]=null;
                if (this.IsNumber(data[index]))
                {
                    value=data[index];
                    result[index]=value;
                    break;
                }
            }

            for(var i=index+1;i<data.length;++i)
            {
                var item=data[i];
                result[i]=result[i-1]+period*(item-result[i-1]);
            }
        }
        
        return result;
    }

    //返回移动平均
    //用法:TMA(X,A,B),A和B必须小于1,算法	Y=(A*Y'+B*X),其中Y'表示上一周期Y值.初值为X
    this.TMA=function(data, a, b)
    {
        var result=[];
        if (this.IsNumber(a) && a<=1 && this.IsNumber(b) && b<1)
        {
            var bFirstFind=false;
            var proValue;   //上一个值
            for(var i in data)
            {
                result[i]=null;
                if (bFirstFind==false)
                {
                    var item=data[i];
                    if (this.IsNumber(item))
                    {
                        result[i]=item;
                        proValue=result[i];
                        bFirstFind=true;
                    }
                }
                else
                {
                    var item=data[i];
                    if (!this.IsNumber(item)) continue;
                    result[i]=a*result[i-1]+b*item;
                    proValue=result[i];
                }
            }
        }

        return result;
    }

    this.ROUND=function(data)
    {
        if (this.IsNumber(data))
        {
            return Math.round(data);
        }
        
        var result=[];
        if (Array.isArray(data))
        {
            for(var i in data)
            {
                var item=data[i];
                if (this.IsNumber(item)) 
                    result[i]=Math.round(item);
                else
                    result[i]=null;
            }
        }

        return result;
    }

    this.ROUND2=function(data,n)
    {
        var ROUND2_SEED=
        [
            1,10,100,1000,
            10000,
            100000,
            1000000,
            10000000,
            100000000,
            1000000000,
            10000000000,
            100000000000,
            1000000000000
        ];
        var decimal=0;
        if (this.IsNumber(n)) decimal=parseInt(n);
        if (n<0) decimal=0;
        else if (n>=ROUND2_SEED.length) decimal=ROUND2_SEED.length-1;

        if (this.IsNumber(data))
        {
            return Math.round(data*ROUND2_SEED[decimal])/ROUND2_SEED[decimal];
        }

        var result=[];
        if (Array.isArray(data))
        {
            for(var i in data)
            {
                var item=data[i];
                if (this.IsNumber(item))
                {
                    result[i]=Math.round(item*ROUND2_SEED[decimal])/ROUND2_SEED[decimal];
                }
                else
                {
                    result[i]=null;
                }
            }
        }

        return result;
    }

    /* 文华
    TRMA(X,N)： 求X在N个周期的三角移动平均值。

    算法：三角移动平均线公式，是采用算数移动平均，并且对第一个移动平均线再一次应用算数移动平均。
    TRMA(X,N) 算法如下
    ma_half= MA(X,N/2)
    trma=MA(ma_half,N/2)

    注：
    1、N包含当前k线。
    2、当N为有效值，但当前的k线数不足N根，函数返回空值。
    3、N为0或空值的情况下，函数返回空值。

    例1：
    TRMA5:TRMA(CLOSE,5);//计算5个周期内收盘价的三角移动平均。(N不能被2整除)
    //TRMA(CLOSE,5)=MA(MA(CLOSE,(5+1)/2)),(5+1)/2);
    例2:
    TRMA10:TRMA(CLOSE,10);// 计算10个周期内收盘价的三角移动平均。(N能被2整除)
    TRMA(CLOSE,10)=MA(MA(CLOSE,10/2),(10/2)+1));
    */

    this.TRMA=function(data,n)
    {
        if (!this.IsNumber(n) || n<=0) return [];
        n=parseInt(n);
        var nFalf=0,nFalf2=0;
        if (n%2==0) 
        {
            nFalf=parseInt(n/2);
            nFalf2=nFalf+1;
        }
        else 
        {
            nFalf=parseInt((n+1)/2);
            nFalf2=nFalf;
        }

        var maFalf=this.MA(data,nFalf);
        var result=this.MA(maFalf,nFalf2);
        return result;
    }

    //VALUEWHEN(COND,X) 
    //当COND条件成立时,取X的当前值,否则取VALUEWHEN的上个值.
    this.VALUEWHEN=function(cond,data)
    {
        if (Array.isArray(cond))
        {
            var result=[];
            if (Array.isArray(data))
            {
                var preValue=null;
                for(var i in cond)
                {
                    if (i>=data.length)
                    {
                        result[i]=preValue;
                        continue;
                    }

                    var item=data[i];
                    if (cond[i])
                    {
                        result[i]=item;
                        preValue=item;
                    }
                    else
                    {
                        result[i]=preValue;
                    }
                }
            }
            else
            {
                var preValue=null;
                for(var i in cond)
                {
                    if (cond[i]) 
                    {
                        result[i]=data;
                        preValue=data;
                    }
                    else
                    {
                        result[i]=preValue;
                    }
                }
            }

            return result;
        }
        else
        {
            return cond? 1:0;
        }
    }

    /*
    HARMEAN(X,N) 求X在N个周期内的调和平均值。

    算法举例：HARMEAN(X,5)=1/[(1/X1+1/X2+1/X3+1/X4+1/X5)/5]

    注：
    1、N包含当前k线。
    2、调和平均值与倒数的简单平均值互为倒数。
    3、当N为有效值，但当前的k线数不足N根，函数返回空值。
    4、N为0或空值的情况下，函数返回空值。
    5、X为0或空值的情况下，函数返回空值。
    6、N可以为变量。

    例：HM5:=HARMEAN(C,5);//求5周期收盘价的调和平均值。
    */
    this.HARMEAN=function(data, n)
    {
        var result=[];

        if (Array.isArray(data))
        {
            if (Array.isArray(n))
            {
                for(var i=0;i<data.length;++i)
                {
                    if (i>=n.length) 
                    {
                        result[i]=null;
                        continue;
                    }

                    var count=parseInt(n[i]);
                    if (count<=0 || count>i) 
                    {
                        result[i]=null;
                        continue;
                    }

                    var sum=0;
                    for(var j=0;j<count;++j)
                    {
                        var item=data[i-j];
                        if (!this.IsNumber(item) || item==0)
                        {
                            sum=null;
                            break;
                        }

                        sum+=1/item;
                    }

                    if (sum==null)
                    {
                        result[i]=null;
                    }
                    else
                    {
                        result[i]=1/(sum/count);
                    }
                }
            }
            else if (this.IsNumber(n))
            {
                n=parseInt(n);
                if (n<=0) return result;

                for(var i=0;i<data.length;++i)
                {
                    if (n>i) 
                    {
                        result[i]=null;
                        continue;
                    }

                    var sum=0;
                    for(var j=0;j<n;++j)
                    {
                        var item=data[i-j];
                        if (!this.IsNumber(item) || item==0)
                        {
                            sum=null;
                            break;
                        }

                        sum+=1/item;
                    }

                    if (sum==null)
                    {
                        result[i]=null;
                    }
                    else
                    {
                        result[i]=1/(sum/n);
                    }
                }
            }
        }

        return result;
    }

    //指定日期到1990.12.19的天数.
    //用法: DATETODAY(date)
    //DATETODAY(date).返回date到1990.12.19的天数.有效日期为(901219-1341231)
    //例如: DATETODAY(901219)返回0.
    this.DATETODAY=function(data)
    {
        var result=[];
        var startDate=new Date('1990-12-19')
        var startValue=19901219;
        var ONE_DAY=1000 * 60 * 60 * 24
        if (Array.isArray(data))
        {
            for(var i in data)
            {
                result[i]=null;
                var item=data[i];
                if (!this.IsNumber(item)) continue;
                var value=item+19000000;
                if (value<startValue) continue;
                var year=parseInt(value/10000);
                var month=parseInt((value%10000)/100);
                var day=parseInt(value%100);
                var dateItem=new Date(`${year}-${month}-${day}`);
                result[i]=Math.round((dateItem-startDate)/ONE_DAY);
            }
        }
        else if (this.IsNumber(data))
        {
            var value=data+19000000;
            if (value>=startValue)
            {
                var year=parseInt(value/10000);
                var month=parseInt((value%10000)/100);
                var day=parseInt(value%100);
                var dateItem=new Date(`${year}-${month}-${day}`);
                return Math.round((dateItem-dateItem)/ONE_DAY);
            }
        }

        return result;
    }

    //求1990.12.19后第若干天的日期.
    //用法:DAYTODATE(N)
    //DAYTODATE(N).返回1990.12.19后第N天的日期.有效天数为(0-20000)
    //例如:DAYTODATE(0)返回901219.
    this.DAYTODATE=function(data)
    {
        var startDate=new Date('1990-12-19')
        var result=[];

        if (Array.isArray(data))
        {
            for(var i in data)
            {
                result[i]=null;
                var item=data[i];
                if (!this.IsNumber(item)) continue;
                startDate.setDate(startDate.getDate()+item);
                var value=startDate.getFullYear()*10000+(startDate.getMonth()+1)*100+startDate.getDate();
                value-=19000000;
                result[i]=value;
                startDate.setDate(startDate.getDate()-item);
            }
        }
        else if (this.IsNumber(data))
        {
            startDate.setDate(startDate.getDate()+data);
            var value=startDate.getFullYear()*10000+(startDate.getMonth()+1)*100+startDate.getDate();
            value-=19000000;
            return value;
        }

        return result;
    }

    //函数调用
    this.CallFunction=function(name,args,node,symbolData)
    {
        switch(name)
        {
            case 'MAX':
            case "MAX6":
                return this.MAX(args,node);
            
            case 'MIN':
            case "MIN6":
                return this.MIN(args,node);
            case 'REF':
                return this.REF(args[0], args[1]);
            case "REFV":
                return this.REFV(args[0], args[1]);
            case 'REFX':
                return this.REFX(args[0], args[1]);
            case "REFXV":
                return this.REFXV(args[0], args[1]);
            case "REFX1":   //文华函数
                return this.REFX(args[0], args[1]);
            case 'ABS':
                return this.ABS(args[0]);
            case 'MA':
                return this.MA(args[0], args[1]);
            case "EMA":
                return this.EMA(args[0], args[1]);
            case "SMA":
                return this.SMA(args[0], args[1],args[2]);
            case "DMA":
                return this.DMA(args[0], args[1]);
            case "XMA":
                return this.XMA(args[0], args[1]);
            case 'EXPMA':
                return this.EXPMA(args[0], args[1]);
            case 'EXPMEMA':
                return this.EXPMEMA(args[0], args[1]);
            case 'COUNT':
                return this.COUNT(args[0], args[1]);
            case 'LLV':
                return this.LLV(args[0], args[1]);
            case "LV":
                return this.LV(args[0], args[1]);
            case 'LLVBARS':
                return this.LLVBARS(args[0], args[1]);
            case 'HHV':
                return this.HHV(args[0], args[1]);
            case 'HV':
                return this.HV(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 "CROSSDOWN":
                return this.CROSSDOWN(args[0], args[1]);
            case "CROSSUP":
                return this.CROSSUP(args[0], args[1]);
            case 'AVEDEV':
                return this.AVEDEV(args[0], args[1]);
            case 'STD':
                return this.STD(args[0], args[1]);
            case 'IF':
            case 'IFF':
            case "IFELSE":
                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 "TROUGH":
                return this.TROUGH(args[0],args[1],args[2]);
            case 'PEAKBARS':
                return this.PEAKBARS(args[0],args[1],args[2]);
            case 'PEAK':
                return this.PEAK(args[0],args[1],args[2]);
            case 'COST':
                return this.COST(args[0]);
            case 'WINNER':
                return this.WINNER(args[0],node);
            case 'PPART':
                return this.PPART(args[0],node);
            case "COSTEX":
                return this.COSTEX(args[0],args[1],node);
            case "LWINNER":
                return this.LWINNER(args[0],args[1],node);
            case "PWINNER":
                return this.PWINNER(args[0],args[1],node);
            case 'FORCAST':
                return this.FORCAST(args[0], args[1]);
            case "TSMA":
                return this.TSMA(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 "VAR2STR":
                return this.VAR2STR(args[0], args[1]);
            case "VARCAT":
                return this.VARCAT(args[0], args[1]);
            case "STRSPACE":
                return this.STRSPACE(args[0]);
            case "FINDSTR":
                return this.FINDSTR(args[0], args[1]);
            case 'DTPRICE':
                return this.DTPRICE(args[0], args[1]);
            case 'ZTPRICE':
                return this.ZTPRICE(args[0], args[1]);
            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 'FRACPART':
                return this.FRACPART(args[0]);
            case 'BARSLASTCOUNT':
                return this.BARSLASTCOUNT(args[0]);
            case 'INTPART':
                return this.INTPART(args[0]);
            case "CONST":
                return this.CONST(args[0]);
            case "TOPRANGE":
                return this.TOPRANGE(args[0]);
            case "LOWRANGE":
                return this.LOWRANGE(args[0]);
            case "FINDLOW":
                return this.FINDLOW(args[0],args[1],args[2],args[3]);
            case "FINDLOWBARS":
                return this.FINDLOWBARS(args[0],args[1],args[2],args[3]);
            case "FINDHIGH":
                return this.FINDHIGH(args[0],args[1],args[2],args[3]);
            case "FINDHIGHBARS":
                return this.FINDHIGHBARS(args[0],args[1],args[2],args[3]);
            case "BARSNEXT":
                return this.BARSNEXT(args[0]);

            case "HOD":
                return this.HOD(args[0], args[1]);
            case "LOD":
                return this.LOD(args[0], args[1]);
            case "AMA":
                return this.AMA(args[0], args[1]);
            case "TMA":
                return this.TMA(args[0],args[1],args[2]);
            case "ROUND":
                return this.ROUND(args[0]);
            case "ROUND2":
                return this.ROUND2(args[0],args[1]);
            case "TRMA":
                return this.TRMA(args[0],args[1]);
            case "VALUEWHEN":
                return this.VALUEWHEN(args[0],args[1]);
            case "HARMEAN":
                return this.HARMEAN(args[0],args[1]);
            case "DATETODAY":
                return this.DATETODAY(args[0]);
            case "DAYTODATE":
                return this.DAYTODATE(args[0]);
          
            //三角函数
            case 'ATAN':
                return this.Trigonometric(args[0],Math.atan);
            case 'ACOS':
                return this.ACOS(args[0]);
            case 'ASIN':
                return this.ASIN(args[0]);
            case 'COS':
                return this.Trigonometric(args[0],Math.cos);
            case 'SIN':
                return this.Trigonometric(args[0],Math.sin);
            case 'TAN':
                return this.Trigonometric(args[0],Math.tan);
            case 'LN':
                return this.Trigonometric(args[0],Math.log);
            case 'LOG':
                return this.Trigonometric(args[0],Math.log10);
            case 'EXP':
                return this.Trigonometric(args[0],Math.exp);
            case 'SQRT':
                return this.Trigonometric(args[0],Math.sqrt);
            case "RAND":
                return this.RAND(args[0]);
            default:
                this.ThrowUnexpectedNode(node,'函数'+name+'不存在', name);
        }
    }

    //调用自定义函数 返回数据格式{Out:输出数据, Draw:绘图数据(可选)}
    this.CallCustomFunction=function(name, args, symbolData, node)
    {
        var functionInfo=g_JSComplierResource.CustomFunction.Data.get(name);
        var dwonloadData=symbolData.GetStockCacheData({ CustomName:name, Node:node });
        if (!functionInfo.Invoke)
            return { Out: dwonloadData }

        JSConsole.Complier.Log('[JSAlgorithm::CallCustomFunction] call custom function functionInfo=',functionInfo);

        var self=this;
        var obj=
        {
            Name:name,
            Args:args,
            Symbol:symbolData.Symbol, Period:symbolData.Period, Right:symbolData.Right, 
            KData:symbolData.Data,  //K线数据
            DownloadData:dwonloadData,
            ThrowError:function(error)
            {
                self.ThrowUnexpectedNode(node, error);
            }
        };

        return functionInfo.Invoke(obj);
    }

    this.ThrowUnexpectedNode=function(node,message,word)
    {
        let marker=node.Marker;
        let msg=message || "执行异常";
       
        return this.ErrorHandler.ThrowError(marker.Index,marker.Line,marker.Column,msg,word);
       
    }
}

//是否有是有效的数字
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 (Array.isArray(condition))
        {
            if (condition.length<=0) return result;

            var IsNumber=this.IsNumber(price);
    
            for(var i in condition)
            {
                drawData[i]=null;
    
                if (isNaN(condition[i]) || !condition[i]) continue;
    
                if (IsNumber) 
                {
                    drawData[i]=price;
                }
                else 
                {
                    if (this.IsNumber(price[i])) drawData[i]=price[i];
                }
            }
        }
        else if (this.IsNumber(condition) && condition)
        {
            var IsNumber=this.IsNumber(price);
            for(var i=0;i<this.SymbolData.Data.Data.length;++i)
            {
                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)
    {
        var drawData={ Value:[], Text:[]  };
        var result={DrawData:drawData, DrawType:'DRAWTEXT_FIX', Text:null, Position:{ X:x, Y:y, Type:type } };
        if (condition.length<=0) return result;

        if (Array.isArray(condition))
        {
            
            for(var i in condition)
            {
                drawData.Text[i]=null;
                drawData.Value[i]=0;
                if (isNaN(condition[i]) || !condition[i]) continue;
    
                drawData.Value[i]=1;
                drawData.Text[i]=text;
            }
        }
        else
        {
            if(condition) 
            {
                for(var i=0;i<this.SymbolData.Data.Data.length;++i)
                {
                    drawData.Text[i]=text;
                    drawData.Value[i]=1;
                }
            }
        }
        
        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 (result.Width<0) result.Width=3;    //<0的宽度 使用K线宽度

        var IsNumber=typeof(data)=="number";
        var IsNumber2=typeof(data2)=="number";

        if (Array.isArray(condition))   //数组
        {
            if(condition.length<=0) return result;
            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]};
                }
            }
        }
        else    //单值
        {
            if(!condition) return result;

            for(var i=0;i<this.SymbolData.Data.Data.length;++i) //以K线长度为数据长度
            {
                drawData[i]=null;

                if (IsNumber && IsNumber2)
                {
                    drawData[i]={Value:data,Value2:data2};
                }
                else if (IsNumber && !IsNumber2)
                {
                    if (!IFrameSplitOperator.IsNumber(data2[i])) continue;
                    drawData[i]={Value:data,Value2:data2[i]};
                }
                else if (!IsNumber && IsNumber2)
                {
                    if (!IFrameSplitOperator.IsNumber(data[i])) continue;
                    drawData[i]={Value:data[i],Value2:data2};
                }
                else
                {
                    if (!IFrameSplitOperator.IsNumber(data[i]) || !IFrameSplitOperator.IsNumber(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) 
                    {
                        if (condition[i] ) //条件1满足
                            lineCache.Start={ID:i, Value:data[i]};  //移动第1个点
                        continue;
                    }

                    if (bCondition2)
                    {
                        bSecondPont=true;
                        lineCache.End={ID:i, Value:data2[i]};   //第2个点
                    }
                }
                else if (bFirstPoint==true && bSecondPont==true)
                {
                    var bCondition2=(condition2[i]!=null && condition2[i]); //条件2
                    if (bCondition2)    //条件2满足
                    {
                        lineCache.End={ID:i, Value:data2[i]};   //移动第2个点
                    }
                    else if (condition[i])  //条件1满足
                    {
                        let lineData=this.CalculateDrawLine(lineCache);     //计算2个点的线上 其他点的数值

                        for(let j in lineData)
                        {
                            let item=lineData[j];
                            drawData[item.ID]=item.Value;
                        }

                        if (expand==1) this.CalculateDrawDataExtendLine(drawData, lineCache.Start.ID-2);//右延长线

                        bFirstPoint=bSecondPont=false;
                        lineCache={Start:{ },End:{ }};

                        bFirstPoint=true;
                        bSecondPont=false;
                        lineCache.Start={ID:i, Value:data[i]};  //第1个点
                    }
                }
            }

            //最后一组线
            if (bFirstPoint==true && bSecondPont==true)
            {
                let lineData=this.CalculateDrawLine(lineCache);     
                for(let j in lineData)
                {
                    let item=lineData[j];
                    drawData[item.ID]=item.Value;
                }
            }
        }

        if (expand==1) this.CalculateDrawDataExtendLine(drawData);//右延长线

        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)
    {
        var drawData=[];
        var result={DrawData:drawData, DrawType:'DRAWBAND', Color:[color.toLowerCase(),color2.toLowerCase()]};  //颜色使用小写字符串
        var isNumber=IFrameSplitOperator.IsNumber(data);
        var isNumber2=IFrameSplitOperator.IsNumber(data2);
        if (!isNumber && !isNumber2)
        {
            var count=Math.max(data.length, data2.length);
            for(var i=0;i<count;++i)
            {
                var item={Value:null, Value2:null};
                if (i<data.length) item.Value=data[i];
                if (i<data2.length) item.Value2=data2[i];
                drawData.push(item);
            }
        }
        else if (isNumber && !isNumber2)
        {
            var count=data2.length;
            for(var i=0;i<count;++i)
            {
                var item={Value:data, Value2:null};
                if (i<data2.length) item.Value2=data2[i];
                drawData.push(item);
            }
        }
        else if (!isNumber && isNumber2)
        {
            var count=data.length;
            for(var i=0;i<count;++i)
            {
                var item={Value:null, Value2:data2};
                if (i<data.length) item.Value=data[i];
                drawData.push(item);
            }
        }
        else if (isNumber && isNumber2)
        {
            var count=this.SymbolData.Data.Data.length;
            for(var i=0;i<count;++i)
            {
                var item={Value:data, Value2:data2};
                drawData.push(item);
            }
        }
        

        return result;
    }

    this.GetDataByIndex=function(data, index)
    {
        var result={Result:false , Data:null };
        if (this.IsNumber(data)) 
        {
            result.Result=true;
            result.Data=data;
        }
        else
        {
            if (index<data.length)
            {
                result.Result=true;
                result.Data=data[index];
            }
            else
            {
                result.Result=false;
            }
        }

        return result;        
    }

    /*
    FILLRGN(MA1>MA2, MA1,MA2),colorred 
    表示MA1>MA2时以红色填充MA1和MA2之间的区域
    */
    this.FILLRGN=function(condition, data,data2)
    {
        let drawData=[];
        let result={DrawData:drawData, DrawType:'FILLRGN'}; 
        var isNumber=this.IsNumber(data);
        var isNumber2=this.IsNumber(data2);

        if (Array.isArray(condition))   //数组
        {
            for(var i in condition)
            {
                drawData[i]=null;
                var condItem=condition[i];
                if (!condItem) continue;
                
                var value=this.GetDataByIndex(data, i);
                if (!value.Result) continue;

                var value2=this.GetDataByIndex(data2, i);
                if (!value2.Result) continue;

                var item={ Value:value.Data, Value2:value2.Data };
                drawData[i]=item;
            }
        }
        else
        {
            if (condition)
            {
                for(var i=0;i<this.SymbolData.Data.Data.length;++i) //以K线长度为数据长度
                {
                    drawData[i]=null;

                    var value=this.GetDataByIndex(data, i);
                    if (!value.Result) continue;

                    var value2=this.GetDataByIndex(data2, i);
                    if (!value2.Result) continue;

                    var item={ Value:value.Data, Value2:value2.Data };
                    drawData[i]=item;
                }
            }
        }

        return result;
    }

    //DRAWKLINE(HIGH,OPEN,LOW,CLOSE).
    //用法:以HIGH为最高价,OPEN为开盘价,LOW为最低,CLOSE收盘画K线
    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;
    }

    /*
    DRAWCOLORKLINE 绘制K线
    用法：
    DRAWCOLORKLINE(Cond,Color,Empty);
    满足Cond条件时，按照Color颜色绘制K线，根据Empty标志判断是空心还是实心。COLOR代表颜色，Empty非0为空心。

    注：
    不支持将该函数定义为变量，即不支持下面的写法：
    A:DRAWCOLORKLINE(Cond,Color,Empty);

    例：
    DRAWCOLORKLINE(C>O,COLORBLUE,0);//收盘价大于开盘价，用蓝色绘制实心K线
    */
    this.DRAWCOLORKLINE=function(condition, color, empty)
    {
        let drawData=[];
        let result={ DrawData:drawData, DrawType:'DRAWCOLORKLINE', IsEmptyBar:!(empty==0), Color:color }; 

        if (Array.isArray(condition))   //数组
        {
            for(var i=0; i<condition.length && i<this.SymbolData.Data.Data.length; ++i)
            {
                drawData[i]=null;
                var condItem=condition[i];
                if (!condItem) continue;
                var kItem=this.SymbolData.Data.Data[i];
                if (!kItem) continue;

                drawData[i]={Open:kItem.Open,High:kItem.High, Low:kItem.Low, Close:kItem.Close};
            }
        }
        else
        {
            if (condition)
            {
                for(var i=0;i<this.SymbolData.Data.Data.length;++i) //以K线长度为数据长度
                {
                    drawData[i]=null;
                    var kItem=this.SymbolData.Data.Data[i];
                    if (!kItem) continue;
                    drawData[i]={Open:kItem.Open,High:kItem.High, Low:kItem.Low, Close:kItem.Close };
                }
            }
        }

        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)
        {
            if (this.IsNumber(condition))
            {
                if (condition) 
                {
                    var count=this.SymbolData.Data.Data.length;
                    for(var i=0;i<count;++i )
                    {
                        drawData[i]=data;
                    }
                }
            }
            else
            {
                var bFind=false;
                for(var i in condition)
                {
                    drawData[i]=null;
                    if (bFind)
                    {
                        drawData[i]=data;
                    }
                    else
                    {
                        if (!condition[i]) continue;
                        
                        bFind=true;
                        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:{ } };
                }
            }

            this.CalculateDrawDataExtendLine(drawData);
        }

        return result
    }

    this.CalculateDrawDataExtendLine=function(drawData, maxCount)
    {
        if (maxCount<0) return;

        var x2=null;
        var count=drawData.length;
        if (this.IsNumber(maxCount) && maxCount<count) count=maxCount;
        for(var i=count-1;i>=0;--i)
        {
            if (this.IsNumber(drawData[i]))
            {
                x2=i;
                break;
            }
        }
        //y3=(y1-y2)*(x3-x1)/(x2-x1)
        if (x2!=null && x2-1>=0)
        {
            var x1=x2-1;
            for(var i=x2+1;i<count;++i)
            {
                var y1=drawData[x1];
                var y2=drawData[x2];
                var y3=(y1-y2)*(i-x1)/(x2-x1);
                if (y1-y3<0) break;
                drawData[i]=y1-y3;
            }
        }
    }

    /*
    画出数字.
    用法:
    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';
        var isArrayData=Array.isArray(data);
        let text;
        if (isNumber) 
        {
            if (IFrameSplitOperator.IsInteger(data2)) text=data2.toString();
            else text=data2.toFixed(2);
        }

        for(let i in condition)
        {
            drawData.Value[i]=null;
            if (!condition[i]) continue;

            if (isArrayData)
            {
                if (i>=data.length || !this.IsNumber(data[i])) continue;

                if (isNumber)
                {
                    drawData.Value[i]=data[i];
                    drawData.Text[i]=text;
                }
                else
                {
                    if (i>=data2.length || !data2[i]) continue;
                    drawData.Value[i]=data[i];
                    if (this.IsNumber(data2[i]))
                    {
                        if (IFrameSplitOperator.IsInteger(data2[i])) drawData.Text[i]=data2[i].toString();
                        else drawData.Text[i] = data2[i].toFixed(2);
                    }
                    else
                    {
                        drawData.Text[i] = data2[i].toString();
                    }
                } 
            }
            else if (this.IsNumber(data))
            {
                if (isNumber)
                {
                    drawData.Value[i]=data;
                    drawData.Text[i]=text;
                }
                else
                {
                    if (i>=data2.length || !data2[i]) continue;
                    drawData.Value[i]=data;
                    if (this.IsNumber(data2[i]))
                    {
                        if (IFrameSplitOperator.IsInteger(data2[i])) drawData.Text[i]=data2[i].toString();
                        else drawData.Text[i] = data2[i].toFixed(2);
                    }
                    else
                    {
                        drawData.Text[i] = data2[i].toString();
                    }
                        
                }       
            }
            
        }

        return result;
    }

    /*
    固定位置显示数字.
    用法: DRAWNUMBER_FIX(COND,X,Y,TYPE,NUMBER),当COND条件满足时,在当前指标窗口内(X,Y)位置书写数字NUMBER,X,Y为书写点在窗口中相对于左上角的百分比,TYPE:0为左对齐,1为右对齐.
    例如: DRAWNUMBER_FIX(CURRBARSCOUNT=1 AND CLOSE/OPEN>1.08,0.5,0.5,0,C)表示最后一个交易日实体阳线大于8%时在窗口中间位置显示收盘价.
    */
    this.DRAWNUMBER_FIX=function(condition,x,y,align,data)
    {
        var drawData={ Value:[], Text:[],  };
        var result={ DrawData:drawData, DrawType:'DRAWNUMBER_FIX', Position:{ X:x, Y:y, Type:align } };
        var isNumber=IFrameSplitOperator.IsNumber(data);

        if (Array.isArray(condition))
        {
            for(var i in condition)
            {
                drawData.Text[i]=null;
                drawData.Value[i]=null;
                if (!condition[i]) continue;

                if (isNumber) 
                {
                    drawData.Text[i]=this.RemoveZero(data.toFixed(2));
                    drawData.Value[i]=data;
                }
                else 
                {
                    if (i>=data.length || !IFrameSplitOperator.IsNumber(data[i])) continue;

                    var item=data[i];
                    drawData.Text[i]=this.RemoveZero(item.toFixed(2));
                    drawData.Value[i]=item;
                }
            }
        }
        else
        {
            if(!condition)
            {
                
            }
            else
            {
                for(var i=0;i<this.SymbolData.Data.Data.length;++i)
                {
                    if (isNumber) 
                    {
                        drawData.Text[i]=this.RemoveZero(data.toFixed(2));
                        drawData.Value[i]=data;
                    } 
                    else
                    {
                        if (i>=data.length || !IFrameSplitOperator.IsNumber(data[i])) continue;

                        var item=data[i];
                        drawData.Text[i]=this.RemoveZero(item.toFixed(2));
                        drawData.Value[i]=item;
                    }
                }
            }
        }

        return result;
    }

    /*
    通达信语法：
    在图形上绘制小图标.
    用法:
    DRAWICON(COND,PRICE,TYPE),当COND条件满足时,在PRICE位置画TYPE号图标(TYPE为1--41).
    例如:
    DRAWICON(CLOSE>OPEN,LOW,1)表示当收阳时在最低价位置画1号图标.

    文华语法：
    DRAWICON：绘制小图标。
    用法：
    DRAWICON(COND,PRICE,ICON);
    当COND条件满足时,在PRICE位置画图标ICON。

    注：
    1、该函数可以指定位置PRICE标注图标ICON
    2、ICON位置可以写成'ICON'的形式，也可以写为数字的形式，即DRAWICON(COND,PRICE,'ICO1');等价于DRAWICON(COND,PRICE,1);
    3、不支持将该函数定义为变量，即不支持下面的写法：
    A:DRAWICON(COND,PRICE,ICON);
    4、该函数可以用ALIGN，VALIGN设置图标的对齐方式。

    例1：
    DRAWICON(CLOSE<OPEN,LOW,'ICO1');//在阴线的最低价上画出图标ICON1。
    写完“DRAWICON(CLOSE<OPEN,LOW,” 以后，点击插入图标按钮，再单击选中的图标插入到函数中，图标用'ICO1'~'ICO105'（或1~105）表示。

    例2：
    MA5:=MA(C,5);
    DRAWICON(C>MA5,MA5,2);//表示在收盘价大于5周期均线的k线对应的MA5数值位置上画出图标ICON2。
    写完“DRAWICON(C>MA5,MA5,” 以后，点击插入图标按钮，再单击选中的图标插入到函数中，图标用ICO1~ICO105（或1~105）表示。
    */
    this.DRAWICON=function(condition,data,type)
    {
        if (IFrameSplitOperator.IsString(type)) //把ICO1=>1
        {
            var value=type.replace('ICO',"");
            type=parseInt(value);
        } 

        var icon=g_JSComplierResource.GetDrawIcon(type);
        if (!icon) g_JSComplierResource.GetDrawTextIcon(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;
    }

    /*
    ICON：在k线图上，显示小图标。

    用法：ICON(TYPE,ICON);
    当TYPE为1，则在K线最高价位置显示图标ICON，当TYPE为0，则在最低价位置显示
    图标ICON。

    注：
    1、该函数与判断条件连用，如：COND,ICON(TYPE,ICON);
    2、该函数支持在函数后设置垂直对齐方式：VALIGN0（上对齐）、VALIGN1（中对齐）、VALIGN2（下对齐）
    即可以写为如下格式：
    CLOSE<OPEN,ICON(1,'阴'),VALIGN0;

    例1：
    CLOSE>OPEN,ICON(1,'ICO1');//表示K线收盘大于开盘时，在最高价上显示图标1。
    写完“ICON(1,” 以后，点击插入图标按钮，再单击选中的图标插入到函数中，图标用
    'ICO1'~'ICO105'表示
    */
    this.ICON=function(position, type)
    {
        if (IFrameSplitOperator.IsString(type)) //把ICO1=>1
        {
            var value=type.replace('ICO',"");
            type=parseInt(value);
        } 

        var icon=g_JSComplierResource.GetDrawIcon(type);
        if (!icon) g_JSComplierResource.GetDrawTextIcon(type);
        if (!icon) icon={Symbol:'🚩'};

        let drawData=[];
        let result={DrawData:drawData, DrawType:'ICON',Icon:icon};

        for(var i=0;i<this.SymbolData.Data.Data.length;++i)
        {
            var kItem=this.SymbolData.Data.Data[i];
            if (!kItem) continue;

            if (position==0) drawData[i]=kItem.Low;
            else if (position==1) drawData[i]=kItem.High;
        }

        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;
    }

    /*
    SOUND 播放声音。用法：SOUND(NAME)，播放NAME
    注：
    1、点击设置声音按钮，在弹出来的界面中设置声音，声音用字符'A'~'J'表示。
    2、自定义声音可以在设置菜单的设置声音文件中设置
    3、条件如果一直满足，则只播放一次，不重复播放。
    4、历史数据不触发该函数

    例：
    CLOSE>OPEN,SOUND('A');//表示K线收盘大于开盘时，播放声音"A"
    */

    this.SOUND=function(value)
    {
        return { Name:"SOUND", Value: value };
    }

    /*
    PLAYSOUND 条件满足时，播放指定声音。用法：PLAYSOUND(COND, 'N') 当条件满足时，播放声音'N'
    注：
    1、点击设置声音按钮，在弹出来的界面中设置声音，声音用字符'A'~'J'表示。
    2、自定义声音可以在设置菜单的设置声音文件中设置
    3、条件如果一直满足，则只播放一次，不重复播放。
    4、历史数据不触发该函数

    例：
    PLAYSOUND(CLOSE>OPEN,'A');//表示CLOSE>OPEN时播放自定义声音'A'。
    */

    this.PLAYSOUND=function(cond, value)
    {
        return null;
    }

    //用法: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 (Array.isArray(item.Cond))
                {
                    if (i<item.Cond.length && item.Cond[i])
                    {
                        rgb=item.RGB;
                        break;
                    }
                }
                else 
                {
                    if (this.IsNumber(item.Cond) && item.Cond)  //单数值条件
                    {
                        rgb=item.RGB;
                        break;
                    }
                }
            }

            if (rgb) 
            {
                drawItem.Value=value;
                drawItem.RGB=rgb;
            }
        }

        return result;
    }

    //函数:FILLRGN,根据条件用RGN颜色填充区域
    //用法：FILLRGN(PRICE1,PRICE2,COND1,COLOR1,COND2,COLOR2...),填充PRICE1到PRICE2之间的区域，当COND1条件满足时,用COLOR1颜色，当COND2条件满足时,用COLOR2颜色，否则不填充，从COLOR1之后的参数均可以省略，最多可以有15组条件。
    //例如：FILLRGN(CLOSE,OPEN,CLOSE>OPEN,RGB(255,0,0),CLOSE<OPEN,RGB(0,255,0))表示填充开盘价和收盘价之间的区域，阳线时用红色，阴线时用绿色，平盘不绘制。
    this.FILLRGN2=function(args)
    {
        let drawData=[];
        let result={DrawData:drawData, DrawType:'FILLRGN2'};
        if (args.length<4) return result;


        var price=args[0];
        var price2=args[1];
        var condition=[];
        for(var i=2;i<args.length && i+1<args.length;i+=2)
        {
            condition.push({Cond:args[i], Color:args[i+1]});
        }

        for(var i=0;i<this.SymbolData.Data.Data.length;++i)
        {
            drawData[i]=null;

            var drawItem={ Value:null, Value2:null, Color:null };

            for(var j in condition)
            {
                var item=condition[j];
                if (Array.isArray(item.Cond))
                {
                    if (i<item.Cond.length && item.Cond[i])
                    {
                        drawItem.Color=item.Color;
                        break;
                    }
                }
                else 
                {
                    if (this.IsNumber(item.Cond) && item.Cond)  //单数值条件
                    {
                        drawItem.Color=item.Color;
                        break;
                    }
                }
            }

            if (!drawItem.Color) continue;

            if (Array.isArray(price))
            {
                if (i>=price.length) continue;
                if (!this.IsNumber(price[i])) continue;
                drawItem.Value=price[i];
            }
            else if (this.IsNumber(price))
            {
                drawItem.Value=price;
            }
            else
            {
                continue;
            }

            if (Array.isArray(price2))
            {
                if (i>=price2.length) continue;
                if (!this.IsNumber(price2[i])) continue;
                drawItem.Value2=price2[i];
            }
            else if　(this.IsNumber(price2))
            {
                drawItem.Value2=price2;
            }
            else
            {
                continue;
            }
             
            drawData[i]=drawItem;
        }

        return result;
    }

    //用法:FLOATRGN(PRICE,WIDTH,COND1,COLOR1,COND2,COLOR2...),以PRICE为基础填充宽度为WIDTH像素的区域,WIDTH为负则向下填充,当COND1条件满足时,用COLOR1颜色,当COND2条件满足时,用COLOR2颜色,否则不填充,从COND1之后的参数均可以省略,最多可以有10组条件
    //例如:FLOATRGN(CLOSE,VOL/HHV(VOL,10)*15,CLOSE>OPEN,RGB(255,0,0),1,RGB(0,255,0))表示沿收盘价填充宽度为成交量的区域,区域最大宽度为15像素,阳线时用红色,阴线时用绿色。
    this.FLOATRGN=function(args)
    {
        let drawData=[];
        let result={DrawData:drawData, DrawType:'FLOATRGN'};
        if (args.length<4) return result;

        var price=args[0];
        var width=args[1];
        var condition=[];
        for(var i=2;i<args.length && i+1<args.length;i+=2)
        {
            condition.push({Cond:args[i], Color:args[i+1]});
        }

        for(var i=0;i<this.SymbolData.Data.Data.length;++i)
        {
            drawData[i]=null;

            var drawItem={ Value:null, Value2:null, Color:null };

            for(var j in condition)
            {
                var item=condition[j];
                if (Array.isArray(item.Cond))
                {
                    if (i<item.Cond.length && item.Cond[i])
                    {
                        drawItem.Color=item.Color;
                        break;
                    }
                }
                else 
                {
                    if (this.IsNumber(item.Cond) && item.Cond)  //单数值条件
                    {
                        drawItem.Color=item.Color;
                        break;
                    }
                }
            }

            if (!drawItem.Color) continue;

            if (Array.isArray(price))
            {
                if (i>=price.length) continue;
                if (!this.IsNumber(price[i])) continue;
                drawItem.Value=price[i];
            }
            else if (this.IsNumber(price))
            {
                drawItem.Value=price;
            }
            else
            {
                continue;
            }

            if (Array.isArray(width))
            {
                if (i>=width.length) continue;
                if (!this.IsNumber(width[i])) continue;
                drawItem.Value2=width[i];
            }
            else if　(this.IsNumber(width))
            {
                drawItem.Value2=width;
            }
            else
            {
                continue;
            }
             
            drawData[i]=drawItem;
        }

        return result;
    }

    //函数:FILLTOPRGN / FILLBOTTOMRGN 根据条件填充顶部或底部区域
    //用法 FILLTOPRGN(PRICE, COND1, COLOR, COND2, COLOR2)
    this.FILLBGRGN=function(type,args)
    {
        let drawData=[];
        let result={DrawData:drawData, DrawType:(type==1 ?'FILLTOPRGN':"FILLBOTTOMRGN")};
        if (args.length<3) return result;

        var price=args[0];
        var condition=[];
        for(var i=1;i<args.length && i+1<args.length;i+=2)
        {
            condition.push({Cond:args[i], Color:args[i+1]});
        }

        for(var i=0;i<this.SymbolData.Data.Data.length;++i)
        {
            drawData[i]=null;
            var drawItem={ Value:null, Color:null };

            for(var j in condition)
            {
                var item=condition[j];
                if (Array.isArray(item.Cond))
                {
                    if (i<item.Cond.length && item.Cond[i])
                    {
                        drawItem.Color=item.Color;
                        break;
                    }
                }
                else 
                {
                    if (this.IsNumber(item.Cond) && item.Cond)  //单数值条件
                    {
                        drawItem.Color=item.Color;
                        break;
                    }
                }
            }

            if (!drawItem.Color) continue;

            if (Array.isArray(price))
            {
                if (i>=price.length) continue;
                if (!this.IsNumber(price[i])) continue;
                drawItem.Value=price[i];
            }
            else if (this.IsNumber(price))
            {
                drawItem.Value=price;
            }
            else
            {
                continue;
            }

            drawData[i]=drawItem;
        }

        return result;
    }

    //函数:FILLVERTICALRGN 根据条件填充顶部到底部区域
    //用法 FILLVERTICALRGN(COND1, COLOR, COND2, COLOR2)
    this.FILLVERTICALRGN=function(args)
    {
        let drawData=[];
        let result={DrawData:drawData, DrawType:"FILLVERTICALRGN"};
        if (args.length<2) return result;

        var condition=[];
        for(var i=0;i<args.length && i+1<args.length;i+=2)
        {
            condition.push({Cond:args[i], Color:args[i+1]});
        }

        for(var i=0;i<this.SymbolData.Data.Data.length;++i)
        {
            drawData[i]=null;
            var drawItem={ Color:null };

            for(var j in condition)
            {
                var item=condition[j];
                if (Array.isArray(item.Cond))
                {
                    if (i<item.Cond.length && item.Cond[i])
                    {
                        drawItem.Color=item.Color;
                        break;
                    }
                }
                else 
                {
                    if (this.IsNumber(item.Cond) && item.Cond)  //单数值条件
                    {
                        drawItem.Color=item.Color;
                        break;
                    }
                }
            }

            if (!drawItem.Color) continue;

            drawData[i]=drawItem;
        }

        return result;
    }

    //填充背景.
    //用法: DRAWGBK(COND,COLOR1,COLOR2,colorAngle)  colorAngle=渐近色角度
    //例如: DRAWGBK(O>C,RGB(0,255,0),RGB(255,0,0),0);
    this.DRAWGBK=function(condition, color, color2, colorAngle)
    {
        let drawData={ Color:[],  Angle:colorAngle };
        if (color) drawData.Color.push(color);
        if (color2) drawData.Color.push(color2);

        let result={DrawData:null, DrawType:'DRAWGBK'};
        if (Array.isArray(condition))
        {
            for(var i in condition)
            {
                var item=condition[i];
                if (item) 
                {
                    result.DrawData=drawData;
                    break;
                }
            }
        }
        else
        {
            if (condition) result.DrawData=drawData;
        }

        return result;
    }

    this.DRAWGBK2=function(condition, color, color2, colorAngle)
    {
        let drawData={ Color:[],  Angle:colorAngle };
        if (color) drawData.Color.push(color);
        if (color2) drawData.Color.push(color2);

        let result={DrawData:null, DrawType:'DRAWGBK2'};
        if (Array.isArray(condition))
        {
            drawData.Data=[];
            for(var i in condition)
            {
                var item=condition[i];
                drawData.Data[i]=item ? 1:0;
            }

            result.DrawData=drawData;
        }
        else
        {
            if (condition) 
            {
                result.DrawData=drawData;
                result.DrawType="DRAWGBK";
            }
        }

        return result;
    }

    //画文字 及线段
    this.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:Math.min(left,right), Top:Math.min(top,bottom), Right:Math.max(right,left), Bottom:Math.max(bottom,top) }, Color:color };
        if (color==0) drawData.Color=null;
        let result={DrawData:drawData, DrawType:'DRAWRECTREL'};

        return result;
    }

    //DRAWTEXTREL(X,Y,TEXT),在图形窗口(X,Y)坐标位置书写文字TEXT，坐标单位是窗口沿水平和垂直方向的1/1000，X、Y取值范围是0—999,超出范围则可能显示在图形窗口外。
    //例如：DRAWTEXTREL(500,500,'注意')表示在图形中间位置显示'注意'字样。
    this.DRAWTEXTREL=function(x, y, text)
    {
        let drawData={ Point:{X:x, Y:y} };
        if (IFrameSplitOperator.IsString(text))
            drawData.Text=text;
        else if (IFrameSplitOperator.IsNonEmptyArray(text)) 
            drawData.Text=text[0];
        
        let result={DrawData:drawData, DrawType:'DRAWTEXTREL'};

        return result;
    }

    //DRAWTEXTABS(X,Y,TEXT),在图形窗口(X,Y)坐标位置书写文字TEXT，坐标单位是像素,图形窗口左上角坐标为(0,0)。
    //例如：DRAWTEXTABS(0,0,'注意')表示在图形最左上角位置显示'注意'字样。
    this.DRAWTEXTABS=function(x, y, text)
    {
        let drawData={ Point:{X:x, Y:y} };
        if (IFrameSplitOperator.IsString(text))
            drawData.Text=text;
        else if (IFrameSplitOperator.IsNonEmptyArray(text)) 
            drawData.Text=text[0];
        
        let result={DrawData:drawData, DrawType:'DRAWTEXTABS'};

        return result;
    }

    //画百分比叠加线
    this.DRAWOVERLAYLINE=function(data, mainData, title)
    {
        let drawData={ Data:data, MainData:mainData };
        if (title && typeof(title)=='string') drawData.Title=title;
        let result={ DrawData:drawData, DrawType:'DRAWOVERLAYLINE' };
       
        return result;
    }

    //绘制斜线.
    //用法:DRAWSL(COND,PRICE,SLOPE,LEN,DIRECT),当COND条件满足时,在PRICE位置画斜线,SLOPE为斜率,LEN为长度,DIRECT为0向右延伸,1向左延伸,2双向延伸.
    //注意:
    //1.K线间的纵向高度差为SLOPE;
    //2.SLOPE为0时,为水平线;
    //3.SLOPE为10000时,为垂直线,LEN为向上的像素高度,DIRECT表示向上或向下延伸;
    //4.SLOPE和LEN支持变量;
    this.DRAWSL=function(condition, data, slope, len, direct)
    {
        let drawData={ Data:[], Option:[] };
        let result={ DrawData:drawData, DrawType:'DRAWSL' };
        var isNumber=this.IsNumber(data);

        if (Array.isArray(condition))
        {
            for(var i in condition)
            {
                drawData[i]=null;
                if (!condition[i]) continue;

                if (isNumber) 
                {
                    drawData.Data[i]=data;
                    drawData.Option[i]={Slope:slope, Length:len, Direct:direct };
                }
                else
                {
                    if (i<data.length && this.IsNumber(data[i]))
                    {
                        drawData.Data[i]=data[i];
                        drawData.Option[i]={Slope:slope, Length:len, Direct:direct };
                    }
                }
            }
        }
        else
        {
            if (condition)
            {
                var count=this.SymbolData.Data.Data.length;
                for(var i=0; i<count; ++i)
                {
                    drawData[i]=null;
                    if (isNumber) 
                    {
                        drawData.Data[i]=data;
                        drawData.Option[i]={Slope:slope, Length:len, Direct:direct };
                    }
                    else
                    {
                        if (i<data.length && this.IsNumber(data[i]))
                        {
                            drawData.Data[i]= data[i];
                            drawData.Option[i]={Slope:slope, Length:len, Direct:direct };
                        }
                    }
                }
            }
        }
        
        return result;
    }

    //含义:在图形上绘制垂直线。
    //用法:
    //VERTLINE(COND,TYPE),当COND条件满足时,沿垂直方向绘制TYPE类型的线段,TYPE=0表示实线，1表示虚线'---'，2表示点线'...'，3表示点划线'-.-.-'，4表示点点划线'-..-..-'。
    //例如：VERTLINE(HIGH>=HHV(HIGH,20),1)表示在创20天新高画垂直虚线。

    this.VERTLINE=function(condition, type)
    {
        let drawData={ Data:[], LineType:type };
        let result={ DrawData:drawData, DrawType:'VERTLINE' };
        if (Array.isArray(condition))
        {
            for(var i=0;i<condition.length;++i)
            {
                var item=condition[i];
                if (item) drawData.Data[i]=1;
                else drawData.Data[i]=0;
            }
        }
        else
        {

        }

        return result;
    }

    //含义:在图形上绘制水平线。
    //用法:
    //HORLINE(COND,PRICE,TYPE,EXTEND),当COND条件满足时,在PRICE位置沿水平方向绘制TYPE类型的线段,TYPE=0表示实线，1表示虚线'---'，2表示点线'...'，3表示点划线'-.-.-'，4表示点点划线'-..-..-'。EXTEND=1 表示向左延长，=2表示向右延长，=3表示左右延长。
    //例如：HORLINE(HIGH>=HHV(HIGH,20),HIGH,1,2)表示在创20天新高时画水平虚线向右延伸。
    this.HORLINE=function(condition, data, type, extend)
    {
        let drawData={ Data:[], LineType:type, Extend:extend };
        let result={ DrawData:drawData, DrawType:'HORLINE' };
        if (Array.isArray(condition) && Array.isArray(data))
        {
            for(var i=0;i<condition.length;++i)
            {
                var item=condition[i];
                drawData.Data[i]=null;
                if (!item) continue;
                if (i>=data.length) continue;
                var value=data[i];
                if (IFrameSplitOperator.IsNumber(value)) drawData.Data[i]=value;
            }
        }
        else if (Array.isArray(condition) && IFrameSplitOperator.IsNumber(data))
        {
            for(var i=0;i<condition.length;++i)
            {
                var item=condition[i];
                drawData.Data[i]=null;
                if (!item) continue;
                drawData.Data[i]=data;
            }
        }
        else if (IFrameSplitOperator.IsNumber(condition) && condition)
        {
            if (this.SymbolData && this.SymbolData.Data && this.SymbolData.Data.Data)
            {
                if (Array.isArray(data))
                {
                    var count=this.SymbolData.Data.Data.length;
                    for(var i=0; i<count; ++i)
                    {
                        drawData.Data[i]=null;
                        if (i>=data.length) continue;
                        var value=data[i];
                        if (IFrameSplitOperator.IsNumber(value)) drawData.Data[i]=value;
                    }
                }
                else if (IFrameSplitOperator.IsNumber(data))
                {
                    var count=this.SymbolData.Data.Data.length;
                    for(var i=0; i<count; ++i)
                    {
                        drawData.Data[i]=data;
                    }
                }
            }
        }

        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',"DRAWKLINE1",'DRAWKLINE_IF',"DRAWCOLORKLINE",'PLOYLINE',
        'POLYLINE','DRAWNUMBER',"DRAWNUMBER_FIX",'DRAWICON','DRAWCHANNEL','PARTLINE','DRAWTEXT_FIX','DRAWGBK','DRAWTEXT_LINE','DRAWRECTREL',"DRAWTEXTABS","DRAWTEXTREL",
        'DRAWOVERLAYLINE',"FILLRGN", "FILLRGN2","FILLTOPRGN", "FILLBOTTOMRGN", "FILLVERTICALRGN","FLOATRGN","DRAWSL", "DRAWGBK2",
        "VERTLINE","HORLINE"
    ]);
    if (setFunctionName.has(name)) return true;

    return false;
}

JSDraw.prototype.RemoveZero = function (strValue)
{
    while(strValue.length>0)
    {
        var index=strValue.length-1;
        var ch=strValue[index];
        if (ch=="0")
        {
            strValue=strValue.substr(0,index);
        }
        else if (ch==".")
        {
            strValue=strValue.substr(0,index);
            break;
        }
        else
        {
            break;
        }
    }

    return strValue;
}

//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.PeriodData=new Map();  //跨周期数据 {Key=period, value=[histroydata]}
    this.IsApiPeriod=false;     //是否是后台api周期数据
    this.SourceData=null;       //不复权的个股数据
    this.MarketValue=null;      //总市值
    this.Period=0;              //周期
    this.Right=0;               //复权
    this.DataType=0;            //默认K线数据 2=分钟走势图数据 3=多日分钟走势图
    this.IsBeforeData=false;    //当日走势图数据是否包含开盘前数据
    this.DayCount;              //多日分时图天数
    this.Arguments=[];          //指标参数

    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.StockHistoryDay2ApiUrl= g_JSComplierResource.Domain+'/API/StockHistoryDay2';  //历史财务数据
    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',                      //多日分时分钟
        g_JSComplierResource.CacheDomain+'/cache/analyze/hk2szshanalyze'            //个股的北上
    ] ;          

    this.MaxRequestDataCount=1000;
    this.MaxRequestMinuteDayCount=5;
    this.KLineDateTimeRange;        //请求的K线日期范围

    this.LatestData=new Map();  //最新行情 key=id value=数据
    this.IndexData;             //大盘指数
    this.LatestIndexData;       //最新大盘数据
    this.MarginData=new Map();  //融资融券
    this.HKToSHSZData=new Map();    //北上资金
    this.NewsAnalysisData=new Map();    //新闻统计
    this.ExtendData=new Map();          //其他的扩展数据
    this.UserData=new Map();            //用户数据
    this.CustomAPIData=new Map();       //自定义API数据
    this.ScriptIndexOutData=new Map();  //调用脚本执行返回的数据
    this.OtherSymbolData=new Map();     //其他股票信息 key=symbol value=[historydata]

    //股票数据缓存 key=函数名(参数)  { Data: value=拟合的数据 , Error: } 
    //FinValue(id)
    this.StockData=new Map();        

    this.SectionFinanceData=new Map();  //截面报告数据
    this.ThrowSFPeirod=new Set();       //重新获取数据

    this.NetworkFilter;                 //网络请求回调 function(data, callback);
    this.DrawInfo;
    
   
    //使用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;
        if (option.Arguments) this.Arguments=option.Arguments;
        if (option.KLineRange) this.KLineDateTimeRange=option.KLineRange;
        if (option.IsApiPeriod) this.IsApiPeriod=option.IsApiPeriod;
        if (option.DrawInfo) this.DrawInfo=option.DrawInfo;
    }

    this.RecvError=function(request)
    {
        JSConsole.Complier.Log('[JSSymbolData::RecvError] ajax error.',request.status);
        throw {FunctionName:'RecvError', Request:request};
    }


    this.GetLatestDataKey=function(key)
    {
        var key=`DYNAINFO-${key}`;
        return key;
    }

    //最新行情
    this.GetLatestData=function(jobItem)
    {
        var aryArgs=this.JobArgumentsToArray(jobItem, 1);
        var lID=aryArgs[0];
        var key=this.GetLatestDataKey(lID);

        if (this.LatestData.has(key)) return this.Execute.RunNextJob();

        var self=this;

        if (this.NetworkFilter)
        {
            var obj=
            {
                Name:'JSSymbolData::GetLatestData', //类名::
                Explain:'DYNAINFO()',
                Args:aryArgs,
                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.ver==2.0) 
        {
            this.RecvLatestDataVer2(data);
            return;
        }

        if (!data.stock || data.stock.length!=1) return;

        let stock=data.stock[0];
        if (!stock) return;

        if (IFrameSplitOperator.IsNumber(stock.yclose)) this.LatestData.set(DYNAINFO_ARGUMENT_ID.YCLOSE,stock.yclose);
        if (IFrameSplitOperator.IsNumber(stock.open)) this.LatestData.set(DYNAINFO_ARGUMENT_ID.OPEN,stock.open);
        if (IFrameSplitOperator.IsNumber(stock.high)) this.LatestData.set(DYNAINFO_ARGUMENT_ID.HIGH,stock.high);
        if (IFrameSplitOperator.IsNumber(stock.low)) this.LatestData.set(DYNAINFO_ARGUMENT_ID.LOW,stock.low);
        if (IFrameSplitOperator.IsNumber(stock.price)) this.LatestData.set(DYNAINFO_ARGUMENT_ID.CLOSE,stock.price);
        if (IFrameSplitOperator.IsNumber(stock.vol)) this.LatestData.set(DYNAINFO_ARGUMENT_ID.VOL,stock.vol);
        if (IFrameSplitOperator.IsNumber(stock.amount)) this.LatestData.set(DYNAINFO_ARGUMENT_ID.AMOUNT,stock.amount);
        if (IFrameSplitOperator.IsNumber(stock.increase)) this.LatestData.set(DYNAINFO_ARGUMENT_ID.INCREASE,stock.increase);
        if (IFrameSplitOperator.IsNumber(stock.exchangerate)) this.LatestData.set(DYNAINFO_ARGUMENT_ID.EXCHANGERATE,stock.exchangerate);
        if (IFrameSplitOperator.IsNumber(stock.amplitude)) this.LatestData.set(DYNAINFO_ARGUMENT_ID.AMPLITUDE,stock.amplitude);
       
        /*
        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] symbol, LatestData', stock.symbol, this.LatestData);
    }

    //data:[{ id:, value: }]
    this.RecvLatestDataVer2=function(data)
    {
        if (!IFrameSplitOperator.IsNonEmptyArray(data.data)) return;

        var symbol=data.symbol;
        for(var i=0;i<data.data.length;++i)
        {
            var item=data.data[i];
            if (!item) continue;
            if (!IFrameSplitOperator.IsNumber(item.id)) continue;
            if (IFrameSplitOperator.IsNumber(item.value) || IFrameSplitOperator.IsString(item.value))
            {
                JSConsole.Complier.Log(`[JSSymbolData::RecvLatestDataVer2] symbol=${symbol} DYNAINFO(${item.id})=${item.value}.`);
                this.LatestData.set(item.id, item.value);
            }
                
        }

        JSConsole.Complier.Log('[JSSymbolData::RecvLatestDataVer2]', this.LatestData);
    }

    this.GetLatestCacheData=function(dataname)
    {
        if (this.LatestData.has(dataname)) return this.LatestData.get(dataname);

        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.GetIndexData=function()
    {
        if (this.IndexData) return this.Execute.RunNextJob();

        var self=this;
        if (ChartData.IsDayPeriod(this.Period,true))     //请求日线数据 9=季线
        {
            if (this.NetworkFilter)
            {
                var dateRange=this.Data.GetDateRange();
                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'],
                            indexSymbol:"000001.sh", symbol: this.Symbol, period:this.Period,
                            dateRange:dateRange 
                        } 
                    },
                    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 dateRange=this.Data.GetDateRange();
                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"],
                            indexSymbol:"000001.sh", symbol: this.Symbol, period:this.Period,
                            dateRange:dateRange 
                        } 
                    },
                    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;

        if (this.IsApiPeriod==true)
        {
            this.IndexData.Period=this.Period;
            this.IndexData.Data=this.Data.FixKData(hisData,this.Period);
        }
        else
        {
            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 (this.IsApiPeriod==true)
        {
            this.IndexData.Period=this.Period;
            this.IndexData.Data=this.Data.FixKData(hisData,this.Period);
        }
        else
        {
            if (ChartData.IsMinutePeriod(this.Period,false))   //周期数据
            {
                let periodData=this.IndexData.GetPeriodData(this.Period);
                this.IndexData.Data=periodData;
            }
        }
    }

    this.GetOtherSymbolParam=function(name)
    {
        var args=name.split("$");
        var setStockDataName=new Set(['CLOSE',"C",'VOL','V','OPEN','O','HIGH','H','LOW','L','AMOUNT','AMO','VOLINSTK']);
        if (!setStockDataName.has(args[1])) return null;
        
        var symbol=args[0];
        if (symbol.length==6)
        {
            if (symbol[0]=="6" || symbol[0]=="5" || symbol[0]=="8" || symbol[0]=="9")
                symbol+=".SH";
            else if (symbol[0]=='0' || symbol[0]=='1' || symbol[0]=='2' || symbol[0]=='3')
                symbol+='.SZ';
        }
        else if (symbol.indexOf("SZ")==0)
        {
            symbol=symbol.substr(2)+".SZ";
        }
        else if (symbol.indexOf("SH")==0)
        {
            symbol=symbol.substr(2)+".SH";
        }
        else if (symbol.indexOf("_")>0)
        {
            var arySymbol=symbol.split("_");
            symbol=`${arySymbol[1]}.${arySymbol[0]}`;
        }
        else 
            return null;

        return { Symbol:symbol.toLowerCase(), DataName:args[1] };
        
    }

    //获取其他股票数据
    this.GetOtherSymbolData=function(job)
    {
        var symbol=this.Symbol;
        if (job.Literal)
        {
            var args=this.GetOtherSymbolParam(job.Literal.toUpperCase());
            if (!args)
            {
                var token=job.Token;
                this.Execute.ErrorHandler.ThrowError(token.Index,token.Line,0,`${job.Literal} Error.`);
            }

            symbol=args.Symbol;
        }
        else
        {
            var args=job.Args;
            if (args.length>0)
            {
                var item=args[0];
                if (item.Type==Syntax.Literal) 
                {
                    symbol=item.Value;
                }
                else if (item.Type==Syntax.Identifier)  //变量 !!只支持默认的变量值
                {
                    var isFind=false;
                    for(var j in this.Arguments)
                    {
                        const argItem=this.Arguments[j];
                        if (argItem.Name==item.Name)
                        {
                            symbol=argItem.Value;
                            isFind=true;
                            break;
                        }
                    }
    
                    if (!isFind) 
                    {
                        var token=job.Token;
                        this.Execute.ErrorHandler.ThrowError(token.Index,token.Line,0,`${job.FunctionName}() Error: can't read ${item.Name}`);
                    }
                }
            }
        }
       

        job.Symbol=symbol.toLowerCase();
        if (job.Symbol==this.Symbol) return this.Execute.RunNextJob();
        if (this.OtherSymbolData.has(job.Symbol)) return this.Execute.RunNextJob();

        var self=this;
        if (this.DataType==HQ_DATA_TYPE.KLINE_ID &&　ChartData.IsDayPeriod(this.Period,true))     //请求日线数据 9=季线
        {
            if (this.NetworkFilter)
            {
                var dateRange=this.Data.GetDateRange();
                var obj=
                {
                    Name:'JSSymbolData::GetOtherSymbolData', //类名::函数名
                    Explain:'指定个股数据',
                    Request:
                    { 
                        Data: 
                        { 
                            symbol:job.Symbol,
                            right:self.Right,
                            period:self.Period,
                            dateRange:dateRange
                        } 
                    },
                    Self:this,
                    PreventDefault:false
                };
                this.NetworkFilter(obj, function(data) 
                { 
                    self.RecvOtherSymbolKData(data,job);
                    self.Execute.RunNextJob();
                });

                if (obj.PreventDefault==true) return;   //已被上层替换,不调用默认的网络请求
            }

            JSNetwork.HttpRequest({
                url: self.KLineApiUrl,
                data:
                {
                    "field": [ "name", "symbol","yclose","open","price","high","low","vol"],
                    "symbol": job.Symbol,
                    "start": -1,
                    "count": self.MaxRequestDataCount+500   //多请求2年的数据 确保股票剔除停牌日期以后可以对上
                },
                type:"post",
                dataType: "json",
                async:true, 
                success: function (recvData)
                {
                    self.RecvOtherSymbolKDayData(recvData,job);
                    self.Execute.RunNextJob();
                },
                error: function(request)
                {
                    self.RecvError(request);
                }
            });
        }
        else  if (ChartData.IsMinutePeriod(this.Period, true) || this.DataType==HQ_DATA_TYPE.MINUTE_ID || this.DataType==HQ_DATA_TYPE.MULTIDAY_MINUTE_ID)          //请求分钟数据
        {
            if (this.NetworkFilter)
            {
                var dateRange=this.Data.GetDateRange();
                var obj=
                {
                    Name:'JSSymbolData::GetOtherSymbolData', //类名::函数名
                    Explain:'指定个股数据',
                    Request:
                    { 
                        Data: 
                        { 
                            symbol:job.Symbol,
                            right:self.Right,
                            period:self.Period,
                            dateRange:dateRange
                        } 
                    },
                    Self:this,
                    PreventDefault:false
                };
                this.NetworkFilter(obj, function(data) 
                { 
                    self.RecvOtherSymbolKData(data,job);
                    self.Execute.RunNextJob();
                });

                if (obj.PreventDefault==true) return;   //已被上层替换,不调用默认的网络请求
            }

            JSNetwork.HttpRequest({
                url: self.MinuteKLineApiUrl,
                data:
                {
                    "field": ["name","symbol","yclose","open","price","high","low","vol"],
                    "symbol": job.Symbol,
                    "start": -1,
                    "count": self.MaxRequestMinuteDayCount+5
                },
                type:"post",
                dataType: "json",
                async:true,
                success: function (data)
                {
                    self.RecvOtherSymbolKMinuteData(data,job);
                    self.Execute.RunNextJob();
                },
                error: function(request)
                {
                    self.RecvError(request);
                }
            });
        }
    }

    //第3方数据对接
    this.RecvOtherSymbolKData=function(data,job)
    {
        JSConsole.Complier.Log('[JSSymbolData::RecvOtherSymbolKDayData2] recv data' , data);

        var kData=new ChartData();
        var hisData=null;
        var period=this.Period;
        if (this.DataType==HQ_DATA_TYPE.KLINE_ID && ChartData.IsDayPeriod(this.Period,true))    //日线数据 
        {
            hisData=this.JsonDataToHistoryData(data);
            kData.DataType=0; 
        }
        else    //分钟线数据
        {
            hisData=this.JsonDataToMinuteHistoryData(data);
            kData.DataType=1; 
            //走势图使用1分钟K线模式
            if (this.DataType==HQ_DATA_TYPE.MINUTE_ID || this.DataType==HQ_DATA_TYPE.MULTIDAY_MINUTE_ID) 
                period=4;
        }
        
        kData.Period=this.Period;
        kData.Right=this.Right;

        kData.Data=this.Data.FixKData(hisData,period);
        this.OtherSymbolData.set(job.Symbol, kData);
    }

    this.RecvOtherSymbolKDayData=function(data,job)
    {
        JSConsole.Complier.Log('[JSSymbolData::RecvOtherSymbolKDayData] recv data' , data);

        let hisData=this.JsonDataToHistoryData(data);
        var kData=new ChartData();
        kData.DataType=0; //日线数据 
        kData.Data=hisData;

        var aryOverlayData=this.SourceData.GetOverlayData(kData.Data);      //和主图数据拟合以后的数据
        kData.Data=aryOverlayData;

        if (ChartData.IsDayPeriod(this.Period,false))   //周期数据
        {
            let periodData=kData.GetPeriodData(this.Period);
            kData.Data=periodData;
        }

        this.OtherSymbolData.set(job.Symbol, kData);
    }

    this.RecvOtherSymbolKMinuteData=function(data, job)
    {
        JSConsole.Complier.Log('[JSSymbolData::RecvOtherSymbolKMinuteData] recv data' , data);

        let hisData=this.JsonDataToMinuteHistoryData(data);
        var kData=new ChartData();
        kData.DataType=1; /*分钟线数据 */
        kData.Data=hisData;

        if (ChartData.IsMinutePeriod(this.Period,false))   //周期数据
        {
            let periodData=kData.GetPeriodData(this.Period);
            kData.Data=periodData;
        }

        this.OtherSymbolData.set(job.Symbol, kData);
    }

    this.GetOtherSymolCacheData=function(obj)
    {
        var symbol,dataName;
        if (obj.FunctionName)
        {
            dataName=obj.FunctionName;
            var args=obj.Args;
            if (args.length<=0) return this.GetSymbolCacheData(dataName);
            symbol=args[0].toString().toLowerCase();
        }
        else if (obj.Literal)
        {
            var args=this.GetOtherSymbolParam(obj.Literal.toUpperCase());
            if (!args) return [];
            symbol=args.Symbol;
            dataName=args.DataName;
        }
        
        if (symbol==this.Symbol) return this.GetSymbolCacheData(dataName);
        if (!this.OtherSymbolData.has(symbol)) return [];

        var kData=this.OtherSymbolData.get(symbol);
        var upperSymbol=symbol.toUpperCase();

        switch(dataName)
        {
            case 'CLOSE':
            case 'C':
                return kData.GetClose();
            case 'VOL':
            case 'V':
                if (MARKET_SUFFIX_NAME.IsSHSZ(upperSymbol)) 
                    return kData.GetVol(100);   //A股的 把股转成手
                return kData.GetVol();
            case 'OPEN':
            case 'O':
                return kData.GetOpen();
            case 'HIGH':
            case 'H':
                return kData.GetHigh();
            case 'LOW':
            case 'L':
                return kData.GetLow();
            case 'AMOUNT':
            case 'AMO':
                return kData.GetAmount();
            case 'VOLINSTK':
                return kData.GetPosition();
        }
    }

    //获取大盘指数缓存数据
    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.GetBlockSymbol=function(symbol)    
    {
        //中文对应板块代码
        const BLOCK_CN_NAME_MAP=new Map([ ["沪深A股","CNA.ci"], ["创业板","GEM.ci"], ["沪市A股","SHA.ci"], ["中小板","SME.ci"], ["深市A股","SZA.ci"] ]);
        if (BLOCK_CN_NAME_MAP.has(symbol)) return BLOCK_CN_NAME_MAP.get(symbol);

        if (!symbol) return null;
        var blockSymbol=null;
        var upperSymbol=symbol.toUpperCase();

        if (upperSymbol.indexOf('.SH')>0 || upperSymbol.indexOf('.SZ')>0 ) 
        {
            const INDEX_SYMBOL_SET=new Set(["000001.SH", "000003.SH", "000016.SH", "000300.SH", "000905.SH", "399001.SZ", " 399005.SZ", "399006.SZ"]);
            if (!INDEX_SYMBOL_SET.has(upperSymbol)) return null;

            blockSymbol=symbol.replace('.SH','.sh');
            blockSymbol=symbol.replace('.SZ','.sz');
        }
        else if (symbol.indexOf('.CI')>0) 
        {
            blockSymbol=symbol.replace('.CI','.ci');
        }

        /*
        const SYMBOL_TO_BLOCK_MAP=new Map([
            ["000001.SH","SME.ci"],
            ["399001.SZ","SZA.ci"],["399001.SZ"," GEM.ci"],["399005.SZ","SME.ci"]
        ]);

        if (SYMBOL_TO_BLOCK_MAP.has(upperSymbol)) return SYMBOL_TO_BLOCK_MAP.get(upperSymbol);

        if(upperSymbol.indexOf('.CI')<0) return null;
        */

        return blockSymbol;
    }

    //分钟涨幅股票个数统计数据下载
    this.GetIndexIncreaseData=function(job)
    {
        var symbol=null;
        if (job.IsSelfSymbol)
        {
            symbol=this.Symbol;
        }
        else
        {
            if (!job.Args || job.Args.length<=0)
            {
                var token=job.Token;
                this.Execute.ErrorHandler.ThrowError(token.Index,token.Line,0,`${job.FunctionName} Error: 参数不能为空`);
            }
            symbol=job.Args[0].Value;
        }

        var blockSymbol=this.GetBlockSymbol(symbol);
        if (!blockSymbol)  
        {
            var token=job.Token;
            this.Execute.ErrorHandler.ThrowError(token.Index,token.Line,0,`${job.FunctionName} Error: can't support ${symbol}`);
        }

        var upKey=job.ID.toString()+'-UpCount-'+blockSymbol;
        var downKey=job.ID.toString()+'-DownCount-'+blockSymbol;
        if (this.ExtendData.has(upKey) && this.ExtendData.has(downKey)) return this.Execute.RunNextJob();

        var self=this;

        if (this.NetworkFilter)
        {
            var dataType={Type: this.DataType};
            if (this.DataType===HQ_DATA_TYPE.KLINE_ID) dataType.Period=this.Period;
            var dateRange=this.Data.GetDateRange();
            var obj=
            {
                Name:'JSSymbolData::GetIndexIncreaseData', //类名::
                Explain:'涨停家数统计',
                DateRange:dateRange,
                DataType:dataType,
                Request:{ Url:'www.121287.com',  Type:'POST' ,
                    Data: { symbol:this.Symbol, blocksymbol:blockSymbol, field: ["up", "down"] } }, 
                Self:this,
                PreventDefault:false
            };
            this.NetworkFilter(obj, function(data) 
            { 
                if (this.DataType===HQ_DATA_TYPE.KLINE_ID) this.RecvHistoryIncreaseDataV2(data, {UpKey:upKey,DownKey:downKey});
                else this.RecvMinuteIncreaseDataV2(data, {UpKey:upKey,DownKey:downKey});
                
                self.Execute.RunNextJob();
            });

            if (obj.PreventDefault==true) return;   //已被上层替换,不调用默认的网络请求
        }

        if (this.DataType===HQ_DATA_TYPE.MINUTE_ID || this.DataType===HQ_DATA_TYPE.MULTIDAY_MINUTE_ID)  //走势图数据
        {
            var apiUrl=g_JSComplierResource.CacheDomain+'/cache/analyze/increaseanalyze/'+blockSymbol+'.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 && ChartData.IsDayPeriod(this.Period,true)) //K线图 日线
        {
            JSConsole.Complier.Log('[JSSymbolData::GetIndexIncreaseData] K day Get url=' , self.KLineApiUrl);
            JSNetwork.HttpRequest({
                url: self.KLineApiUrl,
                data:
                {
                    "symbol": blockSymbol,
                    "start": -1,
                    "count": self.MaxRequestDataCount,
                    "field":['up', 'down']
                },
                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);
                }
            });
        }
        else
        {
            this.Execute.RunNextJob();
        }
    }


    //格式{ ver：2.0 data:[{date, time, up, down}, .....]}
    this.RecvHistoryIncreaseDataV2=function(data,key)
    {
        JSConsole.Complier.Log('[JSSymbolData::RecvHistoryIncreaseData] recv data, key' , data,key);

        var upData=[],downData=[];
        for(var i in data.data)
        {
            var item=data.data[i];
            let upItem=new SingleData();
            let downItem=new SingleData();
            var date=item[0];
            var time=null;
            upItem.Date=date;
            downItem.Date=date;
            if (ChartData.IsMinutePeriod(this.Period,true) && IFrameSplitOperator.IsNumber(item[1])) 
            {
                time=item[1];
                upItem.Time=time;
                downItem.Time=time;
            }
            
            upItem.Value=item[2];
            upData[i]=upItem;
            
            downItem.Value=item[3];
            downData[i]=downItem;
        }

        var upFixedData=this.Data.GetFittingData2(upData,0);
        var downFixedData=this.Data.GetFittingData2(downData,0);

        this.ExtendData.set(key.UpKey,upFixedData);
        this.ExtendData.set(key.DownKey,downFixedData);
    }

    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 upFixedData, downFixedData;
        if (this.SourceData) upFixedData=this.SourceData.GetFittingData(upData);
        else upFixedData=this.Data.GetFittingData(aryData);

        if (this.SourceData) downFixedData=this.SourceData.GetFittingData(downData);
        else downFixedData=this.Data.GetFittingData(aryData);

        this.ExtendData.set(key.UpKey,upFixedData);
        this.ExtendData.set(key.DownKey,downFixedData);
    }

    this.RecvMinuteIncreaseDataV2=function(data, key)
    {
        JSConsole.Complier.Log('[JSSymbolData::RecvMinuteIncreaseDataV2] recv data, key' , data, key);
    }

    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 blockSymbol=this.GetBlockSymbol(symbol);
        if (!blockSymbol) this.Execute.ThrowUnexpectedNode(node,'不支持函数'+funcName+'('+symbol+')');

        var key;
        if (funcName=='UPCOUNT' || funcName=='ADVANCE') key=JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_INDEX_INCREASE_DATA.toString()+'-UpCount-'+blockSymbol;
        else if (funcName=='DOWNCOUNT' || funcName=='DECLINE') key=JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_INDEX_INCREASE_DATA.toString()+'-DownCount-'+blockSymbol;
        
        if (!key || !this.ExtendData.has(key)) this.Execute.ThrowUnexpectedNode(node,'不支持函数'+funcName+'('+symbol+')');

        if (this.DataType===HQ_DATA_TYPE.MINUTE_ID || this.DataType===HQ_DATA_TYPE.MULTIDAY_MINUTE_ID)  //分时图
        {
            return this.ExtendData.get(key);
        }
        else if (this.DataType===HQ_DATA_TYPE.KLINE_ID && ChartData.IsDayPeriod(this.Period,true))  //K线图
        {
            var data=this.ExtendData.get(key);
            var bindData=new ChartData();
            bindData.Data=data;
            bindData.Period=this.Period;    //周期

            if (bindData.Period>0)          //周期数据
            {
                var periodData=bindData.GetPeriodSingleData(bindData.Period);
                bindData.Data=periodData;
            }

            return bindData.GetValue();
        }
        else
        {
            return null;
        }
    }


    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))     //请求日线数据
        {
            if (this.NetworkFilter)
            {
                var obj=
                {
                    Name:'JSSymbolData::GetSymbolData',
                    Explain:"日线数据",
                    Request:
                    { Url:self.RealtimeApiUrl,  Type:'POST' ,
                        Data: 
                        {
                            "field": [ "name", "symbol","yclose","open","price","high","low","vol"],
                            "symbol": self.Symbol,
                            "start": -1,
                            "count": self.MaxRequestDataCount
                        } 
                    },
                    Self:this,
                    PreventDefault:false
                };

                if (this.KLineDateTimeRange)
                {
                    obj.Request.KLineDataTimeRange={Start:{ Date:this.KLineDateTimeRange.Start.Date},  End:{ Date:this.KLineDateTimeRange.End.Date} };
                    if (this.IsNumber(this.KLineDateTimeRange.Start.Time)) obj.Request.KLineDataTimeRange.Start.Time=this.KLineDateTimeRange.Start.Time;
                    if (this.IsNumber(this.KLineDateTimeRange.End.Time)) obj.Request.KLineDataTimeRange.End.Time=this.KLineDateTimeRange.End.Time;
                }

                this.NetworkFilter(obj, function(data) 
                { 
                    self.RecvHistroyData(data);
                    self.Execute.RunNextJob();
                });

                if (obj.PreventDefault==true) return;   //已被上层替换,不调用默认的网络请求
            }

            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))               //请求分钟数据
        {
            if (this.NetworkFilter)
            {
                var obj=
                {
                    Name:'JSSymbolData::GetSymbolData',
                    Explain:"分钟K线数据",
                    Request:
                    { Url:self.MinuteKLineApiUrl,  Type:'POST' ,
                        Data: 
                        {
                            "field": ["name","symbol","yclose","open","price","high","low","vol"],
                            "symbol": self.Symbol,
                            "start": -1,
                            "count": self.MaxRequestMinuteDayCount
                        } 
                    },
                    Self:this,
                    PreventDefault:false
                };

                if (this.KLineDateTimeRange)
                {
                    obj.Request.KLineDataTimeRange={Start:{ Date:this.KLineDateTimeRange.Start.Date},  End:{ Date:this.KLineDateTimeRange.End.Date} };
                    if (this.IsNumber(this.KLineDateTimeRange.Start.Time)) obj.Request.KLineDataTimeRange.Start.Time=this.KLineDateTimeRange.Start.Time;
                    if (this.IsNumber(this.KLineDateTimeRange.End.Time)) obj.Request.KLineDataTimeRange.End.Time=this.KLineDateTimeRange.End.Time;
                }

                this.NetworkFilter(obj, function(data) 
                { 
                    self.RecvMinuteHistroyData(data);
                    self.Execute.RunNextJob();
                });

                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.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.IsApiPeriod)   //后台周期 前端不处理
        {

        }
        else
        {
            if (this.Right>0)    //复权
            {
                let rightData=this.Data.GetRightData(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 (this.IsApiPeriod)   //后台周期 前端不处理
        {

        }
        else
        {
            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();

        var upperSymbol=this.Symbol.toUpperCase();

        switch(dataName)
        {
            case 'CLOSE':
            case 'C':
                return this.Data.GetClose();
            case 'VOL':
            case 'V':
                if (MARKET_SUFFIX_NAME.IsSHSZ(upperSymbol)) 
                    return this.Data.GetVol(100);   //A股的 把股转成手
                return this.Data.GetVol();
            case 'OPEN':
            case 'O':
                return this.Data.GetOpen();
            case 'HIGH':
            case 'H':
                return this.Data.GetHigh();
            case 'LOW':
            case 'L':
                return this.Data.GetLow();
            case 'AMOUNT':
            case 'AMO':
                return this.Data.GetAmount();

            case "OPI":         //文华 持仓量
            case 'VOLINSTK':    //通达信 持仓量
                return this.Data.GetPosition();

            
            case "ZSTJJ":      //均价
                return this.Data.GetAvPrice();
            
            case "SETTLE":  //文华 结算价
            case "QHJSJ":   //通达信 结算价
                return this.Data.GetSettlementPrice();  //结算价

            case "ISEQUAL": //平盘
                return this.Data.GetIsEqual();
            case "ISUP":    //收阳
                return this.Data.GetIsUp();
            case "ISDOWN":  //收阴
                return this.Data.GetIsDown();
        }
    }

    this.GetSymbolPeriodData=function(job)
    {
        var periodID=JSComplierHelper.GetPeriodInfo({ Name:job.PeriodName }).Period;
        var periodInfo={ PeriodID:periodID, PeriodName:job.PeriodName };
        //同周期不请求
        if (periodID==this.Period) this.Execute.RunNextJob(); 
        if (this.IsApiPeriod)
        {
            if (this.PeriodData.has(job.PeriodName)) return this.Execute.RunNextJob();
        }
        else
        {
            if (ChartData.IsDayPeriod(periodID,true)) 
            {
                if (ChartData.IsDayPeriod(this.Period,true)) return this.Execute.RunNextJob();
                periodInfo={PeriodID:0, PeriodName:'DAY' };
            }
            else if (ChartData.IsMinutePeriod(periodID,true))
            {
                if (ChartData.IsMinutePeriod(this.Period,true)) return this.Execute.RunNextJob();
                periodInfo={ PeriodID:4, PeriodName:"MIN1" };
            } 
            else
            {
                return this.Execute.RunNextJob();
            }
        }

        var self=this;
        if (this.NetworkFilter)
        {
            var obj=
            {
                Name:'JSSymbolData::GetSymbolPeriodData',
                Explain:"跨周期数据",
                Request:
                { 
                    Data: 
                    {
                        "field": [ 'symbol','name', job.ValueName ],
                        "period":job.PeriodName,
                        "symbol": self.Symbol,
                    } 
                },
                Self:this,
                PreventDefault:false
            };

            this.NetworkFilter(obj, function(data) 
            { 
                self.RecvSymbolPeriodData(data, periodInfo);
                self.Execute.RunNextJob();
            });

            if (obj.PreventDefault==true) return;   //已被上层替换,不调用默认的网络请求
        }

        if (ChartData.IsMinutePeriod(periodID,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.RecvSymbolPeriodData(data,periodInfo);
                    self.Execute.RunNextJob();
                },
                error: function(request)
                {
                    self.RecvError(request);
                }
            });
        }
        else if (ChartData.IsDayPeriod(periodID,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 (data)
                {
                    self.RecvSymbolPeriodData(data, periodInfo);
                    self.Execute.RunNextJob();
                },
                error: function(request)
                {
                    self.RecvError(request);
                }
            });
        }
        else
        {
            return this.Execute.RunNextJob();
        }

    }

    this.RecvSymbolPeriodData=function(data, periodInfo)
    {
        JSConsole.Complier.Log('[JSSymbolData::RecvSymbolPeriodData] data, periodInfo ' , data, periodInfo);

        if (ChartData.IsDayPeriod(periodInfo.PeriodID,true)) 
        {
            var hisData=this.JsonDataToHistoryData(data);
            var dayData=new ChartData();
            dayData.DataType=0;     //日线数据
            dayData.Data=hisData;   //保存原始数据 不复权
            dayData.Right=0;
            dayData.Period=periodInfo.PeriodID;
            this.PeriodData.set(periodInfo.PeriodName, dayData);
        }
        else if (ChartData.IsMinutePeriod(periodInfo.PeriodID,true))
        {
            var hisData=this.JsonDataToMinuteHistoryData(data);
            var minData=new ChartData();
            minData.DataType=1;     //分钟线数据
            minData.Data=hisData;
            minData.Right=0;
            minData.Period=periodInfo.PeriodID;
            this.PeriodData.set(periodInfo.PeriodName, minData);
        }
    }

    this.GetSymbolPeriodCacheData=function(valueName,periodName)
    {
        var periodInfo=JSComplierHelper.GetPeriodInfo({Name:periodName});
        if (this.Period==periodInfo.Period)
            return this.GetSymbolCacheData(valueName);

        var hisData=null;
        if (this.IsApiPeriod)
        {
            var curPeriodInfo=JSComplierHelper.GetPeriodInfo({PeriodID:this.Period});
            if (!curPeriodInfo) return null;
            if (curPeriodInfo.Order>periodInfo.Order) return null;   //只能小周期转大周期

            if (!this.PeriodData.has(periodName)) return null;
            hisData=this.PeriodData.get(periodName);
            hisData=hisData.Data;
        }
        else
        {
            var curPeriodInfo=JSComplierHelper.GetPeriodInfo({PeriodID:this.Period});
            if (!curPeriodInfo) return null;

            if (curPeriodInfo.Order>periodInfo.Order) return null;   //只能小周期转大周期

            if (ChartData.IsDayPeriod(periodInfo.Period,true) && ChartData.IsMinutePeriod(this.Period,true))
            {
                var dayData=this.PeriodData.get('DAY'); //日线
                if (periodInfo.Period==0) hisData=dayData.Data;
                else hisData=dayData.GetPeriodData(periodInfo.Period);  //日线周期
            }
            else
            {
                var bindData=new ChartData();
                bindData.Data=this.SourceData.Data;
                bindData.Period=this.Period;
                bindData.Right=this.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.Data.ConverPeriod(hisData, this.Period, periodInfo.Period);
        var result=new ChartData();
        result.Data=data;

        var upperSymbol=this.Symbol.toUpperCase();
        switch(valueName)
        {
            case 'C':
            case "CLOSE":
                return result.GetClose();
            case 'O':
            case "OPEN":
                return result.GetOpen();
            case 'H':
            case "HIGH":
                return result.GetHigh();
            case 'L':
            case "LOW":
                return result.GetLow();
            case 'AMO':
            case "AMOUNT":
                return result.GetAmount();
            case 'V':
            case "VOL":
                if (MARKET_SUFFIX_NAME.IsSHSZ(upperSymbol)) 
                    return result.GetVol(100);
                return result.GetVol();
            case "VOLINSTK":
                return result.GetPosition();
            default:
                return null;
        }
    }

    this.GetSymbolPeriodCacheData2=function(valueName,periodName,n)
    {
        var periodInfo=JSComplierHelper.GetPeriodInfo({Name:periodName});
        if (!periodInfo) return null;

        var curPeriodInfo=JSComplierHelper.GetPeriodInfo({PeriodID:this.Period});
        if (!curPeriodInfo) return null;

        if (curPeriodInfo.Order>periodInfo.Order) return null;   //只能小周期转大周期

        var result;
        if (curPeriodInfo.Period==periodInfo.Period) 
        {
            result=this.Data;
        }
        else
        {
            var hisData;
            if (this.IsApiPeriod)
            {
                if (!this.PeriodData.has(periodName)) return null;
                hisData=this.PeriodData.get(periodName);
            }
            else
            {
                if (ChartData.IsMinutePeriod(curPeriodInfo.Period,true) && ChartData.IsDayPeriod(periodInfo.Period,true))
                {
                    var dayData=this.PeriodData.get('DAY'); //日线
                    if (periodInfo.Period==0) hisData=dayData;
                    else hisData=dayData.GetPeriodData(periodInfo.Period);  //日线周期
                }
                else
                {
                    var bindData=new ChartData();
                    bindData.Data=this.SourceData.Data;
                    bindData.Period=this.Period;
                    bindData.Right=this.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.Data.ConverPeriod(hisData, this.Period, periodInfo.Period);
            var result=new ChartData();
            result.Data=data;
        }

        if (IFrameSplitOperator.IsPlusNumber(n))
        {
            var refResult=new ChartData();
            var data=result.GetRef(n);
            refResult.Data=data;
            result=refResult;
        }

        var upperSymbol=this.Symbol.toUpperCase();

        switch(valueName)
        {
            case 'C':
            case "CLOSE":
                return result.GetClose();
            case 'O':
            case "OPEN":
                return result.GetOpen();
            case 'H':
            case "HIGH":
                return result.GetHigh();
            case 'L':
            case "LOW":
                return result.GetLow();
            case 'AMO':
            case "AMOUNT":
                return result.GetAmount();
            case 'V':
            case "VOL":
                if (MARKET_SUFFIX_NAME.IsSHSZ(upperSymbol)) 
                    return result.GetVol(100);
                return result.GetVol();
            case "VOLINSTK":
                return result.GetPosition();
            default:
                return null;
        }
    }

    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+1);   //数据从0开始

        return result;
    }

    //BARPOS 返回从第一根K线开始到当前的周期数。
    //注：
    //1、BARPOS返回本地已有的K线根数，从本机上存在的数据开始算起。
    //2、本机已有的第一根K线上返回值为1。
    this.GetBarPos=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)
            result.push(i+1);   

        return result;
    }

    this.GetTotalTradeMinuteCount=function()
    {
        var data=g_MinuteCoordinateData.GetCoordinateData(this.Symbol);
        if (data && data.Count>0) return data.Count-1;
        return 242;
    }

    this.GetTotalBarsCount=function()
    {
        let lCount=this.Data.Data.length;
        return lCount;
    }

    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;
    }

    //BARSTATUS返回数据位置信息,1表示第一根K线,2表示最后一个数据,0表示中间位置.
    //例如:BARSTATUS=2表示当天是该数据的最后一个周期.
    this.GetBarStatus=function()
    {
        let result=[];
        if (!this.Data || !this.Data.Data || !this.Data.Data.length) return result

        let lCount=this.Data.Data.length;
        for(var i=0 ;i<lCount;++i)
        {
            if (i==0) result[i]=1;
            else if (i==lCount-1) result[i]=2;
            else result[i]=0;
        }

        return result;
    }

    //融资融券函数
    this.GetMarginCacheData=function(id, node)
    {
        let jobID=JS_EXECUTE_JOB_ID.GetMarginJobID(id);
        if (!jobID) this.Execute.ThrowUnexpectedNode(node,'不支持MARGIN('+id+')');
        if(this.MarginData.has(jobID)) return this.MarginData.get(jobID);

        return [];
    }

    //下融资融券
    this.GetMarginData=function(jobID)
    {
        if (this.MarginData.has(jobID)) return this.Execute.RunNextJob();

        JSConsole.Complier.Log('[JSSymbolData::GetMarginData] jobID=', jobID);
        var self=this;
        let fieldList=["name","date","symbol"];
        
        switch(jobID)
        {
        case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BALANCE:           //融资融券余额
            fieldList.push("margin.balance");
            break;
        case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_RATE:              //融资占比
            fieldList.push("margin.rate");
            break;
    
        case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BUY_BALANCE:       //买入信息-融资余额
        case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BUY_AMOUNT:        //买入信息-买入额
        case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BUY_REPAY:         //买入信息-偿还额
        case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BUY_NET:           //买入信息-融资净买入
            fieldList.push("margin.buy");
            break;
    
        case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_SELL_BALANCE:      //卖出信息-融券余量
        case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_SELL_VOLUME:       //卖出信息-卖出量
        case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_SELL_REPAY:        //卖出信息-偿还量
        case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_SELL_NET:          //卖出信息-融券净卖出
            fieldList.push("margin.sell");
            break;
        }

        //请求数据
        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(job)
    {
        var args=job.Args;
        var code=this.Symbol;
        if (args.length>0)
        {
            var item=args[0];
            if (item.Type==Syntax.Literal) 
            {
                code=item.Value;
            }
            else if (item.Type==Syntax.Identifier)  //变量 !!只支持默认的变量值
            {
                var isFind=false;
                for(var j in this.Arguments)
                {
                    const argItem=this.Arguments[j];
                    if (argItem.Name==item.Name)
                    {
                        code=argItem.Value;
                        isFind=true;
                        break;
                    }
                }

                if (!isFind) 
                {
                    var token=job.Token;
                    this.Execute.ErrorHandler.ThrowError(token.Index,token.Line,0,`HK2SHSZ() Error: can't read ${item.Name}`);
                }
            }
        }

        job.Symbol=code;

        if (code==1 || code==2 || code==3)    //下载全市场数据
            this.GetHKToSHSZMarketData(code,job);
        else
            this.GetHKToSHSZStockData(code,job);      //下载个股数据
    }

    this.GetHKToSHSZStockData=function(symbol,job)
    {
        if (this.HKToSHSZData.has(symbol)) return this.Execute.RunNextJob();

        var upperSymbol=symbol.toLowerCase();   //代码小写
        var self=this;
        var url=`${this.HKToSHSZApiUrl[3]}/${upperSymbol}.json`;
        //请求数据
        JSNetwork.HttpRequest({
            url: url,
            type:"get",
            dataType: "json",
            async:true,
            success: function (recvData)
            {
                self.RecvHKToSHSZStockData(recvData,job);
                self.Execute.RunNextJob();
            },
            error:function(request)
            {
                console.warn(`[JSSymbolData::GetHKToSHSZStockData] request url=${url} failed. error=${request.status}`);
                self.RecvHKToSHSZStockData(null,job);
                self.Execute.RunNextJob();
            }
        });
    }

    this.RecvHKToSHSZStockData=function(data,job)
    {
        if (!data) return;

        var symbol=data.symbol;
        var upperSymbol=symbol.toUpperCase();
        var aryData=[];
        for(var i=0;i<data.date.length;++i)
        {
            var item=new SingleData();
            item.Date=data.date[i];
            item.Value=data.vol[i];   //股
            aryData.push(item);
        }

        var aryFixedData=this.Data.GetFittingData(aryData);
        var bindData=new ChartData();
        bindData.Data=aryFixedData;
        bindData.Period=this.Period;    //周期

        if (bindData.Period>0)          //周期数据
        {
            var periodData=bindData.GetPeriodSingleData(bindData.Period);
            bindData.Data=periodData;
        }

        var data=bindData.GetValue();
        this.HKToSHSZData.set(upperSymbol,data);
    }

    this.GetHKToSHSZMarketData=function(symbol,job)
    {
        if (this.HKToSHSZData.has(symbol)) 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::GetHKToSHSZMarketData] code=${symbol} 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,job);
                    self.Execute.RunNextJob();
                }
            });
        }
        else
        {
            //请求数据
            JSNetwork.HttpRequest({
                url: url,
                type:"get",
                dataType: "json",
                async:true,
                success: function (recvData)
                {
                    if (dataType==0) self.RecvHKToSHSZData(recvData,job);
                    else if (dataType==1) self.RecvMinuteHKToSHSZData(recvData,job);
                    self.Execute.RunNextJob();
                }
            });
        }
        
    }

    this.RecvMinuteHKToSHSZData=function(data,job)
    {
        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, ID:1}, 
            {Data:arySHData,ID:2}, 
            {Data:arySZData,ID:3}
        ];

        for(var i in allData)
        {
            var item=allData[i];
            this.HKToSHSZData.set(item.ID,item.Data);
        }
    }

    this.RecvHKToSHSZData=function(data,job)
    {
        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, ID:1}, 
            {Data:arySHData,ID:2 }, 
            {Data:arySZData,ID:3 }
        ];

        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].ID,data);
        }
    }

    this.RecvMulitMinuteHKToSHSZData=function(data,job)   //多日分时图北上资金
    {
        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, ID:1}, 
            {Data:arySHData,ID:2}, 
            {Data:arySZData,ID:3}
        ];

        for(var i in allData)
        {
            var item=allData[i];
            this.HKToSHSZData.set(item.ID,item.Data);
        }
        
    }

    //北上资金函数
    this.GetHKToSHSZCacheData=function(code, node)
    {
        //if (!this.HKToSHSZData.has(code)) this.Execute.ThrowUnexpectedNode(node,`不支持HK2SHSZ(${code})`);
        if (!code) code=this.Symbol;
        if (typeof(code)=='string') code=code.toUpperCase();
        if(this.HKToSHSZData.has(code)) return this.HKToSHSZData.get(code);
        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.GetFinOne=function(jobItem)
    {
        var aryArgs=this.JobArgumentsToArray(jobItem, 3);
        var key=this.GetStockDataKey(jobItem,aryArgs);
        if (this.StockData.has(key)) return this.Execute.RunNextJob();
        var self=this;
        if (this.NetworkFilter)
        {
            var dateRange=this.Data.GetDateRange();
            var obj=
            {
                Name:'JSSymbolData::GetFinOne', //类名::
                Explain:'财务数据FINONE(ID,Y,MMDD)',
                JobID:jobItem.ID,
                Request:{ Url:self.StockHistoryDayApiUrl, Type:'POST', Data:{ Args:aryArgs, symbol: this.Symbol, daterange:dateRange } },
                Self:this,
                PreventDefault:false
            };
            this.NetworkFilter(obj, function(recvData) 
            { 
                self.RecvStockValue(recvData,jobItem,key,1);
                self.Execute.RunNextJob();
            });

            if (obj.PreventDefault==true) return;   //已被上层替换,不调用默认的网络请求
        }

        var apiDownload=new DownloadFinOneData( 
            {
                Job:jobItem, 
                Symbol:this.Symbol, 
                Url:this.StockHistoryDayApiUrl, 
                Args:aryArgs,
                DataKey:key,
                Callback:function(recvData, jobItem, key) 
                { 
                    self.RecvStockValue(recvData, jobItem, key,1);
                    self.Execute.RunNextJob();
                },
                ErrorCallback:function(strError)
                {
                    self.AddStockValueError(key,strError);
                }
            });

        apiDownload.Download();
    }

    this.GetStockDataKey=function(jobItem, aryArgs)
    {
        var key=jobItem.FunctionName;
        if (aryArgs.length>0)
        {
            key+="(";
            for(var i=0;i<aryArgs.length;++i)
            {
                if (i>0) key+=",";
                key+=aryArgs[i].toString();
            }
            key+=")";
        }

        return key;
    }

    this.GetFinValue=function(jobItem)
    {
        var aryArgs=this.JobArgumentsToArray(jobItem, 1);
        var lID=aryArgs[0];
        var key=this.GetStockDataKey(jobItem,aryArgs);
        if (this.StockData.has(key)) return this.Execute.RunNextJob();
        var self=this;
        if (this.NetworkFilter)
        {
            var dateRange=this.Data.GetDateRange();
            var obj=
            {
                Name:'JSSymbolData::GetFinValue', //类名::
                Explain:'财务数据FINVALUE(ID)',
                JobID:jobItem.ID,
                Request:{ Url:self.StockHistoryDayApiUrl, Type:'POST', Data:{ id:lID, symbol: this.Symbol, daterange:dateRange } },
                Self:this,
                PreventDefault:false
            };
            this.NetworkFilter(obj, function(recvData) 
            { 
                self.RecvStockValue(recvData,jobItem,key,0);
                self.Execute.RunNextJob();
            });

            if (obj.PreventDefault==true) return;   //已被上层替换,不调用默认的网络请求
        }

        var apiDownload=new DownloadFinValueData( 
            {
                Job:jobItem, 
                Symbol:this.Symbol, 
                Url:this.StockHistoryDayApiUrl, 
                Args:aryArgs,
                DataKey:key,
                Callback:function(recvData, jobItem, key) 
                { 
                    self.RecvStockValue(recvData, jobItem, key,0);
                    self.Execute.RunNextJob();
                },
                ErrorCallback:function(strError)
                {
                    self.AddStockValueError(key,strError);
                }
            });

        apiDownload.Download();
    }

    this.GetFinance=function(jobItem)
    {
        var aryArgs=this.JobArgumentsToArray(jobItem, 1);
        var lID=aryArgs[0];
        var key=this.GetStockDataKey(jobItem,aryArgs);
        if (this.StockData.has(key)) return this.Execute.RunNextJob();

        var self=this;
        if (this.NetworkFilter)
        {
            var dateRange=this.Data.GetDateRange();
            var obj=
            {
                Name:'JSSymbolData::GetFinance', //类名::
                Explain:'财务数据FINANCE(ID)',
                JobID:jobItem.ID,
                Request:{ Url:self.RealtimeApiUrl, Type:'POST', Data:{ id:lID, symbol: this.Symbol, daterange:dateRange } },
                Self:this,
                PreventDefault:false
            };
            this.NetworkFilter(obj, function(recvData) 
            { 
                self.RecvStockValue(recvData,jobItem,key,0);
                self.Execute.RunNextJob();
            });

            if (obj.PreventDefault==true) return;   //已被上层替换,不调用默认的网络请求
        }

        var apiDownload=new DownloadFinanceData( 
            {
                Job:jobItem, 
                Symbol:this.Symbol, 
                Url:this.StockHistoryDayApiUrl, 
                RealtimeUrl:this.RealtimeApiUrl,
                Args:aryArgs,
                DataKey:key,
                Callback:function(recvData, jobItem, key) 
                { 
                    self.RecvStockValue(recvData, jobItem, key,0);
                    self.Execute.RunNextJob();
                },
                ErrorCallback:function(strError)
                {
                    self.AddStockValueError(key,strError);
                }
            });

        apiDownload.Download();
    }

    this.GetGPJYValue=function(jobItem)
    {
        var aryArgs=this.JobArgumentsToArray(jobItem, 3);
        var key=this.GetStockDataKey(jobItem,aryArgs);
        if (this.StockData.has(key)) return this.Execute.RunNextJob();

        var self=this;
        //TYPE:为1表示做平滑处理,没有数据的周期返回上一周期的值;为0表示不做平滑处理
        var dataType=aryArgs[2]==1?0:2;
        if (this.NetworkFilter)
        {
            var dateRange=this.Data.GetDateRange();
            var obj=
            {
                Name:'JSSymbolData::GetGPJYValue', //类名::
                Explain:'股票交易类数据GPJYVALUE(ID,N,TYPE)',
                JobID:jobItem.ID,
                Request:{ Url:self.StockHistoryDayApiUrl, Type:'POST', Data:{ Args:aryArgs, symbol: this.Symbol, daterange:dateRange } },
                Self:this,
                PreventDefault:false
            };
            this.NetworkFilter(obj, function(recvData) 
            { 
                self.RecvStockValue(recvData,jobItem,key,dataType);
                self.Execute.RunNextJob();
            });

            if (obj.PreventDefault==true) return;   //已被上层替换,不调用默认的网络请求
        }

        var apiDownload=new DownloadGPJYValue( 
            {
                Job:jobItem, 
                Symbol:this.Symbol, 
                Url:this.StockHistoryDayApiUrl,
                Args:aryArgs,
                DataKey:key,
                Callback:function(recvData, jobItem, key) 
                { 
                    self.RecvStockValue(recvData, jobItem, key,dataType);
                    self.Execute.RunNextJob();
                },
                ErrorCallback:function(strError)
                {
                    self.AddStockValueError(key,strError);
                }
            });

        apiDownload.Download();
    }

    this.GetSCJYValue=function(jobItem)
    {
        var aryArgs=this.JobArgumentsToArray(jobItem, 3);
        var key=this.GetStockDataKey(jobItem,aryArgs);
        if (this.StockData.has(key)) return this.Execute.RunNextJob();

        var self=this;
        //TYPE:为1表示做平滑处理,没有数据的周期返回上一周期的值;为0表示不做平滑处理
        var dataType=aryArgs[2]==1?0:2;
        if (this.NetworkFilter)
        {
            var dateRange=this.Data.GetDateRange();
            var obj=
            {
                Name:'JSSymbolData::GetSCJYValue', //类名::
                Explain:'股票交易类数据SCJYVALUE(ID,N,TYPE)',
                JobID:jobItem.ID,
                Request:{ Url:self.StockHistoryDayApiUrl, Type:'POST', Data:{ Args:aryArgs, symbol: this.Symbol, daterange:dateRange } },
                Self:this,
                PreventDefault:false
            };
            this.NetworkFilter(obj, function(recvData) 
            { 
                self.RecvStockValue(recvData,jobItem,key,dataType);
                self.Execute.RunNextJob();
            });

            if (obj.PreventDefault==true) return;   //已被上层替换,不调用默认的网络请求
        }

        var apiDownload=new DownloadSCJYValue( 
            {
                Job:jobItem, 
                Symbol:this.Symbol, 
                Url:this.StockHistoryDayApiUrl,
                Args:aryArgs,
                DataKey:key,
                Callback:function(recvData, jobItem, key) 
                { 
                    self.RecvStockValue(recvData, jobItem, key,dataType);
                    self.Execute.RunNextJob();
                },
                ErrorCallback:function(strError)
                {
                    self.AddStockValueError(key,strError);
                }
            });

        apiDownload.Download();
    }

    this.GetVariantData=function(jobItem)
    {
        var key=jobItem.VariantName;
        if (this.StockData.has(key)) return this.Execute.RunNextJob();

        var self=this;
        if (this.NetworkFilter)
        {
            var dateRange=this.Data.GetDateRange();
            var obj=
            {
                Name:'JSSymbolData::GetVariantData', //类名::函数名
                Explain:'变量数据下载',
                JobID:jobItem.ID,
                Request:{ Url:"www.121287.com", Type:'POST', Data:{ VariantName:jobItem.VariantName, symbol: this.Symbol, daterange:dateRange } },
                Self:this,
                PreventDefault:false
            };
            this.NetworkFilter(obj, function(recvData) 
            { 
                if (recvData.Error) 
                {
                    self.AddStockValueError(key,recvData.Error);
                }
                else
                {
                    var dataType=0;
                    if (IFrameSplitOperator.IsNumber(recvData.DataType)) dataType=recvData.DataType;
                    self.RecvStockValue(recvData.Data,jobItem,key,dataType);
                }
               
                self.Execute.RunNextJob();
            });

            if (obj.PreventDefault==true) return;   //已被上层替换,不调用默认的网络请求
        }

        var errorCallback=function(strError)
        {
            self.AddStockValueError(key,strError);
        };

        var apiDownload;
        if (jobItem.VariantName=="CAPITAL" || jobItem.VariantName=="TOTALCAPITAL" || jobItem.VariantName=="EXCHANGE")
        {
            var callback=function(recvData, jobItem, key) 
            { 
                self.RecvStockValue(recvData, jobItem, key,0);
                self.Execute.RunNextJob();
            };

            apiDownload=new DownloadFinanceData( 
            {
                Job:jobItem, 
                Symbol:this.Symbol, 
                Url:this.StockHistoryDayApiUrl, 
                RealtimeUrl:this.RealtimeApiUrl,
                Args:[jobItem.VariantName],
                DataKey:key,
                Callback:callback,
                ErrorCallback:errorCallback
            });
        }
        else if (jobItem.VariantName=="HYBLOCK" || jobItem.VariantName=="DYBLOCK" || jobItem.VariantName=="GNBLOCK")
        {
            var callback=function(recvData, jobItem, key, dataType) 
            { 
                self.RecvStockValue(recvData, jobItem, key, dataType);
                self.Execute.RunNextJob();
            };

            apiDownload=new DownloadGroupData(
            {
                Job:jobItem, 
                Symbol:this.Symbol, 
                Url:this.StockHistoryDayApiUrl, 
                RealtimeUrl:this.RealtimeApiUrl,
                Args:[jobItem.VariantName],
                DataKey:key,
                Callback:callback,
                ErrorCallback:errorCallback
            });
        }
        else if (jobItem.VariantName=="INBLOCK")
        {
            var errorMessage=`${jobItem.VariantName}, 请对接外部数据.`;
            this.AddStockValueError(key,errorMessage);
            this.Execute.RunNextJob();
            return;
        }
        else
        {
            var errorMessage=`不支持变量${jobItem.VariantName}, 请对接外部数据.`;
            this.AddStockValueError(key,errorMessage);
            this.Execute.RunNextJob();
            return;
        }

        apiDownload.Download();
    }

    //自定义变量数据下载
    this.GetCustomVariantData=function(jobItem)
    {
        var key=jobItem.VariantName;
        if (this.StockData.has(key)) return this.Execute.RunNextJob();

        var variantInfo=g_JSComplierResource.CustomVariant.Data.get(key);
        var self=this;
        if (this.NetworkFilter)
        {
            var dateRange=this.Data.GetDateRange();
            var obj=
            {
                Name:'JSSymbolData::GetCustomVariantData', //类名::函数名
                Explain:'自定义变量数据下载',
                JobID:jobItem.ID,
                Request:
                { 
                    Url:"www.121287.com", Type:'POST', 
                    Data:{ VariantName:jobItem.VariantName, symbol: this.Symbol, daterange:dateRange, period:this.Period } 
                },
                Self:this,
                VariantInfo:variantInfo,
                PreventDefault:false
            };
            this.NetworkFilter(obj, function(recvData) 
            { 
                if (recvData.Error) self.AddStockValueError(key,recvData.Error);
                else self.RecvStockValue(recvData.Data,jobItem,key,recvData.DataType);
                self.Execute.RunNextJob();
            });
        }
        else
        {
            this.AddStockValueError(key, `自定义变量${key}下载失败`);
            this.Execute.RunNextJob();
        }
    }

    this.GetCustomFunctionData=function(jobItem)
    { 
        var key=jobItem.FunctionName;
        var functionInfo=g_JSComplierResource.CustomFunction.Data.get(key);
        if (!functionInfo.IsDownload) return this.Execute.RunNextJob();
        if (this.StockData.has(key)) return this.Execute.RunNextJob();  //一个函数只能缓存一个数据, 保存多个外部自己保存

        var self=this;
        if (this.NetworkFilter)
        {
            var dateRange=this.Data.GetDateRange();
            var obj=
            {
                Name:'JSSymbolData::GetCustomFunctionData', //类名::函数名
                Explain:'自定义函数数据下载',
                JobID:jobItem.ID,
                Request:
                { 
                    Url:"www.121287.com", Type:'POST', 
                    Data:
                    { 
                        FunctionName:jobItem.FunctionName, 
                        symbol: this.Symbol, daterange:dateRange,
                        JobItem:jobItem //函数编译信息
                    } 
                },
                Self:this,
                FunctionInfo:functionInfo,
                PreventDefault:false
            };
            this.NetworkFilter(obj, function(recvData) 
            { 
                if (recvData.Error) self.AddStockValueError(key,recvData.Error);
                else self.RecvStockValue(recvData.Data,jobItem,key,recvData.DataType);
                self.Execute.RunNextJob();
            });
        }
        else
        {
            this.AddStockValueError(key, `自定义函数${key}下载失败`);
            this.Execute.RunNextJob();
        }
    }

    this.RecvStockValue=function(recvData,jobItem,key,dataType)
    {
        if (!recvData)
        {
            JSConsole.Complier.Log(`[JSSymbolData::RecvStockValue] key=${key} data is null`);
            return;
        }

        if (dataType==0)
        {
            if (Array.isArray(recvData))
            {
                var kdata=this.Data;   //K线
                var aryFittingData;
                if (ChartData.IsDayPeriod(this.Period,true))
                    aryFittingData=kdata.GetFittingFinanceData(recvData);        //数据和主图K线拟合
                else if (ChartData.IsMinutePeriod(this.Period,true))
                    aryFittingData=kdata.GetMinuteFittingFinanceData(recvData);  //数据和主图K线拟合
                else 
                    return;
        
                var bindData=new ChartData();
                bindData.Data=aryFittingData;
                var result=bindData.GetValue();

                if (key=="EXCHANGE")    //计算换手率=成交量/流通股本*100
                {
                    for(var i in result)
                    {
                        var kitem=kdata.Data[i];
                        if (IFrameSplitOperator.IsPlusNumber(result[i]))
                            result[i]=kitem.Vol/result[i] * 100;
                    }
                }
        
                this.StockData.set(key,{ Data:result });
            }
            else 
            {
                this.StockData.set(key,{ Data:recvData.Value });
            }
        }
        else if (dataType==1)   //单数值
        {
            this.StockData.set(key,{ Data:recvData.Value });
        }
        else if (dataType==2)
        {
            var kdata=this.Data;   //K线
            var aryFittingData;
            if (ChartData.IsDayPeriod(this.Period,true))
                aryFittingData=kdata.GetFittingTradeData(recvData, 0);        //数据和主图K线拟合
            else if (ChartData.IsMinutePeriod(this.Period,true))
                aryFittingData=kdata.GetMinuteFittingTradeData(recvData, 0);  //数据和主图K线拟合
            else if (ChartData.IsTickPeriod(this.Period))
                aryFittingData=kdata.GetMinuteFittingTradeData(recvData, 0);  //数据和主图K线拟合
            else 
                return;
    
            var bindData=new ChartData();
            bindData.Data=aryFittingData;
            var result=bindData.GetValue();
    
            this.StockData.set(key,{ Data:result });
        }
    }

    this.AddStockValueError=function(key, message)
    {
        this.StockData.set(key,{ Error:message  });
    }

    this.GetStockCacheData=function(obj)
    {
        var key;
        if (obj.FunctionName)
            key=this.GetStockDataKey({FunctionName:obj.FunctionName}, obj.Args);
        else if (obj.VariantName)
            key=obj.VariantName;
        else if (obj.CustomName)
            key=obj.CustomName;  //自定义名字
        else
            return null;

        if (!this.StockData.has(key)) return null;
        var data=this.StockData.get(key);

        if (data.Error) this.Execute.ThrowUnexpectedNode(obj.Node, data.Error);
        return data.Data;
    }

    this.IsInBlock=function(blockName, node)
    {
        var data=this.GetStockCacheData({ VariantName:"INBLOCK", Node:node });
        if (!data) return 0;
        var aryBlock=data.split('|');
        for(var i=0; i<aryBlock.length; ++i)
        {
            var item=aryBlock[i];
            if (item==blockName) return 1;
        }

        return 0;
    }

    this.JobArgumentsToArray=function(job, lCount)
    {
        var args=job.Args;
        if (args.length!=lCount) 
        {
            var token=job.Token;
            this.Execute.ErrorHandler.ThrowError(token.Index,token.Line,0,`${job.FunctionName}() Error: argument count error.`);
        }

        var aryValue=[];
        for(var i=0;i<args.length;++i)
        {
            var item=args[i];
            if (IFrameSplitOperator.IsNumber(item))
            {
                aryValue.push(item);
            }
            else if (item.Type==Syntax.Literal) 
            {
                aryValue.push(item.Value);
            }
            else if (item.Type==Syntax.Identifier)  //变量 !!只支持默认的变量值
            {
                var isFind=false;
                for(var j in this.Arguments)
                {
                    const argItem=this.Arguments[j];
                    if (argItem.Name==item.Name)
                    {
                        aryValue.push(argItem.Value);
                        isFind=true;
                        break;
                    }
                }

                if (!isFind) 
                {
                    var token=job.Token;
                    this.Execute.ErrorHandler.ThrowError(token.Index,token.Line,0,`${job.FunctionName}() Error: can't read ${item.Name}`);
                }
            }
        }

        return aryValue;
    }

    this.DownloadCustomAPIData=function(job)
    {
        if (!this.NetworkFilter) return this.Execute.RunNextJob();

        var args=[];
        for(var i in job.Args)
        {
            var item=job.Args[i];
            if (item.Type==Syntax.Literal) 
            {
                args.push(item.Value);
            }
            else if (item.Type==Syntax.Identifier)  //变量 !!只支持默认的变量值
            {
                var isFind=false;
                for(var j in this.Arguments)
                {
                    const argItem=this.Arguments[j];
                    if (argItem.Name==item.Name)
                    {
                        args.push(argItem.Value);
                        isFind=true;
                        break;
                    }
                }

                if (!isFind) 
                {
                    var token=job.Token;
                    this.Execute.ErrorHandler.ThrowError(token.Index,token.Line,0,`LoadAPIData() Error: can't read ${item.Name}`);
                }
            }
            else 
            {
                return this.Execute.RunNextJob();
            }
        }

        var self=this;
        var obj=
        {
            Name:'JSSymbolData::DownloadCustomAPIData', //类名::函数名
            Explain:'下载自定义api数据',
            Period:this.Period,
            Right:this.Right,
            Symbol:this.Symbol,
            KData:this.Data,        //K线数据
            Cache:this.CustomAPIData,
            Args:args,
            Self:this,
            PreventDefault:false
        };

        this.NetworkFilter(obj, function(data) 
        { 
            self.RecvCustomAPIData(data,args);
            self.Execute.RunNextJob();
        });

        if (obj.PreventDefault==true) return;   //已被上层替换,不调用默认的网络请求

        this.Execute.RunNextJob();
    }

    /*
    recvData: 
    { 
        Type: 0=集合数据(默认)  1=单列数据
        DataType: 0=K线类数据  1=财务类数据
    }
    */
    this.RecvCustomAPIData=function(recvData,args)
    {
        if (!recvData) return;

        if (recvData.Type==1) 
            this.RecvCustomAPISingleData(recvData,args);
        else 
            this.RecvCustomAPIGroupData(recvData,args);
    }

    //集合数据
    this.RecvCustomAPIGroupData=function(recvData,args)
    {
        if (!recvData || !recvData.data) return;

        var data=recvData.data;
        var apiKey=this.GenerateCustomAPIKey(args);
        if (ChartData.IsMinutePeriod(this.Period,true)) //分钟 TODO:
        {
            if (!data.date || !data.time) return;

            var date=data.date;
            var time=data.time;
            for (var key in data)
            {
                if (key=='date' || key=='time') continue;
                var item=data[key];
            }
        }
        else if (ChartData.IsDayPeriod(this.Period,true))
        {
            if (!data.date) return;

            var date=data.date;
            var result={ __Type__:"Object" };
            for (var key in data)
            {
                if (key=='date') continue;

                var item=data[key];
                if (Array.isArray(item))
                {
                    var value=this.FittingCustomAPIArray(item,date);
                    result[key]=value;
                }
                else if (this.IsNumber(item))
                {
                    result[key]=item;
                }
            }

            this.CustomAPIData.set(apiKey, result);
        }
    }

    //单列数据
    this.RecvCustomAPISingleData=function(recvData,args)
    {
        var data=recvData.data;
        var apiKey=this.GenerateCustomAPIKey(args);
        if (ChartData.IsMinutePeriod(this.Period,true)) //分钟 TODO:
        {
            if (!data.date || !data.time) return;

            var date=data.date;
            var time=data.time;
            for (var key in data)
            {
                if (key=='date' || key=='time') continue;
                var item=data[key];
            }
        }
        else if (ChartData.IsDayPeriod(this.Period,true))   //日线
        {
            if (!data.date) return;

            var date=data.date;
            var value=data.value;

            var result=null;
            if (Array.isArray(value))
            {
                if (recvData.DataType==1) result=this.FittingCustomAPIFinanceArray(value,date);
                else result=this.FittingCustomAPIArray(value,date);
            }
            else
            {
                result=value;
            }

            this.CustomAPIData.set(apiKey, result);
        }
    }

    //财务数据拟合
    this.FittingCustomAPIFinanceArray=function(data, date, time)
    {
        var kdata=this.Data;   //K线
        var arySingleData=[];

        for(var i in data)
        {
            var value=data[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(this.Period,true))
            aryFittingData=kdata.GetFittingFinanceData(arySingleData);        
        else if (ChartData.IsMinutePeriod(this.Period,true))
            aryFittingData=kdata.GetMinuteFittingFinanceData(arySingleData); 
        else 
            return null;

        var bindData=new ChartData();
        bindData.Data=aryFittingData;
        var result=bindData.GetValue();
        return result;
    }

    //K线类数据拟合
    this.FittingCustomAPIArray=function(data,date,time)
    {
        var kdata=this.Data;   //K线

        var arySingleData=[];
        for(var i in data)
        {
            var value=data[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(this.Period,true))
            aryFittingData=kdata.GetFittingData(arySingleData);        //数据和主图K线拟合
        else if (ChartData.IsMinutePeriod(this.Period,true))
            aryFittingData=kdata.GetMinuteFittingData(arySingleData);  //数据和主图K线拟合
        else 
            return null;

        var bindData=new ChartData();
        bindData.Data=aryFittingData;
        var result=bindData.GetValue();
        return result;
    }

    this.GenerateCustomAPIKey=function(args)
    {
        if (args.length<=0) return '__12_EMPTY_ARGS__';

        var key='';
        for(var i in args)
        {
            if (key.length>0) key+=','
            key+=args[i];
        }

        return key;
    }

    this.GetCustomApiData=function(args)
    {
        var key=this.GenerateCustomAPIKey(args);

        if (!this.CustomAPIData.has(key)) 
        {
            JSConsole.Complier.Log(`[JSSymbolData::GetCustomApiData] can't find api data key=[${key}]`);
            return null;
        }

        return this.CustomAPIData.get(key);
    }

    this.ReadArgumentValue=function(item, result)    //读取变量值
    {
        result.Name=item.Name;
        if (item.Type==Syntax.Literal)
        {
            result.Value=item.Value;
            return true;
        }

        if (item.Type==Syntax.Identifier)
        {
            var isFind=false;
            for(var i in this.Arguments)
            {
                const argItem=this.Arguments[i];
                if (argItem.Name==item.Name)
                {
                    result.Value=argItem.Value;
                    isFind=true;
                    return true;
                }
            }

            if (!isFind) 
            {
                result.Error=`can't read ${item.Name}` ;
                return false;
            }
        }

        result.Error=`can't read ${item.Name}, type error.`;
        return false;
    }

    //MA.MA1#WEEK
    this.ReadIndexFunctionValue=function(item, result)  //返回 {Period:周期, Out:输出变量, Error:, Name:脚本名字 }
    {
        var indexParam={};
        if (typeof(item)=== 'object')
        {
            if (!this.ReadArgumentValue(item,indexParam))
            {
                result.Error=indexParam.Error;
                return false;
            }
        }
        else
        {
            indexParam.Value=item;
        }
        
        var pos=indexParam.Value.indexOf("\.");
        if (pos!=-1)
        {
            result.Name=indexParam.Value.slice(0, pos);     //名字
            var pos2=indexParam.Value.indexOf('#', pos+1);
            if (pos2!=-1)
            {
                result.Out=indexParam.Value.slice(pos+1, pos2); //输出变量
                result.Period=indexParam.Value.slice(pos2+1);     //周期
            }
            else
            {
                result.Out=indexParam.Value.slice(pos+1);
            }
        }
        else
        {
            var pos2=indexParam.Value.indexOf('#');
            if (pos2!=-1)
            {
                result.Name=indexParam.Value.slice(0,pos2);
                result.Period=indexParam.Value.slice(pos2+1);     //周期
            }
            else
            {
                result.Name=indexParam.Value;
            }
        }

        const PERIOD_MAP=new Map([
            ["DAY",0 ], ["WEEK", 1 ], ["MONTH",2 ], ["SEASON",9 ], ["YEAR", 3], ["HALFYEAR",22], ["WEEK2",21],
            ["MIN1", 4], ["MIN5", 5 ], ["MIN15", 6 ], ["MIN30",7 ], ["MIN60", 8 ],

            ["DAY2", 40002],["MULTIDAY",40002],["DAY3", 40003],["DAY4", 40004],["DAY5",40005],
            ["DAY6", 40006],["DAY7", 40007],["DAY8", 40008],["DAY9", 40009],["DAY10",40010],
            ["DAY11", 40011],["DAY12", 40012],["DAY13", 40013],["DAY14", 40014],["DAY15", 40015],
        ]);

        if (result.Period)
        {
            if (!PERIOD_MAP.has(result.Period))
            {
                result.Error=`${result.Period}, 周期错误`;
                return false;
            }
            result.PeriodID=PERIOD_MAP.get(result.Period);
        }
        return true;
    }

    this.ReadSymbolArgumentValue=function(item, result) //返回{ Value:股票代码, Error:错误信息}
    {
        var readArgument={};
        if (typeof(item)=== 'object')
        {
            if (!this.ReadArgumentValue(item,readArgument))
            {
                result.Error=readArgument.Error;
                return false;
            }
        }
        else
        {
            readArgument.Value=item;
        }

        if (readArgument.Value=='') readArgument.Value=this.Symbol; //缺省使用股票代码

        //A股后缀小写
        if (readArgument.Value.indexOf('.SH')>0) result.Symbol=readArgument.Value.replace('.SH', ".sh");
        else if (readArgument.Value.indexOf('.SZ')>0) result.Symbol=readArgument.Value.replace('.SZ', ".sz");
        else result.Symbol=readArgument.Value;

        return true;
    }

    this.ReadIndexArgumentValue=function(args, result)
    {
        result.Args=[];
        for(var i in result.SytemIndex.Args)    //复制参数
        {
            var item=result.SytemIndex.Args[i];
            result.Args.push({Value:item.Value, Name:item.Name});
        }

        if (args.length>2 && result.SytemIndex.Args && result.SytemIndex.Args.length>0)
        {
            for(var i=2, j=0; i<args.length && j<result.SytemIndex.Args.length; ++i, ++j)
            {
                var readArgument={};
                var item=args[i];
                if (typeof(item)=== 'object')
                {
                    if (!this.ReadArgumentValue(item,readArgument))
                    {
                        result.Error=readArgument.Error;
                        return false;
                    }
                }
                else
                {
                    readArgument.Value=item;
                }

                result.Args[j].Value=readArgument.Value;
            }
        }

        return true;
    }

    //key= (代码,周期),指标(参数) => 输出
    this.GenerateScriptIndexKey=function(indexInfo)
    {
        var indexParam='';
        var args=indexInfo.Args;
        for(var i in args)
        {
            if (indexParam.length>0) indexParam+=',';
            var item=args[i];
            indexParam+=item.Value.toString();
        }

        var out=indexInfo.Out ? indexInfo.Out :"ALL";
        var key=`(${indexInfo.Symbol},${indexInfo.PeriodID}), ${indexInfo.Name}(${indexParam})=>${out}`;

        return key;
    }

    //TMP2:=KDJ.K#WEEK;
    this.CallMemberScriptIndex=function(job)
    {
        if (job.Member.Object.Type!=Syntax.Identifier ||job.Member.Property.Type!=Syntax.Identifier)
        {
            var token=job.Token;
            this.Execute.ErrorHandler.ThrowError(token.Index,token.Line,0,`CallMemberScriptIndex() Error: 参数错误`);
        }

        var objName=job.Member.Object.Name;
        var PropertyName=job.Member.Property.Name;
        if (PropertyName=="" || PropertyName==null)
        {
            var token=job.Token;
            this.Execute.ErrorHandler.ThrowError(token.Index,token.Line,0,`CallMemberScriptIndex() Error: ${objName}.${PropertyName} 指标输出变量错误`);
        }
        
        if (this.Execute.VarTable.has(objName))
        {
            var memberValue=this.Execute.VarTable.get(objName);
            if (memberValue.hasOwnProperty(PropertyName))
            {
                JSConsole.Complier.Log(`[JSSymbolData::CallMemberScriptIndex] index data ${objName}.${PropertyName} in cache.`);
                return this.Execute.RunNextJob();
            }
        }
            
        var callInfo=objName+"."+PropertyName;
        var indexInfo={ Job:job, PeriodID:this.Period , Symbol:this.Symbol };
        if (!this.ReadIndexFunctionValue(callInfo,indexInfo))     //读取指标
        {
            var token=job.Token;
            this.Execute.ErrorHandler.ThrowError(token.Index,token.Line,0,`CallMemberScriptIndex() Error: '${callInfo}' ${indexInfo.Error}`);
        }

        var systemIndex=new JSIndexScript();
        var systemItem=systemIndex.Get(indexInfo.Name);
        if (!systemItem)
        {
            var token=job.Token;
            this.Execute.ErrorHandler.ThrowError(token.Index,token.Line,0,`CallMemberScriptIndex() Error: '${callInfo}' ${indexInfo.Name} 指标不存在`);
        }

        if (Array.isArray(systemItem.Args) && systemItem.Args.length>0)
        {
            indexInfo.Args=[];
            for(var i in systemItem.Args)    //复制参数
            {
                var item=systemItem.Args[i];
                indexInfo.Args.push({Value:item.Value, Name:item.Name});
            }
        }

        JSConsole.Complier.Log('[JSSymbolData::CallMemberScriptIndex] call script index', indexInfo);

        var dateTimeRange=this.Data.GetDateRange();

        var option=
        {
            HQDataType:this.DataType,
            Symbol:indexInfo.Symbol,
            Name:'',
            Right:this.Right,           //复权
            Period:indexInfo.PeriodID,  //周期
            Data:null,
            SourceData:null,
            Callback:(outVar,job, symbolData)=> { 
                this.RecvMemberScriptIndexData(outVar,job,symbolData);
                this.Execute.RunNextJob();
            },
            CallbackParam:indexInfo,
            Async:true,
            MaxRequestDataCount:this.MaxRequestDataCount+30*2,
            MaxRequestMinuteDayCount:this.MaxRequestMinuteDayCount+2,
            Arguments:indexInfo.Args,
            //Condition:this.Condition,
            IsBeforeData:this.IsBeforeData,
            NetworkFilter:this.NetworkFilter,
            KLineRange:dateTimeRange    //K线数据范围
        };

        //执行脚本
        var run=JSComplier.Execute(systemItem.Script,option,(error, indexInfo)=>{this.ExecuteScriptIndexError(error,indexInfo)});
        
    }

    //脚本调用
    //STKINDI('600000.sh','MA.MA1#WEEK',5,10,20,30,60,120);
    //1=股票代码 2=指标名字.输出变量#周期, 3....参数
    this.CallScriptIndex=function(job)
    {
        if (job.Member) return this.CallMemberScriptIndex(job);

        if (!job.Args || !(job.Args.length>=2)) 
        {
            var token=job.Token;
            this.Execute.ErrorHandler.ThrowError(token.Index,token.Line,0,`CallScriptIndex() Error: ${job.FunctionName} 参数错误`);
        }

        var indexInfo={ Job:job, PeriodID:this.Period };
        if (!this.ReadSymbolArgumentValue(job.Args[0],indexInfo))  //读取代码
        {
            var token=job.Token;
            this.Execute.ErrorHandler.ThrowError(token.Index,token.Line,0,`CallScriptIndex() Error: ${indexInfo.Error}`);
        }

        if (!this.ReadIndexFunctionValue(job.Args[1],indexInfo))     //读取指标
        {
            var token=job.Token;
            this.Execute.ErrorHandler.ThrowError(token.Index,token.Line,0,`CallScriptIndex() Error: ${indexInfo.Error}`);
        }

        var systemIndex=new JSIndexScript();
        var systemItem=systemIndex.Get(indexInfo.Name);
        if (!systemItem)
        {
            var token=job.Token;
            this.Execute.ErrorHandler.ThrowError(token.Index,token.Line,0,`CallScriptIndex() ${indexInfo.Name} 指标不存在`);
        }

        indexInfo.SytemIndex=systemItem;    //系统指标
        if (!this.ReadIndexArgumentValue(job.Args,indexInfo))
        {
            var token=job.Token;
            this.Execute.ErrorHandler.ThrowError(token.Index,token.Line,0,`CallScriptIndex() ${indexInfo.Name} 指标参数错误 : ${indexInfo.Error} `);
        }

        JSConsole.Complier.Log('[JSSymbolData::CallScriptIndex] call script index', indexInfo);
        var DateTimeRange=null;
        if (this.Data && this.Data.Data.length>0)
        {
            var start=this.Data.Data[0];
            var end=this.Data.Data[this.Data.Data.length-1];
            DateTimeRange=
            {
                Start:{Date:start.Date, Time: start.Time},
                End:{Date:end.Date, Time: end.Time},
            }
        }

        var option=
        {
            HQDataType:this.DataType,
            Symbol:indexInfo.Symbol,
            Name:'',
            Right:this.Right,           //复权
            Period:indexInfo.PeriodID,  //周期
            Data:null,
            SourceData:null,
            Callback:(outVar,job, symbolData)=> { 
                this.RecvScriptIndexData(outVar,job,symbolData);
                this.Execute.RunNextJob();
            },
            CallbackParam:indexInfo,
            Async:true,
            MaxRequestDataCount:this.MaxRequestDataCount+30*2,
            MaxRequestMinuteDayCount:this.MaxRequestMinuteDayCount+2,
            Arguments:indexInfo.Args,
            //Condition:this.Condition,
            IsBeforeData:this.IsBeforeData,
            NetworkFilter:this.NetworkFilter,
            KLineRange:DateTimeRange    //K线数据范围
        };

        //执行脚本
        var run=JSComplier.Execute(indexInfo.SytemIndex.Script,option,(error, indexInfo)=>{this.ExecuteScriptIndexError(error,indexInfo)});
    }

    this.RecvMemberScriptIndexData=function(outVar,indexInfo,symbolData)
    {
        JSConsole.Complier.Log('[JSSymbolData::RecvMemberScriptIndexData] ', outVar, indexInfo, symbolData);
        var kLine=symbolData.Data.Data;
        var aryOutVar=outVar;
        var data=this.Data.FitKLineIndex(kLine,aryOutVar,this.Period,indexInfo.PeriodID);

        var member=indexInfo.Job.Member;
        var objName=member.Object.Name;
        var propertyName=member.Property.Name;

        var memberValue={};
        if (this.Execute.VarTable.has(objName))
            memberValue=this.Execute.VarTable.get(objName);
        else
            this.Execute.VarTable.set(objName, memberValue);

        //保存所有的指标数据, 下面用到了就可以不用算了
        for(var i in data)
        {
            var key=outVar[i].Name;
            if (indexInfo.Period) key+='#'+indexInfo.Period;    //带周期的变量
            memberValue[key]=data[i].Data;
        }
    }

    this.RecvScriptIndexData=function(outVar,indexInfo,symbolData)
    {
        var key=this.GenerateScriptIndexKey(indexInfo);
        JSConsole.Complier.Log('[JSSymbolData::RecvScriptIndexData] ', outVar, indexInfo, symbolData, key);

        var kLine=symbolData.Data.Data;
        var aryOutVar=outVar;
        if (indexInfo.Out)
        {
            for(var i in outVar)
            {
                var item=outVar[i];
                if (item.Name==indexInfo.Out) 
                {
                    aryOutVar=[item];
                    break;
                }
            }

            var data=this.Data.FitKLineIndex(kLine,aryOutVar,this.Period,indexInfo.PeriodID);
            this.ScriptIndexOutData.set(key,data[0].Data);
        }
        else
        {
            var data=this.Data.FitKLineIndex(kLine,aryOutVar,this.Period,indexInfo.PeriodID);
            var result={ __Type__:"Object" };
            for(var i in data)
            {
                var item=data[i];
                result[item.Name]=item.Data;
            }
            this.ScriptIndexOutData.set(key,result);
        } 
    }

    this.ExecuteScriptIndexError=function(error,indexInfo)
    {
        var token=indexInfo.Job.Token;
        this.Execute.ErrorHandler.ThrowError(token.Index,token.Line,0,`CallScriptIndex() ${indexInfo.Name} 指标执行错误 : ${error} `);
    }

    this.GetScriptIndexOutData=function(args,node)
    {
        var indexInfo={ PeriodID:this.Period };
        if (!this.ReadSymbolArgumentValue(args[0],indexInfo))  //读取代码
            this.Execute.ThrowUnexpectedNode(node,`STKINDI() 股票代码错误: ${indexInfo.Error}`);

        if (!this.ReadIndexFunctionValue(args[1],indexInfo))     //读取指标
            this.Execute.ThrowUnexpectedNode(node,`STKINDI() 指标错误: ${indexInfo.Error}`);

        var systemIndex=new JSIndexScript();
        var systemItem=systemIndex.Get(indexInfo.Name);
        if (!systemItem)
            this.Execute.ThrowUnexpectedNode(node,`STKINDI() 指标错误: ${indexInfo.Name} 指标不存在`);

        indexInfo.SytemIndex=systemItem;    //系统指标
        if (!this.ReadIndexArgumentValue(args,indexInfo))
            this.Execute.ThrowUnexpectedNode(node,`STKINDI()  指标参数错误: ${indexInfo.Error}`);

        var key=this.GenerateScriptIndexKey(indexInfo);
        if (!this.ScriptIndexOutData.has(key)) return null;

        return this.ScriptIndexOutData.get(key);
    }

    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.DATE=function()
    {
        var result=[];
        if (!this.Data || !this.Data.Data || !this.Data.Data.length) return result;

        for(let i in this.Data.Data)
        {
            var item=this.Data.Data[i];
            result[i]=item.Date-19000000;
        }

        return result;
    }

    this.YEAR=function()
    {
        var result=[];
        if (!this.Data || !this.Data.Data || !this.Data.Data.length) return result;

        for(let i in this.Data.Data)
        {
            var item=this.Data.Data[i];
            if (this.IsNumber(item.Date))
                result[i]=parseInt(item.Date/10000);
            else
                result[i]=null;
        }

        return result;
    }

    this.DAY=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%100);
            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;
    }

    this.TIME=function()
    {
        var result=[];
        if (!this.Data || !this.Data.Data || !this.Data.Data.length) return result;

        for(let i in this.Data.Data)
        {
            var item=this.Data.Data[i];
            if (this.IsNumber(item.Time))
                result[i]=item.Time;
            else
                result[i]=0;
        }

        return result;
    }

    //星期 1-7
    this.WEEK=function()
    {
        var result=[];
        if (!this.Data || !this.Data.Data || !this.Data.Data.length) return result;

        var tempDate=new Date();
        for(let i in this.Data.Data)
        {
            var item=this.Data.Data[i];
            result[i]=null;
            if (!this.IsNumber(item.Date)) continue;

            var year=parseInt(item.Date/10000);
            var month=parseInt(item.Date%10000/100);
            var day=item.Date%100;
            
            tempDate.setFullYear(year);
            tempDate.setMonth(month-1);
            tempDate.setDate(day);

            result[i]=tempDate.getDay();
        }

        return result;
    }

    this.REFDATE=function(data,date)
    {
        var result=null;
        var findDate=null;
        if (Array.isArray(date)) 
        {
            if (date.length>0) findDate=date[date.length-1];
        }
        else if (this.IsNumber(date))
        {
            findDate=date;
        }

        if (findDate==null) return null;
        if (findDate<5000000) findDate+=19000000;

        var index=null;
        for(let i in this.Data.Data)   //查找日期对应的索引
        {
            if (this.Data.Data[i].Date==findDate) 
            {
                index=parseInt(i);
                break;
            }
        }

        if (index==null || index>=data.length) return null;

        return data[index];
    }

    //用法:结果从0到11,依次分别是1/5/15/30/60分钟,日/周/月,多分钟,多日,季,年
    this.PERIOD=function()
    {
        //Period周期 0=日线 1=周线 2=月线 3=年线 9=季线 4=1分钟 5=5分钟 6=15分钟 7=30分钟 8=60分钟
        const PERIOD_MAP=[5,6,7,11, 0,1,2,3,4,5, 9];
        if (this.Period>=0 && this.Period<=PERIOD_MAP.length-1)
            return PERIOD_MAP[this.Period];
        
        return this.Period;
    } 

    this.GetDrawNull=function()
    {
        var result=[];
        if (!this.Data || !this.Data.Data || !this.Data.Data.length) return result;

        for(let i in this.Data.Data)
        {
            result[i]=null;
        }

        return result;
    }

    /*
    飞狐函数 SYSPARAM
    SYSPARAM(1)画面上光标位置(K线序号)
    SYSPARAM(2)主图可见K线最初位置
    SYSPARAM(3)主图可见K线最后位置，注意：该函数仅K线图形分析且打开十字光标时有效,否则返回值不确定
    SYSPARAM(4)主图可见K线最高价，注意：该函数仅K线图形分析且打开十字光标时有效,否则返回值不确定
    SYSPARAM(5)主图可见K线最低价，注意：该函数仅K线图形分析且打开十字光标时有效,否则返回值不确定
    SYSPARAM(6)画面上光标数值，注意：该函数仅K线图形分析且打开十字光标时有效,否则返回值不确定
    */
    this.SysParam=function(id, jsExec)
    {
        if (!this.DrawInfo) return [];

        if (id==2)
        {
            jsExec.IsUsePageData=true;
            if (IFrameSplitOperator.IsNumber(this.DrawInfo.Start)) 
                return this.DrawInfo.Start+1;
        }
        else if (id==3)
        {
            jsExec.IsUsePageData=true;
            if (IFrameSplitOperator.IsNumber(this.DrawInfo.End)) 
                return this.DrawInfo.End+1;
        }
        else if (id==4)
        {
            jsExec.IsUsePageData=true;
            if (!IFrameSplitOperator.IsNumber(this.DrawInfo.End) ||!IFrameSplitOperator.IsNumber(this.DrawInfo.Start)) return [];
            if (!this.Data || !IFrameSplitOperator.IsNonEmptyArray(this.Data.Data)) return [];

            var high=null;
            for(var i=this.DrawInfo.Start; i<=this.DrawInfo.End && i<this.Data.Data.length; ++i)
            {
                var item=this.Data.Data[i];
                if (!IFrameSplitOperator.IsNumber(item.High)) continue;
                if (high==null) high=item.High;
                else if(high<item.High) high=item.High;
            }

            return high;
        }
        else if (id==5)
        {
            jsExec.IsUsePageData=true;
            if (!IFrameSplitOperator.IsNumber(this.DrawInfo.End) ||!IFrameSplitOperator.IsNumber(this.DrawInfo.Start)) return [];
            if (!this.Data || !IFrameSplitOperator.IsNonEmptyArray(this.Data.Data)) return [];

            var low=null;
            for(var i=this.DrawInfo.Start;i<=this.DrawInfo.End && i<this.Data.Data.length;++i)
            {
                var item=this.Data.Data[i];
                if (!IFrameSplitOperator.IsNumber(item.Low)) continue;
                if (low==null) low=item.Low;
                else if(low>item.Low) low=item.Low;
            }

            return low;
        }

        return [];
    }
}

//是否有是有效的数字
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_LATEST_INDEX_DATA:8,   //下载最新大盘数据
    JOB_DOWNLOAD_OTHER_SYMBOL_DATA:9,   //下载其他股票的K线数据
    JOB_DOWNLOAD_SYMBOL_PERIOD_DATA:10, //下载周期数据

    JOB_DOWNLOAD_FINVALUE:301,                  //引用专业财务数据 FINVALUE(ID),ID为数据编号
    JOB_DOWNLOAD_FINONE:302,                    //引用指定年和月日的某类型的财务数据 FINONE(ID,Y,MMDD),ID为数据编号,Y和MMDD表示年和月日.
    JOB_DOWNLOAD_FINANCE:303,                   //FINANCE(ID) 基础财务数据
    JOB_DOWNLOAD_GPJYVALUE:304,                 //引用股票交易类数据 GPJYVALUE(ID,N,TYPE),ID为数据编号,N表示第几个数据,TYPE:为1表示做平滑处理,没有数据的周期返回上一周期的值;为0表示不做平滑处理
    JOB_DOWNLOAD_VARIANT:305,                   //CAPITAL , TOTALCAPITAL, EXCHANGE
    JOB_DOWNLOAD_SCJYVALUE:306,                 //引用市场总的交易类数据.SCJYVALUE(ID,N,TYPE),ID为数据编号,N表示第几个数据,TYPE:为1表示做平滑处理,没有数据的周期返回上一周期的值;为0表示不做平滑处理
    
    
   
    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_DOWNLOAD_HK_TO_SHSZ:2053,   //个股北上流入

    

    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_DOWNLOAD_CUSTOM_API_DATA:30000,     //自定义数据

    //调用其他脚本指标 
    //KDJ.K , KDJ.K#WEEK
    //STKINDI('600000.sh','MA.MA1#WEEK',5,10,20,30,60,120);
    JOB_EXECUTE_INDEX:30010,                

    JOB_RUN_SCRIPT:10000, //执行脚本

    //融资融券
    GetMarginJobID:function(value)
    {
        let dataMap=new Map([
            [1,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BALANCE],          //MARGIN(1)   融资融券余额
            [2,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_RATE],             //MARGIN(2)   融资占比

            [3,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BUY_BALANCE],       //MARGIN(3)   买入信息-融资余额
            [4,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BUY_AMOUNT],        //MARGIN(4)   买入信息-买入额
            [5,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BUY_REPAY],         //MARGIN(5)   买入信息-偿还额
            [6,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_BUY_NET],           //MARGIN(6)   买入信息-融资净买入

            [7,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_SELL_BALANCE],      //MARGIN(7)   卖出信息-融券余量
            [8,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_SELL_VOLUME],       //MARGIN(8)   卖出信息-卖出量
            [9,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_SELL_REPAY],        //MARGIN(9)   卖出信息-偿还量
            [10,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_MARGIN_SELL_NET],         //MARGIN(10)  卖出信息-融券净卖出 
        ]);
    
        if (dataMap.has(value)) return dataMap.get(value);
    
        return null;
    },

    GetNewsAnalysisID:function(value)
    {
        let dataMap=new Map([
            [1,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_NEGATIVE],          //NEWS(1)   负面新闻统计
            [2,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_RESEARCH],          //NEWS(2)   机构调研统计
            [3,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_INTERACT],          //NEWS(3)   互动易
            [4,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_HOLDERCHANGE],      //NEWS(4)   股东增持
            [5,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_HOLDERCHANGE2],     //NEWS(5)   股东减持
            [6,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_TRUSTHOLDER],       //NEWS(6)   信托持股
            [7,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_BLOCKTRADING],      //NEWS(7)   大宗交易
            [8,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_COMPANYNEWS],       //NEWS(8)   官网新闻
            [9,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_TOPMANAGERS],       //NEWS(9)   高管要闻
            [10,JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_NEWS_ANALYSIS_PLEDGE],           //NEWS(10)  股权质押    
        ]);

        if (dataMap.has(value)) return dataMap.get(value);
    
        return null;
    },

    //财务截面数据 分报告期
    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.GetEventCallback;
    this.IsUsePageData=false;
    this.IndexCtrl;

    //脚本自动变量表, 只读
    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],['AMO',null], 
        ['VOLR',null],      //量比
        ['VOLINSTK',null], ["OPI",null],    //持仓量
        ["QHJSJ",null], ["SETTLE",null],    //结算价
        ["ZSTJJ",null],     //分时图均价线,对于分时图周期指标有效.
        ["ISEQUAL",null], ["ISUP",null],["ISDOWN"], //ISUP=收阳 ISEQUAL=平盘 ISDOWN=收阴

        //日期类
        ['DATE',null],['YEAR',null],['MONTH',null],['PERIOD', null],['WEEK',null],["TIME",null],["DAY",null],

        //大盘数据
        ['INDEXA',null],['INDEXC',null],['INDEXH',null],['INDEXL',null],['INDEXO',null],['INDEXV',null],
        ['INDEXADV',null],['INDEXDEC',null],

        ["ADVANCE",null],['DECLINE', null],

        ['FROMOPEN',null],      //已开盘有多长分钟
        ['TOTALFZNUM', null],   //该品种的每天的总交易分钟数.

        ['CURRBARSCOUNT',null], //到最后交易日的周期数
        ['TOTALBARSCOUNT',null],
        ['ISLASTBAR',null],     //判断是否为最后一个周期
        ['BARSTATUS',null],     //BARSTATUS返回数据位置信息,1表示第一根K线,2表示最后一个数据,0表示中间位置.

        ["BARPOS", null],   //返回从第一根K线开始到当前的周期数

        ['CAPITAL',null],   //流通股本（手）
        ["TOTALCAPITAL",null], //TOTALCAPITAL  当前总股本 手
        ['EXCHANGE',null],   //换手率
        ['SETCODE', null],  //市场类型
        ['CODE',null],      //品种代码
        ['STKNAME',null],   //品种名称
        ["TQFLAG",null],    //TQFLAG  当前的复权状态,0:无复权 1:前复权 2:后复权 

        ['HYBLOCK',null],   //所属行业板块
        ['DYBLOCK',null],   //所属地域板块
        ['GNBLOCK',null],   //所属概念
        ["FGBLOCK",null],   //所属风格板块
        ["ZSBLOCK",null],   //所属指数板块
        ["ZHBLOCK",null],   //所属组合板块
        ["ZDBLOCK",null],   //所属自定义板块
        ["HYZSCODE",null],  

        ["GNBLOCKNUM",null],    //所属概念板块的个数
        ["FGBLOCKNUM",null],    //所属风格板块的个数
        ["ZSBLOCKNUM",null],    //所属指数板块的个数
        ["ZHBLOCKNUM",null],    //所属组合板块的个数
        ["ZDBLOCKNUM",null],    //所属自定义板块的个数

        ["HYSYL",null],         //指数市盈率或个股所属行业的市盈率
        ["HYSJL",null],         //指数市净率或个股所属行业的市净率

        ['DRAWNULL',null],
        ["NULL",null],

        ["MACHINEDATE",null],["MACHINETIME",null],["MACHINEWEEK",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 (this.CallbackParam.HQChart)
                this.GetEventCallback=(id)=> { return this.CallbackParam.HQChart.GetEventCallback(id); }
        }
        if (option.Arguments) this.Arguments=option.Arguments;
        if (option.IsSectionMode) this.IsSectionMode=option.IsSectionMode;
        if (option.Self) this.IndexCtrl=option.Self;
    }

    this.Execute=function()
    {
        this.OutVarTable=[];
        this.VarTable=new Map();
        JSConsole.Complier.Log('[JSExecute::Execute] Load Arguments', this.Arguments);
        for(let i in this.Arguments)    //预定义的变量
        {
            let item =this.Arguments[i];
            this.VarTable.set(item.Name,item.Value);
        }

        this.RunNextJob();
    }

    this.RunNextJob=function()
    {
        if (this.JobList.length<=0) return;

        JSConsole.Complier.Log('[JSExecute::Execute] JobList', this.JobList);
        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_PERIOD_DATA:
                return this.SymbolData.GetSymbolPeriodData(jobItem);
            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(jobItem);
            case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_VOLR_DATA:  //量比
                return this.SymbolData.GetVolRateData(jobItem);

            case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_OTHER_SYMBOL_DATA:  //指定股票数据
                return this.SymbolData.GetOtherSymbolData(jobItem);
            
            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_SHSZ:
                return this.SymbolData.GetHKToSHSZData(jobItem);

            case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SECTION_SF:
                return this.SymbolData.GetSectionFinanceData(jobItem);   //财务截面报告数据

            case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_FINONE:
                return this.SymbolData.GetFinOne(jobItem);
            case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_FINVALUE:
                return this.SymbolData.GetFinValue(jobItem);
            case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_FINANCE:
                return this.SymbolData.GetFinance(jobItem);
            case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_GPJYVALUE:
                return this.SymbolData.GetGPJYValue(jobItem);
            case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_SCJYVALUE:
                return this.SymbolData.GetSCJYValue(jobItem);

            case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_VARIANT:    //CAPITAL, TOTALCAPITAL 
                return this.SymbolData.GetVariantData(jobItem);

            case JS_EXECUTE_JOB_ID.JOB_CUSTOM_VARIANT_DATA:
                return this.SymbolData.GetCustomVariantData(jobItem);

            case JS_EXECUTE_JOB_ID.JOB_CUSTOM_FUNCTION_DATA:
                return this.SymbolData.GetCustomFunctionData(jobItem);


            case JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_CUSTOM_API_DATA:
                return this.SymbolData.DownloadCustomAPIData(jobItem);
            case JS_EXECUTE_JOB_ID.JOB_EXECUTE_INDEX:
                return this.SymbolData.CallScriptIndex(jobItem);

            case JS_EXECUTE_JOB_ID.JOB_RUN_SCRIPT:
                return this.Run();
        }
    }

    this.ReadSymbolData=function(name,node)
    {
        switch(name)
        {
            case 'CLOSE':
            case 'C':
            case 'VOL':
            case 'V':
            case 'OPEN':
            case 'O':
            case 'HIGH':
            case 'H':
            case 'LOW':
            case 'L':
            case 'AMOUNT':
            case 'AMO':
            case "OPI":
            case 'VOLINSTK':
            case "SETTLE":
            case "QHJSJ":
            case "ZSTJJ":
            case "ISEQUAL": //平盘
            case "ISUP":    //收阳
            case "ISDOWN":  //收阴
                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 "BARPOS":
                return this.SymbolData.GetBarPos();
            case "TOTALBARSCOUNT":
                return this.SymbolData.GetTotalBarsCount();
            case "TOTALFZNUM":
                return this.SymbolData.GetTotalTradeMinuteCount();
            case 'ISLASTBAR':
                return this.SymbolData.GetIsLastBar();
            case "BARSTATUS":
                return this.SymbolData.GetBarStatus();

            case "TOTALCAPITAL":
            case 'CAPITAL':
            case 'EXCHANGE':

            case "HYBLOCK":
            case "DYBLOCK":
            case "GNBLOCK":
            case "FGBLOCK":
            case "ZSBLOCK":
            case "ZHBLOCK":
            case "ZDBLOCK":
            case "HYZSCODE":

            case "GNBLOCKNUM":
            case "FGBLOCKNUM":
            case "ZSBLOCKNUM":
            case "ZHBLOCKNUM":
            case "ZDBLOCKNUM":

            case "HYSYL":
            case "HYSJL":
                return this.SymbolData.GetStockCacheData({ VariantName:name, Node:node });
            case 'SETCODE':
                return this.SymbolData.SETCODE();
            case 'CODE':
                return this.SymbolData.GetSymbol();
            case 'STKNAME':
                return this.SymbolData.GetName();

            case "TIME":
                return this.SymbolData.TIME();
            case 'DATE':
                return this.SymbolData.DATE();
            case 'YEAR':
                return this.SymbolData.YEAR();
            case 'MONTH':
                return this.SymbolData.MONTH();
            case 'WEEK':
                return this.SymbolData.WEEK();
            case "DAY":
                return this.SymbolData.DAY();
            case 'PERIOD':
                return this.SymbolData.PERIOD();
            case 'FROMOPEN':
                return this.SymbolData.GetLatestIndexCacheData('FROMOPEN');

            case 'DRAWNULL':
            case "NULL":
                return this.SymbolData.GetDrawNull();

            case 'ADVANCE':
            case 'DECLINE':
                return this.SymbolData.GetIndexIncreaseCacheData(name,this.SymbolData.Symbol,node);

            case "TQFLAG":
                return this.SymbolData.Right;

            case "MACHINEDATE":
                {
                    var now=new Date();
                    return (now.getFullYear()*10000+(now.getMonth()*1)*100+now.getDate())-19000000;
                }
            case "MACHINETIME":
                {
                    var now=new Date();
                    return now.getHours()*10000+(now.getMinutes()*1)*100+now.getSeconds();
                }
            case "MACHINEWEEK":
                {
                    var now=new Date();
                    return now.getDay();
                }
        }
    }

    this.ReadCustomVariant=function(name,node)
    {
        return this.SymbolData.GetStockCacheData({ VariantName:name, Node:node });
    }

    //读取变量
    this.ReadVariable=function(name,node)
    {
        if (this.ConstVarTable.has(name)) 
        {
            let data=this.ConstVarTable.get(name);

            if (data==null) //动态加载,用到再加载
            {
                data=this.ReadSymbolData(name,node);
                this.ConstVarTable.set(name,data);
            }

            return data;
        }

        if (g_JSComplierResource.IsCustomVariant(name)) return this.ReadCustomVariant(name,node); //读取自定义变量

        if (this.VarTable.has(name)) return this.VarTable.get(name);

        if (name.indexOf('#')>0)
        {
            var aryPeriod=name.split('#');
            return this.SymbolData.GetSymbolPeriodCacheData(aryPeriod[0],aryPeriod[1]);
        }

        if (name.indexOf("COLOR")==0)
        {
            var colorValue=JSComplier.ColorVarToRGB(name);
            if (colorValue) return colorValue;
        }

        this.ThrowUnexpectedNode(node, '变量'+name+'不存在', name);
        return null;
    }

    this.ReadMemberVariable=function(node)
    {
        var obj=node.Object;
        var member=node.Property;

        let maiObj;
        if (obj.Type==Syntax.BinaryExpression || obj.Type==Syntax.LogicalExpression ) 
            maiObj=this.VisitBinaryExpression(obj);
        else if (obj.Type==Syntax.CallExpression)
            maiObj=this.VisitCallExpression(obj);
        else
            maiObj=this.GetNodeValue(obj);

        if (!maiObj) return null;
        var value=maiObj[member.Name];
        if (value) return value;

        return null;
    }

    //单数据转成数组 个数和历史数据一致
    this.SingleDataToArrayData=function(value)
    {
        let count=this.SymbolData.Data.Data.length;
        let result=[];
        for(let i=0;i<count;++i)
        {
            result[i]=value;
        }

        return result;
    }

    this.RunAST=function()
    {
        if (!this.AST) this.ThrowError();
        if (!this.AST.Body) this.ThrowError();

        for(let i=0; i<this.AST.Body.length; ++i)
        {
            let item =this.AST.Body[i];
            this.VisitNode(item);

            //输出变量
            if (item.Type==Syntax.ExpressionStatement && item.Expression)
            {
                if (item.Expression.Type==Syntax.AssignmentExpression)
                {
                    if (item.Expression.Operator==':' && item.Expression.Left)
                    {
                        let assignmentItem=item.Expression;
                        let varName=assignmentItem.Left.Name;
                        let outVar=this.VarTable.get(varName);
                        var type=0;
                        if (outVar && typeof(outVar)=='object' && outVar.__Type__=='Object')
                        {
                            type=1000;
                        }
                        else if (!this.IsSectionMode && !Array.isArray(outVar)) 
                        {
                            if (typeof(outVar)=='string') 
                            {
                                var floatValue=parseFloat(outVar);
                                if (IFrameSplitOperator.IsNumber(floatValue))
                                {
                                    outVar=this.SingleDataToArrayData(floatValue);
                                }
                                else
                                {
                                    outVar=this.SingleDataToArrayData(outVar);
                                    type=1001;
                                }
                                    
                            }
                            else outVar=this.SingleDataToArrayData(outVar);
                        }

                        this.OutVarTable.push({Name:varName, Data:outVar,Type:type});
                    }
                }
                else if (item.Expression.Type==Syntax.CallExpression)
                {
                    let callItem=item.Expression;
                    if (this.Draw.IsDrawFunction(callItem.Callee.Name))
                    {
                        let draw=callItem.Draw;
                        draw.Name=callItem.Callee.Name;
                        this.OutVarTable.push({Name:draw.Name, Draw:draw, Type:1});
                    }
                    else
                    {
                        let outVar=callItem.Out;
                        varName=`__temp_c_${callItem.Callee.Name}_${i}__`;
                        var type=0;
                        if (!Array.isArray(outVar)) outVar=this.SingleDataToArrayData(outVar);
                        this.OutVarTable.push({Name:varName, Data:outVar,Type:type,NoneName:true});
                    }
                }
                else if (item.Expression.Type==Syntax.Identifier)
                {
                    let varName=item.Expression.Name;
                    let outVar=this.ReadVariable(varName,item.Expression);
                    var type=0;
                    if (outVar && typeof(outVar)=='object' && outVar.__Type__=='Object')
                    {
                        type=1000;
                    }
                    else if (!this.IsSectionMode && !Array.isArray(outVar)) 
                    {
                        if (typeof(outVar)=='string') outVar=this.SingleDataToArrayData(parseFloat(outVar));
                        else outVar=this.SingleDataToArrayData(outVar);
                    }

                    varName="__temp_i_"+i+"__";
                    this.OutVarTable.push({Name:varName, Data:outVar, Type:type, NoneName:true});
                }
                else if (item.Expression.Type==Syntax.Literal)  //常量
                {
                    let outVar=item.Expression.Value;
                    if (IFrameSplitOperator.IsString(outVar) && outVar.indexOf("$")>0)
                        outVar=this.SymbolData.GetOtherSymolCacheData({ Literal:outVar });
                    varName="__temp_li_"+i+"__";
                    var type=0;
                    this.OutVarTable.push({Name:varName, Data:outVar, Type:type, NoneName:true});
                }
                else if (item.Expression.Type==Syntax.BinaryExpression)
                {
                    var varName="__temp_b_"+i+"__";
                    let outVar=item.Expression.Out;
                    var type=0;
                    if (!Array.isArray(outVar)) outVar=this.SingleDataToArrayData(outVar);
                    this.OutVarTable.push({Name:varName, Data:outVar,Type:type, NoneName:true});
                }
                else if (item.Expression.Type==Syntax.LogicalExpression)    //逻辑语句 如 T1 AND T2 
                {
                    var varName="__temp_l_"+i+"__";
                    let outVar=item.Expression.Out;
                    var type=0;
                    if (!Array.isArray(outVar)) outVar=this.SingleDataToArrayData(outVar);
                    this.OutVarTable.push({Name:varName, Data:outVar,Type:type, NoneName:true});
                }
                else if (item.Expression.Type==Syntax.SequenceExpression)
                {
                    let varName;
                    let draw;
                    let color;
                    let lineWidth;
                    let colorStick=false;
                    let pointDot=false;
                    let circleDot=false;
                    let lineStick=false;
                    let stick=false;
                    let volStick=false;
                    let isShow=true;
                    let isExData=false;
                    let isDotLine=false;
                    let isOverlayLine=false;    //叠加线
                    var isNoneName=false;
                    var isShowTitle=true;
                    //显示在位置之上,对于DRAWTEXT和DRAWNUMBER等函数有用,放在语句的最后面(不能与LINETHICK等函数共用),比如:
                    //DRAWNUMBER(CLOSE>OPEN,HIGH,CLOSE),DRAWABOVE;
                    var isDrawAbove=false;
                    var isDrawCenter=false;   
                    var isDrawBelow=false;
                    //VALIGN0,VALIGN1,VALIGN2 设置文字垂直对齐方式（上中下）
                    //ALIGN0,ALIGN1,ALIGN2 设置文字水平对齐方式（左中右）
                    var drawAlign=-1, drawVAlign=-1;
                    var fontSize=-1;
                    for(let j=0; j<item.Expression.Expression.length; ++j)
                    {
                        let itemExpression=item.Expression.Expression[j];
                        if (itemExpression.Type==Syntax.AssignmentExpression && itemExpression.Operator==':' && itemExpression.Left)
                        {
                            if (j==0)
                            {
                                varName=itemExpression.Left.Name;
                                let varValue=this.VarTable.get(varName);
                                if (!Array.isArray(varValue)) 
                                {
                                    varValue=this.SingleDataToArrayData(varValue); 
                                    this.VarTable.set(varName,varValue);            //把常量放到变量表里
                                } 
                            }
                            else
                            {
                               
                            }
                        }
                        else if (itemExpression.Type==Syntax.Identifier)
                        {
                            let value=itemExpression.Name;
                            if (value==='COLORSTICK') colorStick=true;
                            else if (value==='POINTDOT') pointDot=true;
                            else if (value==='CIRCLEDOT') circleDot=true;
                            else if (value==='DOTLINE') isDotLine=true;
                            else if (value==='LINESTICK') lineStick=true;
                            else if (value==='STICK') stick=true;
                            else if (value==='VOLSTICK') volStick=true;
                            else if (value==="DRAWABOVE") isDrawAbove=true;
                            else if (value==="DRAWCENTER") isDrawCenter=true;
                            else if (value=="DRAWBELOW") isDrawBelow=true;
                            else if (value.indexOf('COLOR')==0) color=value;
                            else if (value.indexOf('LINETHICK')==0) lineWidth=value;

                            else if (value=="ALIGN0") drawAlign=0;
                            else if (value=="ALIGN1") drawAlign=1;
                            else if (value=="ALIGN2") drawAlign=2;
                           
                            else if (value=="VALIGN0") drawVAlign=0;
                            else if (value=="VALIGN1") drawVAlign=1;
                            else if (value=="VALIGN2") drawVAlign=2;
                           
                            else if (value.indexOf('NODRAW')==0) isShow=false;
                            else if (value.indexOf('EXDATA')==0) isExData=true; //扩展数据, 不显示再图形里面
                            else if (value.indexOf('LINEOVERLAY')==0) isOverlayLine=true;
                            else if (value.indexOf("NOTEXT")==0 || value.indexOf("NOTITLE")==0) isShowTitle=false; //标题不显示
                            else if (value.indexOf("FONTSIZE")==0)
                            {
                                var strFontSize=value.replace("FONTSIZE","");
                                fontSize=parseInt(strFontSize);
                            }
                            else 
                            {
                                if (j==0)
                                {
                                    varName=itemExpression.Name;
                                    let varValue=this.ReadVariable(varName,itemExpression);
                                    if (!Array.isArray(varValue)) varValue=this.SingleDataToArrayData(varValue); 
                                    varName="__temp_si_"+i+"__";
                                    isNoneName=true;
                                    this.VarTable.set(varName,varValue);            //放到变量表里
                                }
                            }
                        }
                        else if(itemExpression.Type==Syntax.Literal)    //常量
                        {
                            if (j==0)
                            {
                                let aryValue=this.SingleDataToArrayData(itemExpression.Value);
                                varName=itemExpression.Value.toString();
                                this.VarTable.set(varName,aryValue);    //把常量放到变量表里
                            }
                        }
                        else if (itemExpression.Type==Syntax.CallExpression)
                        {
                            if (j==0)
                            {
                                if (this.Draw.IsDrawFunction(itemExpression.Callee.Name))
                                {
                                    draw=itemExpression.Draw;
                                    draw.Name=itemExpression.Callee.Name;
                                }
                                else
                                {
                                    let varValue=itemExpression.Out;
                                    varName=`__temp_sc_${itemExpression.Callee.Name}_${i}__`;
                                    isNoneName=true;
                                    this.VarTable.set(varName,varValue);
                                }
                            }
                            else
                            {
                                if (itemExpression.Callee.Name=="RGB" || itemExpression.Callee.Name=="RGBA")
                                {
                                    color=itemExpression.Out;
                                }
                                else if (itemExpression.Callee.Name=="SOUND")
                                {
                                    var event=this.GetSoundEvent();
                                    if (event)
                                    {

                                    }
                                    varName=null;
                                }
                                else if (itemExpression.Callee.Name=="ICON")
                                {
                                    let drawCond=this.VarTable.get(varName);
                                    if (drawCond)
                                    {
                                        draw=this.GetOutIconData(drawCond,itemExpression.Draw);
                                        if (draw) draw.Name=itemExpression.Callee.Name;
                                    }

                                    varName=null;
                                }
                            }
                        }
                        else if (itemExpression.Type==Syntax.BinaryExpression)
                        {
                            if (j==0)
                            {
                                varName="__temp_sb_"+i+"__";
                                let aryValue=itemExpression.Out;
                                isNoneName=true;
                                this.VarTable.set(varName,aryValue);
                            }
                           
                        }
                    }

                    if (pointDot && varName)   //圆点
                    {
                        let outVar=this.VarTable.get(varName);
                        if (!Array.isArray(outVar)) outVar=this.SingleDataToArrayData(outVar);
                        let value={Name:varName, Data:outVar, Radius:g_JSChartResource.POINTDOT.Radius, Type:3};
                        if (color) value.Color=color;
                        if (lineWidth) value.LineWidth=lineWidth;
                        this.OutVarTable.push(value);
                    }
                    else if (circleDot && varName)  //圆点
                    {
                        let outVar=this.VarTable.get(varName);
                        if (!Array.isArray(outVar)) outVar=this.SingleDataToArrayData(outVar);
                        let value={Name:varName, Data:outVar, Radius:g_JSChartResource.CIRCLEDOT.Radius, Type:3};
                        if (color) value.Color=color;
                        if (lineWidth) value.LineWidth=lineWidth;
                        this.OutVarTable.push(value);
                    }
                    else if (lineStick && varName)  //LINESTICK  同时画出柱状线和指标线
                    {
                        let outVar=this.VarTable.get(varName);
                        let value={Name:varName, Data:outVar, Type:4};
                        if (color) value.Color=color;
                        if (lineWidth) value.LineWidth=lineWidth;
                        this.OutVarTable.push(value);
                    }
                    else if (stick && varName)  //STICK 画柱状线
                    {
                        let outVar=this.VarTable.get(varName);
                        let value={Name:varName, Data:outVar, Type:5};
                        if (color) value.Color=color;
                        if (lineWidth) value.LineWidth=lineWidth;
                        this.OutVarTable.push(value);
                    }
                    else if (volStick && varName)   //VOLSTICK   画彩色柱状线
                    {
                        let outVar=this.VarTable.get(varName);
                        let value={Name:varName, Data:outVar, Type:6};
                        if (color) value.Color=color;
                        this.OutVarTable.push(value);
                    }
                    else if (colorStick && varName)  //CYW: SUM(VAR4,10)/10000, COLORSTICK; 画上下柱子
                    {
                        let outVar=this.VarTable.get(varName);
                        let value={Name:varName, Data:outVar, Color:color, Type:2};
                        if (lineWidth) value.LineWidth=lineWidth;
                        if (color) value.Color=color;
                        this.OutVarTable.push(value);
                    }
                    else if (varName && color) 
                    {
                        let outVar=this.VarTable.get(varName);
                        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;
                        if (isOverlayLine==true) value.IsOverlayLine=true;
                        if (isNoneName==true) value.NoneName=true;
                        if (isShowTitle==false) value.IsShowTitle=false;
                        this.OutVarTable.push(value);
                    }
                    else if (draw)  //画图函数
                    {
                        var outVar={Name:draw.Name, Draw:draw, Type:1};
                        if (color) outVar.Color=color;
                        if (isDotLine==true) outVar.IsDotLine=true;
                        if (lineWidth) outVar.LineWidth=lineWidth;
                        if (isDrawAbove) outVar.IsDrawAbove=true;
                        if (isDrawCenter) outVar.IsDrawCenter=true;
                        if (isDrawBelow) outVar.IsDrawBelow=true;
                        if (drawAlign>=0) outVar.DrawAlign=drawAlign;
                        if (drawVAlign>=0) outVar.DrawVAlign=drawVAlign;
                        if (fontSize>0) outVar.DrawFontSize=fontSize;
                        this.OutVarTable.push(outVar);
                    }
                    else if (varName)
                    {
                        let outVar=this.VarTable.get(varName);
                        let value={Name:varName, Data:outVar,Type:0};
                        if (color) value.Color=color;
                        if (lineWidth) value.LineWidth=lineWidth;
                        if (isShow==false) value.IsShow=false;
                        if (isExData==true) value.IsExData = true;
                        if (isDotLine==true) value.IsDotLine=true;
                        if (isOverlayLine==true) value.IsOverlayLine=true;
                        if (isShowTitle==false) value.IsShowTitle=false;
                        this.OutVarTable.push(value);
                    }
                }
            }
        }

        JSConsole.Complier.Log('[JSExecute::Run]', this.VarTable);

        return this.OutVarTable;
    }

    this.GetOutIconData=function(cond, iconDraw)
    {
        if (Array.isArray(cond))
        {
            for(var i=0; i<cond.length && i<iconDraw.DrawData.length; ++i)
            {
                var item=cond[i];
                if (item<=0) iconDraw.DrawData[i]=null;
            }

            return iconDraw;
        }

        if (cond) return iconDraw;

        return null;
    }

    this.GetSoundEvent=function()
    {
        if (!this.GetEventCallback) return null;
        return this.GetEventCallback(JSCHART_EVENT_ID.ON_PLAY_SOUND);
    }

    this.Run=function()
    { 
        try
        {                       
            let data=this.RunAST();//执行脚本
            JSConsole.Complier.Log('[JSComplier.Run] execute finish', data);
            if (this.IndexCtrl) this.IndexCtrl.Status=0;
        
            if (this.UpdateUICallback) 
            {
                JSConsole.Complier.Log('[JSComplier.Run] invoke UpdateUICallback.');
                if (this.CallbackParam && this.CallbackParam.Job && this.CallbackParam.Job.ID==JS_EXECUTE_JOB_ID.JOB_EXECUTE_INDEX)
                {
                    this.UpdateUICallback(data,this.CallbackParam, this.SymbolData);
                }
                else
                {
                    if (this.CallbackParam && this.CallbackParam.Self && this.CallbackParam.Self.ClassName==='ScriptIndexConsole') this.CallbackParam.JSExecute=this;
                    if (this.IsUsePageData==true) this.CallbackParam.Self.IsUsePageData=true;
                    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) 
            {
                if (this.IndexCtrl) this.IndexCtrl.Status=0;
                this.ErrorCallback(error, this.CallbackParam);
            }
        }
    }

    this.VisitNode=function(node)
    {
        switch(node.Type)
        {
            case Syntax.SequenceExpression:
                this.VisitSequenceExpression(node);
                break;
            case Syntax.ExpressionStatement:
                this.VisitNode(node.Expression);
                break;
            case Syntax.AssignmentExpression:
                this.VisitAssignmentExpression(node);
                break;
            case Syntax.BinaryExpression:
            case Syntax.LogicalExpression:
                this.VisitBinaryExpression(node);
                break;
            case Syntax.CallExpression:
                this.VisitCallExpression(node);
                break;
        }
    }

    this.VisitSequenceExpression=function(node)
    {
        for(let i in node.Expression)
        {
            let item =node.Expression[i];
            this.VisitNode(item);
        }
    }

    //函数调用
    this.VisitCallExpression=function(node)
    {
        let funcName=node.Callee.Name;
        let args=[];
        for(let i in node.Arguments)
        {
            let item=node.Arguments[i];
            let value;
            if (item.Type==Syntax.BinaryExpression || item.Type==Syntax.LogicalExpression) 
                value=this.VisitBinaryExpression(item);
            else if (item.Type==Syntax.CallExpression)
                value=this.VisitCallExpression(item);
            else
                value=this.GetNodeValue(item);
            args.push(value);
        }

        //JSConsole.Complier.Log('[JSExecute::VisitCallExpression]' , funcName, '(', args.toString() ,')');

        if (g_JSComplierResource.IsCustomFunction(funcName))
        {
            var data=this.Algorithm.CallCustomFunction(funcName, args, this.SymbolData, node);
            node.Out=[];
            node.Draw=null;

            if (data)
            {
                if (data.Out) node.Out=data.Out;
                if (data.Draw) node.Draw=data.Draw;
            }

            return node.Out;
        }

        switch(funcName)
        {
            case 'DYNAINFO':    //行情最新数据
                node.Out=this.SymbolData.GetLatestCacheData(args[0]);
                break;
            case 'STICKLINE':
                node.Draw=this.Draw.STICKLINE(args[0],args[1],args[2],args[3],args[4]);
                node.Out=[];
                break;
            case 'DRAWTEXT':
                node.Draw=this.Draw.DRAWTEXT(args[0],args[1],args[2]);
                node.Out=[];
                break;
            case '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 "ICON":
                node.Draw=this.Draw.ICON(args[0],args[1]);
                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 "FILLRGN":
                if (args.length>=4) node.Draw=this.Draw.FILLRGN2(args);
                else node.Draw=this.Draw.FILLRGN(args[0],args[1],args[2]);
                node.Out=[];
                break;
            case "FLOATRGN":
                node.Draw=this.Draw.FLOATRGN(args);
                node.Out=[];
                break;
            case "FILLTOPRGN":
                node.Draw=this.Draw.FILLBGRGN(1, args);
                node.Out=[];
                break;
            case "FILLBOTTOMRGN":
                node.Draw=this.Draw.FILLBGRGN(0, args);
                node.Out=[];
                break;
            case "FILLVERTICALRGN":
                node.Draw=this.Draw.FILLVERTICALRGN(args);
                node.Out=[];
                break;
            case 'DRAWKLINE':
            case "DRAWKLINE1":
                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 "DRAWCOLORKLINE":
                node.Draw=this.Draw.DRAWCOLORKLINE(args[0],args[1],args[2]);
                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 "DRAWNUMBER_FIX":
                node.Draw=this.Draw.DRAWNUMBER_FIX(args[0],args[1],args[2],args[3],args[4]);
                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 "RGBA":
                node.Out=this.Draw.RGBA(args[0],args[1],args[2],args[3]);
                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 'DRAWGBK2':
                node.Draw=this.Draw.DRAWGBK2(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 "DRAWTEXTREL":
                node.Draw=this.Draw.DRAWTEXTREL(args[0],args[1],args[2]);
                node.Out=[];
                break;
            case "DRAWTEXTABS":
                node.Draw=this.Draw.DRAWTEXTABS(args[0],args[1],args[2]);
                node.Out=[];
                break;
            case "DRAWOVERLAYLINE":
                node.Draw=this.Draw.DRAWOVERLAYLINE(args[0],args[1],args[2]);
                node.Out=node.Draw.DrawData.Data;
                break;
            case "DRAWSL":
                node.Draw=this.Draw.DRAWSL(args[0],args[1],args[2],args[3],args[4]);
                node.Out=[];
                break;
            case "VERTLINE":
                node.Draw=this.Draw.VERTLINE(args[0],args[1]);
                node.Out=node.Draw.DrawData.Data;
                break;
            case "HORLINE":
                node.Draw=this.Draw.HORLINE(args[0],args[1],args[2],args[3]);
                node.Out=node.Draw.DrawData.Data;
                break;
            case 'CODELIKE':
                node.Out=this.SymbolData.CODELIKE(args[0]);
                break;
            case 'NAMELIKE':
            case "NAMEINCLUDE":
                node.Out=this.SymbolData.NAMELIKE(args[1]);
                break;
            case 'REFDATE':
                node.Out=this.SymbolData.REFDATE(args[0],args[1]);
                break;
            case 'FINANCE':
                node.Out=this.SymbolData.GetStockCacheData( {FunctionName:funcName, Args:args, ArgCount:1, Node:node } );
                break;
            case "FINVALUE":
                node.Out=this.SymbolData.GetStockCacheData( {FunctionName:funcName, Args:args, ArgCount:1, Node:node } );
                break;
            case "FINONE":
                node.Out=this.SymbolData.GetStockCacheData( {FunctionName:funcName, Args:args, ArgCount:3, Node:node } );
                break;
            case "GPJYVALUE":
                node.Out=this.SymbolData.GetStockCacheData( {FunctionName:funcName, Args:args, ArgCount:3, Node:node } );
                break;
            case "SCJYVALUE":
                node.Out=this.SymbolData.GetStockCacheData( {FunctionName:funcName, Args:args, ArgCount:3, Node:node } );
                break;
            case "MARGIN":
                node.Out=this.SymbolData.GetMarginCacheData(args[0],node);
                break;
            case "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;
            case 'LOADAPIDATA':
                node.Out=this.SymbolData.GetCustomApiData(args);
                break;
            case "STKINDI":
                node.Out=this.SymbolData.GetScriptIndexOutData(args,node);
                break;
            case "SOUND":
                node.Draw=this.Draw.SOUND(args[0]);
                node.Out=[];
                break;
            case "PLAYSOUND":
                node.Draw=this.Draw.PLAYSOUND(args[0],args[1]);
                node.Out=[];
                break;
            case 'CLOSE':
            case 'C':
            case 'VOL':
            case 'V':
            case 'OPEN':
            case 'O':
            case 'HIGH':
            case 'H':
            case 'LOW':
            case 'L':
            case 'AMOUNT':
            case 'AMO':
                node.Out=this.SymbolData.GetOtherSymolCacheData( {FunctionName:funcName, Args:args} );
                break;
            case "INBLOCK":
                node.Out=this.SymbolData.IsInBlock(args[0],node);
                break;

            case 'COVER_C':
            case 'COVER_O':
            case 'COVER_H':
            case 'COVER_L':
            case 'COVER_A':
            case 'COVER_V':
                if (args.length==2) return this.SymbolData.GetSymbolPeriodCacheData2(JSComplierHelper.GetConvertValueName(funcName),args[0],args[1]);
                return this.SymbolData.GetSymbolPeriodCacheData(JSComplierHelper.GetConvertValueName(funcName),args[0]);

            case "SYSPARAM":
                return this.SymbolData.SysParam(args[0], this);

            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;
            if (IFrameSplitOperator.IsString(value) && right.Value.indexOf("$")>0)
                value=this.SymbolData.GetOtherSymolCacheData( {Literal:value} );
        }
        else if (right.Type==Syntax.Identifier) //右值是变量
            value=this.ReadVariable(right.Name,right);
        else if (right.Type==Syntax.MemberExpression)
            value=this.ReadMemberVariable(right);
        else if (right.Type==Syntax.UnaryExpression)
        {
            if (right.Operator=='-') 
            {
                var tempValue=this.GetNodeValue(right.Argument);
                value=this.Algorithm.Subtract(0,tempValue);
            }
            else 
            {
                value=right.Argument.Value;
            }
        }

        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);
            case Syntax.MemberExpression:
                return this.ReadMemberVariable(node);
            default:
                this.ThrowUnexpectedNode(node);
        }
    }

    this.ThrowUnexpectedNode=function(node,message,word)
    {
        let marker=node.Marker;
        let msg=message || "执行异常";
       
        return this.ErrorHandler.ThrowError(marker.Index,marker.Line,marker.Column,msg, word);
       
    }

    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 JSExplainer(ast,option)
{
    this.AST=ast;
    this.ErrorHandler=new ErrorHandler();
    this.ErrorCallback;             //执行错误回调
    this.UpdateUICallback;
    this.CallbackParam;
    this.JobList=[];                //执行的任务队列
    this.VarTable=new Map();        //变量表
    this.OutVarTable=[];            //输出变量

    //脚本自动变量表, 只读
    this.ConstVarTable=new Map(
    [
        //个股数据
        ['CLOSE',"收盘价"],['VOL',"成交量"],['OPEN',"开盘价"],['HIGH',"最高价"],['LOW',"最低价"],['AMOUNT',"成交量"],
        ['C',"收盘价"],['V',"成交量"],['O',"开盘价"],['H',"最高价"],['L',"最低价"],['AMO',"成交量"], 
        ['VOLR',"量比"], ['VOLINSTK',"持仓量"], ["OPI","持仓量"], ["ZSTJJ","均价"], ["QHJSJ","结算价"], ["SETTLE", "结算价"],

        //日期类
        ['DATE',"日期"],['YEAR',"年份"],['MONTH',"月份"],['PERIOD', "周期"],['WEEK',"星期"],["TIME","时间"],

        //大盘数据
        ['INDEXA',"大盘成交额"],['INDEXC',"大盘收盘价"],['INDEXH',"大盘最高价"],['INDEXL',"大盘最低价"],['INDEXO',"大盘开盘价"],['INDEXV',"大盘成交量"],
        ['INDEXADV',"大盘上涨家数"],['INDEXDEC',"´大盘下跌家数"],

        ["ADVANCE","上涨家数"], ['DECLINE', "下跌家数"],

        ['FROMOPEN',"当前离开盘分钟数"], 
        ['TOTALFZNUM', "总分钟数"], 

        ['CURRBARSCOUNT',"到最后交易的周期"], //到最后交易日的周期数
        ['TOTALBARSCOUNT',"总的周期数"],
        ['ISLASTBAR',"是否是最后一个周期"],     //判断是否为最后一个周期
        ['BARSTATUS',"数据位置状态"],     //BARSTATUS返回数据位置信息,1表示第一根K线,2表示最后一个数据,0表示中间位置.

        ['CAPITAL',"当前流通股本(手)"], ["TOTALCAPITAL","当前总股本(手)"], 
        ['EXCHANGE',"换手率"],   //换手率
        ['SETCODE', "市场类型"],  //市场类型
        ['CODE',"品种代码"],      //品种代码
        ['STKNAME',"品种名称"],   //品种名称
        ["TQFLAG","当前复权状态"],    //TQFLAG  当前的复权状态,0:无复权 1:前复权 2:后复权 

        ['HYBLOCK',"所属行业"],   //所属行业板块
        ['DYBLOCK',"所属地域"],   //所属地域板块
        ['GNBLOCK',"所属概念"],   //所属概念
        ["FGBLOCK","所属风格板块"],  
        ["ZSBLOCK","所属指数板块"], 
        ["ZHBLOCK",'所属组合板块'],   
        ["ZDBLOCK",'所属自定义板块'], 
        ["HYZSCODE","所属行业的板块指数代码"],  

        ["GNBLOCKNUM","所属概念板块的个数"],    
        ["FGBLOCKNUM","所属风格板块的个数"],    
        ["ZSBLOCKNUM","所属指数板块的个数"],
        ["ZHBLOCKNUM","所属组合板块的个数"],
        ["ZDBLOCKNUM","所属自定义板块的个数"],

        ["HYSYL","指数市盈率或个股所属行业的市盈率"],
        ["HYSJL","指数市净率或个股所属行业的市净率"],

        ['DRAWNULL',"无效数据"]

    ]);   

    if (option)
    {
        if (option.Callback) this.UpdateUICallback=option.Callback;
        if (option.CallbackParam) this.CallbackParam=option.CallbackParam;
        if (option.Arguments) this.Arguments=option.Arguments;
    }

    this.Run=function()
    { 
        try
        {  
            this.OutVarTable=[];
            this.VarTable=new Map();
            JSConsole.Complier.Log('[JSExecute::JSExplainer] Load Arguments', this.Arguments);
            for(let i in this.Arguments)    //预定义的变量
            {
                let item =this.Arguments[i];
                this.VarTable.set(item.Name,item.Value);
            }

            let data=this.RunAST();//执行脚本
            JSConsole.Complier.Log('[JSExplainer.Run] explain finish', data);
            if (this.UpdateUICallback) //回调发送结果, 可以支持异步
            {
                JSConsole.Complier.Log('[JSExplainer.Run] invoke UpdateUICallback.');
                this.UpdateUICallback(data);
            }
        }
        catch(error)
        {
            JSConsole.Complier.Log('[JSExplainer.Run] throw error ', error);
            if (this.ErrorCallback) 
            {
                this.ErrorCallback(error, this.OutVarTable);
            }
        }
    }


    this.RunAST=function()
    {
        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)
                {
                    if (item.Expression.Operator==':' && item.Expression.Left)
                    {
                        let assignmentItem=item.Expression;
                        let varName=assignmentItem.Left.Name;
                        let outVar=`输出${varName}: ${this.VarTable.get(varName)}`;
                        this.OutVarTable.push({ Name:varName, Data:outVar,Type:0});
                    }
                    else if (item.Expression.Operator==':=' && item.Expression.Left)
                    {
                        let assignmentItem=item.Expression;
                        let varName=assignmentItem.Left.Name;
                        let outVar=`赋值${varName}: ${this.VarTable.get(varName)}`;
                        this.OutVarTable.push({ Name:varName, Data:outVar,Type:0, IsOut:false });
                    }
                }
                else if (item.Expression.Type==Syntax.CallExpression)
                {
                    let callItem=item.Expression;
                    if (this.IsDrawFunction(callItem.Callee.Name))
                    {
                        let outVar=callItem.Out;
                        var drawName=callItem.Callee.Name;
                        this.OutVarTable.push({Name:drawName, Draw:`输出: ${outVar}`, Type:1});
                    }
                    else
                    {
                        let outVar=callItem.Out;
                        varName=`__temp_c_${callItem.Callee.Name}_${i}__`;
                        this.OutVarTable.push({Name:varName, Data:`输出: ${outVar}`,Type:0, NoneName:true});
                    }
                }
                else if (item.Expression.Type==Syntax.Identifier)
                {
                    let varName=item.Expression.Name;
                    let outVar=this.ReadVariable(varName,item.Expression);
                    varName="__temp_i_"+i+"__";
                    this.OutVarTable.push({Name:varName, Data:`输出: ${outVar}`, Type:0, NoneName:true});
                }
                else if (item.Expression.Type==Syntax.Literal)  //常量
                {
                    let outVar=item.Expression.Value;
                    if (IFrameSplitOperator.IsString(outVar) && outVar.indexOf("$")>0)
                        outVar=this.GetOtherSymbolExplain({ Literal:outVar }, item);
                    varName="__temp_li_"+i+"__";
                    var type=0;
                    this.OutVarTable.push({Name:varName, Data:`输出: ${outVar}`, Type:0, NoneName:true});
                }
                else if (item.Expression.Type==Syntax.BinaryExpression) // CLOSE+OPEN;
                {
                    var varName="__temp_b_"+i+"__";
                    let outVar=item.Expression.Out;
                    this.OutVarTable.push({Name:varName, Data:`输出: ${outVar}`,Type:0, NoneName:true});
                }
                else if (item.Expression.Type==Syntax.LogicalExpression)    //逻辑语句 如 T1 AND T2 
                {
                    var varName="__temp_l_"+i+"__";
                    let outVar=item.Expression.Out;
                    this.OutVarTable.push({Name:varName, Data:`输出: ${outVar}`,Type:0, NoneName:true});
                }
                else if (item.Expression.Type==Syntax.SequenceExpression)
                {
                    let varName;
                    let drawName;
                    let draw;
                    let color;
                    let lineWidth;
                    let colorStick=false;
                    let pointDot=false;
                    let circleDot=false;
                    let lineStick=false;
                    let stick=false;
                    let volStick=false;
                    let isShow=true;
                    let isExData=false;
                    let isDotLine=false;
                    let isOverlayLine=false;    //叠加线
                    var isNoneName=false;
                    //显示在位置之上,对于DRAWTEXT和DRAWNUMBER等函数有用,放在语句的最后面(不能与LINETHICK等函数共用),比如:
                    //DRAWNUMBER(CLOSE>OPEN,HIGH,CLOSE),DRAWABOVE;
                    var isDrawAbove=false;      
                    for(let j in item.Expression.Expression)
                    {
                        let itemExpression=item.Expression.Expression[j];
                        if (itemExpression.Type==Syntax.AssignmentExpression && itemExpression.Operator==':' && itemExpression.Left)
                        {
                            varName=itemExpression.Left.Name;
                            let varValue=this.VarTable.get(varName);
                            this.VarTable.set(varName,varValue);            //把常量放到变量表里
                        }
                        else if (itemExpression.Type==Syntax.Identifier)
                        {
                            let value=itemExpression.Name;
                            if (value==='COLORSTICK') colorStick=true;
                            else if (value==='POINTDOT') pointDot=true;
                            else if (value==='CIRCLEDOT') circleDot=true;
                            else if (value==='DOTLINE') isDotLine=true;
                            else if (value==='LINESTICK') lineStick=true;
                            else if (value==='STICK') stick=true;
                            else if (value==='VOLSTICK') volStick=true;
                            else if (value==="DRAWABOVE") isDrawAbove=true;
                            else if (value.indexOf('COLOR')==0) color=value;
                            else if (value.indexOf('LINETHICK')==0) lineWidth=value;
                            else if (value.indexOf('NODRAW')==0) isShow=false;
                            else if (value.indexOf('EXDATA')==0) isExData=true; //扩展数据, 不显示再图形里面
                            else if (value.indexOf('LINEOVERLAY')==0) isOverlayLine=true;
                            else 
                            {
                                varName=itemExpression.Name;
                                let varValue=this.ReadVariable(varName,itemExpression);
                                varName="__temp_si_"+i+"__";
                                isNoneName=true;
                                this.VarTable.set(varName,varValue);            //放到变量表里
                            }
                        }
                        else if(itemExpression.Type==Syntax.Literal)    //常量
                        {
                            let aryValue=itemExpression.Value;
                            varName=itemExpression.Value.toString();
                            isNoneName=true;
                            this.VarTable.set(varName,aryValue);    //把常量放到变量表里
                        }
                        else if (itemExpression.Type==Syntax.CallExpression)
                        {
                            if (this.IsDrawFunction(itemExpression.Callee.Name))
                            {
                                draw=itemExpression.Out;
                                drawName=itemExpression.Callee.Name;
                            }
                            else
                            {
                                let varValue=itemExpression.Out;
                                varName=`__temp_sc_${itemExpression.Callee.Name}_${i}__`;
                                isNoneName=true;
                                this.VarTable.set(varName,varValue);
                            }
                        }
                        else if (itemExpression.Type==Syntax.BinaryExpression)
                        {
                            varName="__temp_sb_"+i+"__";
                            let aryValue=itemExpression.Out;
                            isNoneName=true;
                            this.VarTable.set(varName,aryValue);
                        }
                    }

                    var outValue;
                    if (draw) outValue=`输出: ${draw}`;
                    else if (isNoneName) outValue=`输出: ${this.VarTable.get(varName)}`;
                    else outValue=`输出${varName}: ${this.VarTable.get(varName)}`;
                    
                    if (color) outValue+=`,颜色${this.GetColorExplain(color)}`;
                    if (lineWidth) outValue+=`,线段粗细${this.GetLineWidthExplain(lineWidth)}`;
                    if (isShow==false) outValue+=",不显示"; 
                    if (isDotLine==true) outValue+=",画虚线";
                    if (isDrawAbove==true) outValue+=',显示在位置之上';

                    if (pointDot && varName)   //圆点
                    {
                        outValue+=",画小圆点线";
                        let value={Name:varName, Data:outValue, Radius:g_JSChartResource.POINTDOT.Radius, Type:3};
                        this.OutVarTable.push(value);
                    }
                    else if (circleDot && varName)  //圆点
                    {
                        outValue+=",画小圆圈线";
                        let value={Name:varName, Data:outValue, Radius:g_JSChartResource.CIRCLEDOT.Radius, Type:3};
                        this.OutVarTable.push(value);
                    }
                    else if (lineStick && varName)  //LINESTICK  同时画出柱状线和指标线
                    {
                        outValue+=",画出柱状线和指标线";
                        let value={Name:varName, Data:outValue, Type:4};
                        this.OutVarTable.push(value);
                    }
                    else if (stick && varName)  //STICK 画柱状线
                    {
                        outValue+=",画柱状线";
                        let value={Name:varName, Data:outValue, Type:5};
                        this.OutVarTable.push(value);
                    }
                    else if (volStick && varName)   //VOLSTICK   画彩色柱状线
                    {
                        outValue+=",画成交量柱状线";
                        let value={Name:varName, Data:outValue, Type:6};
                        this.OutVarTable.push(value);
                    }
                    else if (varName && color) 
                    {
                        let value={Name:varName, Data:outValue, Color:color, Type:0};
                        this.OutVarTable.push(value);
                    }
                    else if (draw)  //画图函数
                    {
                        var outVar={ Name:drawName, Data:outValue, Type:1 };
                        this.OutVarTable.push(outVar);
                    }
                    else if (colorStick && varName)  //CYW: SUM(VAR4,10)/10000, COLORSTICK; 画上下柱子
                    {
                        outValue+=",画彩色柱状线";
                        let value={Name:varName, Data:outValue, Color:color, Type:2};
                        this.OutVarTable.push(value);
                    }
                    else if (varName)
                    {
                        let value={Name:varName, Data:outValue,Type:0};
                        this.OutVarTable.push(value);
                    }
                }
            }
        }

        JSConsole.Complier.Log('[JSExplainer::Run]', this.VarTable);
        return this.OutVarTable;
    }

    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);
        }

        JSConsole.Complier.Log('[JSExplainer::VisitCallExpression]' , funcName, '(', args.toString() ,')');

        if (g_JSComplierResource.IsCustomFunction(funcName))
        {
            var data=this.Algorithm.CallCustomFunction(funcName, args, this.SymbolData, node);
            node.Out=[];
            node.Draw=null;

            if (data)
            {
                if (data.Out) node.Out=data.Out;
                if (data.Draw) node.Draw=data.Draw;
            }

            return node.Out;
        }

        node.Out=this.CallFunctionExplain(funcName, args, node);
        return node.Out;
    }

    this.FUNCTION_INFO_LIST=new Map(
        [
            ["REF",     { Name:"REF", Param:{ Count:2 }, ToString:function(args) { return `${args[1]}日前的${args[0]}`; } } ],
            ["REFX",    { Name:"REFX", Param:{ Count:2 }, ToString:function(args) { return `${args[1]}日后的${args[0]}`; } } ],
            ["REFV",    { Name:"REFV", Param:{ Count:2 }, ToString:function(args) { return `${args[1]}日前的(未作平滑处理)${args[0]}`; } } ],
            ["REFXV",   { Name:"REFXV", Param:{ Count:2 }, ToString:function(args) { return `${args[1]}日后的(未作平滑处理)${args[0]}`; } } ],

            ["REFDATE", { Name:"REFDATE", Param:{ Count:2 }, ToString:function(args) { return `${args[1]}日${args[0]}`; } } ],
            ["COUNT",   { Name:"COUNT", Param:{ Count:2 }, ToString:function(args) { return `统计${args[1]}日中满足${args[0]}的天数`; } } ],
            ["BARSLASTCOUNT", { Name:"BARSLASTCOUNT", Param:{ Count:1 }, ToString:function(args) { return `条件${args[0]}连续成立次数`; } } ],
            ["BARSCOUNT",   { Name:"BARSCOUNT", Param:{ Count:1 }, ToString:function(args) { return `${args[0]}有效数据周期数`; } } ],
            ["BARSLAST",    { Name:"BARSLAST", Param:{ Count:1 }, ToString:function(args) { return `上次${args[0]}不为0距今天数`; } } ],
            ["BARSNEXT",    { Name:"BARSNEXT", Param:{ Count:1 }, ToString:function(args) { return `下次${args[0]}不为0距今天数`; } } ],
            ["BARSSINCEN",  { Name:"BARSSINCEN", Param:{ Count:2 }, ToString:function(args) { return `在${args[1]}周期内首次${args[0]}距今天数`; } } ],
            ["BARSSINCE",   { Name:"BARSSINCE", Param:{ Count:1 }, ToString:function(args) { return `首次${args[0]}距今天数`; } } ],
            ["HHV", { Name:"HHV", Param:{ Count:2 }, ToString:function(args) { return `${args[1]}日内${args[0]}的最高值`; } } ],
            ["LLV", { Name:"LLV", Param:{ Count:2 }, ToString:function(args) { return `${args[1]}日内${args[0]}的最低值`; } } ],

            ["HOD", { Name:"HOD", Param:{ Count:2 }, ToString:function(args) { return `${args[1]}日内${args[0]}的高值名次`; } } ],
            ["LOD", { Name:"LOD", Param:{ Count:2 }, ToString:function(args) { return `${args[1]}日内${args[0]}的低值名次`; } } ],
            ["REVERSE", { Name:"REVERSE", Param:{ Count:1 }, ToString:function(args) { return `${args[0]}的相反数`; } } ],
            ["FILTER", { Name:"FILTER", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}的${args[1]}日过滤`; } } ],
            ["FILTERX", { Name:"FILTERX", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}的${args[1]}日反向过滤`; } } ],
            ["SUMBARS", { Name:"SUMBARS", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}累加至${args[1]}的天数`; } } ],
            ["MA", { Name:"MA", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}的${args[1]}日简单移动平均`; } } ],
            ["SMA", { Name:"SMA", Param:{ Count:3 }, ToString:function(args) { return `${args[0]}的${args[1]}日[${args[2]}日权重]移动平均`; } } ],
            ["MEMA", { Name:"MEMA", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}的${args[1]}日平滑移动平均`; } } ],
            ["EMA", { Name:"EMA", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}的${args[1]}日指数移动平均`; } } ],
            ["EXPMA", { Name:"EXPMA", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}的${args[1]}日指数移动平均`; } } ],
            ["EXPMEMA", { Name:"EXPMEMA", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}的${args[1]}日指数平滑移动平均`; } }],
            ["WMA", { Name:"WMA", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}的${args[1]}日加权移动平均`; } } ],
            ["DMA", { Name:"DMA", Param:{ Count:2 }, ToString:function(args) { return `以${args[1]}为权重${args[0]}的动态移动平均`; } } ],
            ["XMA", { Name:"XMA", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}的${args[1]}日偏移移动平均`; } } ],

            ["RANGE", { Name:"RANGE", Param:{ Count:3 }, ToString:function(args) { return `${args[0]}位于${args[1]}和${args[2]}之间`; } } ],
            ["CONST", { Name:"CONST", Param:{ Count:1 }, ToString:function(args) { return `${args[0]}的最后一日值`; } } ],
            ["TOPRANGE", { Name:"TOPRANGE", Param:{ Count:1 }, ToString:function(args) { return `当前值是近${args[0]}周期的最大值`; } } ],
            ["LOWRANGE", { Name:"LOWRANGE", Param:{ Count:1 }, ToString:function(args) { return `当前值是近${args[0]}周期的最小值`; } } ],
            ["FINDHIGH", { Name:"FINDHIGH", Param:{ Count:4 }, ToString:function(args) { return `${args[0]}在${args[1]}日前的${args[2]}天内第${args[3]}个最高价`; } } ],
            ["FINDHIGHBARS", { Name:"FINDHIGHBARS", Param:{ Count:4 }, ToString:function(args) { return `${args[0]}在${args[1]}日前的${args[2]}天内第${args[3]}个最高价到当前周期的周期数`; } } ],
            ["FINDLOW", { Name:"FINDLOW", Param:{ Count:4 }, ToString:function(args) { return `${args[0]}在${args[1]}日前的${args[2]}天内第${args[3]}个最低价`; } } ],
            ["FINDLOWBARS", { Name:"FINDLOWBARS", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}在${args[1]}日前的${args[2]}天内第${args[3]}个最低价到当前周期的周期数`; } } ],
            ["SUM", { Name:"SUM", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}${args[1]}日累加`; } } ],
            ["MULAR", { Name:"MULAR", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}和${args[1]}日累乘`; } } ],
            ["AMA", { Name:"AMA", Param:{ Count:2 }, ToString:function(args) { return `以${args[1]}为权重${args[0]}的自适应均线`; } } ],
            ["TMA", { Name:"TMA", Param:{ Count:3 }, ToString:function(args) { return `${args[0]}的${args[1]}日[${args[2]}日权重]移动平均`; } } ],
            ["CROSS", { Name:"CROSS", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}上穿${args[1]}`; } } ],
            ["LONGCROSS", { Name:"LONGCROSS", Param:{ Count:3 }, ToString:function(args) { return `${args[0]}小于${args[1]}保持${args[2]}个交易日后交叉上穿`; } } ],
            ["UPNDAY", { Name:"UPNDAY", Param:{ Count:2 }, ToString:function(args) { return `最近${args[1]}日${args[0]}连涨`; } } ],
            ["DOWNNDAY", { Name:"DOWNNDAY", Param:{ Count:2 }, ToString:function(args) { return `最近${args[1]}日${args[0]}连跌`; } } ],
            ["NDAY", { Name:"NDAY", Param:{ Count:3 }, ToString:function(args) { return `最近${args[2]}日${args[0]}一直大于${args[1]}`; } } ],
            ["EXIST", { Name:"EXIST", Param:{ Count:2 }, ToString:function(args) { return `最近${args[1]}日存在${args[0]}`; } } ],
            ["EXISTR", { Name:"EXISTR", Param:{ Count:3 }, ToString:function(args) { return `从前${args[1]}日到前${args[2]}日存在${args[0]}`; } } ],
            ["EVERY", { Name:"EVERY", Param:{ Count:2 }, ToString:function(args) { return `最近${args[1]}日一直存在${args[0]}`; } } ],
            ["LAST", { Name:"LAST", Param:{ Count:3 }, ToString:function(args) { return `从前${args[1]}日到前${args[2]}日持续${args[0]}`; } } ],
            ["NOT", { Name:"NOT", Param:{ Count:1 }, ToString:function(args) { return `${args[0]}取反`; } } ],
            ["IF", { Name:"IF", Param:{ Count:3 }, ToString:function(args) { return `如果${args[0]},返回${args[1]},否则返回${args[2]}`; } } ],
            ["IFF", { Name:"IFF", Param:{ Count:3 }, ToString:function(args) { return `如果${args[0]},返回${args[1]},否则返回${args[2]}`; } } ],
            ["IFN", { Name:"IFN", Param:{ Count:3 }, ToString:function(args) { return `如果${args[0]},返回${args[1]},否则返回${args[2]}`; } } ],

            ["MAX", { Name:"MAX", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}和${args[1]}的较大值`; } } ],
            ["MIN", { Name:"MIN", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}和${args[1]}的较小值`; } } ],
            ["ACOS", { Name:"ACOS", Param:{ Count:1 }, ToString:function(args) { return `${args[0]}的反余弦`; } } ],
            ["ASIN", { Name:"ASIN", Param:{ Count:1 }, ToString:function(args) { return `${args[0]}的反正弦`; } } ],
            ["ATAN", { Name:"ATAN", Param:{ Count:1 }, ToString:function(args) { return `${args[0]}的反正切`; } } ],
            ["COS", { Name:"COS", Param:{ Count:1 }, ToString:function(args) { return `${args[0]}的余弦`; } } ],
            ["SIN", { Name:"SIN", Param:{ Count:1 }, ToString:function(args) { return `${args[0]}的正弦`; } } ],
            ["TAN", { Name:"TAN", Param:{ Count:1 }, ToString:function(args) { return `${args[0]}的正切`; } } ],
            ["EXP", { Name:"EXP", Param:{ Count:1 }, ToString:function(args) { return `${args[0]}的指数`; } } ],
            ["LN", { Name:"LN", Param:{ Count:1 }, ToString:function(args) { return `${args[0]}的自然对数`; } } ],
            ["LOG", { Name:"LOG", Param:{ Count:1 }, ToString:function(args) { return `${args[0]}的对数`; } } ],
            ["SQRT", { Name:"SQRT", Param:{ Count:1 }, ToString:function(args) { return `${args[0]}的开方`; } } ],
            ["ABS", { Name:"ABS", Param:{ Count:1 }, ToString:function(args) { return `${args[0]}的绝对值`; } } ],
            ["POW", { Name:"POW", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}的${args[1]}乘幂`; } } ],
            ["CEILING", { Name:"CEILING", Param:{ Count:1 }, ToString:function(args) { return `${args[0]}的向上舍入`; } } ],
            ["FLOOR", { Name:"FLOOR", Param:{ Count:1 }, ToString:function(args) { return `${args[0]}的向上舍入`; } } ],
            ["INTPART", { Name:"INTPART", Param:{ Count:1 }, ToString:function(args) { return `${args[0]}的整数部分`; } } ],
            ["BETWEEN", { Name:"BETWEEN", Param:{ Count:3 }, ToString:function(args) { return `${args[0]}位于${args[1]}和${args[2]}之间`; } } ],
            ["FRACPART", { Name:"FRACPART", Param:{ Count:1 }, ToString:function(args) { return `${args[0]}的小数部分`; } } ],
            ["ROUND", { Name:"ROUND", Param:{ Count:1 }, ToString:function(args) { return `对${args[0]}(进行)四舍五入`; } } ],
            ["ROUND2", { Name:"ROUND2", Param:{ Count:2 }, ToString:function(args) { return `对${args[0]}(进行)四舍五入`; } } ],
            ["SIGN", { Name:"SIGN", Param:{ Count:1 }, ToString:function(args) { return `${args[0]}的符号`; } } ],
            ["MOD", { Name:"MOD", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}关于${args[1]}的模`; } } ],
            ["RAND", { Name:"RAND", Param:{ Count:1 }, ToString:function(args) { return `随机正整数`; } } ],

            ["AVEDEV", { Name:"AVEDEV", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}的${args[1]}日平均绝对偏差`; } } ],
            ["DEVSQ", { Name:"DEVSQ", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}的${args[1]}日数据偏差平方和`; } } ],
            ["FORCAST", { Name:"FORCAST", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}的${args[1]}日线性回归预测值`; } } ],
            ["TSMA", { Name:"TSMA", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}在${args[1]}个周期内的时间序列三角移动平均`; } } ],
            ["SLOPE", { Name:"SLOPE", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}的${args[1]}日线性回归斜率`; } } ],
            ["STD", { Name:"STD", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}的${args[1]}日估算标准差`; } } ],
            ["STDP", { Name:"STDP", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}的${args[1]}日总体标准差`; } } ],
            ["STDDEV", { Name:"STDDEV", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}的${args[1]}日标准偏差`; } } ],
            ["VAR", { Name:"VAR", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}的${args[1]}日估算样本方差`; } } ],
            ["VARP", { Name:"VARP", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}的${args[1]}日总体样本方差`; } } ],
            ["COVAR", { Name:"COVAR", Param:{ Count:3 }, ToString:function(args) { return `${args[0]}和${args[1]}的${args[2]}周期的协方差`; } } ],
            ["RELATE", { Name:"RELATE", Param:{ Count:3 }, ToString:function(args) { return `${args[0]}和${args[1]}的${args[0]}周期的相关系数`; } } ],
            ["BETA", { Name:"BETA", Param:{ Count:1 }, ToString:function(args) { return `β(Beta)系数`; } } ],
            ["BETAEX", { Name:"BETAEX", Param:{ Count:3 }, ToString:function(args) { return `${args[0]}和${args[1]}的${args[2]}周期的相关放大系数`; } } ],

            ["COST", { Name:"COST", Param:{ Count:1 }, ToString:function(args) { return `获利盘为${args[0]}%的成本分布`; } } ],
            ["WINNER", { Name:"WINNER", Param:{ Count:1 }, ToString:function(args) { return `以${args[0]}计算的获利盘比例`; } } ],
            ["LWINNER", { Name:"LWINNER", Param:{ Count:2 }, ToString:function(args) { return `最近${args[0]}日那部分成本以${args[1]}价格卖出的获利盘比例`; } } ],
            ["PWINNER", { Name:"PWINNER", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}日前那部分成本以${args[1]}价格卖出的获利盘比例`; } } ],
            ["COSTEX", { Name:"COSTEX", Param:{ Count:2 }, ToString:function(args) { return `位于价格${args[0]}和${args[1]}间的成本`; } } ],
            ["PPART", { Name:"PPART", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}日前那部分成本占总成本的比例`; } } ],

            ["SAR", { Name:"SAR", Param:{ Count:3 }, ToString:function(args) { return `步长为${args[1]}极限值为${args[0]}的${args[2]}日抛物转向`; } } ],
            ["SARTURN", { Name:"SARTURN", Param:{ Count:3 }, ToString:function(args) { return `步长为${args[1]}极限值为${args[0]}的${args[2]}日抛物转向点`; } } ],

            //字符串函数
            ["CON2STR", { Name:"CON2STR", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}转为字符串`; } } ],
            ["VAR2STR", { Name:"VAR2STR", Param:{ Count:2 }, ToString:function(args) { return `${args[0]}转为字符串`; } } ],
            ["STR2CON", { Name:"STR2CON", Param:{ Count:1 }, ToString:function(args) { return `${args[0]}转为数字`; } } ],
            ["STRLEN", { Name:"STRLEN", Param:{ Count:1 }, ToString:function(args) { return `得到${args[0]}字符串长度`; } } ],
            ["STRCAT", { Name:"STRCAT", Param:{ Count:2 }, ToString:function(args) { return `字符串相加`; } } ],
            ["VARCAT", { Name:"VARCAT", Param:{ Count:2 }, ToString:function(args) { return `字符串相加`; } } ],
            ["STRSPACE", { Name:"STRSPACE", Param:{ Count:1 }, ToString:function(args) { return `字符串${args[0]}加一空格`; } } ],
            ["SUBSTR", { Name:"SUBSTR", Param:{ Count:3 }, ToString:function(args) { return `字符串${args[0]}中取一部分`; } } ],
            ["STRCMP", { Name:"STRCMP", Param:{ Count:2 }, ToString:function(args) { return `字符串${args[0]}和字符串${args[1]}比较`; } } ],
            ["FINDSTR", { Name:"FINDSTR", Param:{ Count:2 }, ToString:function(args) { return `字符串${args[0]}中查找字符串${args[1]}`; } } ],
            ["NAMEINCLUD", { Name:"NAMEINCLUD", Param:{ Count:1 }, ToString:function(args) { return `查找品种名称中包含${args[0]}`; } } ],
            ["CODELIKE", { Name:"CODELIKE", Param:{ Count:1 }, ToString:function(args) { return `查找品种名称中包含${args[0]}`; } } ],
            ["INBLOCK", { Name:"AVEDEV", Param:{ Count:1 }, ToString:function(args) { return `属于${args[0]}板块`; } } ],
            

            [
                "HHVBARS", 
                { 
                    Name:"HHVBARS", Param:{ Count:2 }, 
                    ToString:function(args) 
                    { 
                        if (args[1]==0) return `历史${args[0]}新高距今天数`;
                        return `${args[1]}日内${args[0]}新高距今天数`;
                    } 
                } 
            ],

            [
                "LLVBARS", 
                { 
                    Name:"LLVBARS", Param:{ Count:2 }, 
                    ToString:function(args) 
                    { 
                        if (args[1]==0) return `历史${args[0]}新低距今天数`;
                        return `${args[1]}日内${args[0]}新低距今天数`; 
                    } 
                } 
            ]
        ]
    );

    this.CallFunctionExplain=function(funcName, args, node)
    {
        if (this.FUNCTION_INFO_LIST.has(funcName))
        {
            var item=this.FUNCTION_INFO_LIST.get(funcName);
            if (item.Param.Count!=args.length)
                this.ThrowUnexpectedNode(node,`函数${funcName}参数个数不正确. 需要${item.Param.Count}个参数`);
            return item.ToString(args);
        }

        switch(funcName)
        {
            case "CALCSTOCKINDEX":
                return `引用${args[0]}的${args[1]}指标第${args[2]}个输出值`;
            
            case "PEAK":
            case "PEAKBARS":
            case "ZIG":
            case "ZIGA":
            case "TROUGH":
            case "TROUGHBARS":
                return this.GetZIGExplain(funcName,args);

            case "FINANCE":
                return this.GetFinanceExplain(args);
            case "DYNAINFO":
                return this.GetDynainfoExplain(args);
            

            case 'CLOSE':
            case 'C':
            case 'VOL':
            case 'V':
            case 'OPEN':
            case 'O':
            case 'HIGH':
            case 'H':
            case 'LOW':
            case 'L':
            case 'AMOUNT':
            case 'AMO':
                return this.GetOtherSymbolExplain( {FunctionName:funcName, Args:args} ,node);


            //绘图函数
            case "PLOYLINE":
                return `当满足条件${args[0]}时以${args[1]}位置为顶点画折线连接`;
            case "DRAWLINE":
                return `当满足条件${args[0]}时,在${args[1]}位置画直线起点，当满足条件${args[2]}时,在${args[3]}位置画直线终点,${args[4]}表示是否延长`;
            case "DRAWSL":
                return `当满足条件${args[0]}时,在${args[1]}位置画斜线线性回归,${args[2]}斜率,${args[3]}长度,${args[4]}方向`;
            case "DRAWKLINE":
            case "DRAWKLINE1":
                return 'K线';
            case "DRAWICON":
                return `当满足条件${args[0]}时,在${args[1]}位置画${args[2]}号图标`;
            case "DRAWTEXT":
                return `当满足条件${args[0]}时,在${args[1]}位置书写文字`;
            case "DRAWTEXT_FIX":
                return `当满足条件${args[0]}时,在横轴${args[1]}纵轴${args[2]}位置书写文字`;
            case "DRAWNUMBER":
                return `当满足条件${args[0]}时,在${args[1]}位置书写数字`;
            case "DRAWNUMBER_FIX":
                return `当满足条件${args[0]}时,在横轴${args[1]}纵轴${args[2]}位置书写数字`;
            case "RGB":
                return `自定色[${args[0]},${args[1]},${args[2]}]`;
            case "DRAWBAND":
                return '画带状线';
            case "DRAWRECTREL":
                return "相对位置上画矩形.";
            case "DRAWGBK":
                return "填充背景";
            case "STICKLINE":
                var barType="";
                if (args[4]==-1) barType="虚线空心柱";
                else if (args[4]==0) barType="实心柱";
                else barType="实线空心柱";
                return `当满足条件${args[0]}时, 在${args[1]}和${args[2]}位置之间画柱状线,宽度为${args[3]},${barType}`;

            default:
                this.ThrowUnexpectedNode(node,`函数${funcName}不存在`);
        }
    }

    this.GetDynainfoExplain=function(args)
    {
        const DATA_NAME_MAP=new Map(
        [
            [3,"前收盘价"], [4,"开盘价"], [5,"最高价"], [6,"最低价"], [7,"现价"], [8,'总量'], [9,"现量"],
            [10,"总金额"], [11,"均价"], [12,"日涨跌"], [13,"振幅"], [14,"涨幅"], [15,"开盘时的成交金额"],
            [16,"前5日每分钟均量"], [17,"量比"], [18,"上涨家数"], [19,"下跌家数"]
        ]);

        var id=args[0];
        if (DATA_NAME_MAP.has(id)) return DATA_NAME_MAP.get(id);

        return `即时行情[${id}]`;
    }

    this.GetFinanceExplain=function(args)
    {
        const DATA_NAME_MAP=new Map(
        [
            [1,"总股本"], [2,"市场类型"], [3,"沪深品种类型"], [4,"沪深行业代码"], [5,"B股"], [6,"H股"], [7,"流通股本[股]"], [8,"股东人数[户]"], [9,"资产负债率%"],
            [10,"总资产"], [11,"流动资产"], [12,"固定资产"], [13,"无形资产"], [15,"流动负债"], [16,"少数股东权益"]
            
        ]);
        var id=args[0];

        if (DATA_NAME_MAP.has(id)) return DATA_NAME_MAP.get(id);

        return `财务数据[${id}]`;
    }

    this.GetZIGExplain=function(funcName,args)
    {
        var value=args[0];
        if (value==0) value="开盘价";
        else if (value==1) value="最高价";
        else if (value==2) value="最低价";
        else if (value==3) value="收盘价";

        switch(funcName)
        {
        case "PEAK":
            return `${value}的${args[1]}%之字转向的前${args[2]}个波峰值`;
        case "PEAKBARS":
            return `${value}的${args[1]}5%之字转向的前${args[2]}个波峰位置`;
        case "ZIG":
            return `${value}的${args[1]}的之字转向`;
        case "ZIGA":
            return `${value}变化${args[1]}的之字转向`;
        case "TROUGH":
            return `${value}的${args[1]}%之字转向的前${args[2]}个波谷值`;
        case "TROUGHBARS":
            return `${value}的${args[1]}%之字转向的前${args[2]}个波谷位置`;
        }
    }

    this.GetColorExplain=function(colorName)
    {
        const COLOR_MAP=new Map(
        [
            ['COLORBLACK','黑色'],['COLORBLUE','蓝色'],['COLORGREEN','绿色'],['COLORCYAN','青色'],['COLORRED','红色'],
            ['COLORMAGENTA','洋红色'],['COLORBROWN','棕色'],['COLORLIGRAY','淡灰色'],['COLORGRAY','深灰色'],['COLORLIBLUE','淡蓝色'],       
            ['COLORLIGREEN','淡绿色'],['COLORLICYAN','淡青色'],['COLORLIRED','淡红色'],['COLORLIMAGENTA','淡洋红色'],['COLORWHITE','白色'],['COLORYELLOW','黄色']
        ]);

        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)';
    }

    this.GetLineWidthExplain=function(lineWidth)
    {
        var width=parseInt(lineWidth.replace("LINETHICK",""));
        if (IFrameSplitOperator.IsPlusNumber(width)) return width;
        return 1;
    }

    this.SymbolPeriodExplain=function(valueName,period)
    {
        const mapStockDataName=new Map(
        [
            ['CLOSE',"收盘价"],["C","收盘价"],['VOL',"成交量"],['V',"成交量"], ['OPEN',"开盘价"], ['O',"开盘价"], 
            ['HIGH',"最高价"],['H',"最高价"], ['LOW',"最低价"],['L',"最低价"],['AMOUNT',"成交金额"],['AMO',"成交金额"], 
            ['VOLINSTK',"持仓量"]
        ]);
        //MIN1,MIN5,MIN15,MIN30,MIN60,DAY,WEEK,MONTH,SEASON,YEAR
        const mapPeriodName=new Map(
        [
            ["MIN1","1分钟"], ["MIN5", "5分钟"], ["MIN15", "15分钟"], ["MIN30","30分钟"],["MIN60","60分钟"],
            ["DAY","日"],["WEEK","周"], ["MONTH", "月"], ['SEASON',"季"], ["YEAR", "年"],["WEEK2","双周"], ["HALFYEAR", "半年"]
        ]);

        var dataName=valueName;
        if (mapStockDataName.has(valueName)) dataName=mapStockDataName.get(valueName);

        var periodName=period;
        if (mapPeriodName.has(period)) periodName=mapPeriodName.get(period);

        return `${dataName}[取${periodName}数据]`;
    }

    this.GetOtherSymbolExplain=function(obj, node)
    {
        const mapStockDataName=new Map(
        [
            ['CLOSE',"收盘价"],["C","收盘价"],['VOL',"成交量"],['V',"成交量"], ['OPEN',"开盘价"], ['O',"开盘价"], 
            ['HIGH',"最高价"],['H',"最高价"], ['LOW',"最低价"],['L',"最低价"],['AMOUNT',"成交金额"],['AMO',"成交金额"], 
            ['VOLINSTK',"持仓量"]
        ]);
            
        if (obj.FunctionName)
        {
            var args=obj.Args;
            var dataName=mapStockDataName.get(obj.FunctionName);
            return `[${args[0]}]${dataName}`;
        }
        else if (obj.Literal)
        {
            var value=obj.Literal.toUpperCase();
            var args=value.split("$");
            if (!mapStockDataName.has(args[1])) return "";
            var symbol=args[0];
            var dataName=mapStockDataName.get(args[1]);
            return `[${symbol}]${dataName}`;
        }
    }

    this.IsDrawFunction=function(name)
    {
        let setFunctionName=new Set(
        [
            "STICKLINE","DRAWTEXT",'SUPERDRAWTEXT','DRAWLINE','DRAWBAND','DRAWKLINE',"DRAWKLINE1",'DRAWKLINE_IF','PLOYLINE',
            'POLYLINE','DRAWNUMBER',"DRAWNUMBER_FIX",'DRAWICON','DRAWCHANNEL','PARTLINE','DRAWTEXT_FIX','DRAWGBK','DRAWTEXT_LINE','DRAWRECTREL',"DRAWTEXTABS",
            'DRAWOVERLAYLINE',"FILLRGN", "FILLRGN2","FILLTOPRGN", "FILLBOTTOMRGN", "FILLVERTICALRGN","FLOATRGN","DRAWSL", "DRAWGBK2"
        ]);
        if (setFunctionName.has(name)) return true;
    
        return false;
    }

    //赋值
    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;
            if (IFrameSplitOperator.IsString(value) && right.Value.indexOf("$")>0)
                value=this.GetOtherSymbolExplain({ Literal:value }, node);
        }
        else if (right.Type==Syntax.Identifier) //右值是变量
            value=this.ReadVariable(right.Name,right);
        else if (right.Type==Syntax.MemberExpression)
            value=this.ReadMemberVariable(right);
        else if (right.Type==Syntax.UnaryExpression)
        {
            if (right.Operator=='-') 
            {
                var tempValue=this.GetNodeValue(right.Argument);
                value='-'+tempValue;
            }
            else 
            {
                value=right.Argument.Value;
            }
        }

        JSConsole.Complier.Log('[JSExplainer::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);

                    JSConsole.Complier.Log('[JSExplainer::VisitBinaryExpression] BinaryExpression',value , leftValue, rightValue);
                    value.Out=null; //保存中间值

                    value.Out=`(${leftValue} ${value.Operator} ${rightValue})`;
                    if (leftValue=="收盘价" && rightValue=="开盘价") 
                    {
                        if (value.Operator==">") value.Out='(收阳线)';
                        else if (value.Operator=="<") value.Out='(收阴线)';
                        else if (value.Operator=="=") value.Out='(平盘)';
                    }
                    else if (leftValue=="开盘价" && rightValue=="收盘价")
                    {
                        if (value.Operator=="<") value.Out='(收阳线)';
                        else if (value.Operator==">") value.Out='(收阴线)';
                        else if (value.Operator=="=") value.Out='(平盘)';
                    }
                        
                    JSConsole.Complier.Log('[JSExplainer::VisitBinaryExpression] BinaryExpression',value);
                }
                else if (value.Type==Syntax.LogicalExpression)
                {
                    let leftValue=this.GetNodeValue(value.Left);
                    let rightValue=this.GetNodeValue(value.Right);

                    JSConsole.Complier.Log('[JSExecute::VisitBinaryExpression] LogicalExpression',value , leftValue, rightValue);
                    value.Out=null; //保存中间值

                    switch(value.Operator)
                    {
                        case '&&':
                        case 'AND':
                            value.Out=`(${leftValue} 并且 ${rightValue})`;
                            break;
                        case '||':
                        case 'OR':
                            value.Out=`(${leftValue} 或者 ${rightValue})`;
                            break;
                    }

                    JSConsole.Complier.Log('[JSExplainer::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 '-'+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.ReadVariable=function(name,node)
    {
        if (this.ConstVarTable.has(name)) 
        {
            let data=this.ConstVarTable.get(name);
            return data;
        }

        if (g_JSComplierResource.IsCustomVariant(name)) return this.ReadCustomVariant(name,node); //读取自定义变量

        if (this.VarTable.has(name)) return this.VarTable.get(name);

        if (name.indexOf('#')>0)
        {
            var aryPeriod=name.split('#');
            return this.SymbolPeriodExplain(aryPeriod[0],aryPeriod[1]);
        }

        this.ThrowUnexpectedNode(node, '变量'+name+'不存在');
        return name;
    }

    this.ThrowUnexpectedNode=function(node,message)
    {
        let marker=node.Marker;
        let msg=message || "执行异常";
       
        return this.ErrorHandler.ThrowError(marker.Index,marker.Line,marker.Column,msg);
       
    }

    this.ThrowError=function()
    {

    }
}

//对外导出类
function JSComplier()
{
    
}


//词法分析
JSComplier.Tokenize=function(code)
{
    JSConsole.Complier.Log('[JSComplier.Tokenize]', code);
    let tokenizer=new Tokenizer(code);
    let tokens=[];
    try
    {
        while(true)
        {
            let token=tokenizer.GetNextToken();
            if (!token) break;

            tokens.push(token);
        }
    }
    catch(e)
    {

    }

    return tokens;
}

//语法解析 生成抽象语法树(Abstract Syntax Tree)
JSComplier.Parse=function(code)
{
    JSConsole.Complier.Log('[JSComplier.Parse]',code);

    let parser=new JSParser(code);
    parser.Initialize();
    let program=parser.ParseScript();
    let ast=program;
    return ast;
}

/*
    执行
    option.Symbol=股票代码
    option.Name=股票名称
    option.Data=这个股票的ChartData
    option.Right=复权
    option.MaxReqeustDataCount=请求数据的最大个数
*/

function timeout(ms) {
    return new Promise((resolve) => {
      setTimeout(resolve, ms);
    });
  }

  
JSComplier.Execute=function(code,option,errorCallback)
{
    //异步调用
    //var asyncExecute= async function() es5不能执行 去掉异步
    var asyncExecute= function()
    {
        try
        {
            if (option.Self) option.Self.Status=1;
            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);

            if (option.Self) option.Self.Status=2;
            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});

            if (option.Self) option.Self.Status=3;
            let result=execute.Execute();
            
        }catch(error)
        {
            JSConsole.Complier.Log(error);
            if (errorCallback) errorCallback(error, option.CallbackParam);
            if (option.Self) option.Self.Status=0;
        }
    }

    asyncExecute();

    JSConsole.Complier.Log('[JSComplier.Execute] async execute.');
}

JSComplier.Explain=function(code,option, errorCallback)
{
    //异步调用
    //var asyncExecute= async function() es5不能执行 去掉异步
    var asyncExplain= function()
    {
        try
        {
            JSConsole.Complier.Log('[JSComplier.Explain]',code,option);

            JSConsole.Complier.Log('[JSComplier.Explain] parser .....');
            let parser=new JSParser(code);
            parser.Initialize();
            let program=parser.ParseScript(); 
            
            let ast=program;
            JSConsole.Complier.Log('[JSComplier.Explain] parser finish.', ast);

            JSConsole.Complier.Log('[JSComplier.Explain] explain .....');
            let execute=new JSExplainer(ast,option);
            execute.ErrorCallback=errorCallback;            //执行错误回调
            execute.JobList=parser.Node.GetDataJobList();
            execute.JobList.push({ID:JS_EXECUTE_JOB_ID.JOB_RUN_SCRIPT});
            let result=execute.Run();

        }catch(error)
        {
            JSConsole.Complier.Log(error);

            if (errorCallback) errorCallback(error, option.CallbackParam);
        }
    }

    asyncExplain();

    JSConsole.Complier.Log('[JSComplier.Explain] async explain.');
}


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)    //添加函数 { Name:函数名, Description:描述信息, IsDownload:是否需要下载数据, Invoke:函数执行(可选) }
{
    if (!obj || !obj.Name) return;

    var ID=obj.Name.toUpperCase();
    g_JSComplierResource.CustomFunction.Data.set(ID, obj);
}

JSComplier.AddVariant=function(obj) //{ Name:变量名, Description:描述信息 }
{
    if (!obj || !obj.Name) return;

    var ID=obj.Name.toUpperCase();
    g_JSComplierResource.CustomVariant.Data.set(ID, obj);
}

JSComplier.ColorVarToRGB=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+“BBGGRR”：BB、GG、RR表示蓝色、绿色和红色的分量，每种颜色的取值范围是00-FF，采用了16进制。
    //例如：MA5:MA(CLOSE,5)，COLOR00FFFF表示纯红色与纯绿色的混合色：COLOR808000表示淡蓝色和淡绿色的混合色。
    if (colorName.indexOf('COLOR')!=0) return null;

    var strColor=colorName.substr(5);
    if (strColor.length!=6) return null;

    var value=strColor.substr(0,2);
    var b=parseInt(value,16);
    value=strColor.substr(2,2);
    var g=parseInt(value,16);
    value=strColor.substr(4,2);
    var r=parseInt(value,16);
    
    return `rgb(${r},${g},${b})`;
}

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.ClassName="ScriptIndex";
    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.OutName=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;                        //是否显示指标参数
    this.IsUsePageData=false;                       //是否使用了K线界面数据                       

    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.OutName) this.OutName=option.OutName;
    }

    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.CopyTo=function(dest)   //赋值到新实例出来
    {
        dest.FloatPrecision=this.FloatPrecision;
        dest.StringFormat=this.StringFormat;
        dest.KLineType=this.KLineType;
        dest.InstructionType=this.InstructionType;
        dest.Condition=this.Condition;
        dest.TitleFont=this.TitleFont;
        dest.IsShortTitle=this.IsShortTitle;
        dest.OutName=this.OutName;

        dest.Arguments=this.Arguments;
        dest.Script=this.Script;
        dest.Name=this.Name;
    }

    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,
            IsApiPeriod:hqChart.IsApiPeriod,
            DrawInfo:null,
            Self:this,
        };

        if (hqChart)    //当前屏K线信息
        {
            if (hqChart.ChartPaint[0]) 
            {
                var item=hqChart.ChartPaint[0];
                if (item && item.DrawKRange) option.DrawInfo={Start:item.DrawKRange.Start, End:item.DrawKRange.End };
            }
        }

        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;
            if (!this.IsMeetIncludeCondition(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_TWOWEEK_ID:
                case CONDITION_PERIOD.KLINE_QUARTER_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.IsMeetIncludeCondition=function(param,option)
    {
        if (!this.Condition.Include || this.Condition.Include.length<=0) return true;

        var symbol=param.HQChart.Symbol;
        if (symbol) symbol=symbol.toUpperCase();
        for(var i in this.Condition.Include)
        {
            var item=this.Condition.Include[i];
            if (symbol==item) return true;
        }
        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;
        if (varItem.IsShowTitle===false)    //NOTEXT 不绘制标题
        {

        }
        else if (IFrameSplitOperator.IsString(varItem.Name) && varItem.Name.indexOf("NOTEXT")==0) //标题中包含NOTEXT不绘制标题
        {

        }
        else
        {
            if (varItem.NoneName) 
                hqChart.TitlePaint[titleIndex].Data[id]=new DynamicTitleData(line.Data,null,line.Color);
            else
                hqChart.TitlePaint[titleIndex].Data[id]=new DynamicTitleData(line.Data,varItem.Name,line.Color);
        }
        
        hqChart.ChartPaint.push(line);
    }

    this.CreateOverlayLine=function(hqChart,windowIndex,varItem,id)
    {
        let line=new ChartSubLine();
        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.Width=varItem.Draw.Width;
        else bar.Width=0;

        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,resource)
    {
        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;
        chartText.ReloadResource();

        if (varItem.Color) chartText.Color=this.GetColor(varItem.Color);
        else chartText.Color=this.GetDefaultColor(id);
        if (varItem.IsDrawCenter===true) chartText.TextAlign='center';
        if (varItem.IsDrawAbove===true) chartText.Direction=1;
        if (varItem.IsDrawBelow===true) chartText.Direction=2;

        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;

        if (varItem.DrawVAlign>=0)
        {
            if (varItem.DrawVAlign==0) chartText.Direction=1;
            else if (varItem.DrawVAlign==1) chartText.Direction=0;
            else if (varItem.DrawVAlign==2) chartText.Direction=2;
        }

        if (varItem.DrawAlign>=0)
        {
            if (varItem.DrawAlign==0) chartText.TextAlign="left";
            else if (varItem.DrawAlign==1) chartText.TextAlign="center";
            else if (varItem.DrawAlign==2) chartText.TextAlign='right';
        }

        if (varItem.DrawFontSize>0) chartText.FixedFontSize=varItem.DrawFontSize;
        
        //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;
        if (varItem.LineWidth) 
        {
            var width=parseInt(varItem.LineWidth.replace("LINETHICK",""));
            if (!isNaN(width) && width>0) chartMACD.LineWidth=width;
        }

        let titleIndex=windowIndex+1;
        chartMACD.Data.Data=varItem.Data;
        var clrTitle=this.GetDefaultColor(id);
        if (varItem.Color) clrTitle=this.GetColor(varItem.Color);
        hqChart.TitlePaint[titleIndex].Data[id]=new DynamicTitleData(chartMACD.Data,varItem.Name,clrTitle);

        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;

        if (varItem.Name=="DRAWLINE") 
            hqChart.TitlePaint[titleIndex].Data[id]=new DynamicTitleData(line.Data,null,line.Color);

        //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);
    }

    this.CreateFillRGN=function(hqChart,windowIndex,varItem,id)
    {
        let chart=new ChartLineArea();
        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;
        if (varItem.Color) chart.Color=this.GetColor(varItem.Color);
        else chart.Color=this.GetDefaultColor(id);

        hqChart.ChartPaint.push(chart);
    }

    this.CreateFillRGN2=function(hqChart,windowIndex,varItem,id)
    {
        let chart=new ChartFillRGN();
        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.CreateFillBGRGN=function(hqChart,windowIndex,varItem,id)
    {
        let chart=new ChartFillBGRGN();
        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.CreateFLOATRGN=function(hqChart,windowIndex,varItem,id)
    {
        let chart=new ChartFLOATRGN();
        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);
    }

    //创建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.CreateDrawColorKLine=function(hqChart,windowIndex,varItem,i)
    {
        let chart=new ChartColorKline();
        chart.Canvas=hqChart.Canvas;
        chart.Name=varItem.Name;
        chart.DrawName="DRAWCOLORKLINE";
        chart.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder;
        chart.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame;

        chart.Data.Data=varItem.Draw.DrawData;
        if (IFrameSplitOperator.IsBool(varItem.Draw.IsEmptyBar)) chart.IsEmptyBar=varItem.Draw.IsEmptyBar;
        if (varItem.Draw.Color) chart.Color=varItem.Draw.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.IsDotLine) line.IsDotLine=true; //虚线

        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.CreateChartSlopeLine=function(hqChart,windowIndex,varItem,id)
    {
        let line=new ChartSlopeLine();
        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.IsDotLine) line.IsDotLine=true; //虚线

        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.Data;
        line.Option=varItem.Draw.DrawData.Option;
        hqChart.TitlePaint[titleIndex].Data[id]=new DynamicTitleData(line.Data,null,line.Color); //给一个空的标题

        hqChart.ChartPaint.push(line);
    }

    this.CreateChartVericaltLine=function(hqChart,windowIndex,varItem,id)
    {
        var chart=new ChartVericaltLine();
        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;
        }

        this.SetChartLineDash(chart,varItem.Draw.DrawData);
        chart.Data.Data=varItem.Draw.DrawData.Data;

        hqChart.ChartPaint.push(chart);
    }

    this.SetChartLineDash=function(chart, option)
    {
        if (IFrameSplitOperator.IsNumber(option.LineType))
        {
            var lineType=option.LineType;
            var pixelRatio=GetDevicePixelRatio();
            switch(lineType)
            {
                case 1:
                    chart.LineType=[10*pixelRatio,10*pixelRatio];
                    break;
                case 2:
                    chart.LineType=[0,10*pixelRatio];
                    chart.LineCap="square";
                    break;
                case 3:
                    chart.LineType=[10*pixelRatio, 3*pixelRatio, 3*pixelRatio, 3*pixelRatio];
                    break;
                case 4:
                    chart.LineType=[10*pixelRatio, 3*pixelRatio, 3*pixelRatio, 3*pixelRatio,3*pixelRatio,3*pixelRatio];
                    break;
            }
        }
        else if (IFrameSplitOperator.IsString(option.LineType))
        {
            var aryString=option.LineType.split(',');
            var aryLinType=[];
            for(var i=0;i<aryString.length;++i)
            {
                aryLinType.push(parseInt(aryString[i]));
            }
            chart.LineType=aryLinType;
        }
    }

    this.CreateChartHorizontalLine=function(hqChart,windowIndex,varItem,id)
    {
        var chart=new ChartHorizontalLine();
        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;
        }

        this.SetChartLineDash(chart,varItem.Draw.DrawData);
        chart.ExtendType=varItem.Draw.DrawData.Extend;
        chart.Data.Data=varItem.Draw.DrawData.Data;

        hqChart.ChartPaint.push(chart);
    }


    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;

            if (drawData.Data) chart.Data.Data=drawData.Data;
        }

        hqChart.ChartPaint.push(chart);
    }

    this.CreateLineMultiData=function(hqChart,windowIndex,varItem,id)
    {
        let chart=new ChartLineMultiData();
        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;
            if (drawData.PointColor)  chart.PointColor=drawData.PointColor;
            if (IFrameSplitOperator.IsPlusNumber(drawData.PointRadius)) chart.PointRadius=drawData.PointRadius;
            if (IFrameSplitOperator.IsPlusNumber(drawData.LineWidth)) chart.LineWidth=drawData.LineWidth;
            if (drawData.Data) chart.Data.Data=drawData.Data;
        }

        let titleIndex=windowIndex+1;
        var titleData=new DynamicTitleData(chart.Data,varItem.Name,chart.Color); //标题
        titleData.DataType="MULTI_POINT_LINE";
        hqChart.TitlePaint[titleIndex].Data[id]=titleData;

        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;
        chartText.ReloadResource();
        chartText.TextAlign="center";
        
        if (varItem.Color) chartText.Color=this.GetColor(varItem.Color);
        else chartText.Color=this.GetDefaultColor(id);
        if (varItem.IsDrawAbove) chartText.Direction=1;
        else chartText.Direction=2;

        if (varItem.Draw.Position) chartText.Position=varItem.Draw.Position;    //赋值坐标

        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.CreateDrawText=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;
        chartText.ReloadResource();
        
        if (varItem.Color) chartText.Color=this.GetColor(varItem.Color);
        else chartText.Color=this.GetDefaultColor(id);
        if (varItem.IsDrawAbove) chartText.Direction=1;
        else chartText.Direction=0;

        let titleIndex=windowIndex+1;
        chartText.DrawData=varItem.Draw.DrawData;
        //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;
        chartText.Direction=2;
        if (varItem.IsDrawAbove) chartText.Direction=1;

        if (varItem.DrawVAlign>=0)
        {
            if (varItem.DrawVAlign==0) chartText.Direction=1;
            else if (varItem.DrawVAlign==1) chartText.Direction=0;
            else if (varItem.DrawVAlign==2) chartText.Direction=2;
        }

        if (varItem.DrawAlign>=0)
        {
            if (varItem.DrawAlign==0) chartText.TextAlign="left";
            else if (varItem.DrawAlign==1) chartText.TextAlign="center";
            else if (varItem.DrawAlign==2) chartText.TextAlign='right';
        }

        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 };
            if (varItem.Color) chartText.IconFont.Color=this.GetColor(varItem.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)';
        }

        if (varItem.DrawFontSize>0) chartText.FixedFontSize=varItem.DrawFontSize;
        
        //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; 
        if (varItem.Draw.LineDash) chart.LineDash=varItem.Draw.LineDash;
        if (IFrameSplitOperator.IsNumber(varItem.Draw.LineWidth)) chart.LineWidth=varItem.Draw.LineWidth;
        if(varItem.Draw.Arrow)  //箭头配置
        {
            var item=varItem.Draw.Arrow;
            if (item.Start==true) chart.Arrow.Start=true;
            if (item.End==true) chart.Arrow.End=true;
            if (IFrameSplitOperator.IsNumber(item.Angle)) chart.ArrawAngle=item.Angle;
            if (IFrameSplitOperator.IsNumber(item.Length)) chart.ArrawLength=item.Length;
            if (IFrameSplitOperator.IsNumber(item.LineWidth)) chart.ArrawLineWidth=item.LineWidth;
        }
        hqChart.ChartPaint.push(chart);
    }

    this.CreateMultiBar=function(hqChart,windowIndex,varItem,id)
    {
        let chart=new ChartMultiBar();
        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.Bars=varItem.Draw.DrawData; 

        var titleIndex=windowIndex+1;
        var titleData=new DynamicTitleData({ KData:chart.Data, BarData:chart.Bars },varItem.Name,null);
        titleData.IsShow=false;
        titleData.DataType="MULTI_BAR";
        hqChart.TitlePaint[titleIndex].Data[id]=titleData;

        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.CreateMulitHtmlDom=function(hqChart,windowIndex,varItem,i)
    {
        let chart=new ChartMultiHtmlDom();
        chart.Canvas=hqChart.Canvas;
        chart.Name=varItem.Name;
        chart.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder;
        chart.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame;
        chart.HQChart=hqChart;

        chart.Data=hqChart.ChartPaint[0].Data;//绑定K线
        chart.Texts=varItem.Draw.DrawData;
        chart.DrawCallback= varItem.Draw.Callback;
        hqChart.ChartPaint.push(chart);
    }

    this.CreateColorKLine=function(hqChart,windowIndex,varItem,i)
    {
        let chart=new ChartColorKline();
        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.KLineColor= varItem.Draw.DrawData.KLine;
        if (varItem.Color) chart.Color=varItem.Color;
        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);
    }

    this.CreateScriptOverlayLine=function(hqChart,windowIndex,varItem,i)
    {
        let chart=new ChartOverlayLine();
        chart.Canvas=hqChart.Canvas;
        chart.DrawType=1;
        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(i);

        if (varItem.LineWidth) 
        {
            let width=parseInt(varItem.LineWidth.replace("LINETHICK",""));
            if (!isNaN(width) && width>0) chart.LineWidth=width;
        }

        if (varItem.IsDotLine) chart.IsDotLine=true; //虚线
        if (varItem.IsShow==false) chart.IsShow=false;

        let titleIndex=windowIndex+1;
        chart.Data.Data=varItem.Draw.DrawData.Data;
        chart.MainData.Data=varItem.Draw.DrawData.MainData;

        if (varItem.Draw.DrawData.Title)
            hqChart.TitlePaint[titleIndex].Data[i]=new DynamicTitleData(chart.Data,varItem.Draw.DrawData.Title,chart.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;

        //参数
        var 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) indexParam='('+indexParam+')';

        if (this.InstructionType==2)        //五彩K线
        {
            let varItem=this.OutVar[this.OutVar.length-1]; //取最后一组数据作为指示数据
            hqChart.SetInstructionData(this.InstructionType, {Data:varItem.Data, Name:this.Name, Param:indexParam, 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, Param:indexParam, 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==1000 || item.Type==1001) continue;      //数据集合, 字符串

            if (item.Type==0)  
            {
                if (item.IsOverlayLine) this.CreateOverlayLine(hqChart,windowIndex,item,i);
                else 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':
                        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 "FILLRGN":
                        this.CreateFillRGN(hqChart,windowIndex,item,i);
                        break;
                    case "FILLRGN2":
                        this.CreateFillRGN2(hqChart,windowIndex,item,i);
                        break;
                    case "FILLTOPRGN":
                    case "FILLBOTTOMRGN":
                    case "FILLVERTICALRGN":
                        this.CreateFillBGRGN(hqChart,windowIndex,item,i);
                        break;
                    case "FLOATRGN":
                        this.CreateFLOATRGN(hqChart,windowIndex,item,i);
                        break;
                    case 'DRAWKLINE':
                    case "DRAWKLINE1":
                        this.CreateKLine(hqChart,windowIndex,item,i);
                        break;
                    case "DRAWCOLORKLINE":
                        this.CreateDrawColorKLine(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':
                    case "DRAWGBK2":
                        this.CreateBackgroud(hqChart,windowIndex,item,i);
                        break;
                    case 'DRAWTEXT_LINE':
                        this.CreateTextLine(hqChart,windowIndex,item,i);
                        break;
                    case 'DRAWNUMBER':
                    case "DRAWNUMBER_FIX":
                    case 'DRAWTEXT_FIX':
                        this.CreateNumberText(hqChart,windowIndex,item,i);
                        break;
                    case 'DRAWICON':
                        this.CreateIcon(hqChart,windowIndex,item,i);
                        break;
                    case "ICON":
                        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 "DRAWTEXTABS":
                    case "DRAWTEXTREL":
                        this.CreateDrawText(hqChart,windowIndex,item,i);
                        break;
                    case "DRAWOVERLAYLINE":
                        this.CreateScriptOverlayLine(hqChart,windowIndex,item,i);
                        break;
                    case "DRAWSL":
                        this.CreateChartSlopeLine(hqChart,windowIndex,item,i);
                        break;
                    case "VERTLINE":
                        this.CreateChartVericaltLine(hqChart,windowIndex,item,i);
                        break;
                    case "HORLINE":
                        this.CreateChartHorizontalLine(hqChart,windowIndex,item,i);
                        break;
                    case 'MULTI_LINE':
                        this.CreateMultiLine(hqChart,windowIndex,item,i);
                        break;
                    case 'MULTI_BAR':
                        this.CreateMultiBar(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;
                    case "MULTI_HTMLDOM":
                        this.CreateMulitHtmlDom(hqChart,windowIndex,item,i);
                        break;
                    case "COLOR_KLINE":
                        this.CreateColorKLine(hqChart,windowIndex,item,i);
                        break;
                    case "KLINE_BG":
                        this.CreateBackgroud(hqChart,windowIndex,item,i);
                        break;
                    case "MULTI_POINT_LINE":
                        this.CreateLineMultiData(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;

                if (this.OutName && this.OutName.length>0 && this.Arguments && this.Arguments.length>0)
                {
                    titlePaint.SetDynamicTitle(this.OutName,this.Arguments);
                }
            }
        }

        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)
    {
        if (colorName.indexOf("RGB(")==0) return colorName.toLowerCase();
        if (colorName.indexOf("rgb(")==0) return colorName;
        if (colorName.indexOf("RGBA(")==0) return colorName.toLowerCase();
        if (colorName.indexOf("rgba(")==0) return colorName;


        var color=JSComplier.ColorVarToRGB(colorName);
        if (color) return color;

        return 'rgb(30,144,255)';

        /*
        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.ClassName="OverlayScriptIndex";
    //叠加指标
    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;    //给子框架设置标题
        if (this.OutName && this.OutName.length>0 && this.Arguments && this.Arguments.length>0)
        {
            titlePaint.SetDynamicTitle(this.OutName,this.Arguments, this.OverlayIndex.Identify);
        }

        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':
                        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':
                    case "DRAWNUMBER_FIX":  
                    case 'DRAWTEXT_FIX':  
                        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 'DRAWTEXT_LINE':
                        this.CreateTextLine(hqChart,windowIndex,item,i);
                        break;
                    case "VERTLINE":
                        this.CreateChartVericaltLine(hqChart,windowIndex,item,i);
                        break;
                    case "HORLINE":
                        this.CreateChartHorizontalLine(hqChart,windowIndex,item,i);
                        break;

                    case 'MULTI_LINE':
                        this.CreateMultiLine(hqChart,windowIndex,item,i);
                        break;
                    case 'MULTI_BAR':
                        this.CreateMultiBar(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;
                    case "MULTI_HTMLDOM":
                        this.CreateMulitHtmlDom(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) chart.LineWidth=width;
        }

        if (varItem.IsShow==false) chart.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.Width=varItem.Draw.Width;
        else chart.Width=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, drawName)
    {
        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;
        chart.ReloadResource();

        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];
        var clrTitle=this.GetDefaultColor(id);
        if (varItem.Color) clrTitle=this.GetColor(varItem.Color);
        titlePaint.OverlayIndex.get(overlayIndex.Identify).Data[id]=new DynamicTitleData(chart.Data,varItem.Name,clrTitle);

        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;
        chart.ReloadResource();

        chart.TextAlign="center";
        if (varItem.Color) chart.Color=this.GetColor(varItem.Color);
        else chart.Color=this.GetDefaultColor(id);
        if (varItem.IsDrawAbove) chart.Direction=1;
        else chart.Direction=2;

        if (varItem.Draw.Position) chart.Position=varItem.Draw.Position;    //赋值坐标

        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.CreateTextLine=function(hqChart,windowIndex,varItem,id)
    {
        var overlayIndex=this.OverlayIndex;
        var frame=overlayIndex.Frame;
        let chart=new ChartTextLine();
        chart.Canvas=hqChart.Canvas;

        chart.Name=varItem.Name;
        chart.ChartBorder=frame.Frame.ChartBorder;
        chart.ChartFrame=frame.Frame;
        if (varItem.Draw && varItem.Draw.DrawData)
        {
            var drawData=varItem.Draw.DrawData;
            chart.Text=drawData.Text;
            chart.Line=drawData.Line;
            chart.Price=drawData.Price;
        }

        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);
    }

    this.CreateMultiLine=function(hqChart,windowIndex,varItem,i)
    {
        var overlayIndex=this.OverlayIndex;
        var frame=overlayIndex.Frame;
        let chart=new ChartMultiLine();
        chart.Canvas=hqChart.Canvas;
        chart.Name=varItem.Name;
        chart.ChartBorder=frame.Frame.ChartBorder;
        chart.ChartFrame=frame.Frame;
        chart.Identify=overlayIndex.Identify;

        chart.Data=hqChart.ChartPaint[0].Data;//绑定K线
        chart.Lines=varItem.Draw.DrawData; 
        if (varItem.Draw.LineDash) chart.LineDash=varItem.Draw.LineDash;
        if (IFrameSplitOperator.IsNumber(varItem.Draw.LineWidth)) chart.LineWidth=varItem.Draw.LineWidth;
        if(varItem.Draw.Arrow)  //箭头配置
        {
            var item=varItem.Draw.Arrow;
            if (item.Start==true) chart.Arrow.Start=true;
            if (item.End==true) chart.Arrow.End=true;
            if (IFrameSplitOperator.IsNumber(item.Angle)) chart.ArrawAngle=item.Angle;
            if (IFrameSplitOperator.IsNumber(item.Length)) chart.ArrawLength=item.Length;
            if (IFrameSplitOperator.IsNumber(item.LineWidth)) chart.ArrawLineWidth=item.LineWidth;
        }
        frame.ChartPaint.push(chart);
    }

    this.CreateMultiBar=function(hqChart,windowIndex,varItem,id)
    {
        var overlayIndex=this.OverlayIndex;
        var frame=overlayIndex.Frame;
        let chart=new ChartMultiBar();
        chart.Canvas=hqChart.Canvas;
        chart.Name=varItem.Name;
        chart.ChartBorder=frame.Frame.ChartBorder;
        chart.ChartFrame=frame.Frame;
        chart.Identify=overlayIndex.Identify;

        chart.Data=hqChart.ChartPaint[0].Data;//绑定K线
        chart.Bars=varItem.Draw.DrawData; 

        var titleIndex=windowIndex+1;
        var titlePaint=hqChart.TitlePaint[titleIndex];
        var titleData=new DynamicTitleData({ KData:chart.Data, BarData:chart.Bars },varItem.Name,null);
        titleData.IsShow=false;
        titleData.DataType="MULTI_BAR";
        titlePaint.OverlayIndex.get(overlayIndex.Identify).Data[id]=titleData;

        frame.ChartPaint.push(chart);
    }

    this.CreateMultiText=function(hqChart,windowIndex,varItem,i)
    {
        var overlayIndex=this.OverlayIndex;
        var frame=overlayIndex.Frame;
        let chart=new ChartMultiText();
        chart.Canvas=hqChart.Canvas;
        chart.Name=varItem.Name;
        chart.ChartBorder=frame.Frame.ChartBorder;
        chart.ChartFrame=frame.Frame;
        chart.Identify=overlayIndex.Identify;

        chart.Data=hqChart.ChartPaint[0].Data;//绑定K线
        chart.Texts=varItem.Draw.DrawData; 
        frame.ChartPaint.push(chart);
    }

    this.CreateMultiSVGIcon=function(hqChart,windowIndex,varItem,i)
    {
        var overlayIndex=this.OverlayIndex;
        var frame=overlayIndex.Frame;
        let chart=new ChartMultiSVGIcon();
        chart.Canvas=hqChart.Canvas;
        chart.Name=varItem.Name;
        chart.ChartBorder=frame.Frame.ChartBorder;
        chart.ChartFrame=frame.Frame;
        chart.Identify=overlayIndex.Identify;

        chart.Data=hqChart.ChartPaint[0].Data;//绑定K线
        chart.Family=varItem.Draw.DrawData.Family;
        chart.Icon= varItem.Draw.DrawData.Icon;
        frame.ChartPaint.push(chart);
    }

    this.CreateMulitHtmlDom=function(hqChart,windowIndex,varItem,i)
    {
        var overlayIndex=this.OverlayIndex;
        var frame=overlayIndex.Frame;
        let chart=new ChartMultiHtmlDom();
        chart.Canvas=hqChart.Canvas;
        chart.Name=varItem.Name;
        chart.ChartBorder=frame.Frame.ChartBorder;
        chart.ChartFrame=frame.Frame;
        chart.Identify=overlayIndex.Identify;
        chart.HQChart=hqChart;

        chart.Data=hqChart.ChartPaint[0].Data;//绑定K线
        chart.Texts=varItem.Draw.DrawData;
        chart.DrawCallback= varItem.Draw.Callback;
        frame.ChartPaint.push(chart);
    }

    this.CreateChartVericaltLine=function(hqChart,windowIndex,varItem,id)
    {
        var overlayIndex=this.OverlayIndex;
        var frame=overlayIndex.Frame;
        var chart=new ChartVericaltLine();
        chart.Canvas=hqChart.Canvas;
        chart.Name=varItem.Name;
        chart.ChartBorder=frame.Frame.ChartBorder;
        chart.ChartFrame=frame.Frame;
        chart.Identify=overlayIndex.Identify;
        chart.HQChart=hqChart;

        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;
        }

        this.SetChartLineDash(chart,varItem.Draw.DrawData);
        chart.Data.Data=varItem.Draw.DrawData.Data;

        frame.ChartPaint.push(chart);
    }

    this.CreateChartHorizontalLine=function(hqChart,windowIndex,varItem,id)
    {
        var overlayIndex=this.OverlayIndex;
        var frame=overlayIndex.Frame;
        var chart=new ChartHorizontalLine();
        chart.Canvas=hqChart.Canvas;
        chart.Name=varItem.Name;
        chart.ChartBorder=frame.Frame.ChartBorder;
        chart.ChartFrame=frame.Frame;
        chart.Identify=overlayIndex.Identify;
        chart.HQChart=hqChart;

        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;
        }

        this.SetChartLineDash(chart,varItem.Draw.DrawData);
        chart.ExtendType=varItem.Draw.DrawData.Extend;
        chart.Data.Data=varItem.Draw.DrawData.Data;

       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, isOverlay)
{
    if (isOverlay) this.newMethod=OverlayScriptIndex;   
    else this.newMethod=ScriptIndex;
    this.newMethod(name,script,args,option);
    delete this.newMethod;

    this.ClassName="APIScriptIndex";
    this.IsOverlayIndex=(isOverlay==true);  //是否是叠加指标
    this.ApiUrl;    //指标执行api地址
    this.HQDataType;
    this.Version=1; //1=默认数据格式  1=新的.net数据格式

    if (option && 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;
        if (option.API.Version>0) this.Version=option.API.Version;
        if (option.API.IsUsePageData===true) this.IsUsePageData=option.API.IsUsePageData;
    }

    this.Super_CopyTo=this.CopyTo;  //父类方法
    this.CopyTo=function(dest)      //赋值到新实例出来
    {
        this.Super_CopyTo(dest);

        dest.ApiUrl=this.ApiUrl;
        dest.Version=this.Version;
        dest.IsOverlayIndex=this.IsOverlayIndex;
    }

    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线
        var dateRange=null;
        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;                             //分钟数据

            dateRange=hisData.GetDateRange();
        }
        else if (hqChart.ClassName==='HistoryMinuteChartContainer') 
        {
            hqDataType=HQ_DATA_TYPE.HISTORY_MINUTE_ID;   //历史分钟
        }
        else 
        {
            dateRange=hisData.GetDateRange();
        }

        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;
        if (hqChart.GetRequestDataCount) 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, hqdatatype: hqDataType
        };

        if (dateRange) postData.DateRange=dateRange;

        if (requestCount)
        {
            postData.maxdatacount=requestCount.MaxRequestDataCount;
            postData.maxminutedaycount=requestCount.MaxRequestMinuteDayCount;
        }

        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) 
            { 
                if (self.Version==2)
                    self.RecvAPIData2(data,hqChart,windowIndex,hisData);
                else 
                    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);
            }
        });
    }

    //.net 新版后台指标计算格式
    this.RecvAPIData2=function(data,hqChart,windowIndex,hisData)
    {
        JSConsole.Complier.Log('[APIScriptIndex::RecvAPIData2] recv data ', this.Name,data );
        //if (data.code!=0) return;

        if (this.HQDataType==HQ_DATA_TYPE.KLINE_ID)
        {
            this.OutVar=this.ConvertToLocalData(data,hqChart);
            JSConsole.Complier.Log('[APIScriptIndex::RecvAPIData2] conver to OutVar ', this.OutVar);
        }
        else if (this.HQDataType==HQ_DATA_TYPE.MINUTE_ID)
        {
            this.OutVar=this.ConvertToLocalData(data,hqChart);
            JSConsole.Complier.Log('[APIScriptIndex::RecvAPIData2] conver to OutVar ', this.OutVar);
        }
        else if (this.HQDataType==HQ_DATA_TYPE.MULTIDAY_MINUTE_ID)
        {
            this.OutVar=this.ConvertToLocalData(data,hqChart);
            JSConsole.Complier.Log('[APIScriptIndex::RecvAPIData2] conver to OutVar ', this.OutVar);
        }

        this.BindData(hqChart,windowIndex,hisData);
        
        hqChart.UpdataDataoffset();           //更新数据偏移
        hqChart.UpdateFrameMaxMin();          //调整坐标最大 最小值
        hqChart.Draw();

        if (hqChart.GetIndexEvent)
        {
            var event=hqChart.GetIndexEvent();  //指标计算完成回调
            if (event)
            {
                var data={ OutVar:this.OutVar, WindowIndex: windowIndex, Name: this.Name, Arguments: this.Arguments, HistoryData: hisData, 
                        Stock: {Symbol:hqChart.Symbol,Name:hqChart.Name} };
                event.Callback(event,data,this);
            }
        }
    }

    this.ConvertToLocalData=function(jsonData, hqChart)
    {
        var outVar=jsonData.OutVar;
        if (hqChart.ClassName=="MinuteChartContainer" || hqChart.ClassName=="MinuteChartHScreenContainer")
        {
            var kdata=hqChart.SourceData;
            var aryDataIndex=kdata.GetAPIDataIndex(jsonData.Date,jsonData.Time);
        }
        else
        { 
            var kdata=hqChart.ChartPaint[0].Data;
            if (ChartData.IsDayPeriod(jsonData.Period,true))
                var aryDataIndex=kdata.GetAPIDataIndex(jsonData.Date);
            else
                var aryDataIndex=kdata.GetAPIDataIndex(jsonData.Date,jsonData.Time);
        }

        var localOutVar=[];
        for(var i in outVar)
        {
            var item=outVar[i];
            var outItem={ Type:item.Type, Name:item.Name };

            if (item.Type==0)
            {
                outItem.Data=[];
                for(var j=0;j<aryDataIndex.length;++j)
                {
                    var indexItem=aryDataIndex[j];
                    if (indexItem.Index<0) outItem.Data[j]=null;
                    else outItem.Data[j]=item.Data[indexItem.Index];
                }

                if (outItem.Name && outItem.Name.indexOf("@NODRAW@")>=0)
                    outItem.Name=outItem.Name.replace("@NODRAW@","");

            }
            else if (item.Type==1)  //绘图函数
            {
                outItem.Name=item.DrawType;
                outItem.Draw={ DrawType:item.DrawType };
                var draw=item.Draw;
                switch(item.DrawType)
                {
                    case "STICKLINE":
                        {
                            var drawData=[];
                            for(var j=0;j<aryDataIndex.length;++j)
                            {
                                drawData[j]=null;
                                var indexItem=aryDataIndex[j];
                                var index=indexItem.Index;
                                if (index<0) continue;
                                
                                var price=draw.Price[index];
                                var price2=draw.Price2[index];
                                if ( !IFrameSplitOperator.IsNumber(price) || !IFrameSplitOperator.IsNumber(price2))
                                    continue;

                                drawData[j]={ Value:price, Value2:price2 };
                            }
                            outItem.Draw.DrawData=drawData;
                            outItem.Draw.Width=draw.Width;
                            outItem.Draw.Type=draw.Empty;
                        }
                        break;
                    case "DRAWTEXT":
                        {
                            var drawData=[];
                            var aryText=[];
                            for(var j=0;j<aryDataIndex.length;++j)
                            {
                                drawData[j]=null;
                                var indexItem=aryDataIndex[j];
                                var index=indexItem.Index;
                                if (index<0) continue;
                                
                                var price=draw.Price[index];
                                if ( IFrameSplitOperator.IsNumber(price))
                                {
                                    drawData[j]=price;
                                }

                                if (Array.isArray(draw.Text))    //字符串数组
                                {
                                    var item=draw.Text[index];
                                    if (IFrameSplitOperator.IsString(item)) aryText[j]=item;
                                }
                            }

                            if (Array.isArray(draw.Text))  outItem.Draw.Text=aryText;
                            else outItem.Draw.Text=draw.Text;

                            outItem.Draw.DrawData=drawData;
                        }
                        break;
                    case "DRAWNUMBER":
                        {
                            var drawData={Value:[], Text:[]};
                            for(var j=0;j<aryDataIndex.length;++j)
                            {
                                drawData.Value[j]=null;
                                drawData.Text[j]=null;
                                var indexItem=aryDataIndex[j];
                                var index=indexItem.Index;
                                if (index<0) continue;
                                
                                var price=draw.Price[index];
                                var number=draw.Number[index];
                                if ( !IFrameSplitOperator.IsNumber(price) || !IFrameSplitOperator.IsNumber(number)) continue;

                                drawData.Value[j]=price;
                                drawData.Text[j]=number.toFixed(2);
                            }
                            outItem.Draw.DrawData=drawData;
                        }
                        break;
                    case "DRAWBAND":
                        {
                            var drawData=[];
                            for(var j=0;j<aryDataIndex.length;++j)
                            {
                                drawData[j]=null;
                                var indexItem=aryDataIndex[j];
                                var index=indexItem.Index;
                                if (index<0) continue;
                                
                                var price=draw.Val1[index];
                                var price2=draw.Val2[index];
                                if ( !IFrameSplitOperator.IsNumber(price) || !IFrameSplitOperator.IsNumber(price2)) continue;

                                drawData[j]={ Value:price, Value2:price2 };
                            }
                            outItem.Draw.DrawData=drawData;
                            outItem.Draw.Color=[draw.Color1.toLowerCase(), draw.Color2.toLowerCase()];
                        }
                        break;
                    case "DRAWKLINE":
                        {
                            var drawData=[];
                            for(var j=0;j<aryDataIndex.length;++j)
                            {
                                var item={ Open:null,High:null, Low:null, Close:null };
                                drawData[j]=item;

                                var indexItem=aryDataIndex[j];
                                var index=indexItem.Index;
                                if (index<0) continue;

                                var high=draw.High[index];
                                var low=draw.Low[index];
                                var open=draw.Open[index];
                                var close=draw.Close[index];
                                if ( IFrameSplitOperator.IsPlusNumber(high) && IFrameSplitOperator.IsPlusNumber(low) &&
                                    IFrameSplitOperator.IsPlusNumber(open) && IFrameSplitOperator.IsPlusNumber(close)) 
                                {
                                    item.Open=open;
                                    item.Close=close;
                                    item.High=high;
                                    item.Low=low;
                                }
                            }
                            outItem.Draw.DrawData=drawData;
                        }
                        break;
                    case "DRAWTEXT_FIX":
                        {
                            var drawData={ Value:[], Text:[] };
                            for(var j=0;j<aryDataIndex.length;++j)
                            {
                                drawData.Value[j]=0;
                                drawData.Text[j]=null;
                                var indexItem=aryDataIndex[j];
                                var index=indexItem.Index;
                                if (index<0) continue;
                                
                                var condItem=draw.Cond[index];
                                if (!condItem) continue;

                                drawData.Value[j]=1;
                                drawData.Text[j]=draw.Text;
                            }
                            outItem.Draw.DrawData=drawData;
                            outItem.Draw.Position={ X:draw.X, Y:draw.Y, Type:draw.Type };
                        }
                        break;
                    case "DRAWNUMBER_FIX":
                        {
                            var drawData={ Value:[], Text:[] };
                            for(var j=0;j<aryDataIndex.length;++j)
                            {
                                drawData.Value[j]=null;
                                drawData.Text[j]=null;
                                var indexItem=aryDataIndex[j];
                                var index=indexItem.Index;
                                if (index<0) continue;
                                
                                var value=draw.Number[index];
                                if (!IFrameSplitOperator.IsNumber(value)) continue;

                                drawData.Value[j]=value;
                                drawData.Text[j]=IFrameSplitOperator.RemoveZero(value.toFixed(2));
                            }
                            outItem.Draw.DrawData=drawData;
                            outItem.Draw.Position={ X:draw.X, Y:draw.Y, Type:draw.Type };
                        }
                        break;
                    case "DRAWICON":
                        {
                            var icon=g_JSComplierResource.GetDrawIcon(draw.Type);
                            if (!icon) g_JSComplierResource.GetDrawTextIcon(draw.Type);
                            if (!icon) icon={Symbol:'🚩'};
                            outItem.Draw.Icon=icon;
                            var drawData=[];
                            for(var j=0;j<aryDataIndex.length;++j)
                            {
                                drawData[j]=null;
                                var indexItem=aryDataIndex[j];
                                var index=indexItem.Index;
                                if (index<0) continue;
                                
                                var value=draw.Price[index];
                                if (!IFrameSplitOperator.IsNumber(value)) continue;

                                drawData[j]=value;
                            }
                            outItem.Draw.DrawData=drawData;
                        }
                        break;
                    case "PARTLINE":
                        {
                            var drawData=[];
                            for(var j=0;j<aryDataIndex.length;++j)
                            {
                                drawData[j]={Value:null, RGB:null};
                                var indexItem=aryDataIndex[j];
                                var index=indexItem.Index;
                                if (index<0) continue;

                                var color=draw.Color[index];
                                if (!IFrameSplitOperator.IsString(color)) continue;
                                var value=draw.Price[index];
                                if (!IFrameSplitOperator.IsNumber(value)) continue;

                                drawData[j].Value=value;
                                drawData[j].RGB=color;
                            }

                            outItem.Draw.DrawData=drawData;
                        }
                        break;
                    case "FILLRGN":
                        {
                            var drawData=[];
                            for(var j=0;j<aryDataIndex.length;++j)
                            {
                                drawData[j]=null;
                                var indexItem=aryDataIndex[j];
                                var index=indexItem.Index;
                                if (index<0) continue;

                                var color=draw.Color[index];
                                if (!IFrameSplitOperator.IsString(color)) continue;
                                var value=draw.Price[index];
                                if (!IFrameSplitOperator.IsNumber(value)) continue;
                                var value2=draw.Price2[index];
                                if (!IFrameSplitOperator.IsNumber(value2)) continue;

                                drawData[j]={ Value:value, Value2:value2, Color:color };
                            }

                            outItem.Draw.DrawData=drawData;
                            outItem.Draw.DrawType="FILLRGN2";
                        }
                        break;
                    default:
                        continue;
                }
            }
            else
            {
                continue;
            }

            for(var i in item.Attribute)
            {
                var attr=item.Attribute[i];
                switch(attr)
                {
                    case "COLORSTICK":
                        outItem.Type=2; //画上下柱子
                        break;
                    case "POINTDOT":
                        outItem.Radius=g_JSChartResource.POINTDOT.Radius;
                        outItem.Type=3;
                        break;
                    case "CIRCLEDOT":
                        outItem.Radius=g_JSChartResource.CIRCLEDOT.Radius;
                        outItem.Type=3;
                        break;
                    case "DOTLINE":
                        outItem.IsDotLine=true;
                        break;
                    case "DRAWABOVE":
                        outItem.IsDrawAbove=true;
                        break;
                    case "LINESTICK":
                        outItem.Type=4;
                        break;
                    case "STICK":   //STICK 画柱状线
                        outItem.Type=5;
                        break;
                    case "VOLSTICK":    //成交量柱子
                        outItem.Type=6;
                        break;
                    case "NODRAW":  //不画该线
                        outItem.IsShow = false;
                        break;
                    case "NONE_OUT_NAME":   //不显示标题
                        outItem.NoneName=true;
                        break;
                    case "NOTEXT":  //不显示标题
                        outItem.IsShowTitle=false;
                        break;
                }
                
               
                if (attr.indexOf('COLOR')==0)
                {
                    outItem.Color=attr;
                }
                else if (attr.indexOf('LINETHICK')==0) 
                {
                    outItem.LineWidth=attr;
                }
            }

            localOutVar.push(outItem);
        }

        return localOutVar;
    }

    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;

        if (data.outdata.args)  //外部修改参数
        {
            this.Arguments=[];
            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 data={ OutVar:this.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,true))
            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 kdata=hqChart.ChartPaint[0].Data;   //K线

            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) || ChartData.IsTickPeriod(hqChart.Period)) //分钟线
        {
            var kdata=hqChart.ChartPaint[0].Data;   //K线

            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;
        }
        else if (this.HQDataType==HQ_DATA_TYPE.MINUTE_ID || this.HQDataType==HQ_DATA_TYPE.MULTIDAY_MINUTE_ID)
        {
            var minuteData=hqChart.SourceData;

            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; 
                }
            );

            minuteData.GetDateTimeIndex(aryPoint);
            return sourceData;
        }
        
        return null;
    }

    this.FittingMultiText=function(sourceData,date,time,hqChart)
    {
        if (ChartData.IsDayPeriod(hqChart.Period,true))  //日线
        {
            var kdata=hqChart.ChartPaint[0].Data;   //K线

            sourceData.sort(function(a,b) { return a.Date-b.Date; });
            kdata.GetDateIndex(sourceData);
            return sourceData;
        }
        else if (ChartData.IsMinutePeriod(hqChart.Period,true) || ChartData.IsTickPeriod(hqChart.Period)) //分钟线
        {
            var kdata=hqChart.ChartPaint[0].Data;   //K线

            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;
        }
        else if (this.HQDataType==HQ_DATA_TYPE.MINUTE_ID || this.HQDataType==HQ_DATA_TYPE.MULTIDAY_MINUTE_ID)
        {
            var minuteData=hqChart.SourceData;

            sourceData.sort(function(a,b) 
                { 
                    if (a.Date==b.Date) return a.Time-b.Time;
                    return a.Date-b.Date; 
                }
            );

            minuteData.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) 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);
                    for(var k in drawItem.DrawData)
                    {
                        this.GetKLineData(drawItem.DrawData[k].Point, hqChart);
                    }
                    outVarItem.Draw=drawItem;
                    if (draw.LineDash) drawItem.LineDash=draw.LineDash;
                    if (draw.Arrow) drawItem.Arrow=draw.Arrow;
                    if (IFrameSplitOperator.IsNumber(draw.LineWidth)) drawItem.LineWidth=draw.LineWidth;

                    result.push(outVarItem);
                }
                else if (draw.DrawType=='MULTI_BAR')
                {
                    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);
                    this.GetKLineData(drawItem.DrawData, 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 };
                    this.GetKLineData(drawItem.DrawData.Icon, hqChart);
                    outVarItem.Draw=drawItem;

                    result.push(outVarItem);
                }
                else if (draw.DrawType=="MULTI_HTMLDOM")    //外部自己创建dom
                {
                    drawItem.Text=draw.Text;
                    drawItem.Name=draw.Name;
                    drawItem.DrawType=draw.DrawType;
                    drawItem.Callback=draw.Callback;
                    drawItem.DrawData=this.FittingMultiText(draw.DrawData,date,time,hqChart);
                    this.GetKLineData(drawItem.DrawData, hqChart);
                    outVarItem.Draw=drawItem;

                    result.push(outVarItem);
                }
                else if (draw.DrawType=="COLOR_KLINE")
                {
                    drawItem.Text=draw.Text;
                    drawItem.Name=draw.Name;
                    drawItem.DrawType=draw.DrawType;
                    var klineOption=this.FittingMultiText(draw.DrawData.KLine,date,time,hqChart);
                    var mapKLineOption=new Map();
                    for(var i in klineOption)
                    {
                        var item=klineOption[i];
                        mapKLineOption.set(item.Index,item);
                    }

                    drawItem.DrawData={ KLine:mapKLineOption };
                    if (draw.Color)  outVarItem.Color=draw.Color;
                    outVarItem.Draw=drawItem;

                    result.push(outVarItem);
                }
                else if (draw.DrawType=="KLINE_BG")
                {
                    drawItem.Name=draw.Name;
                    drawItem.DrawType=draw.DrawType;
                    drawItem.DrawData={ };
                    drawItem.DrawData.Color=draw.Color;
                    drawItem.DrawData.Angle=draw.Angle;
                    if (draw.Ver==2.0) drawItem.DrawData.Data=this.FittingKLineBG_V2(draw.DrawData, hqChart);
                    else drawItem.DrawData.Data=this.FittingKLineBG(draw.DrawData, hqChart);

                    outVarItem.Draw=drawItem;
                    outVarItem.Name=draw.DrawType;
                    result.push(outVarItem);
                }
                else if (draw.DrawType=='MULTI_POINT_LINE')
                {
                    drawItem.Name=draw.Name;
                    drawItem.DrawType=draw.DrawType;
                    drawItem.DrawData={ };
                    drawItem.DrawData.Color=draw.Color;
                    drawItem.DrawData.PointRadius=draw.PointRadius;
                    drawItem.DrawData.PointColor=draw.PointColor;
                    drawItem.DrawData.LineWidth=draw.LineWidth;
                    drawItem.DrawData.Data=this.FittingMultiPointLine(draw.DrawData, hqChart);

                    outVarItem.Draw=drawItem;
                    //outVarItem.Name=draw.DrawType;
                    result.push(outVarItem);
                }
            }
        }

        return result;
    }

    // h, high, low l. c, close
    this.GetKLineData=function(data,hqChart)
    {
        if (!data) return;
        if (!Array.isArray(data)) return;

        if (this.HQDataType==HQ_DATA_TYPE.MINUTE_ID || this.HQDataType==HQ_DATA_TYPE.MULTIDAY_MINUTE_ID)
            var kData=hqChart.SourceData;   //走势图分钟数据
        else 
            var kData=hqChart.ChartPaint[0].Data;   //K线

        for(var i in data)
        {
            var item=data[i];
            if (!IFrameSplitOperator.IsString(item.Value)) continue;
            if (!IFrameSplitOperator.IsNumber(item.Index)) continue;
            if (item.Index<0 || item.Index>=kData.Data.length) continue;
            var valueName=item.Value.toUpperCase();
            var kItem=kData.Data[item.Index];
            switch(valueName)
            {
                case "HIGH":
                case "H":
                    item.Value=kItem.High;
                    break;
                case "L":
                case "LOW":
                    item.Value=kItem.Low;
                    break;
                case "C":
                case "CLOSE":
                    item.Value=kItem.Close;
                    break;
            }
        }
    }

    this.FittingKLineBG=function(data, hqChart)
    {
        var kData=hqChart.ChartPaint[0].Data;   //K线
        var result=[];
        if (ChartData.IsDayPeriod(hqChart.Period,true))  //日线
        {
            var bFill=false;
            for(var i=0,j=0;i<kData.Data.length;)
            {
                result[i]=0;
                var kItem=kData.Data[i];
                if (j>=data.length) 
                {
                    ++i;
                    continue;
                }
                var dataItem=data[j];

                if (dataItem.Date<kItem.Date)
                {
                    ++j;
                }
                else if (dataItem.Date>kItem.Date)
                {
                    ++i;
                }
                else
                {
                    bFill=true;
                    result[i]=1;
                    ++j;
                    ++i;
                }
            }

            if (bFill) return result;
        }
        else if (ChartData.IsMinutePeriod(hqChart.Period,true)) //分钟线
        {
            var bFill=false;
            for(var i=0,j=0;i<kData.Data.length;)
            {
                result[i]=0;
                var kItem=kData.Data[i];
                if (j>=data.length) 
                {
                    ++i;
                    continue;
                }
                var dataItem=data[j];

                if (dataItem.Date<kItem.Date || (dataItem.Date==kItem.Date && dataItem.Time<kItem.Time))
                {
                    ++j;
                }
                else if (dataItem.Date>kItem.Date || (dataItem.Date==kItem.Date && dataItem.Time>kItem.Time))
                {
                    ++i;
                }
                else
                {
                    bFill=true;
                    result[i]=1;
                    ++j;
                    ++i;
                }
            }

            if (bFill) return result;
        }
        
        return null;
    }

    this.FittingKLineBG_V2=function(data, hqChart)  //2.0版本通过  [{ Start:, End: }, .....]来填充背景色
    {
        var kData=hqChart.ChartPaint[0].Data;   //K线
        var result=[];
        if (ChartData.IsDayPeriod(hqChart.Period,true))  //日线
        {
            var bFill=false;
            for(var i=0,j=0;i<kData.Data.length;++i)
            {
                result[i]=0;
                var kItem=kData.Data[i];
                var date=kItem.Date;
                for(j=0;j<data.length;++j)
                {
                    var rangeItem=data[j];
                    if (date>=rangeItem.Start.Date && date<=rangeItem.End.Date)
                    {
                        result[i]=1;
                        bFill=true;
                        break;
                    }

                }
            }

            if (bFill) return result;
        }
        else if (ChartData.IsMinutePeriod(hqChart.Period,true)) //分钟线
        {
            var aryRange=[];
            for(var i=0;i<data.length;++i)
            {
                var item=data[i];
                var startDatetime=item.Start.Date*10000;
                if (IFrameSplitOperator.IsNumber(item.Start.Time)) startDatetime+=item.Start.Time;
                var endDatetime=item.End.Date*10000;
                if (IFrameSplitOperator.IsNumber(item.End.Time)) endDatetime+=item.End.Time;

                aryRange.push({ Start:startDatetime , End:endDatetime});
            }

            var bFill=false;
            for(var i=0,j=0;i<kData.Data.length; ++i)
            {
                result[i]=0;
                var kItem=kData.Data[i];

                var date=kItem.Date*10000+kItem.Time;
                for(j=0;j<aryRange.length;++j)
                {
                    var rangeItem=aryRange[j];
                    if (date>=rangeItem.Start && date<=rangeItem.End)
                    {
                        result[i]=1;
                        bFill=true;
                        break;
                    }
                }
            }

            if (bFill) return result;
        }
        
        return null;
    }

    this.FittingMinuteData=function(jsonData, hqChart)
    {
        var outVar=jsonData.outvar;
        var date=jsonData.date;
        var time=jsonData.time;
        var result=[];
        
        for(var i in outVar)
        {
            var 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);
            }
            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.FittingMinuteArray(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.FittingMinuteArray(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.FittingMinuteArray(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);
                    for(var k in drawItem.DrawData)
                    {
                        this.GetKLineData(drawItem.DrawData[k].Point, hqChart);
                    }
                    
                    outVarItem.Draw=drawItem;
                    if (draw.LineDash) drawItem.LineDash=draw.LineDash;
                    if (draw.Arrow) drawItem.Arrow=draw.Arrow;

                    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);
                    this.GetKLineData(drawItem.DrawData, 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 };
                    this.GetKLineData(drawItem.DrawData.Icon, hqChart);
                    outVarItem.Draw=drawItem;

                    result.push(outVarItem);
                }
                else if (draw.DrawType=="MULTI_HTMLDOM")    //外部自己创建dom
                {
                    drawItem.Text=draw.Text;
                    drawItem.Name=draw.Name;
                    drawItem.DrawType=draw.DrawType;
                    drawItem.Callback=draw.Callback;
                    drawItem.DrawData=this.FittingMultiText(draw.DrawData,date,time,hqChart);
                    this.GetKLineData(drawItem.DrawData, hqChart);
                    outVarItem.Draw=drawItem;

                    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;
    }

    this.FittingMultiPointLine=function(data, hqChart)
    {
        var period=hqChart.Period;              //周期
        var arySrouceData=data.Data;
        var aryData=[];
        if (ChartData.IsDayPeriod(period,true))  //日线
        {
            //arySrouceData.sort((a,b)=> { return a.Date-b.Date});
            var firstItem=arySrouceData[0];
            var kdata=hqChart.ChartPaint[0].Data;   //K线
            var firstKItem=kdata.Data[0];
            var kIndex=0, dataIndex=0;
            if (firstItem.Date>firstKItem.Date)
            {
                var preIndex=0;
                for(kIndex=0;kIndex<kdata.Data.length;++kIndex)
                {
                    var kItem=kdata.Data[kIndex];
                    if (kItem.Date==firstItem.Date) 
                        break;
                    if (kItem.Date>firstItem.Date)
                    {
                        kIndex=preIndex;
                        break;
                    }
                    preIndex=kIndex;
                }
            }
            else
            {
                for(dataIndex=0;dataIndex<arySrouceData.length;++dataIndex)
                {
                    var item=arySrouceData[dataIndex];
                    if (item.Date>=firstKItem.Date) 
                        break;
                }
            }
            
            var preItem=null;
            for(var i=kIndex, j=dataIndex; i<kdata.Data.length && j<arySrouceData.length; )
            {
                var kItem=kdata.Data[i];
                var item=arySrouceData[j];
                if (item.Date<=kItem.Date)
                {
                    if (!aryData[i]) aryData[i]=[];
                    aryData[i].push({Date:item.Date, Value:item.Value, Data:item.Data, KDate:kItem.Date, Type:1 });
                    preItem=item;
                    ++j;
                }
                else
                {
                    if (preItem && !aryData[i]) aryData[i]={ Date:preItem.Date, Value:preItem.Value , Type: 0 };
                    ++i;
                }
            }

            if (preItem)
            {
                for( ;i<kdata.Data.length; ++i) //补齐最后的数据
                {
                    if (!aryData[i]) aryData[i]={ Date:preItem.Date, Value:preItem.Value , Type: 0 };
                }
            }
            

           
            return aryData;
        }
        else if (ChartData.IsMinutePeriod(period,true)) //分钟线
        {
            var kdata=hqChart.ChartPaint[0].Data;   //K线
            
            return aryData;
        }
    }

}

// 本地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;   //截面报表模式
    this.NetworkFilter;         //数据接口

    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;
        if (obj.NetworkFilter) this.NetworkFilter=obj.NetworkFilter;
    }

    //执行脚本
    //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',
            NetworkFilter:this.NetworkFilter,
        };

        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);
}

//////////////////////////////////////////////////////////////////////////////////////////////
//内置财务数据下载
//
function DownloadFinValueData(obj)
{
    this.Url=obj.Url;
    this.Job=obj.Job;
    this.Symbol=obj.Symbol;
    this.Args=obj.Args;
    this.DataKey=obj.DataKey;
    this.RecvCallback=obj.Callback;
    this.ErrorCallback=obj.ErrorCallback;

    this.Download=function()
    {
        var self=this;
        var fieldList=this.GetFieldList();
        if (!fieldList)
        {
            message=`${this.Job.FunctionName}(${this.Args[0]}) can't support.`;
            this.ErrorCallback(message);
            self.RecvCallback(null, self.Job, self.DataKey);
            return;
        }

        //请求数据
        JSNetwork.HttpRequest({
            url: this.Url,
            data:
            {
                "field": fieldList,
                "symbol": [this.Symbol],
                "condition":[ {"item":["finance","doc","exists","true"]}] ,
                "start": 0,
                "end": 200
            },
            type:"post",
            dataType: "json",
            async:true,
            success: function (recvData)
            {
                var data=self.ToHQChartData(recvData);
                if (data) //排序
                    data.sort(function (a, b) { return (a.Date - b.Date) });

                self.RecvCallback(data, self.Job, self.DataKey);
            }
        });
    }

    this.ToHQChartData=function(recvData)
    {
        if (!recvData.stock || recvData.stock.length!=1) return null;

        var aryData=[];
        var setDate=new Set();  //有重复数据 去掉
        var stock=recvData.stock[0];
        for(var i in stock.stockday)
        {
            var item=stock.stockday[i];
            if (item.announcement1)
            {
                var hqchartItem=this.ToHQChartItemData(item.announcement1, item.finance1, item);
                if (hqchartItem && !setDate.has(hqchartItem.Date)) 
                {
                    aryData.push(hqchartItem);
                    setDate.add(hqchartItem.Date);
                }
            }

            if (item.announcement2)
            {
                var hqchartItem=this.ToHQChartItemData(item.announcement2, item.finance2, item);
                if (hqchartItem && !setDate.has(hqchartItem.Date)) 
                {
                    aryData.push(hqchartItem);
                    setDate.add(hqchartItem.Date);
                }
            }

            if (item.announcement3)
            {
                var hqchartItem=this.ToHQChartItemData(item.announcement3, item.finance3, item);
                if (hqchartItem && !setDate.has(hqchartItem.Date)) 
                {
                    aryData.push(hqchartItem);
                    setDate.add(hqchartItem.Date);
                }
            }

            if (item.announcement4)
            {
                var hqchartItem=this.ToHQChartItemData(item.announcement4, item.finance4, item);
                if (hqchartItem && !setDate.has(hqchartItem.Date)) 
                {
                    aryData.push(hqchartItem);
                    setDate.add(hqchartItem.Date);
                }
            }
        }

        return aryData;
    }

    //{ Date：日期 , Value:数值 }
    this.ToHQChartItemData=function(announcement, finance, sourceItem)
    {
        var id=this.Args[0];
        var date=announcement.year*10000;
        var quarter=announcement.quarter;
        switch(quarter)
        {
            case 1:
                date+=331;
                break;
            case 2:
                date+=630;
                break;
            case 3:
                date+=930;
                break;
            case 4:
                date+=1231;
                break;
            default:
                return null;
        }

        var result={ Date:date, Value:0 };
        switch(id)
        {
            case 0:
                result.Value=date%1000000;  //0--返回报告期(YYMMDD格式),150930表示为2015年第三季
                break;
            case 1:
                result.Value=finance.persearning;
                break;
            case 3:
                result.Value=finance.peruprofit;
                break;
            case 4:
                result.Value=finance.pernetasset;
                break;
            case 5:
                result.Value=finance.percreserve;
                break;
            case 6:
                result.Value=finance.woewa;
                break;
            case 7:
                result.Value=finance.perccfo;
                break;
            case 8:
                result.Value=finance.monetaryfunds;
                break;
            case 11:
                result.Value=finance.areceivable;
                break;
        }

        return result;
    }

    this.GetFieldList=function()
    {
        var id=this.Args[0];
        switch(id)
        {
            case 0:
                return ["finance.date"];
            case 1: //persearning	每股收益
                return ["finance.persearning"];
            case 3: //peruprofit	每股未分配利润
                return ["finance.peruprofit"];
            case 4: //pernetasset	每股净资产
                return ["finance.pernetasset"];
            case 5: //percreserve	每股资本公积金
                return ["finance.percreserve"];
            case 6: //woewa	加权平均净资产收益
                return ["finance.woewa"];
            case 7: //perccfo	每股经营性现金流
                return ["finance.perccfo"];
            case 8: //monetaryfunds	货币资金
                return ["finance.monetaryfunds"];
            case 11: //areceivable	应收账款
                return ["finance.areceivable"];
            default:
                return null;
        }
    }
}

/////////////////////////////////////////////////////////
// 内置财务数据下载 某一期的数据
//
function DownloadFinOneData(obj)
{
    this.newMethod=DownloadFinValueData;   //派生
    this.newMethod(obj);
    delete this.newMethod;

    this.Download=function()
    {
        var self=this;
        var fieldList=this.GetFieldList();
        if (!fieldList)
        {
            message=`${this.Job.FunctionName}(${this.Args[0]}, ${this.Args[1]}, ${this.Args[2]}) can't support.`;
            this.ErrorCallback(message);
            self.RecvCallback(null, self.Job, self.DataKey);
            return;
        }

        var aryCondition=[ {"item":["finance","doc","exists","true"] } ];

        var year=this.Args[1];
        var month=this.Args[2];
        var dataIndex=0;
        var dataEnd=3;
        var preYear=null;
        if (year==0 && month==0)    //如果Y和MMDD都为0,表示最新的财报;
        {

        }
        else if (year==0 && month<300)  //如果Y为0,MMDD为小于300的数字,表示最近一期向前推MMDD期的数据,如果是331,630,930,1231这些,表示最近一期的对应季报的数据;
        {
            dataIndex=month;
            dataEnd=200;
        }
        else if (month==0 && year<1000) //如果Y为0,MMDD为小于300的数字,表示最近一期向前推MMDD期的数据,如果是331,630,930,1231这些,表示最近一期的对应季报的数据;
        {
            preYear=year;
        }
        else if (year>1909)
        {
            if (month==331) 
            {
                aryCondition=
                [
                    {"item":["announcement1.year","int32","eq",year]},
                    {"item":["finance1","doc","exists","true"]}
                ];

                fieldList.push("announcement1.year");
                fieldList.push("announcement1.quarter");
            }
            else if (month==630)
            {
                aryCondition=
                [
                    {"item":["announcement2.year","int32","eq",year]},
                    {"item":["finance2","doc","exists","true"]}
                ];

                fieldList.push("announcement2.year");
                fieldList.push("announcement2.quarter");
            }
            else if (month==930)
            {
                aryCondition=
                [
                    {"item":["announcement3.year","int32","eq",year]},
                    {"item":["finance3","doc","exists","true"]}
                ];

                fieldList.push("announcement4.year");
                fieldList.push("announcement4.quarter");
            }
            else
            {
                aryCondition=
                [
                    {"item":["announcement4.year","int32","eq",year]},
                    {"item":["finance4","doc","exists","true"]}
                ];

                fieldList.push("announcement4.year");
                fieldList.push("announcement4.quarter");
            }
        }

        //请求数据
        JSNetwork.HttpRequest({
            url: this.Url,
            data:
            {
                "field": fieldList,
                "symbol": [this.Symbol],
                "condition":aryCondition,
                "start": 0,
                "end": dataEnd
            },
            type:"post",
            dataType: "json",
            async:true,
            success: function (recvData)
            {
                var data=self.ToHQChartData(recvData);
                var result=null;
                if (data && data.length>0) 
                {
                    data.sort(function (a, b) { return (b.Date-a.Date) });
                    if (preYear==null)
                        result=data[dataIndex];   //返回一个数据
                    else 
                        result=self.GetPreYearData(data, preYear);
                }
                self.RecvCallback(result, self.Job, self.DataKey);
            }
        });
    }

    this.GetPreYearData=function(data, preYear)
    {
        //331,630,930,1231这些,表示最近一期的对应季报的数据;
        if (preYear==331 || preYear==630|| preYear==930 || preYear==1231)
        {
            for(var i in data)
            {
                var item=data[i];
                if (item.Date%10000==preYear) return item;
            }
        }
        else
        {   
            //如果MMDD为0,Y为一数字,表示最近一期向前推Y年的同期数据;
            var month=data[0].Date%1000;
            for(var i=1, j=0; i<data.length ;++i)
            {
                var item=data[i];
                if (item.Date%10000==month)
                {
                    ++j;
                    if (j==preYear) return item;
                }
            }

            return null;
        }
    }
}


function DownloadFinanceData(obj)
{
    this.Url=obj.Url;
    this.RealtimeUrl=obj.RealtimeUrl;
    this.Job=obj.Job;
    this.Symbol=obj.Symbol;
    this.Args=obj.Args;
    this.DataKey=obj.DataKey;
    this.RecvCallback=obj.Callback;
    this.ErrorCallback=obj.ErrorCallback;
    
    this.Download=function()
    {
        var id=this.Args[0];
        switch(id)
        {
            case 1: //FINANCE(1) 总股本(随时间可能有变化) 股
            case 7: //FINANCE(7) 流通股本(随时间可能有变化) 股
            case "EXCHANGE": //换手率
                this.DownloadHistoryData(id);
                break;
            case 3:
                this.GetSymbolType(id);
                break;

            case 9:     //FINANCE(9)  资产负债率
            case 18:    //FINANCE(18)  每股公积金
            case 30:    //FINANCE(30)  净利润
            case 32:    //FINANCE(32)  每股未分配利润
            case 33:    //FINANCE(33)  每股收益(折算为全年收益),对于沪深品种有效
            case 34:    //FINANCE(34)  每股净资产
            case 38:    //FINANCE(38)  每股收益(最近一期季报)
            case 40:    //FINANCE(40)  流通市值 
            case 41:    //FINANCE(41)  总市值
            case 42:    //FINANCE(42)  上市的天数
            case 43:    //FINANCE(43)  利润同比

            case "CAPITAL":
            case "TOTALCAPITAL":

            //定制
            case 100:   //股东人数
                this.DownloadRealtimeData(id);
                break;
            
            default:
                this.DownloadRealtimeData(id);
                break;
        }
    }

    //FINANCE(3) 沪深品种类型
    //0:指数,1:A股主板,2:中小板,3:创业板,4:科创板,5:B股,6:债券,7:基金,8:权证,9:其它,10:非沪深品种
    this.GetSymbolType=function(id)
    {
        var value=1;
        if (MARKET_SUFFIX_NAME.IsSHSZIndex(this.Symbol)) value=0;
        var data={ Date:null, Value:value };
        this.RecvCallback(data,this.Job, this.DataKey);
    }

    //最新一期数据
    this.DownloadRealtimeData=function(id)
    {
        var self=this;
        var fieldList=this.GetFieldList();
        if (!fieldList)
        {
            if (this.Job.FunctionName2) message=`${this.Job.FunctionName2} can't support.`;
            else if (this.Job.FunctionName) message=`${this.Job.FunctionName}(${this.Args[0]}) can't support.`;
            else message=`${this.Args[0]} can't support.`;
            this.ErrorCallback(message);
            self.RecvCallback(null, self.Job, self.DataKey);
            return;
        }

        //请求数据
        JSNetwork.HttpRequest({
            url: this.RealtimeUrl,
            data:
            {
                "field": fieldList,
                "symbol": [this.Symbol],
                "condition":[ ] ,
                "start": 0,
                "end": 10
            },
            type:"post",
            dataType: "json",
            async:true,
            success: function (recvData)
            {
                var data=self.RealtimeDataToHQChartData(recvData);
                self.RecvCallback(data, self.Job, self.DataKey);
            }
        });
    }

    //历史数据
    this.DownloadHistoryData=function(id)
    {
        var self=this;
        var fieldList=this.GetFieldList();
        if (!fieldList)
        {
            message=`${this.Job.FunctionName}(${this.Args[0]}) can't support.`;
            this.ErrorCallback(message);
            self.RecvCallback(null, self.Job, self.DataKey);
            return;
        }

        //请求数据
        JSNetwork.HttpRequest({
            url: this.Url,
            data:
            {
                "field": fieldList,
                "symbol": [this.Symbol],
                "condition":[ ] ,
                "start": 0,
                "end": 200
            },
            type:"post",
            dataType: "json",
            async:true,
            success: function (recvData)
            {
                var data=self.ToHQChartData(recvData);
                if (data) //排序
                    data.sort(function (a, b) { return (a.Date - b.Date) });

                self.RecvCallback(data, self.Job, self.DataKey);
            }
        });
    }

    this.GetFieldList=function()
    {
        var id=this.Args[0];
        switch(id)
        {
            case 1:
                return ["capital.total", "capital.date"];
            case 7:
                return ["capital.a", "capital.date"];
            case "EXCHANGE":
                return ["capital.a", "capital.date"];

            case 9:
                return ["finance.peruprofit","symbol","date"];
            case 18:
                return ["finance.percreserve","symbol","date"];
            case 30:
                return ["finance.nprofit","symbol","date"];
            case 32:
                return ["finance.peruprofit","symbol","date"];
            case 33:
                return ["finance.persearning","symbol","date"];
            case 34:
                return ["finance.pernetasset","symbol","date"];
            case 38:
                return ["finance.persearning","symbol","date"];
            case 40:
                return ["capital.a", "capital.date","symbol","date", "price"];
            case 41:
                return ["capital.total", "capital.date","symbol","date","price"];
            case "CAPITAL":
                return ["capital.a", "capital.date","symbol","date"];
            case "TOTALCAPITAL":
                return ["capital.total", "capital.date","symbol","date"];
            case 42:
                return ["company.releasedate","symbol","date"];
            case 43:
                return ["dividendyield","symbol","date"];
            case 100:
                return ["shareholder","symbol","date"]
            default:
                return null;
        }
    }

    //最新报告期数据
    this.RealtimeDataToHQChartData=function(recvData,id)
    {
        if (!recvData.stock || recvData.stock.length!=1) return null;
        var stock=recvData.stock[0];
        var id=this.Args[0];
        var date=stock.date;
        switch(id)
        {
            case 9:
                if (!stock.finance) return null;
                return { Date:date, Value:stock.finance.peruprofit };
            case 18:
                if (!stock.finance) return null;
                return { Date:date, Value:stock.finance.percreserve };
            case 30:
                if (!stock.finance) return null;
                return { Date:date, Value:stock.finance.nprofit };
            case 32:
                if (!stock.finance) return null;
                return { Date:date, Value:stock.finance.peruprofit };
            case 33:
                if (!stock.finance) return null;
                return { Date:date, Value:stock.finance.persearning };
            case 34:
                if (!stock.finance) return null;
                return { Date:date, Value:stock.finance.pernetasset };
            case 38:
                if (!stock.finance) return null;
                return { Date:date, Value:stock.finance.persearning };
            case 40:    //FINANCE(40)  流通市值
                if (!stock.capital) return null;
                return { Date:date, Value:stock.capital.a*stock.price };    //流通股*最新价格
            case 41:   //FINANCE(41)  总市值 
                if (!stock.capital) return null;
                return { Date:date, Value:stock.capital.total*stock.price };    //总股本*最新价格
            case 42:    //FINANCE(42)  上市的天数
                if (!stock.company) return null;
                {
                    var releaseDate=stock.company.releasedate;
                    var year=parseInt(releaseDate/10000);
                    var month=parseInt((releaseDate%10000)/100);
                    var day=releaseDate%100;
                    var firstDate=new Date(year, month-1, day);
                    var nowDate=new Date();
                    var days=parseInt((nowDate.getTime()-firstDate.getTime())/(1000 * 60 * 60 * 24));
                    return { Date:date, Value:days+1 };
                }
            case 43:
                if (!stock.dividendyield) return null;
                return { Date:date, Value:stock.dividendyield.quarter4 };
            case 100:
                if (!stock.shareholder) return null;
                return { Date:date, Value:stock.shareholder.count };
            case "CAPITAL": 
                if (!stock.capital) return null;
                return { Date:date, Value:stock.capital.a/100 };    //当前流通股本 手
            case "TOTALCAPITAL":
                if (!stock.capital) return null;
                return { Date:date, Value:stock.capital.total/100 };    //当前流通股本 手    
        }
    }

    //历史数据转
    this.ToHQChartData=function(recvData)
    {
        if (!recvData.stock || recvData.stock.length!=1) return null;

        var aryData=[];
        var setDate=new Set();  //有重复数据 去掉
        var stock=recvData.stock[0];
        var id=this.Args[0];
        for(var i in stock.stockday)
        {
            var item=stock.stockday[i];

            var hqchartItem=this.ToHQChartItemData(item,id);
            if (hqchartItem && !setDate.has(hqchartItem.Date)) 
            {
                aryData.push(hqchartItem);
                setDate.add(hqchartItem.Date);
            }
        }

        return aryData;
    }

    this.ToHQChartItemData=function(item, id)
    {
        if (!item) return null;
        var date=item.date;
        switch(id)
        {
            case 1:
                if (!item.capital) return null;
                return { Date:date, Value:item.capital.total };
            case 7:
            case "EXCHANGE":    //换手率 历史流通股本
                if (!item.capital) return null;
                return { Date:date, Value:item.capital.a };
               
            default:
                return null;
        }
    }
}

function DownloadGPJYValue(obj)
{
    this.Url=obj.Url;
    this.RealtimeUrl=obj.RealtimeUrl;
    this.Job=obj.Job;
    this.Symbol=obj.Symbol;
    this.Args=obj.Args;
    this.DataKey=obj.DataKey;
    this.RecvCallback=obj.Callback;
    this.ErrorCallback=obj.ErrorCallback;

    this.Download=function()
    {
        var self=this;
        var fieldList=this.GetFieldList();
        if (!fieldList)
        {
            message=`${this.Job.FunctionName}(${this.Args[0]}, ${this.Args[1]}, ${this.Args[2]}) can't support.`;
            this.ErrorCallback(message);
            self.RecvCallback(null, self.Job, self.DataKey, true);
            return;
        }

        //请求数据
        JSNetwork.HttpRequest({
            url: this.Url,
            data:
            {
                "field": fieldList,
                "symbol": [this.Symbol],
                "orderfield":"date",             
                "order":-1,   
                "start":0,
                "end":5
            },
            type:"post",
            dataType: "json",
            async:true,
            success: function (recvData)
            {
                var data=self.ToHQChartData(recvData);
                if (data && data.length>0) 
                {
                    data.sort(function (a, b) { return (a.Date-b.Date) });
                }
                self.RecvCallback(data, self.Job, self.DataKey);
            }
        });
    }

    this.GetFieldList=function()
    {
        var id=this.Args[0];
        switch(id)
        {
            case 1: //1--股东人数 股东户数(户)           
                return ["shareholder", "date", "symbol"];
            case 2: //2--龙虎榜   买入总计(万元) 卖出总计(万元)
                return ["tradedetail.buy","tradedetail.sell", "date", "symbol"];
            case 3: //3--融资融券1 融资余额(万元) 融券余量(股)
                return ["margin","date", "symbol"];
            case 4: //4--大宗交易 成交均价(元) 成交额(万元)
                return ["blocktrading.amount","blocktrading.price","date", "symbol"]
            default:
                return null;
        }
    }

    this.ToHQChartData=function(recvData)
    {
        if (!recvData.stock || recvData.stock.length!=1) return null;

        var aryData=[];
        var setDate=new Set();  //有重复数据 去掉
        var stock=recvData.stock[0];
        var id=this.Args[0];
        var subID=this.Args[1];
        for(var i in stock.stockday)
        {
            var item=stock.stockday[i];

            var hqchartItem=this.ToHQChartItemData(item,id,subID);
            if (hqchartItem && !setDate.has(hqchartItem.Date)) 
            {
                aryData.push(hqchartItem);
                setDate.add(hqchartItem.Date);
            }
        }

        return aryData;
    }

    this.ToHQChartItemData=function(item, id, subID)
    {
        if (!item) return null;
        var date=item.date;
        switch(id)
        {
            case 1:
                if (!item.shareholder) return null;
                return { Date:date, Value:item.shareholder.count };
            case 2:
                if (!item.tradedetail && item.tradedetail[0]) return null;
                if (subID==0)
                    return { Date:date, Value:item.tradedetail[0].buy };
                else 
                    return { Date:date, Value:item.tradedetail[0].sell };
            case 3:
                if (!item.margin) return null;
                if (subID==0)
                {
                    if (item.margin.buy)
                        return { Date:date, Value:item.margin.buy.balance };
                }
                else
                {
                    if (item.margin.sell)
                        return { Date:date, Value:item.margin.sell.balance };
                }
                return null;
            case 4:
                if (!item.blocktrading) return null;
                if (subID==0)
                    return { Date:date, Value:item.blocktrading.price };
                else
                    return { Date:date, Value:item.blocktrading.amount };
            default:
                return null;
        }
    }
}



/*
引用市场总的交易类数据.如果指标支持云数据函数,则不需要[专业财务数据]下载.
SCJYVALUE(ID,N,TYPE),ID为数据编号,N表示第几个数据,TYPE:为1表示做平滑处理,没有数据的周期返回上一周期的值;为0表示不做平滑处理

市场交易类数据函数，数据编号如下:
1--融资融券       沪深融资余额(万元) 沪深融券余额(万元)
2--陆股通资金流入 沪股通流入金额(亿元) 深股通流入金额(亿元)
3--沪深涨停股个数 涨停股个数  曾涨停股个数 [注：该指标展示20160926日之后的数据]
4--沪深跌停股个数 跌停股个数  曾跌停股个数
5--上证50股指期货  净持仓(手)[注：该指标展示20171009日之后的数据]
6--沪深300股指期货 净持仓(手) [注：该指标展示20171009日之后的数据]
7--中证500股指期货 净持仓(手) [注：该指标展示20171009日之后的数据]
8--ETF基金规模数据 ETF基金规模(亿) ETF净申赎(亿)
9--每周新增投资者 新增投资者(万户)
10--增减持统计    增持额(万元)  减持额(万元)[注：部分公司公告滞后,造成每天查看的数据可能会不一样] 
11--大宗交易      溢价的大宗交易额(万元) 折价的大宗交易额(万元)
12--限售解禁      限售解禁计划额(亿元)  限售解禁股份实际上市金额(亿元)[注：该指标展示201802月之后的数据;部分股票的解禁日期延后，造成不同日期提取的某天的计划额可能不同]
13--分红          市场总分红额(亿元)[注：除权派息日的A股市场总分红额] 
14--募资          市场总募资额(亿元)[注：发行日期/除权日期的首发、配股和增发的总募资额] 
15--打板资金    封板成功资金(亿元) 封板失败资金(亿元) [注：该指标展示20160926日之后的数据]
*/
function DownloadSCJYValue(obj)
{
    this.Url=obj.Url;
    //this.RealtimeUrl=obj.RealtimeUrl;
    this.Job=obj.Job;
    this.Symbol=obj.Symbol;
    this.Args=obj.Args;
    this.DataKey=obj.DataKey;
    this.RecvCallback=obj.Callback;
    this.ErrorCallback=obj.ErrorCallback;
    
    this.Download=function()
    {
        var self=this;
        var query=this.GetQueryCondtion();
        if (!query)
        {
            message=`${this.Job.FunctionName}(${this.Args[0]}, ${this.Args[1]}, ${this.Args[2]}) can't support.`;
            this.ErrorCallback(message);
            self.RecvCallback(null, self.Job, self.DataKey, true);
            return;
        }

        //请求数据
        JSNetwork.HttpRequest({
            url: this.Url,
            data:
            {
                "field": query.Field,
                "symbol": query.Symbol,
                "condition":query.Cond ,
                "start": 0,
                "end": 2000
            },
            type:"post",
            dataType: "json",
            async:true,
            success: function (recvData)
            {
                var data=self.ToHQChartData(recvData);
                if (data) //排序
                    data.sort(function (a, b) { return (a.Date - b.Date) });

                self.RecvCallback(data, self.Job, self.DataKey);
            }
        });

    }

    this.GetQueryCondtion=function()
    {
        var day=new Date();
        var endDate=day.getFullYear()*10000+(day.getMonth()+1)*100+day.getDate();
        day.setDate(day.getDate()-100); //取最近1000条数据
        var startDate=day.getFullYear()*10000+(day.getMonth()+1)*100+day.getDate()
        var id=this.Args[0];
        switch(id)
        {
            case 1:
                var data=
                {
                    Symbol:["CNA.ci"],
                    Field:["margin"], 
                    Cond:
                    [
                        {"item":["date","int32","gte",startDate.toString(),"lte",endDate.toString()]}, 
                        {"item":["margin","doc","exists","true"]}
                    ]
                }
                return data;
        }
    }

    this.ToHQChartData=function(recvData)
    {
        if (!recvData.stock || recvData.stock.length!=1) return null;

        var aryData=[];
        var setDate=new Set();  //有重复数据 去掉
        var stock=recvData.stock[0];
        var id=this.Args[0];
        var subID=this.Args[1];
        for(var i in stock.stockday)
        {
            var item=stock.stockday[i];

            var hqchartItem=this.ToHQChartItemData(item,id,subID);
            if (hqchartItem && !setDate.has(hqchartItem.Date)) 
            {
                aryData.push(hqchartItem);
                setDate.add(hqchartItem.Date);
            }
        }

        return aryData;
    }

    this.ToHQChartItemData=function(item, id, subID)
    {
        if (!item) return null;
        var date=item.date;
        var subItem=null;
        switch(id)
        {
            case 1:
                if (!item.margin) return null;
                subItem=item.margin;
                if (subID==1)
                {
                    if (!subItem.buy || !IFrameSplitOperator.IsNumber(subItem.buy.balance)) return null;
                    return { Date:date, Value:subItem.buy.balance }
                }
                else
                {
                    if (!IFrameSplitOperator.IsNumber(subItem.sell.balance)) return null;
                    return { Date:date, Value:subItem.sell.balance }
                }
                
            default:
                return null;
        }
    }
}

function DownloadGroupData(obj)
{
    this.Url=obj.Url;
    this.RealtimeUrl=obj.RealtimeUrl;
    this.Job=obj.Job;
    this.Symbol=obj.Symbol;
    this.Args=obj.Args;
    this.DataKey=obj.DataKey;
    this.RecvCallback=obj.Callback;
    this.ErrorCallback=obj.ErrorCallback;

    this.Download=function()
    {
        var varName=this.Args[0];
        switch(varName)
        {
            case "HYBLOCK":
            case "DYBLOCK":
            case "GNBLOCK":
                this.DownloadGroupName(varName);
                break;
        }
    }

    this.DownloadGroupName=function(blockType)
    {
        var self=this;
        var field=["name","symbol"];
        if (blockType=="HYBLOCK") field.push("industry");
        else if (blockType=="DYBLOCK") field.push("region");
        else if (blockType=="GNBLOCK") field.push("concept");

        JSNetwork.HttpRequest({
            url: self.RealtimeUrl,
            data:
            {
                "field": field,
                "symbol": [this.Symbol]
            },
            type:"post",
            dataType: "json",
            async:true, 
            success: function (recvData)
            {
                var data=self.RecvGroupName(recvData);
                self.RecvCallback(data, self.Job, self.DataKey, 1);
            },
            error: function(request)
            {
                self.ErrorCallback(request);
            }
        });
    }

    this.RecvGroupName=function(recvData)
    {
        if (!recvData.stock || recvData.stock.length!=1) return null;
        var stock=recvData.stock[0];
        var varName=this.Args[0];
        var value=null;
        if (varName=="HYBLOCK")
        {
            var industry=stock.industry;
            if (!industry) return null;
            var value;
            for(var i in industry)
            {
                var item=industry[i];
                value=item.name;
            }
        }
        else if (varName=="DYBLOCK")
        {
            var region=stock.region;
            if (!region) return null;
            for(var i in region)
            {
                var item=region[i];
                value=item.name;
            }
        }
        else if (varName=="GNBLOCK")
        {
            var concept=stock.concept;
            if (!concept) return null;
            value="";
            for(var i in concept)
            {
                var item=concept[i];
                if (value.length>0) value+=' ';
                value+=item.name;
            }
            
        }

        return { Value:value };
    }
}

/* 测试例子
var code1='VARHIGH:IF(VAR1<=REF(HH,-1),REF(H,BARSLAST(VAR1>=REF(HH,1))),DRAWNULL),COLORYELLOW;';
var code2='VAR1=((SMA(MAX((CLOSE - LC),0),3,1) / SMA(ABS((CLOSE - LC)),3,1)) * 100);';
var code3='mm1=1-2*-9+20;';

JSConsole.Complier.Log(code1+code2)
var tokens=JSComplier.Tokenize(code1+code2);
var ast=JSComplier.Parse(code2+code1);

JSConsole.Complier.Log(ast);
*//*
   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)", //平盘
    EmptyBarBGColor:'rgb(0,0,0)',   //空心柱子背景色

    Minute: 
    {
        VolBarColor: null,
        PriceColor: "rgb(25,180,231)",
        AreaPriceColor:"rgba(63,158,255,.3)",
        AvPriceColor: "rgb(255,236,0)",
        PositionColor:'rgb(218,165,32)', 
        VolTitleColor:"rgb(190,190,190)",
        Before:
        {
            BGColor:"rgba(105,105,105,0.5)",
            AvPriceColor:'rgb(248,248,255)'     //均线
        }
    },


    DefaultTextColor: "rgb(101,104,112)",
    DefaultTextFont: 14*GetDevicePixelRatio() +'px 微软雅黑',
    TitleFont: 13*GetDevicePixelRatio() +'px 微软雅黑',    //标题字体(动态标题 K线及指标的动态信息字体)
    IndexTitleColor:"rgb(101,104,112)",                           //指标名字颜色

    UpTextColor: "rgb(238,21,21)",
    DownTextColor: "rgb(25,158,0)",
    UnchagneTextColor: "rgb(101,104,112)",
    CloseLineColor: 'rgb(178,34,34)',

    Title:
    {
        TradeIndexColor:'rgb(105,105,105)', //交易指标颜色
        ColorIndexColor:'rgb(112,128,144)',  //五彩K线颜色

        VolColor:"rgb(101,104,112)",       //标题成交量
        AmountColor:"rgb(101,104,112)",    //成交金额 
        DateTimeColor:"rgb(101,104,112)",  //时间,日期  
        SettingColor:"rgb(101,104,112)",   //周期,复权
        NameColor:"rgb(101,104,112)" ,     //股票名称
        TurnoverRateColor:'rgb(101,104,112)',       //换手率
        PositionColor:"rgb(101,104,112)"       //持仓
    },

    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)",      //标题栏背景色
    OverlayIndexTitleBGColor:'rgba(0,0,0,0.7)', //叠加指标背景色

    Frame:
    { 
        XBottomOffset:1*GetDevicePixelRatio(), //X轴文字向下偏移
       
        PercentageText:      //百分比坐标文字颜色
        { 
            PriceColor:'rgb(101,104,112)', 
            PercentageColor:"rgb(101,104,112)", 
            SplitColor:"rgb(101,104,112)",
            Font:14*GetDevicePixelRatio() +"px 微软雅黑"
        }
    },   


    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)",           //十字光标线段颜色

    CorssCursor:
    { 
        RightButton : 
        { 
            BGColor:'rgb(43,54,69)', 
            PenColor:'rgb(255,255,255)',
            Icon: { Text:'\ue6a3', Color:'rgb(255,255,255)', Family:"iconfont", Size:18 }
        } 
    },

    //订单流配置
    OrderFlow:
    { 
        UpColor:{BG:'rgb(223,191,180)', Border:"rgb(196,84,86)" },          //阳线
        DownColor:{ BG:"rgb(176,212,184)", Border:'rgb(66,94,74)' },        //阴线
        UnchagneColor: {BG:"rgb(216,221,177)", Border:"rgb(209,172,129)"},  //平盘
        Text:{ Color: "rgb(248,248,255)" , Family:'Arial', FontMaxSize:16, MaxValue:"8888" },  //文字
        Line:{ UpDownColor: "rgb(220,220,220)", MiddleColor:"rgb(211,211,211)" }  //最大, 最低,中间 竖线
    },

    KLine:
    {
        MaxMin: { Font: 12*GetDevicePixelRatio() +'px 微软雅黑', Color: 'rgb(255,250,240)', RightArrow:"→", LeftArrow:"←", HighYOffset:0, LowYOffset:0 },   //K线最大最小值显示
        Info:  //信息地雷
        {
            Investor:
                {
                    ApiUrl:'/API/NewsInteract', //互动易
                    IconFont: { Family:'iconfont', Text:'\ue631' , HScreenText:'\ue684', Color:'#1c65db'} //SVG 文本
                },
                Announcement:                                           //公告
                {
                    ApiUrl:'/API/ReportList',
                    IconFont: { Family:'iconfont', Text:'\ue633', HScreenText:'\ue685', Color:'#f5a521' }, //SVG 文本
                    IconFont2: { Family:'iconfont', Text:'\ue634', HScreenText:'\ue686', Color:'#ed7520' } //SVG 文本 //季报
                },
                Pforecast:  //业绩预告
                {
                    ApiUrl:'/API/StockHistoryDay',
                    IconFont: { Family:'iconfont', Text:'\ue62e', HScreenText:'\ue687', Color:'#986cad' } //SVG 文本
                },
                Research:   //调研
                {
                    ApiUrl:'/API/InvestorRelationsList',
                    IconFont: { Family:'iconfont', Text:'\ue632', HScreenText:'\ue688', Color:'#19b1b7' } //SVG 文本
                },
                BlockTrading:   //大宗交易
                {
                    ApiUrl:'/API/StockHistoryDay',
                    IconFont: { Family:'iconfont', Text:'\ue630', HScreenText:'\ue689', Color:'#f39f7c' } //SVG 文本
                },
                TradeDetail:    //龙虎榜
                {
                    ApiUrl:'/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(255,255,0)"
        ],

        PointColor: 
        [
            "rgb(228,228,228)",
            "rgb(192,192,192)"
        ],
    },

    TooltipPaint : 
    {
        BGColor:'rgba(20,20,20,0.8)',    //背景色
        BorderColor:'rgb(210,210,210)',     //边框颜色
        TitleColor:'rgb(210,210,210)',       //标题颜色
        TitleFont:13*GetDevicePixelRatio() +'px 微软雅黑',   //字体
        DateTimeColor:'rgb(210,210,210)',
        VolColor:"rgb(210,210,210)",       //标题成交量
        AmountColor:"rgb(210,210,210)",    //成交金额
    },

    //走势图 信息地雷
    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)'
    },

    //筹码分布图
    StockChip:
    {
        InfoColor:'rgb(255,255,255)', //文字颜色
        DayInfoColor:'rgb(0,0,0)' //周期颜色内文字颜色
    },

    //深度图
    DepthChart:
    {
        BidColor: { Line:"rgb(82,176,123)", Area:"rgba(82,176,123,0.5)"},  //卖
        AskColor: { Line:"rgb(207,76,89)", Area:"rgba(207,76,89, 0.5)"},   //买
        LineWidth:4
    },

    DepthCorss:
    {
        BidColor: { Line:"rgb(82,176,123)" },  //卖
        AskColor: { Line:"rgb(207,76,89)" },   //买
        LineWidth:2,    //线段宽度
        LineDash:[3,3],
        Tooltip:
        { 
            BGColor:'rgba(54,54,54, 0.8)', TextColor:"rgb(203,215,224)",
            Border:{ Top:5, Left:20, Bottom:5, Center: 5},
            Font:14*GetDevicePixelRatio() +"px 微软雅黑",
            LineHeight:16   //单行高度
        }
    },

    //区间选择
    RectSelect:
    {
        LineColor:"rgb(115,83,64)",          //竖线  
        LineWidth:1*GetDevicePixelRatio(),
        LineDotted:[3,3], 
        AreaColor:"rgba(26,13,7,0.5)",     //面积
    }
    
};

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,    //格式化字符串方法
    FrameSplitKLinePriceY:FrameSplitKLinePriceY,
    FrameSplitKLineX:FrameSplitKLineX,
    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,    //日志输出

    KLineTooltipPaint:KLineTooltipPaint,    //K线tooltip
    MinuteTooltipPaint:MinuteTooltipPaint,  //走势图tooltip

    CoordinateInfo:CoordinateInfo,
}

