class VixVxvRatio(Strategy): def __init__(self, stg_id: str, stg_cls: str, state: StrategyState = None): super(VixVxvRatio, self).__init__(stg_id=stg_id, stg_cls=stg_cls, state=state) self.day_count = 0 self.order = None def _start(self, app_context: Context) -> None: self.qty = self._get_stg_config("qty", 1) self.threshold = self._get_stg_config("threshold", 1) self.xiv = app_context.ref_data_mgr.get_inst('XIV', 'SMART') self.vxx = app_context.ref_data_mgr.get_inst('VXX', 'SMART') self.vxv = app_context.ref_data_mgr.get_inst('VXV', 'SMART') self.vix = app_context.ref_data_mgr.get_inst( 'VIX', 'SMART') # TODO: Review index instruments = [self.vxx, self.xiv, self.vix] self.vix_bar = app_context.inst_data_mgr.get_series( "Bar.%s.Time.86400" % self.vix.get_symbol()) # non tradable self.vxv_bar = app_context.inst_data_mgr.get_series( "Bar.%s.Time.86400" % self.vxv.get_symbol()) # non tradable self.xiv_bar = app_context.inst_data_mgr.get_series( "Bar.%s.Time.86400" % self.xiv.get_symbol()) self.vxx_bar = app_context.inst_data_mgr.get_series( "Bar.%s.Time.86400" % self.vxx.get_symbol()) self.vix_strm = BehaviorSubject(0) self.vxv_strm = BehaviorSubject(0) self.ratio_strm = rx.Observable \ .zip(self.vix_strm, self.vxv_strm, lambda x, y: x / y) \ .subscribe(self.on_ratio) super(VixVxvRatio, self)._start(app_context) def _stop(self): super(VixVxvRatio, self)._stop() def on_bar(self, bar): if bar.inst_id == self.vix.id(): self.vix_strm.on_next(bar.close) elif bar.inst_id == self.vxv.id(): self.vxv_strm.on_next(bar.close) def on_ratio(self, ratio): # what is order is not filled and there is signal again? if self.order is None: # long XIV at the close when VIX index closed below the VXV index # long XIV when ratio < 0.92 if ratio < self.threshold[0]: # logger.info("%s,B,%.2f" % (bar.timestamp, bar.close)) self.order = self.market_order(inst_id=self.xiv.id(), action=Buy, qty=self.qty) # long VXX when ratio > 1.08 elif ratio > self.threshold[1]: # logger.info("%s,B,%.2f" % (bar.timestamp, bar.close)) self.order = self.market_order(inst_id=self.vxx, action=Buy, qty=self.qty)
class VixVxvRatio(Strategy): def __init__(self, stg_id=None, stg_configs=None): super(VixVxvRatio, self).__init__(stg_id=stg_id, stg_configs=stg_configs) self.day_count = 0 self.order = None def _start(self, app_context, **kwargs): self.qty = self.get_stg_config_value("qty", 1) self.threshold = self.get_stg_config_value("threshold", 1) self.xiv = app_context.ref_data_mgr.get_inst('XIV', 'SMART') self.vxx = app_context.ref_data_mgr.get_inst('VXX', 'SMART') self.vxv = app_context.ref_data_mgr.get_inst('VXV', 'SMART') self.vix = app_context.ref_data_mgr.get_inst('VIX', 'SMART') # TODO: Review index instruments = [self.vxx, self.xiv, self.vix] self.vix_bar = app_context.inst_data_mgr.get_series("Bar.%s.Time.86400" % self.vix.get_symbol()) # non tradable self.vxv_bar = app_context.inst_data_mgr.get_series("Bar.%s.Time.86400" % self.vxv.get_symbol()) # non tradable self.xiv_bar = app_context.inst_data_mgr.get_series("Bar.%s.Time.86400" % self.xiv.get_symbol()) self.vxx_bar = app_context.inst_data_mgr.get_series("Bar.%s.Time.86400" % self.vxx.get_symbol()) self.vix_strm = BehaviorSubject(0) self.vxv_strm = BehaviorSubject(0) self.ratio_strm = rx.Observable \ .zip(self.vix_strm, self.vxv_strm, lambda x, y: x / y) \ .subscribe(self.on_ratio) super(VixVxvRatio, self)._start(app_context, **kwargs) def _stop(self): super(VixVxvRatio, self)._stop() def on_bar(self, bar): if bar.inst_id == self.vix.id(): self.vix_strm.on_next(bar.close) elif bar.inst_id == self.vxv.id(): self.vxv_strm.on_next(bar.close) def on_ratio(self, ratio): # what is order is not filled and there is signal again? if self.order is None: # long XIV at the close when VIX index closed below the VXV index # long XIV when ratio < 0.92 if ratio < self.threshold[0]: # logger.info("%s,B,%.2f" % (bar.timestamp, bar.close)) self.order = self.market_order(inst_id=self.xiv.id(), action=OrdAction.BUY, qty=self.qty) # long VXX when ratio > 1.08 elif ratio > self.threshold[1]: # logger.info("%s,B,%.2f" % (bar.timestamp, bar.close)) self.order = self.market_order(inst_id=self.vxx, action=OrdAction.BUY, qty=self.qty)
class SerialHelper: ser = serial.Serial('/dev/ttyACM0', 115200) def __init__(self): self.messages = BehaviorSubject("") self.read() # def read(self, recieved): # while self.ser.in_waiting: # recieved(self.ser.readline()) # def read(self): self.threadObj = threading.Thread(target=worker, args=(self,)) self.threadObj.start() def setMessage(self, message): self.messages.on_next(message) def write(self, message): self.ser.write(message);
class Integrator: def __init__(self, new_players, exiting_players): self._new_players = [] self._players = [] self._removed_players = [] new_players.subscribe(self.add_player) exiting_players.subscribe(self.remove_player) # streams api self.new_players_broadcast = Subject() self.removed_players_broadcast = Subject() self.collisions = Subject() self.players = BehaviorSubject([]) self.players_count = self.players \ .map(lambda ps: len(ps)) def add_player(self, player): self._new_players.append(player) def remove_player(self, player): self._removed_players.append(player) def broadcast(self, message): for p in self._players: p.ws_subject.on_next(message) def update(self, dt): if len(self._new_players): self._do_add_players() self._integrate_speed(dt) self._collide() if len(self._removed_players): self._do_remove_players() def _collide(self): for a, b in combinations(self._players, 2): posa = a.pos.value posb = b.pos.value sizea = a.size.value sizeb = b.size.value distance = math.sqrt((posa["x"] - posb["x"]) ** 2 + (posa["y"] - posb["y"]) ** 2) if distance < sizea + sizeb: self.collisions.on_next((a, b)) def _integrate_speed(self, dt): for player in self._players: direction = player.dir.value if direction is not None \ and direction["x"] != 0 \ and direction["y"] != 0: position = player.pos.value speed = 300 * dt result = { "x": position["x"] + direction["x"] * speed, "y": position["y"] + direction["y"] * speed } player.pos.on_next(result) def _do_add_players(self): self._players.extend(self._new_players) self.new_players_broadcast.on_next( (self._players, self._new_players.copy())) self._new_players.clear() self.players.on_next(self._players) def _do_remove_players(self): for p in self._removed_players: self._players.remove(p) self.removed_players_broadcast.on_next( (self._players, self._removed_players.copy())) self._removed_players.clear() self.players.on_next(self._players)
class PairTradingWithOUSpread(Strategy): """ This is the baby version that assume the asset we are trading paris that the spread follows Ornstein-Uhlenbeck mean reverting process with known parameters in advance in reality this is not true So for more advanced version the strategy itself should able to call statistical inference logic to get the appreciation rate and volatility of the asset So now this class is used as testing purpose """ def __init__(self, stg_id=None, stg_configs=None): """ :param stg_id: :param portfolio: :param instruments: :param ou_params: a dictionary with k, theta, eta as keys :param gamma: risk preference :param trading_config: :return: """ super(PairTradingWithOUSpread, self).__init__(stg_id=stg_id, stg_configs=stg_configs) self.buy_order = None def _start(self, app_context, **kwargs): self.ou_params = self.get_stg_config_value("ou_params", 1) self.gamma = self.get_stg_config_value("gamma", 1) self.bar_0 = app_context.inst_data_mgr.get_series("Bar.%s.Time.86400" % self.app_context.app_config.instrument_ids[0]) self.bar_0.start(app_context) self.bar_1 = app_context.inst_data_mgr.get_series("Bar.%s.Time.86400" % self.app_context.app_config.instrument_ids[1]) self.bar_1.start(app_context) self.instruments = self.app_context.app_config.instrument_ids self.log_spot_0 = BehaviorSubject(0) self.log_spot_1 = BehaviorSubject(0) self.spread_stream = rx.Observable \ .zip(self.log_spot_0, self.log_spot_1, lambda x, y: [x, y, x - y]) \ .subscribe(self.rebalance) super(PairTradingWithOUSpread, self)._start(app_context, **kwargs) def _stop(self): super(PairTradingWithOUSpread, self)._stop() def on_bar(self, bar): # logger.info("%s,%s,%.2f" % (bar.inst_id, bar.timestamp, bar.close)) if bar.inst_id == self.instruments[0]: self.log_spot_0.on_next(math.log(bar.close)) elif bar.inst_id == self.instruments[1]: self.log_spot_1.on_next(math.log(bar.close)) def rebalance(self, spread_triple): if spread_triple[0] == 0: return # we have to rebalance on each bar k = self.ou_params['k'] eta = self.ou_params['eta'] theta = self.ou_params['theta'] spread = spread_triple[2] weight = k * (spread - theta) / eta ** 2 portfolio = self.get_portfolio() allocation_0 = -portfolio.total_equity * weight allocation_1 = portfolio.total_equity * weight # TODO: need to check if the portoflio.positions is empty delta_0 = allocation_0 delta_1 = allocation_1 if self.instruments[0] in portfolio.positions.keys(): delta_0 = allocation_0 - portfolio.positions[self.instruments[0]].current_value() if self.instruments[1] in portfolio.positions.keys(): delta_1 = allocation_1 - portfolio.positions[self.instruments[1]].current_value() qty = abs(delta_0) / spread_triple[0] # assume no lot size here if delta_0 > 0: self.market_order(inst_id=self.instruments[0], action=OrdAction.BUY, qty=qty) else: self.market_order(inst_id=self.instruments[0], action=OrdAction.SELL, qty=qty) qty = abs(delta_1) / spread_triple[1] # assume no lot size here if delta_1 > 0: self.market_order(inst_id=self.instruments[1], action=OrdAction.BUY, qty=qty) else: self.market_order(inst_id=self.instruments[1], action=OrdAction.SELL, qty=qty)
class Backend(QObject): def __init__(self, parent=None): super().__init__(parent) self._commandSubject = BehaviorSubject(kine.Command.arc(0, 0)) @pyqtSlot() def forward(self): self._commandSubject.on_next(kine.Command.arc(0.5, 0.0)) @pyqtSlot() def backward(self): self._commandSubject.on_next(kine.Command.arc(-0.5, 0.0)) @pyqtSlot() def left(self): self._commandSubject.on_next(kine.Command.arc(0.5, 0.5)) @pyqtSlot() def right(self): self._commandSubject.on_next(kine.Command.arc(0.5, -0.5)) @pyqtSlot() def stop(self): self._commandSubject.on_next(kine.Command.arc(0.0, 0.0)) @pyqtSlot() def pivotLeft(self): self._commandSubject.on_next( kine.Command(velocity=0, angularVelocity=0.3)) @pyqtSlot() def pivotRight(self): self._commandSubject.on_next( kine.Command(velocity=0, angularVelocity=-0.3)) @pyqtSlot() def toOrigin(self): self._commandSubject.on_next( kine.Command.arc_to(self.robot.pose, Vec2.zero(), 0.5)) @property def commands(self): return self._commandSubject
class PairTradingWithOUSpread(Strategy): """ This is the baby version that assume the asset we are trading paris that the spread follows Ornstein-Uhlenbeck mean reverting process with known parameters in advance in reality this is not true So for more advanced version the strategy itself should able to call statistical inference logic to get the appreciation rate and volatility of the asset So now this class is used as testing purpose """ def __init__(self, stg_id: str, stg_cls: str, state: StrategyState = None): super(PairTradingWithOUSpread, self).__init__(stg_id=stg_id, stg_cls=stg_cls, state=state) self.buy_order = None def _start(self, app_context: Context) -> None: self.ou_params = self._get_stg_config("ou_params", default=1) self.gamma = self._get_stg_config("gamma", default=1) self.instruments = app_context.config.get_app_config("instrumentIds") self.bar_0 = self.app_context.inst_data_mgr.get_series( "Bar.%s.Time.86400" % self.instruments[0]) self.bar_1 = self.app_context.inst_data_mgr.get_series( "Bar.%s.Time.86400" % self.instruments[1]) self.bar_0.start(app_context) self.bar_1.start(app_context) self.log_spot_0 = BehaviorSubject(0) self.log_spot_1 = BehaviorSubject(0) self.spread_stream = rx.Observable \ .zip(self.log_spot_0, self.log_spot_1, lambda x, y: [x, y, x - y]) \ .subscribe(self.rebalance) super(PairTradingWithOUSpread, self)._start(app_context) def _stop(self): super(PairTradingWithOUSpread, self)._stop() def on_bar(self, bar): # logger.info("%s,%s,%.2f" % (bar.inst_id, bar.timestamp, bar.close)) if bar.inst_id == self.instruments[0]: self.log_spot_0.on_next(math.log(bar.close)) elif bar.inst_id == self.instruments[1]: self.log_spot_1.on_next(math.log(bar.close)) def rebalance(self, spread_triple): if spread_triple[0] == 0: return # we have to rebalance on each bar k = self.ou_params['k'] eta = self.ou_params['eta'] theta = self.ou_params['theta'] spread = spread_triple[2] weight = k * (spread - theta) / eta**2 portfolio = self.get_portfolio() allocation_0 = -portfolio.total_equity * weight allocation_1 = portfolio.total_equity * weight # TODO: need to check if the portoflio.positions is empty delta_0 = allocation_0 delta_1 = allocation_1 if self.instruments[0] in portfolio.positions.keys(): delta_0 = allocation_0 - portfolio.positions[ self.instruments[0]].current_value() if self.instruments[1] in portfolio.positions.keys(): delta_1 = allocation_1 - portfolio.positions[ self.instruments[1]].current_value() qty = abs(delta_0) / spread_triple[0] # assume no lot size here if delta_0 > 0: self.market_order(inst_id=self.instruments[0], action=Buy, qty=qty) else: self.market_order(inst_id=self.instruments[0], action=Sell, qty=qty) qty = abs(delta_1) / spread_triple[1] # assume no lot size here if delta_1 > 0: self.market_order(inst_id=self.instruments[1], action=Buy, qty=qty) else: self.market_order(inst_id=self.instruments[1], action=Sell, qty=qty)