使用.NET搭建基于掘金平台的量化交易框架

360影视 动漫周边 2025-05-04 17:24 2

摘要:合规说明:本文章仅供学习交流使用,文中涉及到的投资策略、操作方式、提及的个股等等,均是技术性演示使用,仅供技术性学习参考,不构成投资建议,请大家遵守!

合规说明:本文章仅供学习交流使用,文中涉及到的投资策略、操作方式、提及的个股等等,均是技术性演示使用,仅供技术性学习参考,不构成投资建议,请大家遵守!

前言:之前写过一部分量化开发文章,不过都是自个儿操作,或者借助QMT交易来操作。QMT量化交易只能使用Python开发,虽然可以利用C# 进行开发策略,然后通过python开发的miniqmt框架进行通信对接来间接交易,但是整体上还是感觉有点怪怪的,有种慢半拍的即视感。所以现在打算写一篇入门版本的,基于掘金平台,完全使用C# 进行开发的小例子。只做基础框架开发,供参考。

首先你需要自己注册掘金量化平台的账号。注册地址:

如果你是只做策略研究使用,就可以使用免费的基础版本

如果你需要通过程序化进行交易,你需要先和你的券商客户经理了解,有没有和掘金量化平台合作,有合作的话,自行申请量化交易权限以后,再找掘金平台提供指定券商的股票版本进行使用,不然是没办法盘中程序化交易的。按照目前市场标准情况,QMT门槛是2万到500W不等;量化交易权限是5W到500W不等,根据你的券商情况而定(咨询你自己的客户经理)。

接下来,我做个从头搭建一个量化框架的入门教程,供参考。先创建一个asp.net core webapi项目

SDK版本我本地直接使用.net 8

掘金平台客户端上面,找到 我的策略->新建策略,使用C# 创建一个空策略

创建完成,会生成一个策略ID,可以保存下来备用,后面做数据回测时候需要用到。

接着,还需要一个你的账户token,用于授权使用。右上角 系统设置内,找到密钥管理,这个密钥也需要用到,可以一起拿着备用。

在前面创建的项目上,可以添加一个策略文件夹,文件夹用于存储你自己的策略集合。例如第一个策略,也放这里面来。

安装掘金SDK,我使用的64位,大家可以根据自己的系统来定。

在新建的策略类里面,继承Strategy,并且补全构造函数,以及重写OnInit函数,这个步骤是必须的。然后就可以在OnInit里面进行策略的开发,可以做数据订阅、定时器等等。以下我就按照最简单的,做一个策略,每天下午14点55分执行一次判断,需要订阅数据推送,订阅的数据,需要在重写的OnTick函数里面接收,然后在尾盘55分时候执行判断是不是符合规则。如下图所示。

接下来写一个简单的小策略,例如,10日线上穿20日线买入,下穿20日线卖出

做策略回测,需要写一个对应的回测类,回测里面就需要你的策略ID和用户Token了,这样就可以根据测试结果,推送到你的掘金客户端上面展示

然后执行回测类的测试函数,在策略研究里面,就可以看到策略执行进度

客户端的绩效分析里面,可以看到一些回测具体信息,以及你的历史BS点,这样就可以轻松看出你和指数的比较,以及你的策略是不是符合你的预期收益了。

继续换一个简单策略,例如股价第一次站上20日线买入,跌破卖出

策略不一样,同一个个股来说,一般执行的回测收益也会有差异

以上只是演示量化回测的例子,并不具有投资建议属性,千万不要无脑直接拿去用。

上面测试的源码如下:

