HQChart使用教程60-新版k线训练使用教程


样例页面

https://opensource2.zealink.com/hqweb/demo/demo_ktrain.html">​手机端页面 https://opensource2.zealink.com/hqweb/demo/demo_ktrain.html​

https://opensource2.zealink.com/hqweb/demo/demo_ktrain2.html">​手机端横屏页面 https://opensource2.zealink.com/hqweb/demo/demo_ktrain2.html​

K线训练重构

老的K训练缺陷:


  1. 算法比较单一, 只能买一卖一, 无法一条数据上多次卖买。
  2. K线回放只是简单的在显示的时候限制数据个数,而不是数据一个一个的增加.导致复权和有些指标计算会不正确.
  3. 不支持数据拖拽,手机端手势操作

基于这些缺陷, 决定重构新版本的K线训练.

 1.  支持一条K线上多次买卖,这样就可以训练T+0的模拟

 2.  支持移动端手势和PC鼠标对数据的操作,缩放,移动等

 3.  模拟K线回放,数据是一个一个的增加.

创建K线图

通过setoption来创建K线训练图, option参数和K线图参数一致。type使用K线训练

Type: ‘K线训练’ 横屏使用 “K线训练横屏”

Train K线训练配置


  1. DataCount: 训练数据个数
  2. StartDate: 数据训练的起始位置 { Date:日期, Time:时间(分钟K线训练使用) }
    下面是一个创建K线训练的配置, 使用600000股票训练,从20180201 开始训练,训练200个数据

this.Option = 
{
Type: 'K线训练',
Windows: //窗口指标
[
//{Index:"EMPTY"},
{Index:"MA", Modify:false,Change:false},
{Index:"VOL", Modify:false,Change:false}
],
Symbol: "600000.sh",
IsAutoUpate: false, //是自动更新数据

IsShowRightMenu: false, //右键菜单
CorssCursorTouchEnd:true,

CorssCursorInfo:{ Left:0, Right:2, Bottom:1, IsShowCorss:true },

KLine:
{
Right: 0, //复权 0 不复权 1 前复权 2 后复权
Period: 0, //周期 0 日线 1 周线 2 月线 3 年线
MaxReqeustDataCount: 2000, //数据个数
PageSize: 50, //一屏显示多少数据
IsShowTooltip: false, //是否显示K线提示信息
RightSpaceCount:2,
},

KLineTitle: //标题设置
{
IsShowName: false, //不显示股票名称
IsShowSettingInfo: false, //不显示周期/复权
IsShowDateTime:true
},

Border: //边框
{
Top:1,
Left: 1, //左边间距
Right: 1 //右边间距
},

Frame: //子框架设置
[
{ SplitCount: 3, IsShowLeftText:false },
{ SplitCount: 2, IsShowLeftText:false }
],

Train:
{
DataCount:200, //训练数据
StartDate:{ Date:20180201 }
},

ExtendChart: //扩展图形
[
{ Name:'KLineTooltip' }, //手机端tooltip
{ Name:'背景图', FrameID:0 }
],
}

操作接口

K线训练接口没有对外开放,可以通过内部图形实例来操作

this.Chart.JSChartContainer JSChartContainer就是hqchart实例的内部图形实例变量, 所有K线训练操作都通过调用它的成员函数来实现。

下一个K线

MoveNextKLineData(option)

移动一个K线

option可选, k不填默认移动一个K线

{

PageSize: 移动以后一屏显示多少个数据(可选) 默认是当前的数据个数一致

Step:移动一个K线,(可选), 默认移动1个K线

}

this.MoveNextKLine=function()
{
this.Chart.JSChartContainer.MoveNextKLineData();
}

自动/停止自动移动K线

Run(option)/Stop()

Run(option)

option可选, 不填每次移动1个K线

option和 MoveNextKLineData()里的option设置一致

this.Run=function()
{
this.Chart.JSChartContainer.Run();
}

this.Stop=function()
{
this.Chart.JSChartContainer.Stop();
}

买卖股票

BuyOrSell=function(data, isDraw);

data 买卖股票的数据 { Price:价格, Vol:数量, Op: 买/卖 0=buy 1=sell, ID:单号 }

