ricequant / rqalpha

A extendable, replaceable Python algorithmic backtest && trading framework supporting multiple securities
http://rqalpha.io
Other
5.39k stars 1.62k forks source link

使用next_bar 撮合交易时的问题 #166

Closed LunaFire1989 closed 7 years ago

LunaFire1989 commented 7 years ago

提 ISSUE 须知

请先阅读文档 rqalpha文档

如果仍有问题的话请在 issue列表 中寻找是否有相关问题的解决方案

如果没有的话 麻烦开一个issue 描述以下问题:

1. RQAlpha的版本

2.2.7

2. Python的版本

3.6.1

3. 是Windows/Linux/MacOS or others?

MacOS

4. 您出现问题对应的源码/或者能复现问题的简易代码 以及对应的配置

def init(context):
    context.stock = "000300.XSHG"
    context.short_period = 5
    context.long_period = 30

def handle_bar(context, bar_dict):
    signal = get_signal(stock=context.stock,
                        short_period=context.short_period,
                        long_period=context.long_period)
    curr_quantity = context.portfolio.positions[context.stock].quantity
    if signal > 0 and curr_quantity == 0:
        logger.debug("Buy")
        order_target_percent(context.stock, 1)
    if signal < 0 and curr_quantity:
        logger.debug("Sell")
        order_target_percent(context.stock, 0)

def get_signal(stock, short_period, long_period):
    close_vals = history_bars(stock, long_period * 2, "1d", "close")
    short_sma = ta.SMA(close_vals, short_period)
    long_sma = ta.SMA(close_vals, long_period)

    plot("SHORT SMA", short_sma[-1])
    plot("LONG SMA", long_sma[-1])

    signal = 0
    if short_sma[-2] < long_sma[-2] and short_sma[-1] >= long_sma[-1]:
        signal = 1
    elif short_sma[-2] > long_sma[-2] and short_sma[-1] <= long_sma[-1]:
        signal = -1
    return signal

5. 您出现的错误堆栈日志信息

在使用next_bar进行交易的时候 不能在连续天进行买卖,例如代码中2015-12-08 下单买入 则不能在2015-12-09日下单卖出 控制台输出如下: 2015-12-08 DEBUG Buy 2015-12-09 DEBUG Sell 2015-12-09 WARN 订单被拒单: 仓位不足。平仓量: 374,可平数量: 0。

wh1100717 commented 7 years ago

next_bar 是根据下一个bar来进行撮合,成交是算作下一个bar的。这时候如果卖出的话,对应的股票算作今仓,因此发平仓单的时候进行事前风控的时候 认为此时没有昨仓,无法平仓。

这个理解上确实有点奇怪,但如果是分钟线或者更细力度的回测就不会有这个问题了。

日线回测建议使用 current_bar 或者 signal 模式。 否则确实会存在资金还没有释放或者仓位不能平的场景。

LunaFire1989 commented 7 years ago

嗯 这一点的确会比较奇怪,因为日线级别的策略很多时候是在收盘后计算的,并在第二天一早执行买卖,使用current_bar撮合会与实际情况有些出入

joey-chan commented 7 years ago

日线回撤 用signal模式也同样会出现题主的情况,又是怎么回事呢

joey-chan commented 7 years ago

@wh1100717

wh1100717 commented 7 years ago

@LunaFire1989 @jeoy-chan

这个主要是因为风控是在当前bar 进行的,而next_bar_open 会在下一个开平仓。

导致 T 下的开仓指令, T+1的时候成交,并认为T+1是今仓,T+1下的平仓指令,前端风控在T+1认为是平今仓,所以报可平仓位不足。

目前前端风控没有区分不同的撮合逻辑,因为是两个不同的东西...

目前想到可以通过关闭 股票T+1交易的逻辑来规避掉这个问题。

不过 开启/关闭 T+1 的交易逻辑目前没有进行抽离,无法直接设置。

等一下,我一会实现完了再试一下...

wh1100717 commented 7 years ago

Release 3.0.1 支持 --no-stock-t1 或者直接在配置 "mod.sys_accounts.stock_t1" 具体用法如下:

# -*- coding: utf-8 -*-

from rqalpha.api import *
from rqalpha import run_func

def init(context):
    context.stock = "000300.XSHG"
    context.counter = 0

def handle_bar(context, bar_dict):
    context.counter += 1
    if context.counter == 1:
        print(111)
        order_target_percent(context.stock, 1)
    elif context.counter == 2:
        print(222)
        order_target_percent(context.stock, 0)

config = {
  "base": {
    "start_date": "2015-12-07",
    "end_date": "2015-12-15",
    "benchmark": "000300.XSHG",
    "accounts": {
      "stock": 100000
    }
  },
  "extra": {
    "log_level": "verbose",
  },
  "mod": {
    "sys_accounts": {
      "stock_t1": False
    },
    "sys_analyser": {
      "enabled": True,
      # "plot": True
    },
    "sys_simulation": {
      "matching_type": "next_bar"
    }
  }
}

# 如果你的函数命名是按照 API 规范来,则可以直接按照以下方式来运行
run_func(**globals())
wh1100717 commented 7 years ago

@joey-chan @LunaFire1989 目前这种方式其实只是 规避 股票 T+1 并且使用 next_bar 撮合,并不算是真正解决问题。

这个如果从风控的角度支持多种撮合逻辑,目前看来还是不想耦合在一起。

LunaFire1989 commented 7 years ago

@wh1100717 问题解决了 感谢~~