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

今天看了陈老师给出来的几个策略代码,发现所有代码下面的内容都是一样的,
为何self.load_bar(10) 中的参数是10 而不是其他的数字? 这句话具体是有什么用?

def on_init(self):
"""策略初始化"""

    #注册
    self.write_log('策略初始化')
    self.load_bar(10)
Administrator
avatar
加入于:
帖子: 4500
声望: 320

load_bar,在回测时加载10个交易日数据用于初始化,实盘中加载10个自然日数据用于初始化。

10这个数字具体请根据你策略需要的数据量进行调整,一般10天已经戳戳有余,所以这么设计。

Member
avatar
加入于:
帖子: 69
声望: 3

谢谢! 如果我从2019年1月1日开始测试。这个load_bar是指的从数据库中往前数10天,也就是2018年12月21日开始load数据吗?

Administrator
avatar
加入于:
帖子: 4500
声望: 320

不是哦,是2019年1月1日开始的所有数据中,最前面的10天(大概2019年1月11日前的吧)

Member
avatar
加入于:
帖子: 69
声望: 3

谢谢啦!

Member
avatar
加入于:
帖子: 152
声望: 4

用Python的交易员 wrote:

load_bar,在回测时加载10个交易日数据用于初始化,实盘中加载10个自然日数据用于初始化。

10这个数字具体请根据你策略需要的数据量进行调整,一般10天已经戳戳有余,所以这么设计。

请问一下如果不用到历史数据,
这个设为0有没有问题?

Administrator
avatar
加入于:
帖子: 4500
声望: 320

常山之蛇 wrote:

用Python的交易员 wrote:

load_bar,在回测时加载10个交易日数据用于初始化,实盘中加载10个自然日数据用于初始化。

10这个数字具体请根据你策略需要的数据量进行调整,一般10天已经戳戳有余,所以这么设计。

请问一下如果不用到历史数据,
这个设为0有没有问题?

有问题,不能设置为0,初始化的时候同时回测引擎需要绑定行情回调函数

Member
avatar
加入于:
帖子: 152
声望: 4

用Python的交易员 wrote:

不是哦,是2019年1月1日开始的所有数据中,最前面的10天(大概2019年1月11日前的吧)

再请问一下,那实盘是怎么样的?

比如从2019年1月1日开始跑实盘,self.load_bar(10),它不会从2019年1月11日才开实交易吧?

Member
avatar
加入于:
帖子: 18
声望: 0

常山之蛇 wrote:

用Python的交易员 wrote:

不是哦,是2019年1月1日开始的所有数据中,最前面的10天(大概2019年1月11日前的吧)

再请问一下,那实盘是怎么样的?

比如从2019年1月1日开始跑实盘,self.load_bar(10),它不会从2019年1月11日才开实交易吧?
应该是在跑实盘之前初始化就会下载前10个交易日的数据,不然初始化不成功,没法实盘。

Administrator
avatar
加入于:
帖子: 4500
声望: 320

常山之蛇 wrote:

用Python的交易员 wrote:

不是哦,是2019年1月1日开始的所有数据中,最前面的10天(大概2019年1月11日前的吧)

再请问一下,那实盘是怎么样的?

比如从2019年1月1日开始跑实盘,self.load_bar(10),它不会从2019年1月11日才开实交易吧?

如果没有准备历史数据,加载不到的话自然就没有回放了。那么策略中如果用到ArrayManager,则会因为数据不足无法完成初始化,然后on_bar里的逻辑判断就会阻止交易

Member
avatar
加入于:
帖子: 49
声望: 0

请教这10天是必须连续的 还是可以间断呢?

Administrator
avatar
加入于:
帖子: 4500
声望: 320

回测中的10天是10个交易日,实盘中的10天是10个自然日。

所以加载数据尽可能多一点,避免节假日的影响。

Member
avatar
加入于:
帖子: 7
声望: 0

load_bar在实盘中是否还起到了策略重启的数据恢复作用?关于它还有两个实盘相关的疑问:

  1. 实盘时load_bar的过程,一旦满足am.sise,初始化的过程也会运行策略逻辑,岂不是会针对历史数据有下单操作?
  2. load_bar默认应该是从数据库拿数据的吧?但实盘最好是从broker api拿数据比较可靠,vnpy内部逻辑有支持么?
