纳指期货涨的太狠了,老板交给我一个任务,看看能不能实现程序化交易。我想这操蛋啊,当年玩比特币俩月亏了一半,最后勉强回本就不玩了。结果刚不玩就一波大涨突破十万了。。。只能说哥们没这个命。但老板的任务得琢磨琢磨啊,经过一番学习,量化水真深。一开始还想着自己写个平台,发现毛都不懂,好不容易整出来的东西还死慢,不如直接用大佬的东西,发现了VNPY,开源万岁。

VNPY简单入门

安装

Windows直接去官网安装社区版就好了,甚至省去了git clone的功夫,现在直接可以安装可视化界面了,傻瓜式部署。

数据导入

根据文档,通常可以直接下载数据,但是一些海外市场的数据可能没有,或者有自己导入数据的需求,可以直接准备数据导入即可。

这里勾选应用模块下的DataManager,点击启动。

事实上,可以一次全部启动所需要的模块,这里为了演示,每次只启动一个。

勾选DataManager

在弹出窗后的工具栏选择 功能 -> 数据管理,弹出以下窗口,随后导入数据,一步步根据实际情况导入数据即可。这里假设我需要导入的是微型纳指100指数期货的历史小时数据。

导入数据

导入完成后,左侧刷新会看到导入好的数据,本地代码为MNQ.CME,之后回测会用到。

效果如下,可以看到代码(Ticker)

回测

回到之前的界面,这次勾选CtaBacktester(CTA回测研究模块),启动。同样,在弹出的窗口功能栏点击CTA回测启动新窗口。

在新窗口,输入必要的信息,如刚才记录的本地代码,回测策略,交易费用等信息。这里的DemoStrategy是最简单的双均线策略,不存在与预设的策略中,怎么加自定义策略后面会讲。

这里就多尝试功能吧,不赘述了,运行过后所有结果都会出现在右侧。

自定义策略

注意到在启动时,最右下角有个运行目录了吗?这就是项目信息保存的目录,我们的自定义策略也需要放在这个下面。

运行目录

导航到这个文件夹下,新建文件夹“strategies”,这个文件夹里头存放的就是自己写的策略,每次程序启动就会扫描这个文件夹,然后把策略显示在回测平台。

示例代码如下,我忘了从哪抄的了,想起来补上出处,只是一个最简单的双均线策略,但是可以通过代码学习以下如何开发适合这个平台的策略。

from vnpy_ctastrategy import (
    CtaTemplate,
    StopOrder,
    TickData,
    BarData,
    TradeData,
    OrderData,
    BarGenerator,
    ArrayManager,
)


class DemoStrategy(CtaTemplate):
    """演示用的简单双均线"""

    # 策略作者
    author = "Smart Trader"

    # 定义参数
    fast_window = 10
    slow_window = 20

    # 定义变量
    fast_ma0 = 0.0
    fast_ma1 = 0.0
    slow_ma0 = 0.0
    slow_ma1 = 0.0

    # 添加参数和变量名到对应的列表
    parameters = ["fast_window", "slow_window"]
    variables = ["fast_ma0", "fast_ma1", "slow_ma0", "slow_ma1"]

    def __init__(self, cta_engine, strategy_name, vt_symbol, setting):
        """
        构造函数
        """
        super().__init__(cta_engine, strategy_name, vt_symbol, setting)

        # K线合成器:从Tick合成分钟K线用
        self.bg = BarGenerator(self.on_bar)

        # 时间序列容器:计算技术指标用
        self.am = ArrayManager()

    def on_init(self):
        """
        当策略被初始化时调用该函数。
        """
        self.write_log("策略初始化")

        # 加载10天的历史数据用于初始化回放
        self.load_bar(10)

    def on_start(self):
        """
        当策略被启动时调用该函数。
        """
        self.write_log("策略启动")

        # 通知图形界面更新(策略最新状态)
        self.put_event()

    def on_stop(self):
        """
        当策略被停止时调用该函数。
        """
        self.write_log("策略停止")

        self.put_event()

    def on_tick(self, tick: TickData):
        """
        通过该函数收到Tick推送。
        """
        self.bg.update_tick(tick)

    def on_bar(self, bar: BarData):
        """
        通过该函数收到新的1分钟K线推送。
        """
        am = self.am

        # 更新K线到时间序列容器中
        am.update_bar(bar)

        # 若缓存的K线数量尚不够计算技术指标,则直接返回
        if not am.inited:
            return

        # 计算快速均线
        fast_ma = am.sma(self.fast_window, array=True)
        self.fast_ma0 = fast_ma[-1]     # T时刻数值
        self.fast_ma1 = fast_ma[-2]     # T-1时刻数值

        # 计算慢速均线
        slow_ma = am.sma(self.slow_window, array=True)
        self.slow_ma0 = slow_ma[-1]
        self.slow_ma1 = slow_ma[-2]

        # 判断是否金叉
        cross_over = (self.fast_ma0 > self.slow_ma0 and
                      self.fast_ma1 < self.slow_ma1)

        # 判断是否死叉
        cross_below = (self.fast_ma0 < self.slow_ma0 and
                       self.fast_ma1 > self.slow_ma1)

        # 如果发生了金叉
        if cross_over:
            price = bar.close_price + 5

            if self.pos == 0:  # 当前无仓位,则直接开多
                self.buy(price, 1)
            elif self.pos < 0:  # 当前持有空头仓位,则先平空,再开多
                self.cover(price, 1)
                self.buy(price, 1)

        # 如果发生了死叉
        elif cross_below:
            price = bar.close_price - 5

            if self.pos == 0:  # 当前无仓位,则直接开空
                self.short(price, 1)
            elif self.pos > 0:  # 当前持有多头仓位,则先平多,再开空
                self.sell(price, 1)
                self.short(price, 1)

        self.put_event()

    def on_order(self, order: OrderData):
        """
        通过该函数收到委托状态更新推送。
        """
        pass

    def on_trade(self, trade: TradeData):
        """
        通过该函数收到成交推送。
        """
        self.put_event()

    def on_stop_order(self, stop_order: StopOrder):
        """
        通过该函数收到本地停止单推送。
        """
        pass

保存后,再次启动程序回测时就能看到了。

总结

这篇文章简单讲了一下VNPY这个开源量化平台的基本使用,下一篇应该讲讲如何对接IB盈透证券使用吧,主要讲讲如何先使用延迟数据测试,毕竟哪有那么对富人呢,对吧,都是臭打工的。