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

order_value() 加入佣金和滑点 的考虑,以解决全仓买入时手续费不足的bug #366

Closed wmsby closed 6 years ago

wmsby commented 6 years ago

在原代码中,order_percent(security, 1)全仓买入某只股票,出现 "创建订单失败:可用资金不足"的拒单行为。拒单本身是对的,这是因为全仓买后没有足够的手续费。但可用金额远远大于买入一手股票的资金,“可用资金不足”显然不合逻辑,令人费解。

修改后的代码可以解决这个bug,不但加入了佣金的考虑,还加入了市价单滑点的考虑,修改如下

文件路径:/mod/rqalpha_mod_sys_accounts/api/api_stock.py

order_value函数:

===================================================================


    if cash_amount > 0:
        commission_decider = env.broker._matcher._commission_decider.deciders[DEFAULT_ACCOUNT_TYPE.STOCK.name]
        commission_rate = commission_decider.rate * commission_decider.multiplier
        min_commission = commission_decider.min_commission
        cash_amount = min(cash_amount, 
                          account.cash / (1 + commission_rate), 
                          account.cash - min_commission)

    if isinstance(style, MarketOrder):
        slippage_decider = env.broker._matcher._slippage_decider.decider
        slippage_rate = slippage_decider.rate
        if cash_amount > 0:
            amount = int(Decimal(cash_amount) / Decimal(price * (1 + slippage_rate)))
        else:
            amount = int(Decimal(cash_amount) / Decimal(price * (1 - slippage_rate)))
    else:
        amount = int(Decimal(cash_amount) / Decimal(style.get_limit_price()))

================================================================= 欢迎讨论,如有理解有误,请一定指正。

Cuizi7 commented 6 years ago

多谢提交。 我认为 order_percent 的含义是,买入价值占总权益一定比例的证券,而不是花掉价值占总权益一定比例的现金。所以目前的拒单是合理的。

wmsby commented 6 years ago

这样也有一定道理,但从策略编写的角度来看,常常的想法是出现买点全仓买入,出现卖点全仓卖出,这时候不管是用order_value(security, availbale_cash), 还是order_percent(security, 1), 时不时会出现拒单行为...比如现在空仓有1000万可用资金,全仓买入一个10元的股票,无论order_value(security, availbale_cash)或order_percent(security, 1)都会买入100万股,这时候会拒单。除非在下单前,先根据佣金和滑点算好要买的股数,这就增加了策略编写端的复杂度了,有没有更好的处理办法呢?另外cash_amount 只有在非常接近或等于amount.cash的情况下,才会重新赋值account.cash / (1 + commission_rate)或account.cash - min_commission,其它情况cash_amount 依然不变;而加入滑点才是实际的市价成交价格,计算的成交数量才是真正要买入的数量,否则买入的价值因滑点的影响会更多,.比如要1000万买入一个10元的股票,滑点是0.1,原代码会计算买入100万股,就买入了1100万。

Cuizi7 commented 6 years ago

下单api考虑滑点意义不大,实盘中滑点是没法控制的。 如果策略是面向实盘的,计算下多少股的问题需要策略考虑;如果只是用来回测简单验证想法,直接关掉滑点即可。 另外实盘中不应依赖 order_value order_percent 这类 ”智能“ 的 API,在没有 executor 之前这种 api 一个大单打出去是非常危险的。