def cmd_valued(self, bot, update): LOGGER.debug("valued command caught") self.renew_connection() Client().refresh() result = Client().api.account.funds['result'] num_pos = len(Client().api.account.positions) self.send_msg("Actual value is *{:.2f}* with *{}* positions".format( result, num_pos))
def open(self): if not self.auto.preserver.check_margin(self.symbol, self.quantity): LOGGER.warning( "Transaction can't be executed due to missing funds") if self.mode == ACTIONS.BUY: Client().open_pos(self.symbol, 'buy', self.quantity) if self.mode == ACTIONS.SELL: Client().open_pos(self.symbol, 'sell', self.quantity)
def get_free_margin(self): """get free margin left""" Client().refresh() total_funds = Client().funds['total'] free_funds = Client().funds['free'] used_funds = total_funds - free_funds avaible_margin = self.funds_risk * total_funds - used_funds return max(avaible_margin, 0)
def __init__(self, strat='default'): super().__init__() # LEVEL ZERO - access to apis and track errors self.sentry = SentryClient() self.client = Client(self) self.mediate = Mediator(self) # LEVEL ONE - algorithmic core self.predict = Predicter('predict') # LEVEL TWO - automation self.automate = Automaton('automate', self)
def cmd_close_all(self, bot, update): LOGGER.debug("close_all command caught") self.renew_connection() Client().refresh() LOGGER.info("closing all positions") old_results = Client().results Client().close_all() profit = Client().results - old_results LOGGER.info("profit: {:.2f}".format(profit)) self.send_msg( "Closed all positions with profit of *{:.2f}*".format(profit))
def run(self): """run method for threading""" while self.active.is_set(): start = time.time() # record timing for pos in Client().positions: Client().refresh() # refresh and update action = self.check(pos) if action is not None: self.handle_request(action, pos=pos, checker=self.__class__.__name__) wait_precisely(self.sleep_time, start, self.active) # wait and repeat
def complete(self): Client().refresh() poss = [ pos for pos in Client().api.positions if pos.instrument == self.symbol ] if self.mode == ACTIONS.BUY: if self.fix: # if requested to fix self._fix_trend(poss, 'sell') self.open() elif self.mode == ACTIONS.SELL: if self.fix: # if requested to fix self._fix_trend(poss, 'buy') self.open() LOGGER.debug("transaction completed")
def _fix_trend(self, poss, mode): pos_left = [x for x in poss if x.mode == mode] # get position of mode LOGGER.debug("{} trends to fix".format(len(pos_left))) if pos_left: # if existent for pos in pos_left: # iterate over LOGGER.debug("fixing trend for {}".format(pos.instrument)) Client().close_pos(pos)
def _time_left(self): """get time left to update of hist data""" # check EURUSD for convention hist = Client().api.get_historical_data('EURUSD', 1, self.timeframe[0]) last_time = int(hist[0]['timestamp']) / 1000 # remove milliseconds time_left = self.timeframe[1] - (time.time() - last_time) LOGGER.debug("time left (in minutes): {}".format(time_left / 60)) return time_left
def check_margin(self, symbol, quantity): """check if margin allows more buys""" free = self.get_free_margin() to_use = Client().get_margin(symbol, quantity) if to_use <= free: return True else: return False
def check(self, position): candles = Client().get_last_candles(position.instrument, self.count, self.timeframe) band = self.Meanrev.get_band(candles) if position.mode == 'buy' and position.current_price >= band: LOGGER.debug("overtaken band") return ACTIONS.CLOSE elif position.mode == 'sell' and position.current_price <= band: LOGGER.debug("overtaken band") return ACTIONS.CLOSE
def handle_request(self, event, **kw): """handle requests from chainers""" if event == ACTIONS.CLOSE: LOGGER.debug("{} checker triggered for {}".format( kw['checker'], kw['pos'].id)) Client().close_pos(kw['pos']) elif event == ACTIONS.KEEP: LOGGER.debug("{} checker keeps position {}".format( kw['checker'], kw['pos'].id)) else: self.pass_request(event, **kw)
def test_open_pos(self, caplog): caplog.set_level(logging.DEBUG, logger="forecaster") SentryClient().captureException = lambda: True # test every instrument Client().open_pos('EURUSD_ZERO', 'buy', 5000) # test if market closed if "Market closed" in caplog.records[-1].message: return Client().open_pos('GBPUSD_ZERO', 'buy', 5000) Client().open_pos('USDCAD_ZERO', 'buy', 5000) Client().open_pos('USDCHF_ZERO', 'buy', 5000) Client().open_pos('USDJPY_ZERO', 'buy', 5000) # test over quantity Client().open_pos('EURUSD_ZERO', 'buy', 60000) assert "Maximum quantity exceeded" in caplog.records[-1].message Client().open_pos('EURUSD_ZERO', 'buy', 1000) assert "Minimum quantity exceeded" in caplog.records[-1].message # test too transactions Client().open_pos('EURUSD_ZERO', 'buy', 45000) Client().open_pos('EURUSD_ZERO', 'buy', 10000) assert "Product not avaible" in caplog.records[-1].message
def check(self, position): pos_price = position.price curr_price = position.current_price candles = Client().get_last_candles(position.instrument, self.avg['count'], self.avg['timeframe']) ATR = AverageTrueRange(candles) diff = pos_price - ATR fav_price = pos_price + diff * self.gain unfav_price = pos_price - diff * self.loss # closer to 1 cross the limit, as it goes down the loss increases progress = -(fav_price - curr_price) / (fav_price - pos_price) + 1 unprogress = -(unfav_price - curr_price) / (unfav_price - pos_price) + 1 LOGGER.debug("progress to profit {:.2f}%%".format(100 * progress)) LOGGER.debug("progress to loss {:.2f}%%".format(100 * unprogress)) if progress >= 1 or unprogress >= 1: return ACTIONS.CLOSE else: return ACTIONS.KEEP
def test_close_pos(self): Client().open_pos('EURUSD_ZERO', 'buy', 5000) pos = Client().api.positions[-1] Client().close_pos(pos)
def cmd_results(self, bot, update): LOGGER.debug("results command caught") self.renew_connection() self.send_msg("Actual results are *{:.2f}*".format(Client().results))
class Bot(Chainer): """Mediator for every component and head of chaining of resposabilities""" def __init__(self, strat='default'): super().__init__() # LEVEL ZERO - access to apis and track errors self.sentry = SentryClient() self.client = Client(self) self.mediate = Mediator(self) # LEVEL ONE - algorithmic core self.predict = Predicter('predict') # LEVEL TWO - automation self.automate = Automaton('automate', self) def handle_request(self, request, **kw): """handle requests from chainers""" # start the bot if request == ACTIONS.START_BOT: self.start_bot() # stop the bot elif request == ACTIONS.STOP_BOT: self.stop_bot() # shutdown the foreground elif request == ACTIONS.SHUTDOWN: self.stop() # predict elif request == ACTIONS.PREDICT: return self.predict.predict(*kw['args']) # notify handler elif request == ACTIONS.CHANGE_MODE: return self.echo_request(self.client, request, **kw) # swap mode elif request == EVENTS.MODE_FAILURE: self.echo_request(self.mediate, EVENTS.MODE_FAILURE) self.client.swap() # notify mediator elif request in (EVENTS.MISSING_DATA, EVENTS.CLOSED_POS, EVENTS.MARKET_CLOSED): self.echo_request(self.mediate, request, **kw) # connection error elif request == EVENTS.CONNECTION_ERROR: self.echo_request(self.mediate, request) self.handle_request(ACTIONS.STOP_BOT) self.mediate.log("Bot stopped") raise def start(self): """start cycle""" # first level: interface for receiving commands self.mediate.start() LOGGER.debug("BOT: ready") def stop(self): self.automate.stop() self.mediate.stop() ThreadHandler().stop_all() LOGGER.debug("BOT: shutted down") os.kill(os.getpid(), signal.SIGINT) def idle(self): LOGGER.debug("BOT: idling") self.mediate.idle() def start_bot(self): """start bot cycle""" self.client.start() self.automate.start() LOGGER.debug("BOT: started") def stop_bot(self): self.automate.stop() LOGGER.debug("BOT: stopped")
def predict(self, symbol, interval, timeframe): candles = Client().get_last_candles(symbol, interval, timeframe) prediction = self.MeanReversion.predict(candles) return prediction
def test_start(self): self._change_mode() Client().start()
def _change_mode(self): if Client().mode == 'live': Client().swap()
def test_get_margin(self): margin = Client().get_margin('EURUSD', 10) assert isinstance(margin, (int, float))
def test_last_candler(self): prices = Client().get_last_candles('EURUSD', 5, '1h') assert isinstance(prices, list)
def test_properties(self): assert isinstance(Client().positions, list) assert isinstance(Client().account, object) assert isinstance(Client().funds, dict)
def test_init(): Client()
def test_refresh(self): Client().refresh()
def cmd_who_am_i(self, bot, update): LOGGER.debug("who_am_i command caught") text = "username: {}".format(Client().username) self.send_msg(text)
def test_close_all_pos(self): Client().open_pos('EURUSD_ZERO', 'buy', 5000) Client().open_pos('EURUSD_ZERO', 'buy', 5000) Client().close_all()