namespace WeskyQuant.Strategies{ /// /// 第一个策略 /// public class MyFirstStrategy : Strategy { public MyFirstStrategy(string token, string strategyId, StrategyMode mode) : base(token, strategyId, mode) { } /// /// 重写OnInit事件,进行策略开发 /// public override void OnInit { Console.WriteLine("策略开始初始化"); Subscribe("SZSE.000001", "tick"); return; } DateTime currentDate; // 当前时间 /// /// 接收掘金推送的数据 /// ///

public override void OnTick(Tick tick) { if (tick.createdAt.Hour { return; // 14点之前,不操作 } if (tick.createdAt.Hour == 14 && tick.createdAt.Minute { return; // 14点55分之前,不操作 } if (currentDate == tick.createdAt.Date) { return; // 今天已经处理过了,防止重复处理 } currentDate = tick.createdAt.Date; GMDataList historyBar = GMApi.HistoryBars(tick.symbol, "1d", tick.createdAt.AddDays(-15).ToString("yyyy-MM-dd HH:mm:ss"), tick.createdAt.ToString("yyyy-MM-dd HH:mm:ss"), Adjust.ADJUST_PREV); if (historyBar == ) { Console.WriteLine("获取历史数据失败"); return; } var ma10 = historyBar.data.TakeLast(10).Average(x => x.close); var ma10_ref1 = historyBar.data.TakeLast(11).SkipLast(1).Average(x => x.close); var ma20 = historyBar.data.TakeLast(20).Average(x => x.close); var ma20_ref1 = historyBar.data.TakeLast(21).SkipLast(1).Average(x => x.close); var close = historyBar.data.Last.close; var close_ref1 = historyBar.data.SkipLast(1).Last.close; if (close > ma20 && close_ref1 { GMData o = OrderValue("SZSE.300127", 100000, OrderSide.OrderSide_Buy, OrderType.OrderType_Market, PositionEffect.PositionEffect_Open, 0); if (o.status == 0) { Console.WriteLine($"{tick.createdAt}:委托买入成功"); } else { Console.WriteLine("委托买入失败"); } } else if (close = ma20_ref1) { GMData o = OrderValue("SZSE.300127", 100000, OrderSide.OrderSide_Sell, OrderType.OrderType_Market, PositionEffect.PositionEffect_Close, 0); if (o.status == 0) { Console.WriteLine($"{tick.createdAt}:委托卖出成功"); } else { Console.WriteLine("委托卖出失败"); } } //if (ma10 > ma20) //{ // if (ma10_ref1 // { // // 10日上穿20日 // GMData o = OrderValue("SZSE.300127", 100000, OrderSide.OrderSide_Buy, OrderType.OrderType_Market, PositionEffect.PositionEffect_Open, 0); // if (o.status == 0) // { // Console.WriteLine($"{tick.createdAt}:委托买入成功"); // } // else // { // Console.WriteLine("委托买入失败"); // } // } //} //else if (ma10 //{ // if (ma10_ref1 >= ma20_ref1) // { // // 下穿 // GMData o = OrderValue("SZSE.300127", 100000, OrderSide.OrderSide_Sell, OrderType.OrderType_Market, PositionEffect.PositionEffect_Close, 0); // { // Console.WriteLine($"{tick.createdAt}:委托卖出成功"); // } // else // { // Console.WriteLine("委托卖出失败"); // } // } //} /// /// 第一个策略的回测函数 /// public class MyFirstStrategyBackTest { public void Test { //回测一年 var startTime = DateTime.Now.AddDays(-365).ToString("yyyy-MM-dd 8:20:00"); var endTime = DateTime.Now.AddDays(-1).ToString("yyyy-MM-dd 17:30:00"); MyFirstStrategy s = new MyFirstStrategy("你的token", "你的策略ID,每次新建策略,都会有一个唯一ID,你的回测数据会在策略ID对应的策略下面查看到", StrategyMode.MODE_BACKTEST); s.SetBacktestConfig(startTime, endTime); int nRet = s.Run; if (nRet != 0) { System.Console.WriteLine("回测失败, 错误码: {0}", nRet); } else { System.Console.WriteLine("回测完成!"); } } } }}

来源:opendotnet

相关推荐