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 match(self, price_dic, date=19700101, time=150000): self._validate_price(price_dic) results = [] for order in self.__orders.values(): symbol = order.symbol symbol_dic = price_dic[symbol] # get fill price if isinstance(order, FixedPriceTypeOrder): price_target = order.price_target fill_price = symbol_dic[price_target] elif isinstance(order, VwapOrder): if order.start != -1: raise NotImplementedError("Vwap of a certain time range") fill_price = symbol_dic['vwap'] elif isinstance(order, Order): # TODO fill_price = symbol_dic['close'] else: raise NotImplementedError("order class {} not support!".format( order.__class__)) # get fill size fill_size = order.entrust_size - order.fill_size # create trade indication trade_ind = Trade(order) trade_ind.set_fill_info(fill_price, fill_size, date, time, self._next_fill_no(), trade_date=date) # update order status order.fill_price = (order.fill_price * order.fill_size + fill_price * fill_size) / (order.fill_size + fill_size) order.fill_size += fill_size if order.fill_size == order.entrust_size: order.order_status = common.ORDER_STATUS.FILLED order_status_ind = OrderStatusInd(order) results.append((trade_ind, order_status_ind)) self.__orders = { k: v for k, v in self.__orders.items() if not v.is_finished } # self.cancel_order(order.entrust_no) # TODO DEBUG return results
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, trade_date=last_trade_date) 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 test_order_trade_task(): from jaqs.data.basic import TradeStat, Trade, Task, TaskInd, Order, OrderStatusInd order = Order() order.symbol = 'SPY' order.task_id = 10000001 order.entrust_no = '123' order.entrust_size = 10 order.entrust_action = 'Short' order.entrust_price = 1.2 order.entrust_time = 95055 order.entrust_date = 20171201 order.fill_price = 1.19 order.fill_size = 3 order.commission = 0.001 str(order) o2 = Order(order) o2.entrust_no = '124' o3 = Order.new_order('SPY', 'Buy', 10, 10, 20111111, 143029, 'Limit') oind = OrderStatusInd(order) OrderStatusInd.create_from_dict({'symbol': 'SPY'}) str(oind) task = Task(order.task_id, 'vwap', {'a': 'b'}, order, 'place_order', order.entrust_date) assert (not task.is_finished) task.task_status = common.TASK_STATUS.DONE assert task.is_finished tind = TaskInd(task.task_id, task.task_status, task.algo, 'success') str(tind) tind2 = TaskInd.create_from_dict({'task_id': 2011223}) trade = Trade(order) trade.set_fill_info(15, 20, 20171202, 112311, 12345) str(trade) t2 = Trade.create_from_dict({'symbol': 'SPY'}) tstat = TradeStat() str(tstat)
def match(self, price_dic, date=19700101, time=150000): self._validate_price(price_dic) results = [] for order in self.__orders.values(): symbol = order.symbol symbol_dic = price_dic[symbol] # get fill price if isinstance(order, FixedPriceTypeOrder): price_target = order.price_target fill_price = symbol_dic[price_target] elif isinstance(order, VwapOrder): if order.start != -1: raise NotImplementedError("Vwap of a certain time range") fill_price = symbol_dic['vwap'] elif isinstance(order, Order): # TODO fill_price = symbol_dic['close'] else: raise NotImplementedError("order class {} not support!".format(order.__class__)) # get fill size fill_size = order.entrust_size - order.fill_size # create trade indication trade_ind = Trade(order) trade_ind.set_fill_info(fill_price, fill_size, date, time, self._next_fill_no()) # update order status order.fill_price = (order.fill_price * order.fill_size + fill_price * fill_size) / (order.fill_size + fill_size) order.fill_size += fill_size if order.fill_size == order.entrust_size: order.order_status = common.ORDER_STATUS.FILLED order_status_ind = OrderStatusInd(order) results.append((trade_ind, order_status_ind)) self.__orders = {k: v for k, v in self.__orders.items() if not v.is_finished} # self.cancel_order(order.entrust_no) # TODO DEBUG return results
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 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('_daily_adjust_factor', start_date=start, end_date=end) # FIXME: the first day should have been balanced before? df_adj = df_adj[1:] pm = self.ctx.pm # Find symbols which has adj_factor not equaling 1 tmp = df_adj[df_adj != 1].fillna(0.0).sum() adj_symbols = set(tmp[tmp != 0].index).intersection( pm.holding_securities) #for symbol in pm.holding_securities: for symbol in adj_symbols: ser = df_adj.loc[:, symbol] ser_adj = ser.dropna() 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, trade_date=date) self.ctx.strategy.on_trade(trade_ind)
def on_trade(self, ind_dic): """ Parameters ---------- ind_dic : dict """ # print("\nGateway on trade: ") # print(ind_dic) if 'security' in ind_dic: ind_dic['symbol'] = ind_dic.pop('security') ind = Trade.create_from_dict(ind_dic) self.ctx.strategy.on_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)
def on_trade(self, ind_dic): """ Parameters ---------- ind_dic : dict """ # print("\nGateway on trade: ") # print(ind_dic) if 'security' in ind_dic: ind_dic['symbol'] = ind_dic.pop('security') ind = Trade.create_from_dict(ind_dic) ind.task_no = self._task_no_id_map[ind.task_id] e = Event(EVENT_TYPE.TRADE_IND) e.dic['ind'] = ind self.ctx.instance.put(e)
def _make_trade_bar(self, quote_dic): result = [] for entrust_no, order in self.orders.items(): quote = quote_dic[order.symbol] low = quote.low high = quote.high quote_date = quote.trade_date quote_time = quote.time volume = quote.volume ''' if order.order_type == common.ORDER_TYPE.LIMIT: if order.entrust_action == common.ORDER_ACTION.BUY and order.entrust_price >= low: trade = Trade() trade.init_from_order(order) trade.send_fill_info(order.entrust_price, order.entrust_size, quote_date, quote_time, self._next_fill_no()) order.order_status = common.ORDER_STATUS.FILLED order.fill_size = trade.fill_size order.fill_price = trade.fill_price orderstatus_ind = OrderStatusInd() orderstatus_ind.init_from_order(order) result.append((trade, orderstatus_ind)) elif order.entrust_action == common.ORDER_ACTION.SELL and order.entrust_price <= high: trade = Trade() trade.init_from_order(order) trade.send_fill_info(order.entrust_price, order.entrust_size, quote_date, quote_time, self._next_fill_no()) order.order_status = common.ORDER_STATUS.FILLED order.fill_size = trade.fill_size order.fill_price = trade.fill_price orderstatus_ind = OrderStatusInd() orderstatus_ind.init_from_order(order) result.append((trade, orderstatus_ind)) elif order.order_type == common.ORDER_TYPE.STOP: if order.entrust_action == common.ORDER_ACTION.BUY and order.entrust_price <= high: trade = Trade() trade.init_from_order(order) trade.send_fill_info(order.entrust_price, order.entrust_size, quote_date, quote_time, self._next_fill_no()) order.order_status = common.ORDER_STATUS.FILLED order.fill_size = trade.fill_size order.fill_price = trade.fill_price orderstatus_ind = OrderStatusInd() orderstatus_ind.init_from_order(order) result.append((trade, orderstatus_ind)) if order.entrust_action == common.ORDER_ACTION.SELL and order.entrust_price >= low: trade = Trade() trade.init_from_order(order) trade.send_fill_info(order.entrust_price, order.entrust_size, quote_date, quote_time, self._next_fill_no()) order.order_status = common.ORDER_STATUS.FILLED order.fill_size = trade.fill_size order.fill_price = trade.fill_price orderstatus_ind = OrderStatusInd() orderstatus_ind.init_from_order(order) result.append((trade, orderstatus_ind)) ''' entrust_price = order.entrust_price entrust_size = order.entrust_size fill_size = 0 if order.order_type == common.ORDER_TYPE.LIMIT: if common.ORDER_ACTION.is_positive( order.entrust_action) and entrust_price >= low: fill_price = min(entrust_price, high) # fill_size = min(entrust_size, self.participation_rate * volume) fill_size = entrust_size elif common.ORDER_ACTION.is_negative( order.entrust_action) and order.entrust_price <= high: fill_price = max(entrust_price, low) # fill_size = min(entrust_size, self.participation_rate * volume) fill_size = entrust_size elif order.order_type == common.ORDER_TYPE.STOP: if common.ORDER_ACTION.is_positive( order.entrust_action) and order.entrust_price <= high: fill_price = max(entrust_price, low) # fill_size = min(entrust_size, self.participation_rate * volume) fill_size = entrust_size if common.ORDER_ACTION.is_negative( order.entrust_action) and order.entrust_price >= low: fill_price = min(entrust_price, high) # fill_size = min(entrust_size, self.participation_rate * volume) fill_size = entrust_size elif order.order_type == common.ORDER_TYPE.VWAP: fill_price = quote.vwap fill_size = entrust_size if not fill_size: continue trade_ind = Trade(order) trade_ind.set_fill_info(order.entrust_price, order.entrust_size, quote_date, quote_time, self._next_fill_no()) order.fill_price = ( (order.fill_price * order.fill_size + fill_size * fill_price) / (order.fill_size + fill_size)) order.fill_size += fill_size if order.fill_size == order.entrust_size: order.order_status = common.ORDER_STATUS.FILLED order_status_ind = OrderStatusInd(order) result.append((trade_ind, order_status_ind)) self.orders = { k: v for k, v in self.orders.items() if not v.is_finished } return result
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
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_date=date) 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",trade_date=date) 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 _make_trade_bar(self, quote_dic): result = [] for entrust_no, order in self.orders.items(): quote = quote_dic[order.symbol] low = quote.low high = quote.high quote_date = quote.trade_date quote_time = quote.time volume = quote.volume ''' if order.order_type == common.ORDER_TYPE.LIMIT: if order.entrust_action == common.ORDER_ACTION.BUY and order.entrust_price >= low: trade = Trade() trade.init_from_order(order) trade.send_fill_info(order.entrust_price, order.entrust_size, quote_date, quote_time, self._next_fill_no()) order.order_status = common.ORDER_STATUS.FILLED order.fill_size = trade.fill_size order.fill_price = trade.fill_price orderstatus_ind = OrderStatusInd() orderstatus_ind.init_from_order(order) result.append((trade, orderstatus_ind)) elif order.entrust_action == common.ORDER_ACTION.SELL and order.entrust_price <= high: trade = Trade() trade.init_from_order(order) trade.send_fill_info(order.entrust_price, order.entrust_size, quote_date, quote_time, self._next_fill_no()) order.order_status = common.ORDER_STATUS.FILLED order.fill_size = trade.fill_size order.fill_price = trade.fill_price orderstatus_ind = OrderStatusInd() orderstatus_ind.init_from_order(order) result.append((trade, orderstatus_ind)) elif order.order_type == common.ORDER_TYPE.STOP: if order.entrust_action == common.ORDER_ACTION.BUY and order.entrust_price <= high: trade = Trade() trade.init_from_order(order) trade.send_fill_info(order.entrust_price, order.entrust_size, quote_date, quote_time, self._next_fill_no()) order.order_status = common.ORDER_STATUS.FILLED order.fill_size = trade.fill_size order.fill_price = trade.fill_price orderstatus_ind = OrderStatusInd() orderstatus_ind.init_from_order(order) result.append((trade, orderstatus_ind)) if order.entrust_action == common.ORDER_ACTION.SELL and order.entrust_price >= low: trade = Trade() trade.init_from_order(order) trade.send_fill_info(order.entrust_price, order.entrust_size, quote_date, quote_time, self._next_fill_no()) order.order_status = common.ORDER_STATUS.FILLED order.fill_size = trade.fill_size order.fill_price = trade.fill_price orderstatus_ind = OrderStatusInd() orderstatus_ind.init_from_order(order) result.append((trade, orderstatus_ind)) ''' entrust_price = order.entrust_price entrust_size = order.entrust_size fill_size = 0 if order.order_type == common.ORDER_TYPE.LIMIT: if common.ORDER_ACTION.is_positive(order.entrust_action) and entrust_price >= low: fill_price = min(entrust_price, high) # fill_size = min(entrust_size, self.participation_rate * volume) fill_size = entrust_size elif common.ORDER_ACTION.is_negative(order.entrust_action) and order.entrust_price <= high: fill_price = max(entrust_price, low) # fill_size = min(entrust_size, self.participation_rate * volume) fill_size = entrust_size elif order.order_type == common.ORDER_TYPE.STOP: if common.ORDER_ACTION.is_positive(order.entrust_action) and order.entrust_price <= high: fill_price = max(entrust_price, low) # fill_size = min(entrust_size, self.participation_rate * volume) fill_size = entrust_size if common.ORDER_ACTION.is_negative(order.entrust_action) and order.entrust_price >= low: fill_price = min(entrust_price, high) # fill_size = min(entrust_size, self.participation_rate * volume) fill_size = entrust_size elif order.order_type == common.ORDER_TYPE.VWAP: fill_price = quote.vwap fill_size = entrust_size if not fill_size: continue trade_ind = Trade(order) trade_ind.set_fill_info(order.entrust_price, order.entrust_size, quote_date, quote_time, self._next_fill_no()) order.fill_price = ((order.fill_price * order.fill_size + fill_size * fill_price) / (order.fill_size + fill_size)) order.fill_size += fill_size if order.fill_size == order.entrust_size: order.order_status = common.ORDER_STATUS.FILLED order_status_ind = OrderStatusInd(order) result.append((trade_ind, order_status_ind)) self.orders = {k: v for k, v in self.orders.items() if not v.is_finished} return result
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