Member
avatar
加入于:
帖子: 4622
声望: 284
  1. 要load_bar完成后(初始化完成后),trading状态才会变为true。
  2. 可以去engine.py看一下load_bar函数。默认use_database为false,会先去接口拿数据,没有的话会去rqdata找,最后才会去database。
Member
avatar
加入于:
帖子: 26
声望: 0

xiaohe wrote:

  1. 要load_bar完成后(初始化完成后),trading状态才会变为true。
  2. 可以去engine.py看一下load_bar函数。默认use_database为false,会先去接口拿数据,没有的话会去rqdata找,最后才会去database。

如果数据库中只有两天的数据,load_bar(10) 会不会出问题?

Member
avatar
加入于:
帖子: 419
声望: 170

李贵珍 wrote:

xiaohe wrote:

  1. 要load_bar完成后(初始化完成后),trading状态才会变为true。
  2. 可以去engine.py看一下load_bar函数。默认use_database为false,会先去接口拿数据,没有的话会去rqdata找,最后才会去database。

如果数据库中只有两天的数据,load_bar(10) 会不会出问题?

关于这个问题,可以看看这篇帖子:https://www.vnpy.com/forum/topic/4890-fen-xi-yi-xia-pan-zhong-qi-dong-ctace-lue-dai-lai-de-di-yi-gen-he-cheng-kxian-cuo-wu

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

还是不太理解回测的场景(不是实盘场景)下,这个load _bar的作用。
我的策略用到20日均线,策略如下。为何我 load _bar 30天和load _bar 40天的结果会不一样?请指教。


# 策略
class DoubleMaStrategy(CtaTemplate):
    author = "用Python的交易员"

    fast_window = 10
    slow_window = 20



    def __init__(self, cta_engine, strategy_name, vt_symbol, setting):
        """"""
        print('in init')
        super().__init__(cta_engine, strategy_name, vt_symbol, setting)

        # self.bg = BarGenerator(self.on_bar) # 当用tick合成k线时才需要
        self.am = ArrayManager(size=25)

    def on_init(self):
        """
        Callback when strategy is inited.
        """
        self.write_log("策略初始化")

        self.load_bar(days=30, interval = Interval.DAILY)
        self.count=0

    def on_start(self):
        """
        Callback when strategy is started.
        """
        self.write_log("策略启动")
        # self.put_event()

    def on_stop(self):
        """
        Callback when strategy is stopped.
        """
        self.write_log("策略停止")

        # self.put_event()



    def on_bar(self, bar: BarData):
        """
        Callback of new bar data update.
        """
        self.count+=1
        print('onbar',self.count,  bar.datetime,bar.open_price)
        am = self.am
        am.update_bar(bar)
        if not am.inited:            
            return

        fast_ma = am.sma(self.fast_window, array=True) 

        slow_ma = am.sma(self.slow_window, array=True)

        cross_over = fast_ma[-1] > slow_ma[-1] and fast_ma[-2] < slow_ma[-2]
        cross_below =  fast_ma[-1] < slow_ma[-1] and fast_ma[-2] > slow_ma[-2]

        if cross_over:
            if self.pos == 0:
                print('buy creat0',bar.vt_symbol,bar.datetime,bar.close_price)
                self.buy(bar.close_price, 1)
            elif self.pos < 0:
                print('cover creat',bar.datetime,bar.close_price, 'pos',self.pos)
                self.cover(bar.close_price, 1)
                print('buy creat',bar.vt_symbol,bar.datetime,bar.close_price)
                self.buy(bar.close_price, 1)

        elif cross_below:
            if self.pos == 0:
                print('short creat0',bar.symbol,bar.vt_symbol,bar.datetime,bar.close_price)
                self.short(bar.close_price, 1)
            elif self.pos > 0:
                print('sell creat',bar.datetime,bar.close_price)
                self.sell(bar.close_price, 1)
                print('short creat',bar.datetime,bar.close_price)
                self.short(bar.close_price, 1)
Member
avatar
加入于:
帖子: 4622
声望: 284

load_bar是加载数据做初始化,之前load完剩下的数据才用来回测(初始化结束后策略的trading状态才为true,才能发单)。load30天比load20天剩下回测的数据少10天,当然结果不一样了。

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

又仔细看了一下代码,感觉比较混乱。

# 这个是回测,不是实盘
from vnpy.app.cta_strategy.backtesting import BacktestingEngine, OptimizationSetting
from vnpy.app.cta_strategy.strategies.atr_rsi_strategy import (
    AtrRsiStrategy,
)
# from vnpy.app.cta_strategy.strategies.double_ma_strategy import (
#     DoubleMaStrategy,
# )
from vnpy.trader.constant import Interval

