def configure_poloniex(): api_key = config.API_KEY api_secret = config.API_SECRET polo = Poloniex(api_key, api_secret) _timing = time.time() def _arc(f): def decorator(*args, **kwargs): logging.info(('request', f.__name__, str(args), str(kwargs))) while time.time() - _timing < 0.5: time.sleep(0.01) return f(*args, **kwargs) return decorator polo.buy = _arc(polo.buy) polo.sell = _arc(polo.sell) polo.returnCompleteBalances = _arc(polo.returnCompleteBalances) polo.returnOpenOrders = _arc(polo.returnOpenOrders) polo.cancelOrder = _arc(polo.cancelOrder) polo.moveOrder = _arc(polo.moveOrder) polo.returnTradeHistory = _arc(polo.returnTradeHistory) return polo
class PoloData: def __init__(self, *args, **kwargs): self._polo = Poloniex(*args, **kwargs) self.ticker_update_freq = 1 self.ticker_updated = datetime(1970, 1, 1) self._ticker = {} self.ticker = None self.ticker_active = False self._ticker_thread = None self.charts_update_freq = 60 self.charts_updated = datetime(1970, 1, 1) self.charts = {} self.charts_active = False self._charts_thread = None self.chart_path = None self._new_chart = False self.balances_update_freq = 1 self.balances_updated = datetime(1970, 1, 1) self.balances = None self.balances_active = False self._balances_thread = None self.markets = self._get_markets() def start_ticker(self, update_freq): self.ticker_update_freq = update_freq self._ticker_thread = threading.Thread(target=self._get_ticker) self._ticker_thread.setDaemon(True) self.ticker_active = True self._ticker_thread.start() def _get_ticker(self): while self.ticker_active: # print(datetime.now(), "Ticker Update") self._ticker = self._polo.returnTicker() self._populate_ticker() self.ticker_updated = datetime.now() time.sleep(self.ticker_update_freq) print("Ticker thread stopped.") def stop_ticker(self): self.ticker_active = False def _get_markets(self): ticker = self._polo.returnTicker() markets = {} for k in ticker.keys(): pc, sc = k.split("_") if pc not in markets: markets[pc] = pd.DataFrame(columns=[ 'last', 'highestBid', 'baseVolume', 'lowestAsk', 'quoteVolume', 'low24hr', 'high24hr', 'percentChange', 'isFrozen', 'id', 'favourite' ], dtype=float) if sc not in markets[pc]: markets[pc].ix[sc, "favourite"] = 0 return markets def _populate_ticker(self): self.ticker = pd.DataFrame.from_dict(self._ticker, orient='index', dtype=float).fillna(0) def start_charts(self, update_freq, chart_path): self.charts_update_freq = update_freq self.chart_path = chart_path self._charts_thread = threading.Thread(target=self._get_charts) self._charts_thread.setDaemon(True) self.charts_active = True self._charts_thread.start() def _get_charts(self): while self.charts_active: # print(datetime.now(), "Charts Update") update_time = datetime.now() + timedelta( seconds=self.charts_update_freq) for chart in self.charts: market, currency = chart.split("_") if self.charts[chart] is None: self.charts[chart] = self._load_chart( market, currency, datetime.now() - timedelta(days=90), datetime.now()) self._new_chart = False else: self.charts[chart] = self._update_chart( market, currency, self.charts[chart]) self.charts_updated = datetime.now() while datetime.now() < update_time and not self._new_chart: time.sleep(1) print("Charts thread stopped.") def stop_charts(self): self.charts_active = False def add_chart(self, market): if market not in self.charts: self.charts[market] = None self._new_chart = True def remove_chart(self, market): if market is not None: del self.charts[market] def start_balances(self, update_freq): self.balances_update_freq = update_freq self._balances_thread = threading.Thread(target=self._get_balances) self._balances_thread.setDaemon(True) self.balances_active = True self._balances_thread.start() def _get_balances(self): while self.balances_active: # print(datetime.now(), "Balances Update") self.balances = self._polo.returnCompleteBalances() self.balances_updated = datetime.now() time.sleep(self.balances_update_freq) print("Balances thread stopped.") def stop_balances(self): self.balances_active = False def _retrieve_chart_data(self, market, currency, start_date, end_date, freq=300): start_date = start_date.timestamp() end_date = end_date.timestamp() raw_chart_data = self._polo.returnChartData(market + "_" + currency, freq, start_date, end_date) chart_data = pd.DataFrame(raw_chart_data, dtype=float) chart_data["Date"] = [ datetime.fromtimestamp(d) for d in chart_data["date"] ] chart_data.set_index(["Date"], inplace=True) chart_data.drop("date", axis=1, inplace=True) chart_data = chart_data.drop_duplicates() freq_str = str(int(freq / 60)) + "Min" chart_data = chart_data.asfreq(freq_str, method='pad') return chart_data def _load_chart(self, market, currency, start_date, end_date, freq=300, force_reload=False): path = self.chart_path + market + "_" + currency + ".csv" if isfile(path) and not force_reload: # print("Loading:", market + "_" + currency, end='', flush=True) chart_data = pd.read_csv(path, parse_dates=True, index_col="Date") # print(" OK.") else: # print("Downloading:", market + "_" + currency) chart_data = self._retrieve_chart_data(market, currency, start_date, end_date, freq) chart_data.to_csv(path) return chart_data def _update_chart(self, market, currency, chart_data, freq=300): path = self.chart_path + market + "_" + currency + ".csv" next_entry = chart_data.ix[-1].name.to_pydatetime() + timedelta( minutes=int(freq / 60)) update = self._retrieve_chart_data(market, currency, next_entry, datetime.now(), freq) # print("Updating:", market + "_" + currency) if update.shape[0] > 1: chart_data = pd.concat([chart_data, update]) chart_data = chart_data.drop_duplicates() freq_str = str(int(freq / 60)) + "Min" chart_data = chart_data.asfreq(freq_str, method='pad') chart_data.to_csv(path) return chart_data def calculate_macd(self, closes, ema_fast, ema_slow, ema_signal): ema_fast = closes.ewm(ema_fast).mean() ema_slow = closes.ewm(ema_slow).mean() macd_line = ema_fast - ema_slow signal_line = macd_line.ewm(ema_signal).mean() histogram = macd_line - signal_line return macd_line, signal_line, histogram def calculate_rsi(self, closes, periods): delta = closes.diff() up_periods, down_periods = delta.copy(), delta.copy() up_periods[up_periods <= 0] = 0 down_periods[down_periods > 0] = 0 up_ema = up_periods.ewm(periods).mean() down_ema = down_periods.ewm(periods).mean().abs() rs = up_ema / down_ema rsi = 100 - (100 / (1 + rs)) return rsi def buy(self, market, price, amount): current_price = float(self.ticker.ix[market, 'lowestAsk']) orderType = 'postOnly' if float( price) < current_price else 'immediateOrCancel' result = self._polo.buy(market, price, amount, orderType=orderType) return result def sell(self, market, price, amount): current_price = float(self.ticker.ix[market, 'highestBid']) orderType = 'postOnly' if float( price) > current_price else 'immediateOrCancel' result = self._polo.sell(market, price, amount, orderType=orderType) return result
class LiveTrader: params = {"initial_depth": 4, "max_depth": 4, "variance_threshold": 0.00013, "band_threshold": 0.00013, "iteration_level": 3, "division_threshold": 0.00013, "max_weight": 8.0, "activation": "tanh"} # Config for CPPN. config = neat.config.Config(neat.genome.DefaultGenome, neat.reproduction.DefaultReproduction, neat.species.DefaultSpeciesSet, neat.stagnation.DefaultStagnation, 'config_trader') def __init__(self, ticker_len, target_percent, hd): self.polo = Poloniex(key, secret) self.hist_depth = hd self.target_percent = target_percent self.ticker_len = ticker_len self.end_ts = datetime.now()+timedelta(seconds=(ticker_len*55)) self.hs = HistWorker() self.refresh_data() self.tickers = self.polo.returnTicker() self.bal = self.polo.returnBalances() self.sellCoins() self.set_target() self.inputs = self.hs.hist_shaped.shape[0]*(self.hs.hist_shaped[0].shape[1]) self.outputs = self.hs.hist_shaped.shape[0] self.make_shapes() self.leaf_names = [] self.db = tinydb.database("live_hist/memories.json") for l in range(len(self.in_shapes[0])): self.leaf_names.append('leaf_one_'+str(l)) self.leaf_names.append('leaf_two_'+str(l)) #self.load_net() self.poloTrader() def load_net(self): #file = open("./champ_gens/thot-checkpoint-13",'rb') g = neat.Checkpointer.restore_checkpoint("./champ_gens/thot-checkpoint-25") best_fit = 0.0 for gx in g.population: if g.population[gx].fitness != None: if g.population[gx].fitness > best_fit: bestg = g.population[gx] g = bestg #file.close() [the_cppn] = create_cppn(g, self.config, self.leaf_names, ['cppn_out']) self.cppn = the_cppn def refresh_data(self): self.hs.pull_polo_live(20) self.hs.combine_live_frames(self.hist_depth) def make_shapes(self): self.in_shapes = [] self.out_shapes = [] sign = 1 for ix in range(1,self.outputs+1): sign = sign *-1 self.out_shapes.append((0.0-(sign*.005*ix), -1.0, -1.0)) for ix2 in range(1,(self.inputs//self.outputs)+1): self.in_shapes.append((0.0+(sign*.01*ix2), 0.0-(sign*.01*ix2), 1.0)) def get_one_bar_input_2d(self,end_idx=10): master_active = [] for x in range(0, self.hist_depth): active = [] #print(self.outputs) for y in range(0, self.outputs): sym_data = self.hs.hist_shaped[y][self.hist_depth-x] #print(len(sym_data)) active += sym_data.tolist() master_active.append(active) #print(active) return master_active def closeOrders(self): try: orders = self.polo.returnOpenOrders() except: print('error getting open orers') time.sleep(360) self.closeOrder() for o in orders: if orders[o] != []: try: ordnum = orders[o][0]['orderNumber'] self.polo.cancelOrder(ordnum) except: print('error closing') def sellCoins(self): for b in self.tickers: if(b[:3] == "BTC"): price = self.get_price(b) price = price - (price * .005) self.sell_coin(b, price) def buy_coin(self, coin, price): amt = self.target / price if(self.bal['BTC'] > self.target): self.polo.buy(coin, price, amt, fillOrKill=1) print("buying: ", coin) return def sell_coin(self, coin, price): amt = self.bal[coin[4:]] if (amt*price > .0001): try: self.polo.sell(coin, price, amt,fillOrKill=1) print("selling this shit: ", coin) except: print('error selling', coin) return def reset_tickers(self): try: self.tickers = self.polo.returnTicker() self.bal = self.polo.returnBalances() except: time.sleep(360) self.reset_tickers() return def get_price(self, coin): return self.tickers[coin]['last'] def set_target(self): total = 0 full_bal = self.polo.returnCompleteBalances() for x in full_bal: total += full_bal[x]["btcValue"] self.target = total*self.target_percent def poloTrader(self): end_prices = {} active = self.get_one_bar_input_2d() self.load_net() sub = Substrate(self.in_shapes, self.out_shapes) network = ESNetwork(sub, self.cppn, self.params) net = network.create_phenotype_network_nd('paper_net.png') net.reset() for n in range(1, self.hist_depth+1): out = net.activate(active[self.hist_depth-n]) #print(len(out)) rng = len(out) #rng = iter(shuffle(rng)) self.reset_tickers() for x in np.random.permutation(rng): sym = self.hs.coin_dict[x] #print(out[x]) try: if(out[x] < -.5): print("selling: ", sym) p = self.get_price('BTC_'+sym) price = p -(p*.01) self.sell_coin('BTC_'+sym, price) elif(out[x] > .5): print("buying: ", sym) self.target_percent = .1 + out[x] - .45 p = self.get_price('BTC_'+sym) price = p*1.01 self.buy_coin('BTC_'+sym, price) except: print('error', sym) #skip the hold case because we just dont buy or sell hehe if datetime.now() >= self.end_ts: return else: time.sleep(self.ticker_len) self.refresh_data() #self.closeOrders() self.poloTrader()
class LiveTrader: params = { "initial_depth": 3, "max_depth": 4, "variance_threshold": 0.00013, "band_threshold": 0.00013, "iteration_level": 3, "division_threshold": 0.00013, "max_weight": 8.0, "activation": "tanh" } # Config for CPPN. config = neat.config.Config(neat.genome.DefaultGenome, neat.reproduction.DefaultReproduction, neat.species.DefaultSpeciesSet, neat.stagnation.DefaultStagnation, 'config_trader') def __init__(self, ticker_len, target_percent, hd, base_sym="BTC"): self.base_sym = base_sym self.load_polo_client() self.hd = hd self.target_percent = target_percent self.ticker_len = ticker_len self.end_ts = datetime.now() + timedelta(seconds=(ticker_len * 55)) self.hs = HistWorker() self.refresh_data() self.tickers = self.polo.returnTicker() self.refresh_balances() self.sellCoins() self.set_target() self.inputs = self.hs.hist_shaped.shape[0] * ( self.hs.hist_shaped[0].shape[1]) self.outputs = self.hs.hist_shaped.shape[0] self.end_idx = len(self.hs.hist_shaped[0]) - 1 self.make_shapes() self.load_net() self.poloTrader() def load_polo_client(self): keys = self.get_keys() self.polo = Poloniex(keys[0], keys[1]) def purge_polo_client(self): self.polo = None def load_net(self): champ_file = open("./champ_data/latest_greatest.pkl", 'rb') g = pickle.load(champ_file) #file.close() the_cppn = neat.nn.FeedForwardNetwork.create(g, self.config) self.cppn = the_cppn def refresh_data(self): try: self.hs.pull_polo_usd_live(21) self.hs.combine_live_usd_frames() except Exception as e: print(e) time.sleep(360) self.refresh_data() def refresh_balances(self): try: self.bal = self.polo.returnCompleteBalances() except Exception as e: print(e) time.sleep(360) self.refresh_balances() def get_one_bar_input_2d(self): master_active = [] try: for x in range(0, self.hd): active = [] #print(self.outputs) for y in range(0, self.outputs): sym_data = self.hs.hist_shaped[y][self.end_idx - x] #print(len(sym_data)) active += sym_data.tolist() master_active.append(active) except: print("error getting look back data") self.refresh_data() self.get_one_bar_input_2d() #print(active) return master_active def closeOrders(self): try: orders = self.polo.returnOpenOrders() except Exception as e: print(e) print('error getting open orers') time.sleep(360) self.closeOrders() for o in orders: if orders[o] != []: try: ordnum = orders[o][0]['orderNumber'] self.polo.cancelOrder(ordnum) except Exception as e: print(e) print('error closing') def sellCoins(self): for b in self.tickers: if (b.split("_")[0] == self.base_sym): price = self.get_price(b) price = price - (price * .005) self.sell_coin(b, price) def buy_coin(self, coin, price): amt = self.target / price if (self.bal[self.base_sym]["available"] > self.target): try: self.polo.buy(coin, price, amt) print("buying: ", coin) except Exception as e: print("error buying ", coin) print(e) return def sell_coin(self, coin, price): if (self.base_sym != "BTC"): amt = self.bal[coin.split("_")[1]]["available"] else: amt = self.bal[coin.split("_")[1]]["btcValue"] if (amt * price > .0001): try: self.polo.sell(coin, price, amt) print("selling this shit: ", coin) except Exception as e: print("error selling ", coin) print(e) return def reset_tickers(self): try: self.tickers = self.polo.returnTicker() self.bal = self.polo.returnCompleteBalances() except Exception as e: print(e) time.sleep(360) self.reset_tickers() return def get_keys(self): with open("./godsplan.txt") as f: content = f.readlines() content[0] = content[0][:-1] if (content[1][-1:] == "\n"): content[1] = content[1][:-1] return content def make_shapes(self): sign = 1 self.out_shapes = [] self.in_shapes = [] for ix in range(1, self.outputs + 1): sign = sign * -1 self.out_shapes.append((0.0 - (sign * .005 * ix), 0.0, -1.0)) for ix2 in range(1, (self.inputs // self.outputs) + 1): self.in_shapes.append( (0.0 + (sign * .01 * ix2), 0.0 - (sign * .01 * ix2), 0.0)) self.subStrate = Substrate(self.in_shapes, self.out_shapes) def get_price(self, coin): return self.tickers[coin]['last'] def set_target(self): total = 0 full_bal = self.polo.returnCompleteBalances() for x in full_bal: total += full_bal[x]["btcValue"] if (self.base_sym != "BTC"): total = total * self.get_price(self.base_sym + "_" + "BTC") * self.target_percent print(total) self.target = total def poloTrader(self): self.refresh_balances() end_prices = {} active = self.get_one_bar_input_2d() self.load_net() network = ESNetwork(self.subStrate, self.cppn, self.params, self.hd) net = network.create_phenotype_network_nd('paper_net.png') net.reset() sell_syms = [] buy_syms = [] buy_signals = [] sell_signals = [] self.closeOrders() for n in range(1, self.hd): net.activate(active[self.hd - n]) out = net.activate(active[0]) for x in range(len(out)): sym = self.hs.coin_dict[x] end_prices[sym] = self.get_price(self.base_sym + "_" + sym) if (out[x] > .5): buy_signals.append(out[x]) buy_syms.append(sym) if (out[x] < -.5): sell_signals.append(out[x]) sell_syms.append(sym) #rng = iter(shuffle(rng)) sorted_buys = np.argsort(buy_signals)[::-1] sorted_sells = np.argsort(sell_signals) self.reset_tickers() for x in sorted_sells: sym = sell_syms[x] p = self.get_price(self.base_sym + "_" + sym) price = p - (p * .005) self.sell_coin(self.base_sym + "_" + sym, price) for x in sorted_buys: sym = buy_syms[x] self.target_percent = .1 + out[x] - .45 p = self.get_price(self.base_sym + "_" + sym) price = p * 1.005 self.buy_coin(self.base_sym + "_" + sym, price) if datetime.now() >= self.end_ts: return else: self.purge_polo_client() time.sleep(self.ticker_len) self.load_polo_client() self.refresh_data() self.make_shapes() #self.closeOrders() self.poloTrader()
class Checker: def __init__(self, ex_ev): self.ex_ev = ex_ev self.log = None self.loop = asyncio.new_event_loop() self.polo = Poloniex(POLONIEX_API_KEY, POLONIEX_API_SECRET) async def eternity(self, timeout): while not self.ex_ev.is_set(): await asyncio.sleep(timeout) async def get_balance(self, balances, user_exchange): total_btc = float(0) for coin, balance in balances.items(): total_balance = float(balance['available']) + \ float(balance['onOrders']) total_btc += float(balance['btcValue']) try: coin_balance = await get_first_by_filter(session=session, model=UserBalance, ue=user_exchange, coin=coin.lower()) except Exception as e: self.log.error(f'Error getting coin balance: {e}') send_telegram(title='ERROR', text=f'Error getting coin balance: {e}') coin_balance = None if coin_balance: data = { 'total': total_balance, 'btc_value': balance['btcValue'], 'conversions': '', 'used': balance['onOrders'], 'free': balance['available'], 'last_update': datetime.now(timezone.utc) } await update_model(session=session, model=UserBalance, pk=coin_balance.id, data=data) else: data = { 'ue_id': user_exchange.id, 'coin': coin, 'total': total_balance, 'btc_value': balance['btcValue'], 'conversions': '', 'used': balance['onOrders'], 'free': balance['available'], 'last_update': datetime.now(timezone.utc) } await create(session=session, model=UserBalance, **data) # ================================================= data = { 'total_btc': total_btc, 'total_usd': get_usd_value('btc', total_btc), 'error': '', } await update_model(session=session, model=UserExchange, pk=user_exchange.id, data=data) async def pull_exchanges_balances(self, ue_pk=None): while not self.ex_ev.is_set(): # print("=========CHECKER PULL EXCHANGE BALANCE========") try: if ue_pk is None: user_exchanges = await get_by_filter(session=session, model=UserExchange) else: user_exchanges = await get_by_filter(session=session, model=UserExchange, id=ue_pk) except Exception as e: self.log.error(f'Get Exchange Error: {e}') return if not user_exchanges: self.log.error('No Active Exchanges!') for user_exchange in user_exchanges: try: balances = self.polo.returnCompleteBalances() try: await self.get_balance(balances, user_exchange) except Exception as e: self.log.error(f'Get Balance Error: {e}') send_telegram(title='ERROR', text=f'Get Balance Error: {e}') data = {'error': '', 'is_correct': True, 'is_active': True} await update_model(session=session, model=UserExchange, pk=user_exchange.id, data=data) except Exception as e: self.log.error(f'Get Balance From Poloniex Error: {e}') send_telegram(title='ERROR', text='Incorrect apikey or secret') data = { 'error': 'Incorrect apikey or secret', 'is_correct': False, 'is_active': False } await update_model(session=session, model=UserExchange, pk=user_exchange.id, data=data) if self.ex_ev.is_set(): break try: await asyncio.wait_for(self.eternity(10), timeout=60.0) except asyncio.TimeoutError: ... if ue_pk: break if self.ex_ev.is_set(): self.log.info('=========EXIT EVENT PULL EXCHANGE BALANCE========') async def check_open(self, uo, orders_to_close): if uo in orders_to_close: self.log.info(f'Time to close for order # ' f'{uo.order_number} {uo.pair}') canceled = {} i = 3 if uo.is_fake: canceled['success'] = 1 else: while not self.ex_ev.is_set(): try: self.log.info(f'Trying to cancel order ' f'{uo.order_number} {uo.pair}') canceled = self.polo.cancelOrder(str(uo.order_number)) except Exception as e: self.log.error(f'Cancel order error: {e}') await asyncio.sleep(.5) self.polo = Poloniex(POLONIEX_API_KEY, POLONIEX_API_SECRET) if 'success' in e: canceled['success'] = 1 if canceled or i == 0: break i -= 1 if canceled['success'] == 1: data = { 'date_cancel': datetime.now(timezone.utc), 'date_updated': datetime.now(timezone.utc), 'cancel_desc': 'TTL' } try: await update_model(session=session, model=UserOrder, pk=uo.id, data=data) self.log.info(f'Order # {uo.order_number}({uo.pair}) ' f'was canceled') send_telegram(title='Order was canceled', text=f'Order # {uo.order_number}({uo.pair}) ' f'was canceled') except Exception as e: self.log.error( f'Order # {uo.order_number} update error {e}') send_telegram( title='ERROR', text=f'Order # {uo.order_number} update error {e}') else: balance_main_coin = await get_first_by_filter( session=session, model=UserBalance, ue=uo.ue, coin=uo.pair.main_coin.symbol.lower()) if balance_main_coin: try: data = { 'interim_main_coin': balance_main_coin.total, 'date_updated': datetime.now(timezone.utc), } await update_model(session=session, model=UserOrder, pk=uo.id, data=data) except Exception as e: self.log.error( f'Order # {uo.order_number} update error {e}') send_telegram( title='ERROR', text=f'Order # {uo.order_number} update error {e}') async def check_close(self, uo): current_balance_main_coin = await get_first_by_filter( session=session, model=UserBalance, ue=uo.ue, coin=uo.pair.main_coin.symbol.lower()) fact_total = 0 data = {} if current_balance_main_coin: data['main_coin_after_total'] = current_balance_main_coin.total data['main_coin_after_free'] = current_balance_main_coin.free data['main_coin_after_used'] = current_balance_main_coin.used else: data['main_coin_after_total'] = '-1' data['main_coin_after_free'] = '-1' data['main_coin_after_used'] = '-1' current_balance_second_coin = await get_first_by_filter( session=session, model=UserBalance, ue=uo.ue, coin=uo.pair.second_coin.symbol.lower()) if current_balance_second_coin: data['second_coin_after_total'] = current_balance_second_coin.total data['second_coin_after_used'] = current_balance_second_coin.free data['second_coin_after_free'] = current_balance_second_coin.used else: data['second_coin_after_total'] = '-1' data['second_coin_after_used'] = '-1' data['second_coin_after_free'] = '-1' if uo.order_type == 'buy': fact_total = float(uo.interim_main_coin) - float( current_balance_main_coin.total) if uo.order_type == 'sell': fact_total = float(current_balance_main_coin.total) - float( uo.interim_main_coin) data['fact_total'] = fact_total if fact_total != 0: fact_fee = 100.0 * float(uo.total) / float(fact_total) - 100.0 data['fact_fee'] = fact_fee if fact_fee > 0.2: data['is_ok'] = False try: data['to_close'] = False data['cancel_desc'] = 'Worked' data['date_updated'] = datetime.now(timezone.utc) data['date_cancel'] = datetime.now(timezone.utc) await update_model(session=session, model=UserOrder, pk=uo.id, data=data) self.log.warning(f'[!!!!!] Order # {uo.order_number}, ' f'Pair {uo.pair} saved [!!!!!]') send_telegram(title='!!! Order saved', text=f'Order # {uo.order_number}, ' f'Pair {uo.pair} saved') except Exception as e: self.log.error(f'Save Order Error: {e}') send_telegram(title='ERROR', text=f'Save Order Error: {e}') async def group_check_orders(self, uo, orders_to_close): try: order_status = self.polo.returnOrderStatus(uo.order_number) if order_status.get('success') == 1: await self.check_open(uo, orders_to_close) if order_status.get('success') == 0: await self.check_close(uo) except Exception as e: self.log.error(f'Error getting orders for {uo.order_number}: {e}') send_telegram( title='ERROR', text=f'Error getting orders for {uo.order_number}: {e}') async def check_orders(self): while not self.ex_ev.is_set(): # print('===========CHECKER CHECK ORDERS================') user_orders = None try: user_orders = await get_by_filter(session=session, model=UserOrder, cancel_desc='') except Exception as e: self.log.error(f'Error getting user orders to close: {e}') if user_orders: try: orders_to_close = session.query(UserOrder).filter( UserOrder.date_created <= datetime.now(timezone.utc) - timedelta(minutes=ORDER_TTL), UserOrder.cancel_desc == '', UserOrder.to_close.is_(False)).all() [ asyncio.ensure_future(self.group_check_orders( uo, orders_to_close), loop=self.loop) for uo in user_orders ] except Exception as e: self.log.error(f'Check orders error: {e}') send_telegram(title='ERROR', text=f'Check orders error: {e}') await asyncio.sleep(1) if self.ex_ev.is_set(): self.log.info('==========CHECKER EXIT EVENT check_orders=======') async def open_real_order(self, to_trade): pair = f'{to_trade.user_pair.main_coin}_' \ f'{to_trade.user_pair.second_coin}' order_id = None try: if to_trade.type == 'buy': order = self.polo.buy(currencyPair=pair, rate=to_trade.price, amount=to_trade.amount, postOnly=1) self.log.warning(f'Answer (buy): {order}') order_id = order.get('orderNumber') send_telegram(title=f'Order open: {pair}, ' f'price: {to_trade.price: .8f}, ' f'amount: {to_trade.amount}', text=f'Answer (buy): {order}') elif to_trade.type == 'sell': order = self.polo.sell(currencyPair=pair, rate=to_trade.price, amount=to_trade.amount, postOnly=1) self.log.warning(f'Answer (sell): {order}') order_id = order.get('orderNumber') send_telegram(title=f'Order open: {pair}, ' f'price: {to_trade.price: .8f}, ' f'amount: {to_trade.amount}', text=f'Answer (sell): {order}') except Exception as e: self.log.error(f'Open order {pair}, {to_trade.amount}, ' f'{to_trade.price}. Error: {e}') send_telegram( title='ERROR', text=f'Open order for: {pair}, amount: {to_trade.amount}, ' f'price: {to_trade.price: .8f}. Error: {e}') await asyncio.sleep(1) return order_id async def check_to_trade(self): while not self.ex_ev.is_set(): # print('================CHECK TO TRADE===================') try: to_trade = session.query(ToTrade).filter( ToTrade.date_updated >= datetime.now(timezone.utc) - timedelta(minutes=5)).order_by( ToTrade.date_updated).first() if not to_trade: await asyncio.sleep(5) continue self.log.info(f'Found order to trade: {to_trade}') already_in_orders = await get_by_filter( session=session, model=UserOrder, pair_id=to_trade.user_pair.pair.id, date_cancel=None) self.log.info(f'Already in orders: {already_in_orders}') if len(already_in_orders) > 0: to_delete = session.query(ToTrade).filter( ToTrade.id == to_trade.id) _ = to_delete.delete() session.commit() else: self.log.info('Trying to open order...') order_id = await self.open_real_order(to_trade) if not order_id: await asyncio.sleep(5) continue await self.pull_exchanges_balances( to_trade.user_pair.user_exchange.id) self.log.info('Balance Checked') main_coin_balance = await get_first_by_filter( session=session, model=UserBalance, ue=to_trade.user_pair.user_exchange, coin=to_trade.user_pair.pair.main_coin.symbol) second_coin_balance = await get_first_by_filter( session=session, model=UserBalance, ue=to_trade.user_pair.user_exchange, coin=to_trade.user_pair.pair.second_coin.symbol) self.log.info(f'Main coin: {main_coin_balance}, ' f'Second coin: {second_coin_balance}') data = { 'ue_id': to_trade.user_pair.user_exchange.id, 'pair_id': to_trade.user_pair.pair.id, 'order_type': to_trade.type, 'order_number': order_id, 'interim_main_coin': main_coin_balance.total, 'main_coin_before_total': main_coin_balance.total, 'main_coin_before_free': main_coin_balance.free, 'main_coin_before_used': main_coin_balance.used, 'second_coin_before_total': second_coin_balance.total, 'second_coin_before_free': second_coin_balance.free, 'second_coin_before_used': second_coin_balance.used, 'price': to_trade.price, 'amount': to_trade.amount, 'total': to_trade.price * to_trade.amount, 'date_created': datetime.now(timezone.utc), 'date_updated': datetime.now(timezone.utc), 'fee': FEE, } self.log.info('Create order') try: await create(session=session, model=UserOrder, **data) self.log.warning(f"Order {order_id} added. " f"Type {to_trade.type}, " f"Pair {to_trade.user_pair.pair}, " f"Price {to_trade.price: .8f}") to_delete = session.query(ToTrade).filter( ToTrade.id == to_trade.id) _ = to_delete.delete() session.commit() except Exception as e: self.log.exception(f'Create Order Error: {e}') send_telegram(title='ERROR', text=f'Error write order to DB: {e}') except Exception as e: self.log.error(f'check_to_trade error: {e}') await asyncio.sleep(5) if self.ex_ev.is_set(): self.log.info('============CHECK TO TRADE EXIT EVENT===========') def run(self): self.log = get_logger('checker') self.log.info('Start Checker') asyncio.set_event_loop(self.loop) tasks = [ self.pull_exchanges_balances(), self.check_orders(), self.check_to_trade() ] group = asyncio.gather(*tasks) self.loop.run_until_complete(group) if self.ex_ev.is_set(): self.log.info('=======CHECKER RUN EXIT EVENT=================') self.loop.stop() self.loop.close()