利用Warensoft Stock Service编写高频交易软件
无论是哪种交易软件,对于程序员来讲,最麻烦的就是去实现各种算法。本文以sar算法的实现过程为例,为大家说明如何使用warensoft stock service来实现高频交易软件的快速开发。
目前warensoftstockservice已经实现了c# 版本的客户端驱动,可以直接在nuget上搜索warensoft并安装。客户端驱动已经编译为跨平台.net standard1.6版本,可以在桌面应用(wpf,winform)、xamarin手机应用(wp,android,ios)、web(asp.net,asp.net core)中应用,操作系统可以是window,android,ios,imac,linux。
下面将以android为例(注:本demo可以直接平移到wpf中),说明sar指标的实现过程,其他指标计算的综合应用,在其他文章中会专门讲解。
软件环境说明
ide |
vs2017 rc |
客户端 |
android4.4 |
服务器环境 |
ubuntu16 |
客户端运行环境 |
xamarin.forms |
客户端图形组件 |
oxyplot |
建立一个xamarin.forms手机app
这里选择基于xaml的app,注意共享库使用pcl。
工程目录下图所示:
添加nuget引用包
首先,为warensoft.stockapp共享库添加oxyplot引用(此处可能需要*),如下图所示:
然后再分别安装warensoft.entlib.common,warensoft.entlib.stockserviceclient,如下图所示:
然后为warensoft.stockapp.droid添加oxyplot的nuget引用,如下所示:
然后在android的mainactivity中加入平台注册代码:
oxyplot.xamarin.forms.platform.android.plotviewrenderer.init();
mainactivity.cs的代码如下所示:
protected override void oncreate(bundle bundle) { tablayoutresource = resource.layout.tabbar; toolbarresource = resource.layout.toolbar; oxyplot.xamarin.forms.platform.android.plotviewrenderer.init(); base.oncreate(bundle); global::xamarin.forms.forms.init(this, bundle); loadapplication(new app()); }
实现主窗口
主界面的实现采用mvvm模式来实现,关于mvvm的讲解,网上应该有很多了,后面的文章中,我会把我自己的理解写出来,让大家分享。本demo的mvvm框架已经集成在了warensoft.entlib.common中,使用起来很简单。
第一步:
编写主界面(需要了解xaml语法),并修改mainpage.xaml,如代码如下:
<?xml version="1.0" encoding="utf-8" ?> <contentpage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:local="clr-namespace:warensoft.stockapp" xmlns:oxy="clr-namespace:oxyplot.xamarin.forms;assembly=oxyplot.xamarin.forms" x:class="warensoft.stockapp.mainpage"> <!-- 此处要注意在头中注册oxyplot的命名空间 xmlns:oxy="clr-namespace:oxyplot.xamarin.forms;assembly=oxyplot.xamarin.forms"--> <grid> <!--此处添加图形组件--> <oxy:plotview model="{binding model}" verticaloptions="center" horizontaloptions="center" /> </grid> </contentpage>
第二步:
打开mainpage.xaml.cs并为视图(图面)添加其对应的模型,代码如下(注意要引入warensoft.entlib.common):
public partial class mainpage : contentpage { public mainpage() { initializecomponent(); //此处注册viewmodel this.bindingcontext = new mainpageviewmodel(); } } public class mainpageviewmodel : viewmodelbase { public override task showcancel(string title, string message) { throw new notimplementedexception(); } public override task<bool> showconfirm(string title, string message) { throw new notimplementedexception(); } public override void showmessage(string message) { application.current.mainpage.displayalert("提示",message,"ok"); } protected override void initbindingproperties() { } }
第三步:
定义图像组件的模型,并为图像添加x、y坐标轴,添加一个k线和一条直线,代码如下所示:
public plotmodel model { get { return this.getproperty<plotmodel>("model"); } set { this.setproperty("model", value); } } protected override void initbindingproperties() { this.model = new plotmodel(); //添加x、y轴 this.model.axes.add(new oxyplot.axes.datetimeaxis() { position = axisposition.bottom, stringformat = "hh:mm", majorgridlinestyle = linestyle.solid, intervaltype = datetimeintervaltype.minutes, intervallength = 30, minorintervaltype = datetimeintervaltype.minutes, key = "time", }); this.model.axes.add(new oxyplot.axes.linearaxis() { position = axisposition.right, majorgridlinestyle = linestyle.solid, minorgridlinestyle = linestyle.dot, intervallength = 30, ispanenabled = false, iszoomenabled = false, tickstyle = tickstyle.inside, }); //添加k线和直线 this.candle = new oxyplot.series.candlestickseries(); this.line = new oxyplot.series.lineseries() { color = oxycolors.blue }; this.model.series.add(this.candle); this.model.series.add(this.line); }
第四步:
添加获取k线函数(以okcoin为例),代码如下:
/// <summary> /// 读取okcoin的15分钟k线 /// </summary> /// <returns></returns> public async task<list<kline>> loadkline() { var url = $"https://www.okcoin.cn/api/v1/kline.do?symbol=btc_cny&type=15min&size=100"; httpclient client = new httpclient(); var result = await client.getstringasync(url); dynamic k = newtonsoft.json.jsonconvert.deserializeobject(result); list<kline> lines = new list<kline>(); int index = 0; foreach (var item in k) { list<double> d = new list<double>(); foreach (var dd in item) { d.add((double)((dynamic)dd).value); } lines.add(new kline() { data = d.toarray()}); index++; } return lines; }
第五步:
添加定时刷新并绘制图像的函数,代码如下所示:
private stockservicedriver driver; public async task updatedata() { //初始化warensoftsocketservice客户端驱动,此处使用的是测试用appkey和secretkey this.driver = new stockservicedriver("c6651783-a3b9-4b72-8b02-a2e67a59c5a6", "6c442b3af58d4dda81bb03b353c0d7d8"); await task.run(async()=> { while (true) { try { //读取k线 var kline =await this.loadkline(); //远程warensoft stock service 分析sar曲线 var sar = await this.driver.getsar(kline); //绘图,注意办为需要更新ui,因此需要在主线程中执行更新代码 this.safeinvoke(()=> { //每次更新前,需要将旧数据清空 this.candle.items.clear(); this.line.points.clear(); foreach (var item in kline.orderby(k=>k.time)) { //注意将时间改为oxyplot能识别的格式 var time = oxyplot.axes.datetimeaxis.todouble(item.time); this.candle.items.add(new highlowitem(time,item.high,item.low,item.open,item.close)); } if (sar.operationdone) { foreach (var item in sar.additionaldata.orderby(s=>s.datetime)) { var time= oxyplot.axes.datetimeaxis.todouble(item.datetime); this.line.points.add(new datapoint(time, item.value)); } } //更新ui this.model.invalidateplot(true); }); } catch (exception ex) { } await task.delay(5000); } }); }
完整的viewmodel代码如下:
using system; using system.collections.generic; using system.linq; using system.text; using system.threading.tasks; using xamarin.forms; using warensoft.entlib.common; using warensoft.entlib.stockserviceclient; using oxyplot; using oxyplot.axes; using oxyplot.series; using warensoft.entlib.stockserviceclient.models; using system.net.http; namespace warensoft.stockapp { public partial class mainpage : contentpage { public mainpage() { initializecomponent(); this.bindingcontext = new mainpageviewmodel(); } } public class mainpageviewmodel : viewmodelbase { private candlestickseries candle; private lineseries line; public override task showcancel(string title, string message) { throw new notimplementedexception(); } public override task<bool> showconfirm(string title, string message) { throw new notimplementedexception(); } public override void showmessage(string message) { application.current.mainpage.displayalert("提示",message,"ok"); } public plotmodel model { get { return this.getproperty<plotmodel>("model"); } set { this.setproperty("model", value); } } protected override void initbindingproperties() { this.model = new plotmodel(); //添加x、y轴 this.model.axes.add(new oxyplot.axes.datetimeaxis() { position = axisposition.bottom, stringformat = "hh:mm", majorgridlinestyle = linestyle.solid, intervaltype = datetimeintervaltype.minutes, intervallength = 30, minorintervaltype = datetimeintervaltype.minutes, key = "time", }); this.model.axes.add(new oxyplot.axes.linearaxis() { position = axisposition.right, majorgridlinestyle = linestyle.solid, minorgridlinestyle = linestyle.dot, intervallength = 30, ispanenabled = false, iszoomenabled = false, tickstyle = tickstyle.inside, }); //添加k线和直线 this.candle = new oxyplot.series.candlestickseries(); this.line = new oxyplot.series.lineseries() { color = oxycolors.blue }; this.model.series.add(this.candle); this.model.series.add(this.line); this.updatedata(); } /// <summary> /// 读取okcoin的15分钟k线 /// </summary> /// <returns></returns> public async task<list<kline>> loadkline() { var url = $"https://www.okcoin.cn/api/v1/kline.do?symbol=btc_cny&type=15min&size=100"; httpclient client = new httpclient(); var result = await client.getstringasync(url); dynamic k = newtonsoft.json.jsonconvert.deserializeobject(result); list<kline> lines = new list<kline>(); int index = 0; foreach (var item in k) { list<double> d = new list<double>(); foreach (var dd in item) { d.add((double)((dynamic)dd).value); } lines.add(new kline() { data = d.toarray()}); index++; } return lines; } private stockservicedriver driver; public async task updatedata() { //初始化warensoftsocketservice客户端驱动,此处使用的是测试用appkey和secretkey this.driver = new stockservicedriver("c6651783-a3b9-4b72-8b02-a2e67a59c5a6", "6c442b3af58d4dda81bb03b353c0d7d8"); await task.run(async()=> { while (true) { try { //读取k线 var kline =await this.loadkline(); //远程warensoft stock service 分析sar曲线 var sar = await this.driver.getsar(kline); //绘图,注意办为需要更新ui,因此需要在主线程中执行更新代码 this.safeinvoke(()=> { //每次更新前,需要将旧数据清空 this.candle.items.clear(); this.line.points.clear(); foreach (var item in kline.orderby(k=>k.time)) { //注意将时间改为oxyplot能识别的格式 var time = oxyplot.axes.datetimeaxis.todouble(item.time); this.candle.items.add(new highlowitem(time,item.high,item.low,item.open,item.close)); } if (sar.operationdone) { foreach (var item in sar.additionaldata.orderby(s=>s.datetime)) { var time= oxyplot.axes.datetimeaxis.todouble(item.datetime); this.line.points.add(new datapoint(time, item.value)); } } //更新ui this.model.invalidateplot(true); }); } catch (exception ex) { } await task.delay(5000); } }); } } }
最后编译,并部署到手机上,最终运行效果如下:
最终编译完毕的apk文件(下载)。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持!
下一篇: Mysql全局ID生成方法