from vnpy.app.cta_strategy import (
    CtaTemplate,
    StopOrder,
    TickData,
    BarData,
    TradeData,
    OrderData,
    BarGenerator,
    ArrayManager,
)
from vnpy.app.cta_strategy.base import BacktestingMode


# 策略
class DoubleMaStrategy(CtaTemplate):
    author = "用Python的交易员"

    fast_window = 10
    slow_window = 20



    def __init__(self, cta_engine, strategy_name, vt_symbol, setting):
        """"""
        print('in init')
        super().__init__(cta_engine, strategy_name, vt_symbol, setting)

        # self.bg = BarGenerator(self.on_bar) # 当用tick合成k线时才需要
        amsize=25
        self.am = ArrayManager(size=amsize)

    def on_init(self):
        """
        Callback when strategy is inited.
        """
        print("策略初始化")

        load_days=30
        self.load_bar(days=load_days, interval = Interval.DAILY)
        self.count=0




    def on_bar(self, bar: BarData):
        """
        Callback of new bar data update.
        """
        self.count+=1
        print('onbar',self.count,  bar.datetime,bar.open_price)
        am = self.am
        am.update_bar(bar)
        if not am.inited:            
            return

        fast_ma = am.sma(self.fast_window, array=True) 

        slow_ma = am.sma(self.slow_window, array=True)

        cross_over = fast_ma[-1] > slow_ma[-1] and fast_ma[-2] < slow_ma[-2]
        cross_below =  fast_ma[-1] < slow_ma[-1] and fast_ma[-2] > slow_ma[-2]

        if cross_over:
            if self.pos == 0:
                print('buy creat0',bar.vt_symbol,bar.datetime,bar.close_price)
                self.buy(bar.close_price, 1)
            elif self.pos < 0:
                print('cover creat',bar.datetime,bar.close_price, 'pos',self.pos)
                self.cover(bar.close_price, 1)
                print('buy creat',bar.vt_symbol,bar.datetime,bar.close_price)
                self.buy(bar.close_price, 1)

        elif cross_below:
            if self.pos == 0:
                print('short creat0',bar.symbol,bar.vt_symbol,bar.datetime,bar.close_price)
                self.short(bar.close_price, 1)
            elif self.pos > 0:
                print('sell creat',bar.datetime,bar.close_price)
                self.sell(bar.close_price, 1)
                print('short creat',bar.datetime,bar.close_price)
                self.short(bar.close_price, 1)



################
# 主程序开始
#####################
from datetime import datetime


engine = BacktestingEngine()
engine.set_parameters(
    vt_symbol="600000.SSE",
    interval="d",
    start=datetime(2000, 1, 4),
    end=datetime(2000, 3, 30),
    rate=0.3/10000,
    slippage=0.00,
    size=300,
    pricetick=0.0001, # 下单的时候,vnpy会把成交价格处理成与pricetick的小数位数相同,且是pricetick的整数倍。
    capital=1_000_000,
    mode=BacktestingMode.BAR,
)
engine.add_strategy(DoubleMaStrategy, {})


engine.load_data()
engine.run_backtesting()
df = engine.calculate_result()
engine.calculate_statistics()
engine.show_chart()

策略里的self.load_bar(days=30, interval = Interval.DAILY)并不是加载30天或30根bar的数据。
(所有数据在此之前已经通过回测引擎engine.load_data()从数据库加载到history_data了)

策略里的self.load_bar(days=30)只是设置引擎的self.days = 30
之后,在engine.run_backtesting()函数中:
1 回测引擎会对这30根bar,依次调用30次策略的on_bar (注意,这里有可能创建订单)。
2 结束这初始30根bar的处理后,设置
self.strategy.inited = True
self.strategy.on_start()
self.strategy.trading = True
3 对30根bar后面剩余的每根bar
调用策略的 on_bar(bar) (这里也可能创建订单)
更新每日结果daily_results

所以,在1和3处都有可能创建订单。
特别是1处是初始30根bar以内的。我的问题是这初始30根bar以内创建的订单会不会影响回测结果,会不会执行?

Member
avatar
加入于:
帖子: 4622
声望: 284

楼上已经说过了,初始化结束后策略的trading状态才为true,才能发单。初始化的时候,trading状态为false,是不会发单的

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

沪公网安备 31011502017034号

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