今天解读一下backtrader的order_target_percent,目前我们的大类资产配置,轮动的模板,细心的同学可能发现了,只用了这一个下单函数。
Rebalance的函数进行了优化,先卖后买:
import numpy as np import pandas as pd from .algo_base import Algo from loguru import logger class Rebalance(Algo): def __init__(self): super(Rebalance, self).__init__() def __call__(self, target): if "weights" not in target.temp: return True target_weights = target.temp["weights"] # print(targets) if type(target_weights) is pd.Series: targets = target_weights.to_dict() # 要清仓的 symbols = target.get_current_holding_symbols() for s in symbols: if s not in target_weights.keys(): # logger.info('清空:{}'.format(s)) # logger.info('{}平仓:{}'.format(target.now, s)) target.close(s) # 如果调仓就1个,且当前有持仓就1个,二者还相等,那不执行 if len(target_weights.keys()) == 1 and list(target_weights.keys())[0] in symbols and len(symbols) == 1: return True # 目标仓位里,分成两部分:目标仓位小于当前仓位的,要卖一部分,其余的,都是买入,含新增的(curr_w=0) # to_sell / to_buy to_sell = [] to_buy = [] for s in target_weights.keys(): # 取当前仓位比例 mv = target.broker.getvalue() curr_w = target.get_symbol_mv(s) / mv if target_weights[s] < curr_w: to_sell.append(s) else: to_buy.append(s) for s in to_sell: w = target_weights[s] target.order_target_percent(s, w * 0.95) for s in to_buy: w = target_weights[s] target.order_target_percent(s, w * 0.9) # 这里还有一个逻辑,就是仓位变少的(卖出)要选执行,然后才是买入,否则现金会不够多。 #for symbol, w in target_weights.items(): # # logger.info('{}调仓:{},{}'.format(target.now, data, w)) return True
就是把symbol调整到目标仓位。
我们来仔细看下它的具体操作。
target *= self.broker.getvalue(),就是:目标市值=总市值*权重
possize = self.getposition(data, self.broker).size # 这一句是多余的 target *= self.broker.getvalue() return self.order_target_value(data=data, target=target, **kwargs)
order_target_value就是仓位变成了目标市值。
possize = self.getposition(data, self.broker).size if not target and possize: # closing a position return self.close(data=data, size=possize, price=price, **kwargs) else: value = self.broker.getvalue(datas=[data]) comminfo = self.broker.getcommissioninfo(data) # Make sure a price is there price = price if price is not None else data.close[0] if target > value: size = comminfo.getsize(price, target - value) return self.buy(data=data, size=size, price=price, **kwargs) elif target < value: size = comminfo.getsize(price, value - target) return self.sell(data=data, size=size, price=price, **kwargs)
这里的逻辑也简单,就是目标市值如果大,那就买入指定size(份额),目标市值如果小,那就卖出。
buy就是提交一个“市价单“:
def buy(self, owner, data, size, price=None, plimit=None, exectype=None, valid=None, tradeid=0, **kwargs): order = BuyOrder(owner=owner, data=data, size=size, price=price, pricelimit=plimit, exectype=exectype, valid=valid, tradeid=tradeid) order.addinfo(**kwargs) vcorder = self._makeorder(order.ordtype, owner, data, size, price, plimit, exectype, valid, tradeid, **kwargs) return self.submit(order, vcorder)
这里有一个很关键的逻辑,就是一次我们会提交N个订单,有买有卖,那么第二次订单的成交顺序是什么呢?
如果按时间而言,卖单没有成交,买单是不够现金的,会产生margin的错误单(保证金不够)。
发布者:股市刺客,转载请注明出处:https://www.95sca.cn/archives/103829
站内所有文章皆来自网络转载或读者投稿,请勿用于商业用途。如有侵权、不妥之处,请联系站长并出示版权证明以便删除。敬请谅解!