isDraw 是否更新图形

可以多次买卖无限制

this.Sell=function()    
{
.....
++this.OrderID;
//以最新价格卖出
var data={ Price:this.LatestKData.Close, Vol:10 ,Op:1 , ID:this.OrderID }; //{ Price:价格, Vol:数量, Op: 买/卖 0=buy 1=sell, ID:单号 }
......

this.Chart.JSChartContainer.BuyOrSell(data, false);
this.Chart.JSChartContainer.MoveNextKLineData(); //卖了股票移动到下一个K线上
}

this.Buy=function()
{
........
++this.OrderID;
//以最新价格买入
var data={ Price:this.LatestKData.Close, Vol:10 ,Op:0 , ID:this.OrderID }; //{ Price:价格, Vol:数量, Op: 买/卖 0=buy 1=sell, ID:单号 }
........
this.Chart.JSChartContainer.BuyOrSell(data, false);
this.Chart.JSChartContainer.MoveNextKLineData(); //买了股票移动到下一个K线上
}

K线移动监听事件

事件ID JSCHART_EVENT_ID.RECV_TRAIN_MOVE_STEP

回调函数格式 function(event,data,obj)

event 注册的事件信息

data k训练信息


  1. TrainDataCount: 剩余训练数据个数
  2. BuySellData 所有的买卖数据
  3. LastData 最新一条K线原始数据(为复权或计算周期的)
  4. LastShowData 最新一条K线显示数据 (已复权或已计算周期的)
  5. KLine K线信息 { Start 训练起始位置, End 当前最后一个数据位置 }

obj k线训练内部实例

this.Create=function()  //创建图形
{
var self=this;
$(window).resize(function() { self.OnSize(); }); //绑定窗口大小变化事件

var blackStyle=HQChartStyle.GetStyleConfig(STYLE_TYPE_ID.BLACK_ID); //读取黑色风格配置
//JSChart.SetStyle(blackStyle);
//this.DivKLine.style.backgroundColor=blackStyle.BGColor; //设置最外面的div背景

this.OnSize(); //让K线全屏
this.Chart.SetOption(this.Option); //设置K线配置

//注册K线移动监听事件
this.Chart.AddEventCallback({
event:JSCHART_EVENT_ID.RECV_TRAIN_MOVE_STEP,
callback:(event,data,obj)=> { this.OnKLineMove(event,data,obj); }
});
}

//K线移动事件回调, 把最后的K线信息显示到元素上。
this.OnKLineMove=function(event,data,obj)
{
console.log("[KLineChart::OnKLineMove] data", data);

this.LatestKData=data.LastShowData;

var dateTime=`日期:${this.LatestKData.Date}`;
if (this.LatestKData.Time) dateTime=`日期:${this.LatestKData.Date} 时间:${this.LatestKData.Time}`;

//更新界面显示信息
var message=`状态:${data.Description} ${dateTime} 最新价格: ${this.LatestKData.Close.toFixed(2)} 剩余数据:${data.TrainDataCount}`;

$("#traininfo")[0].innerText=message;

if (data.TrainDataCount<=0) this.LatestKData=null;
}

重新开始训练

RestartTrain=function(option)

option:

{

Symbol:训练的股票

Train:{ DataCount:训练数据格式, DateTime{ Date:训练起始日期, Time:训练起始时间(分钟K线才有)}

Period: 周期

Right: 复权

}

//重新开始训练
this.RestartTrain=function()
{
//外部清空上一次训练数据
.......
var option=
{
Symbol:"000001.sz",
Train:{ DataCount:30, DateTime: { Date:20190301 } } ,
Period:0, //周期
Right:1, //复权
}
this.Chart.JSChartContainer.RestartTrain(option);
}
}

买卖数据计算

由于训练成绩的规则会根据业务需求调整,所有k线训练内部不计算成绩, 有外部自行计算收益和成绩,你可以通过卖入价和卖出价简单的统计胜率, 或使用初始资金,买卖股票,最后通过持仓计算最后资金来计算复杂收益

K线背景色设置功能

为了在UI上直观的体现用户在训练的时候那次操作时赚钱的,那次操作时赔钱的。我增加了K线背景色的设置,可以设置一个时间区间段的颜色。效果如下图

