VeighNa量化社区
你的开源社区量化交易平台
Member
avatar
加入于:
帖子: 57
声望: 1

我一直在用backtrader,也想看看vnpy。但vnpy很多示例代码都不是极简的,参合着界面相关部分,使得我始终抓不住vnpy的核心。
希望有朋友能把下述简单的策略逻辑用vnpy实现一下。

极简的双均线策略:使用日线数据,基本思想是短期均线上穿长期均线(金叉)买入,下穿长期均线(死叉)卖出。
以下是backtrader的实现代码。代码无需考虑日线长度,backtrader会自动取得恰好足够长的数据,用以计算均线值。

希望有精通vnpy的朋友,也写个极简的代码实现同样的逻辑(删除所有不必要的部分,比如给界面传递事件信息的部分),看看vnpy的核心编制思路是咋样的。谢谢。

# 创建策略类
class SmaCross(bt.Strategy):
    # 定义参数
    params = dict(
        fast_period=5,  # 快速移动平均期数
        slow_period = 10,)  # 慢速移动平均期数

    def __init__(self):
        # 股票stock的快速移动平均线指标
        fastMA = {stock: bt.ind.MovingAverageSimple(stock, period=self.params.fast_period) for stock in self.datas}

        # 股票stock的慢速移动平均线指标
        slowMA = {stock: bt.ind.MovingAverageSimple(stock, period=self.params.slow_period) for stock in self.datas}

        # 股票stock的移动均线交叉信号指标
        self.crossover = {stock: bt.ind.CrossOver(fastMA[stock], slowMA[stock]) for stock in self.datas}        

        self.orderlist = []    # 以往订单列表


    def next(self): # 每个新bar触发调用一次,相当于其他框架的 on_bar()方法
        for o in self.orderlist:
            self.cancel(o) # 取消以往所有订单
            self.orderlist=[] # 置空

        for stock in self.datas:
            if not self.getposition(stock):  # 还没有仓位,才可以买
                if self.crossover[stock] > 0:  # 金叉           
                    order = self.buy(data=stock,size=100)
                    self.orderlist.append(order)

            # 已有仓位,才可以卖
            elif self.crossover[stock] < 0:  # 死叉          
                order = self.sell(data=stock, size=100)
                self.orderlist.append(order)
Member
avatar
加入于:
帖子: 4622
声望: 284

可以参考自带的双均线策略

Member
avatar
加入于:
帖子: 57
声望: 1

有自带的多股双均线策略吗?我只看到单股的,如下,里头有很多不必要的,策略无关的东西,比如self.put_event(),以及 variables = ["fast_ma0", "fast_ma1", "slow_ma0", "slow_ma1"]之类。所以我想看看极简化的,去掉这些干扰的代码。

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()
        print('__init__')

    def on_init(self):
        """
        当策略被初始化时调用该函数。
        """
        print('in on_init')
        # 输出个日志信息,下同
        self.write_log("策略初始化")

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

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

        # 通知图形界面更新(策略最新状态)
        # 不调用该函数则界面不会变化
        self.put_event()

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

        self.put_event()

    def on_tick(self, tick: TickData):
        """
        通过该函数收到Tick推送。
        """
        print(f'in on_tick:  {tick.vt_symbol},{tick.datetime}, ask_price_1: {tick.ask_price_1}')
        self.bg.update_tick(tick)

    def on_bar(self, bar: BarData):
        """
        通过该函数收到新的1分钟K线推送。
        """
        print(f'on_bar: {bar.vt_symbol},{bar.datetime}, close price: {bar.close_price}')
        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:
            print('发生金叉')
            # 为了保证成交,在K线收盘价上加5发出限价单
            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:
            print('发生死叉')
            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
Member
avatar
加入于:
帖子: 4622
声望: 284

可以按照portfolio_strategy的示例策略修改迁移过去,不想要put_event就自己删掉就好了

Member
avatar
加入于:
帖子: 57
声望: 1

不是没太明白吗?所以才希望有懂的帮帮忙啊

© 2015-2022 上海韦纳软件科技有限公司
备案服务号:沪ICP备18006526号

沪公网安备 31011502017034号

【用户协议】
【隐私政策】
【免责条款】