def settle_for_stocks(self, last_date, date): if self.df_dividend is None: return df = self.df_dividend.loc[(self.df_dividend['exdiv_date'] > last_date) & (self.df_dividend['exdiv_date'] <= date)] if df.empty: return df2 = df.set_index('symbol') for symbol in df2.index: if symbol in self.ctx.pm.holding_securities: df_symbol = df2.loc[symbol] shares_ratio = df_symbol['shares'] cash_ratio = df_symbol['cash_tax'] pos = self.ctx.pm.get_position(symbol).current_size if cash_ratio > 0: cash_added = cash_ratio * pos #self.ctx.pm.cash += cash_added trade_ind1, trade_ind2 = generate_cash_trade_ind(symbol, cash_added, date, 60000) self.ctx.strategy.on_trade(trade_ind1) self.ctx.strategy.on_trade(trade_ind2) if shares_ratio > 0: pos_diff = abs(pos * shares_ratio) trade_ind = Trade() trade_ind.symbol = symbol trade_ind.task_id = self.POSITION_ADJUST_NO trade_ind.entrust_no = self.POSITION_ADJUST_NO if pos > 0: trade_ind.entrust_action = common.ORDER_ACTION.BUY else: trade_ind.entrust_action = common.ORDER_ACTION.SELL trade_ind.set_fill_info(price=0.0, size=pos_diff, date=date, time=60000, no=self.POSITION_ADJUST_NO) self.ctx.strategy.on_trade(trade_ind)
def delist_adjust(self): df_inst = self.ctx.dataview.data_inst start = self.last_rebalance_date # start will be one day later end = self.current_rebalance_date # end is the same to ensure position adjusted for dividend on rebalance day mask = np.logical_and(df_inst['delist_date'] >= start, df_inst['delist_date'] <= end) dic_inst = df_inst.loc[mask, :].to_dict(orient='index') if not dic_inst: return pm = self.ctx.pm for symbol in pm.holding_securities.copy(): value_dic = dic_inst.get(symbol, None) if value_dic is None: continue pos = pm.get_position(symbol).current_size last_trade_date = self._get_last_trade_date(value_dic['delist_date']) last_close_price = self.ctx.dataview.get_snapshot(last_trade_date, symbol=symbol, fields='close') last_close_price = last_close_price.at[symbol, 'close'] trade_ind = Trade() trade_ind.symbol = symbol trade_ind.task_id = self.DELIST_ADJUST_NO trade_ind.entrust_no = self.DELIST_ADJUST_NO trade_ind.entrust_action = common.ORDER_ACTION.SELL # for now only BUY trade_ind.set_fill_info(price=last_close_price, size=pos, date=last_trade_date, time=150000, no=self.DELIST_ADJUST_NO) self.ctx.strategy.cash += trade_ind.fill_price * trade_ind.fill_size #self.ctx.pm.cash += trade_ind.fill_price * trade_ind.fill_size self.ctx.strategy.on_trade(trade_ind)
def generate_cash_trade_ind(symbol, amount, date, time=200000): trade_ind = Trade() trade_ind.symbol = symbol trade_ind.task_id = 0 trade_ind.entrust_no = "0" trade_ind.set_fill_info(price=0.0, size=abs(amount), date=date, time=time, no="0") trade_ind2 = Trade() trade_ind2.symbol = symbol trade_ind2.task_id = 0 trade_ind2.entrust_no = "0" trade_ind2.set_fill_info(price=1.0, size=abs(amount), date=date, time=time, no="0") if amount > 0: trade_ind.entrust_action = common.ORDER_ACTION.BUY trade_ind2.entrust_action = common.ORDER_ACTION.SELL else: trade_ind.entrust_action = common.ORDER_ACTION.SELL trade_ind2.entrust_action = common.ORDER_ACTION.BUY return trade_ind, trade_ind2
def delist_adjust(self): df_inst = self.ctx.dataview.data_inst start = self.last_rebalance_date # start will be one day later end = self.current_rebalance_date # end is the same to ensure position adjusted for dividend on rebalance day mask = np.logical_and(df_inst['delist_date'] >= start, df_inst['delist_date'] <= end) dic_inst = df_inst.loc[mask, :].to_dict(orient='index') if not dic_inst: return pm = self.ctx.pm for symbol in pm.holding_securities.copy(): value_dic = dic_inst.get(symbol, None) if value_dic is None: continue pos = pm.get_position(symbol).current_size last_trade_date = self._get_last_trade_date( value_dic['delist_date']) last_close_price = self.ctx.dataview.get_snapshot(last_trade_date, symbol=symbol, fields='close') last_close_price = last_close_price.at[symbol, 'close'] trade_ind = Trade() trade_ind.symbol = symbol trade_ind.task_id = self.DELIST_ADJUST_NO trade_ind.entrust_no = self.DELIST_ADJUST_NO trade_ind.entrust_action = common.ORDER_ACTION.SELL # for now only BUY trade_ind.set_fill_info(price=last_close_price, size=pos, date=last_trade_date, time=150000, no=self.DELIST_ADJUST_NO) self.ctx.strategy.cash += trade_ind.fill_price * trade_ind.fill_size self.ctx.strategy.on_trade(trade_ind)
def settle_for_stocks(self, last_date, date): df = self.df_dividend.loc[(self.df_dividend['exdiv_date'] > last_date) & (self.df_dividend['exdiv_date'] <= date)] if df.empty: return df2 = df.set_index('symbol') for symbol in df2.index: if symbol in self.ctx.pm.holding_securities: df_symbol = df2.loc[symbol] shares_ratio = df_symbol['shares'] cash_ratio = df_symbol['cash_tax'] pos = self.ctx.pm.get_position(symbol).current_size if cash_ratio > 0: cash_added = cash_ratio * pos #self.ctx.pm.cash += cash_added trade_ind1, trade_ind2 = generate_cash_trade_ind( symbol, cash_added, date, 60000) self.ctx.strategy.on_trade(trade_ind1) self.ctx.strategy.on_trade(trade_ind2) if shares_ratio > 0: pos_diff = abs(pos * shares_ratio) trade_ind = Trade() trade_ind.symbol = symbol trade_ind.task_id = self.POSITION_ADJUST_NO trade_ind.entrust_no = self.POSITION_ADJUST_NO if pos > 0: trade_ind.entrust_action = common.ORDER_ACTION.BUY else: trade_ind.entrust_action = common.ORDER_ACTION.SELL trade_ind.set_fill_info(price=0.0, size=pos_diff, date=date, time=60000, no=self.POSITION_ADJUST_NO) self.ctx.strategy.on_trade(trade_ind)
def position_adjust(self): """ adjust happens after market close Before each re-balance day, adjust for all dividend and cash paid actions during the last period. We assume all cash will be re-invested. Since we adjust our position at next re-balance day, PnL before that may be incorrect. """ start = self.last_rebalance_date # start will be one day later end = self.current_rebalance_date # end is the same to ensure position adjusted for dividend on rebalance day df_adj = self.ctx.dataview.get_ts('adjust_factor', start_date=start, end_date=end) pm = self.ctx.pm for symbol in pm.holding_securities: ser = df_adj.loc[:, symbol] ser_div = ser.div(ser.shift(1)).fillna(1.0) mask_diff = ser_div != 1 ser_adj = ser_div.loc[mask_diff] for date, ratio in ser_adj.iteritems(): pos_old = pm.get_position(symbol).current_size # TODO pos will become float, original: int pos_new = pos_old * ratio pos_diff = pos_new - pos_old # must be positive if pos_diff <= 0: # TODO this is possible # raise ValueError("pos_diff <= 0") continue trade_ind = Trade() trade_ind.symbol = symbol trade_ind.task_id = self.POSITION_ADJUST_NO trade_ind.entrust_no = self.POSITION_ADJUST_NO trade_ind.entrust_action = common.ORDER_ACTION.BUY # for now only BUY trade_ind.set_fill_info(price=0.0, size=pos_diff, date=date, time=200000, no=self.POSITION_ADJUST_NO) self.ctx.strategy.on_trade(trade_ind)
if __name__ == '__main__': props = dict() props['start_date'] = 20170702 props['end_date'] = 20170712 props['future_commission_rate'] = 0.005 props['stock_commission_rate'] = 0.005 props['stock_tax_rate'] = 0.002 props['symbol'] = '600030.SH' pnlmgr = PnlManager() from jaqs.data import RemoteDataService ds = RemoteDataService() pnlmgr.initFromConfig(props, ds) trades = [] t1 = Trade() t1.symbol = '600030.SH' t1.action = common.ORDER_ACTION.BUY t1.fill_date = 20170704 t1.fill_size = 100 t1.fill_price = 16.72 t2 = Trade() t2.symbol = '600030.SH' t2.action = common.ORDER_ACTION.SELL t2.fill_date = 20170706 t2.fill_size = 50 t2.fill_price = 16.69 t3 = Trade() t3.symbol = '600030.SH' t3.action = common.ORDER_ACTION.SELL t3.fill_date = 20170707 t3.fill_size = 50