HQChart使用教程60-新版k线训练使用教程_hqchart

  1. 创建
    在setoption里面(ExtendChart)创建背景色的画法并绑定到第1个窗口
    Name:固定背景图
    FrameID: 绑定窗口的索引
ExtendChart:    //扩展图形
[
{ Name:'KLineTooltip' }, //手机端tooltip
{ Name:'背景图', FrameID:0 }
],
  1. 获取背景色画法实例
    遍历所有的扩展画法,找到背景色画法实例
this.GetBGChartPaint=function()
{
for(var i in this.Chart.JSChartContainer.ExtendChartPaint)
{
var item=this.Chart.JSChartContainer.ExtendChartPaint[i];
if (item.ClassName=='BackgroundPaint') return item;
}

return null;
}
  1. 设置背景色
    data:[ ] 背景色数组
    单个背景数据结构
{ Start: 起始位置
{Date:日期, Time:时间(分钟K线才有)},
End: 结束位置
{ Date:日期, Time:时间(分钟K线才有) } ,
Color:背景颜色 'rgba(200,200,200,0.5)
};
//计算成绩
this.CalulateScore=function()
{
var count=0, success=0;
var aryBGData=[]; //背景颜色

.... 生成背景色数据

var bgPaint=this.GetBGChartPaint();
if (bgPaint) bgPaint.Data=aryBGData; //设置到背景色画法里面
}

买卖图标修改

通过获取全局的资源配置修改K线训练的配置就可以。

​HQChart使用教程4- 如何自定义K线图颜色风格​

图标使用SVG, Family 为iconfont字体名字 Text:为竖屏图标字符 HScreenText:为横屏字符。 横屏和竖屏使用2个不同的图标字符。

下面是h5用的。

this.KLineTrain = 
{
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)' }, //最后一个K线
}
};

小程序和uniapp画布都不支持SVG. 只能是文字输出作为买卖图标,比SVG效果要差好多(平台不行我也没办法)

读取全局资源配置,修改下面的配置就可以

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'},
}

完整代码

就贴一个竖屏的吧,横屏的都一样,就UI布局改下,具体看demo页面源码就可以了,我就不贴出来了。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

<title>K线图训练(手机)</title>
<!-- 加载资源 -->
<link rel="stylesheet" href="../jscommon/umychart.resource/css/tools.css" />
<link rel="stylesheet" href="../jscommon/umychart.resource/font/iconfont.css" />

<style>
.line-box{
height: 25px;
}
.btn-style{
padding: 3px 8px;
border: 1px solid #ececec;
border-radius: 5px;
background-color: #f5f5f5;
cursor: pointer;
}

</style>
</head>
<body>
<div id="kline" style="width: 900px;height:400px;position: relative;"></div>
<div class="line-box">
<span class="btn-style" id='nextkline'>下一K线</span>
<label>
<input type="checkbox" id='autorun' /> K线自动前进
</label>
<span class="btn-style" id='reset'>重新开始</span>
</div>
<div class="line-box">
<span class="btn-style" id='buy'>[ 买 ]</span>
<span class="btn-style" id='sell'>[ 卖 ]</span>
</div>
<div>
<span id='traininfo'>加载中......</span>

</div>
<div>
<span id='traininfo2'>成绩:</span>
</div>

<script src="content/js/jquery.min.js"></script>
<script src="content/js/webfont.js"></script>
<script src='../jscommon/umychart.console.js'></script> <!-- 日志输出 -->
<script src="../jscommon/umychart.network.js"></script> <!-- 网络请求分装 -->
<script src="../jscommon/umychart.js"></script> <!-- K线图形 -->
<script src="../jscommon/umychart.complier.js"></script> <!-- 麦语言解析执行器 -->
<script src="../jscommon/umychart.index.data.js"></script> <!-- 基础指标库 -->
<script src="../jscommon/umychart.style.js"></script> <!-- 白色风格和黑色风格配置信息 -->

<script>

//JSConsole.Chart.Log=() =>{}
//JSConsole.Complier.Log=()=>{}

//简单的把K线控件封装下
function KLineChart(divKLine)
{
this.DivKLine=divKLine;
this.Chart=JSChart.Init(divKLine); //把K线图绑定到一个Div上
this.LatestKData; //最新的K线数据
this.LatestTrade; //最新一条交易记录
this.AryTrade=[]; //交易记录 {Buy:, Sell:} 成对

this.ClearDivDOM=function()
{
var childList = this.DivKLine.childNodes;
for(var i in childList)
{
this.DivKLine.removeChild(childList[i]);
}
}

//K线配置信息
this.Option = {
Type: 'K线训练',
Windows: //窗口指标
[
//{Index:"EMPTY"},
{Index:"MA", Modify:false,Change:false},
{Index:"VOL", Modify:false,Change:false}
],
Symbol: "600000.sh",
IsAutoUpate: false, //是自动更新数据

IsShowRightMenu: false, //右键菜单
CorssCursorTouchEnd:true,

CorssCursorInfo:{ Left:0, Right:2, Bottom:1, IsShowCorss:true },

KLine:
{
Right: 0, //复权 0 不复权 1 前复权 2 后复权
Period: 0, //周期 0 日线 1 周线 2 月线 3 年线
MaxReqeustDataCount: 2000, //数据个数
PageSize: 50, //一屏显示多少数据
IsShowTooltip: false, //是否显示K线提示信息
RightSpaceCount:2,
},

KLineTitle: //标题设置
{
IsShowName: false, //不显示股票名称
IsShowSettingInfo: false, //不显示周期/复权
IsShowDateTime:true
},

Border: //边框
{
Top:1,
Left: 1, //左边间距
Right: 1 //右边间距
},

Frame: //子框架设置
[
{ SplitCount: 3, IsShowLeftText:false },
{ SplitCount: 2, IsShowLeftText:false }
],

Train:
{
DataCount:200, //训练数据
//StartDate:{ Date:20180201 }
},

ExtendChart: //扩展图形
[
{ Name:'KLineTooltip' }, //手机端tooltip
{ Name:'背景图', FrameID:0 }
],
}

this.Create=function() //创建图形
{
var self=this;
$(window).resize(function() { self.OnSize(); }); //绑定窗口大小变化事件

var blackStyle=HQChartStyle.GetStyleConfig(STYLE_TYPE_ID.BLACK_ID); //读取黑色风格配置
//JSChart.SetStyle(blackStyle);
//this.DivKLine.style.backgroundColor=blackStyle.BGColor; //设置最外面的div背景

this.OnSize(); //让K线全屏
this.Chart.SetOption(this.Option); //设置K线配置

this.Chart.AddEventCallback({
event:JSCHART_EVENT_ID.RECV_TRAIN_MOVE_STEP,
callback:(event,data,obj)=> { this.OnKLineMove(event,data,obj); }
});
}

this.OnSize=function() //自适应大小调整
{
var height= $(window).height()-90;
var width = $(window).width();
this.DivKLine.style.top='px';
this.DivKLine.style.left='px';
this.DivKLine.style.width=width+'px';
this.DivKLine.style.height=height+'px';
this.Chart.OnSize();
}

this.MoveNextKLine=function()
{
this.Chart.JSChartContainer.MoveNextKLineData();
}

this.Run=function()
{
this.Chart.JSChartContainer.Run();
}

this.Stop=function()
{
this.Chart.JSChartContainer.Stop();
}

this.OnKLineMove=function(event,data,obj)
{
console.log("[KLineChart::OnKLineMove] data", data);

this.LatestKData=data.LastShowData;

var dateTime=`日期:${this.LatestKData.Date}`;
if (this.LatestKData.Time) dateTime=`日期:${this.LatestKData.Date} 时间:${this.LatestKData.Time}`;

//更新界面显示信息
var message=`状态:${data.Description} ${dateTime} 最新价格: ${this.LatestKData.Close.toFixed(2)} 剩余数据:${data.TrainDataCount}`;

$("#traininfo")[0].innerText=message;

if (data.TrainDataCount<=0) this.LatestKData=null;
}

this.OrderID=10; //模拟单号

this.Sell=function()
{
if (!this.LatestKData) return;

++this.OrderID;
//以最新价格卖出
var data={ Price:this.LatestKData.Close, Vol:10 ,Op:1 , ID:this.OrderID }; //{ Price:价格, Vol:数量, Op: 买/卖 0=buy 1=sell, ID:单号 }
this.LatestTrade=data;
var tradeItem=this.AryTrade[this.AryTrade.length-1];
tradeItem.Sell={ Price:data.Price, ID:data.ID , Date:this.LatestKData.Date, Time:this.LatestKData.Time };
this.CalulateScore();

$("#sell").hide();
$("#buy").show();

this.Chart.JSChartContainer.BuyOrSell(data, false);
this.Chart.JSChartContainer.MoveNextKLineData();
}

this.Buy=function()
{
if (!this.LatestKData) return;

++this.OrderID;
//以最新价格买入
var data={ Price:this.LatestKData.Close, Vol:10 ,Op:0 , ID:this.OrderID }; //{ Price:价格, Vol:数量, Op: 买/卖 0=buy 1=sell, ID:单号 }
this.LatestTrade=data;

var tradeItem={ Buy:{Price:data.Price, ID:data.ID, Date:this.LatestKData.Date, Time:this.LatestKData.Time } };
this.AryTrade.push(tradeItem);

$("#buy").hide();
$("#sell").show();

this.Chart.JSChartContainer.BuyOrSell(data, false);
this.Chart.JSChartContainer.MoveNextKLineData();

this.CalulateScore();
}

//计算成绩
this.CalulateScore=function()
{
var count=0, success=0;
var aryBGData=[]; //背景颜色
for(var i in this.AryTrade)
{
var item=this.AryTrade[i];
if (!item.Buy || !item.Sell) continue;

var bgItem={ Start:{Date:item.Buy.Date, Time:item.Buy.Time}, End:{ Date:item.Sell.Date, Time:item.Sell.Time } };
if (item.Buy.Price<item.Sell.Price)
{
++success;
bgItem.Color='rgba(250,128,114,0.5)';
}
else
{
bgItem.Color='rgba(152,251,152,0.5)';
}

aryBGData.push(bgItem);
++count;
}

var result=0;
if (count>0) result=success/count;
var message=`成绩:交易次数${count} 成功次数${success} 胜率:${result.toFixed(2)}`;
$("#traininfo2")[0].innerText=message;

var bgPaint=this.GetBGChartPaint();
if (bgPaint) bgPaint.Data=aryBGData;
}

this.GetBGChartPaint=function()
{
for(var i in this.Chart.JSChartContainer.ExtendChartPaint)
{
var item=this.Chart.JSChartContainer.ExtendChartPaint[i];
if (item.ClassName=='BackgroundPaint') return item;
}

return null;
}

//重新开始训练
this.RestartTrain=function()
{
this.AryTrade=[];
this.LatestKData=null;
this.LatestTrade=null;
$("#traininfo2")[0].innerText='成绩:';
$("#traininfo")[0].innerText='加载中......';
$("#buy").show();
$("#sell").hide();

var bgPaint=this.GetBGChartPaint();
if (bgPaint) bgPaint.Data=null;

var option=
{
Symbol:"000001.sz",
Train:{ DataCount:30, DateTime: { Date:20190301 } } ,
Period:0, //周期
Right:1, //复权
}
this.Chart.JSChartContainer.RestartTrain(option);
}
}

$(function ()
{
WebFont.load({ custom: { families: ['iconfont'] } }); //预加载下iconfont资源

var klineControl=new KLineChart(document.getElementById('kline'));
klineControl.Create();

$("#nextkline").click(function() { klineControl.MoveNextKLine()} );
$("#autorun").click(function()
{
if (this.checked) klineControl.Run();
else klineControl.Stop();
});

$("#buy").click(function() { klineControl.Buy()} );
$("#sell").click(function() { klineControl.Sell({ Price:8.2, Vol:14 , Op:1 })} );
$("#reset").click(function() { klineControl.RestartTrain()} );

$("#buy").show();
$("#sell").hide();
})

</script>
</body>
</html>

如果还有问题或新的需求可以加交流QQ群: 950092318

HQChart代码地址

地址https://github.com/jones2000/HQChart

如果教程或hqchart对你有帮助, 请在git上star,教程点下赞 。谢谢~~