def get_timeframe(): timeframe = SettingValue.query.filter_by( slug=slugs['timeframe']).one_or_none() if not timeframe: timeframe = '1d' logger(description="timeframe не найден, установленно значание 1d") SettingValue.create('timeframe', '1d') else: timeframe = timeframe.value return timeframe
def _analysis(klines): klines = klines[:len(klines) - int(not USE_OPEN_CANDLES)] closes = [float(x[4]) for x in klines] high = [float(x[2]) for x in klines] low = [float(x[3]) for x in klines] # Скользящая средняя sma_5 = ta.SMA(closes, 5) sma_100 = ta.SMA(closes, 100) ema_5 = ta.EMA(closes, 5) ema_100 = ta.EMA(closes, 100) enter_points = 0 if ema_5[-1] > ema_100[-1] and sma_5[-1] > sma_100[-1]: # Быстрая EMA выше медленной и быстрая SMA выше медленной, считаем, что можно входить enter_points += 1 macd, macdsignal, macdhist = ta.MACD(closes, 12, 26, 9) if macd[-1] > macdsignal[-1] and macdhist[-1] > 0: # Линия макд выше сигнальной и на гистограмме они выше нуля enter_points += 1.3 rsi_9 = ta.RSI(closes, 9) rsi_14 = ta.RSI(closes, 14) rsi_21 = ta.RSI(closes, 21) if rsi_9[-1] < 70 and rsi_14[-1] < 70 and rsi_21[-1] < 70: # RSI не показывает перекупленности enter_points += 2 fast, slow = ta.STOCH(high, low, closes, 5, 3, 3) if fast[-1] > slow[-1]: # Быстрая линия стохастика выше медленной, вход enter_points += 1.5 fast, slow = ta.STOCHRSI(closes, 14, 3, 3) if fast[-1] > slow[-1]: # Быстрая линия STOCHRSI выше медленной, вход enter_points += 1.8 upper, middle, lower = ta.BBANDS(closes, ma_period=21) if high[-1] > upper[-1]: # Свеча пробила верхнюю полосу Боллинджера enter_points += 3 points_to_enter = get_points_to_enter() log_data = { 'description': f"Свеча набрала {enter_points} баллов, минимум {points_to_enter}", 'log_type': 'debug', } logger(**log_data) return enter_points < points_to_enter
def get_setting_value(slug, default, value_type): value = SettingValue.query.filter_by(slug=slug).one_or_none() if not value: value = value_type(default) logger( description=f"{slug} не найден, установленно значание {default}") SettingValue.create(f"{slug}", f"{default}") return value else: value = value_type(value.value) return value
def get_points_to_enter(): points_to_enter = SettingValue.query.filter_by( slug=slugs['points_to_enter']).one_or_none() if points_to_enter: points_to_enter = float(points_to_enter.value) else: points_to_enter = 7 logger( description="points_to_enter не найден, установленно значание 7") SettingValue.create('points_to_enter', '7') return points_to_enter
def get_klines_limits(): klines_limits = SettingValue.query.filter_by( slug=slugs['klines_limits']).one_or_none() if klines_limits: klines_limits = int(klines_limits.value) else: klines_limits = 200 logger( description="klines_limits не найден, установленно значание 200") SettingValue.create('klines_limits', '200') return klines_limits
def create_order(self, side, recvWindow, quantity, price=0.): quantity = float(quantity) new_order = api.createOrder( symbol=self.pair, recvWindow=recvWindow, side=side, type='MARKET', quantity="{quantity:0.{precision}f}".format( quantity=quantity, precision=self.get_limit()['baseAssetPrecision']), newOrderRespType='FULL') if 'orderId' in new_order: if side.lower() == 'buy': self.order_id = new_order['orderId'] logger(description= f"Создан ордер на покупку id:{new_order['orderId']} \ price: {price},quantity: {quantity}", log_type='info') order = Order(order_type='buy', pair=self.pair, buy_order_id=new_order['orderId'], buy_amount=quantity, buy_price=price) session.add(order) session.commit() self.update_rate(method='buy') elif side.lower() == 'sell': logger( description=f"Создан ордер на продажу по рынку {new_order}", log_type='info', ) session.query(Order).filter_by( buy_order_id=self.order_id).update({ 'order_type': side.lower(), 'sell_finished': datetime.datetime.utcnow(), 'sell_created': datetime.datetime.utcnow(), 'sell_order_id': new_order['orderId'], 'sell_amount': quantity, 'sell_price': price }) session.commit() self.update_rate(method='sell') else: raise Exception('error order doesn\'t create') return new_order
def calc_sell_avg_rate(order_trades, log): sold = 0 got = 0 fee = 0 for trade in order_trades: sold += trade.trade_amount got += trade.trade_amount * trade.trade_rate fee += trade.trade_fee logger(description='По ордеру была сделка {id} на продажу {am:0.8f} по курсу {r:0.8f}, комиссия {fee:0.8f} {f_a}'.format( id=trade.trade_id, am=trade.trade_amount, r=trade.trade_rate, fee=trade.trade_fee, f_a=trade.fee_type ), log_type='debug',) try: avg_rate = got / sold except ZeroDivisionError: logger(description='Не удалось посчитать средневзвешенную цену, деление на 0', log_type='debug',) avg_rate = 0 logger(description='Средневзвешенная цена {ar:0.8f}'.format(ar=avg_rate), log_type='debug',) return avg_rate
def calc_buy_avg_rate(order_trades, log): bought = 0 spent = 0 fee = 0 avg_rate = 0 for trade in order_trades: bought += trade.trade_amount spent += trade.trade_amount * trade.trade_rate fee += trade.trade_fee try: logger(description='По ордеру была сделка {id} на покупку {am:0.8f} по курсу {r:0.8f}, комиссия {fee:0.8f} {f_a}'.format( id=trade.trade_id, am=trade.trade_amount, r=trade.trade_rate, fee=trade.trade_fee, f_a=trade.fee_type ), log_type='debug',) avg_rate = spent / bought except ZeroDivisionError: logger(description='Не удалось посчитать средневзвешенную цену, деление на 0', log_type='debug',) avg_rate = 0 logger( description='Средневзвешенная цена {ar:0.8f}'.format(ar=avg_rate), log_type='debug', ) return avg_rate
def sync_time(bot, log, pause): while True: try: # Получаем ограничения торгов по всем парам с биржи limits = bot.exchangeInfo() local_time = int(time.time()) server_time = int(limits['serverTime']) // 1000 # Бесконечный цикл программы shift_seconds = server_time - local_time if local_time + shift_seconds != server_time: bot.set_shift_seconds(shift_seconds) logger( description=""" Текущее время: {local_time_d} {local_time_u} Время сервера: {server_time_d} {server_time_u} Разница: {diff:0.8f} {warn} Бот будет работать, как будто сейчас: {fake_time_d} {fake_time_u} """.format( local_time_d=datetime.fromtimestamp(local_time), local_time_u=local_time, server_time_d=datetime.fromtimestamp(server_time), server_time_u=server_time, diff=abs(local_time - server_time), warn="ТЕКУЩЕЕ ВРЕМЯ ВЫШЕ" if local_time > server_time else '', fake_time_d=datetime.fromtimestamp(local_time + shift_seconds), fake_time_u=local_time + shift_seconds ), log_type='debug', ) except: log.exception('sync_time error') if pause: time.sleep(10000) else: break
def analysis_apo(klines): sma_p = get_setting_value(slugs['apo_sma_p'], 17, int) NUM_PERIODS_FAST = get_setting_value(slugs['APO_NUM_PERIODS_FAST'], 6, int) NUM_PERIODS_SLOW = get_setting_value(slugs['APO_NUM_PERIODS_SLOW'], 24, int) APO_VALUE_FOR_BUY_ENTRY = get_setting_value(slugs['APO_VALUE_FOR_BUY_ENTRY'], -5, int) closes = [float(x[4]) for x in klines] timestamp_open_list = [float(x[1]) for x in klines] timestamp_close_list = [float(x[6]) for x in klines] high_list = [float(x[2]) for x in klines] low_list = [float(x[3]) for x in klines] data = [] for op, close, high, low in zip(timestamp_open_list, closes, high_list, low_list): data.append({'open': op, 'close': close, 'high': high, 'low': low}) data = pd.DataFrame(data, index=timestamp_close_list) price_history = [] K_FAST = 2 / (NUM_PERIODS_FAST + 1) ema_fast = 0 ema_fast_values = [] K_SLOW = 2 / (NUM_PERIODS_SLOW + 1) ema_slow = 0 ema_slow_values = [] apo_valus = [] stdev_factors = [] close = data['close'] for close_price in close: price_history.append(close_price) if len(price_history) > sma_p: del price_history[0] sma = stat.mean(price_history) variance = 0 for hist_price in price_history: variance = variance + ((hist_price - sma) ** 2) stdev = math.sqrt(variance / len(price_history)) stdev_factor = stdev / 15 if stdev_factor == 0: stdev_factor = 1 stdev_factors.append(stdev_factor) if ema_fast == 0: ema_fast = close_price ema_slow = close_price else: ema_fast = (close_price - ema_fast) * K_FAST * stdev_factor + ema_fast ema_slow = (close_price - ema_slow) * K_SLOW * stdev_factor + ema_slow ema_fast_values.append(ema_fast) ema_slow_values.append(ema_slow) apo = ema_fast - ema_slow apo_valus.append(apo) apo = apo_valus[-1] stdev_factor = stdev_factors[-1] trand = ema_slow_values[-1] > ema_slow_values[-2] > ema_slow_values[-3] buy = apo < APO_VALUE_FOR_BUY_ENTRY * stdev_factor and trand log_data = { 'description': f"trand {trand} and {apo} < {APO_VALUE_FOR_BUY_ENTRY * stdev_factor}, res:{buy}", 'log_type': 'debug', } logger(**log_data) return buy
def main_flow(): while True: time.sleep(request_pause()) if not run(): logger(description='no run', log_type='no') continue open_orders = get_running_orders() all_pairs = get_pairs() if open_orders: for order in open_orders: order_trade_data = api.orderInfo(symbol=order.pair, orderId=order.order_id) if 'status' not in order_trade_data: logger( description= '\'status\' not in order_trade_data, pair={order.pair}, orderId={order.order_id}', log_type='warning') continue order_status = order_trade_data['status'] order_type = order.order_type pair = order.pair profit_markup = all_pairs[ order_trade_data['symbol']]['profit_markup'] sell_verified = order.obj.sell_verified use_stop_loss = all_pairs[pair]['use_stop_loss'] stop_loss = all_pairs[pair]['stop_loss'] order_process = OrderProcess( order_id=order.order_id, pair=order.pair, order_data=order_trade_data, ) if order.order_type == 'buy': if not order.verified: order_process.update_rate(method='buy') if order_status == 'FILLED': got_qty = order_process.get_qty() bit_price = order_process.get_bit_price() price_change = order_process.price_change( bit_price, order.obj.buy_price) logger( description= f"Цена изменилась на {price_change}%, процент для продажи {all_pairs[pair]['profit_markup']}", log_type='info') if price_change >= profit_markup: order_process.create_order(side='SELL', recvWindow=5000, quantity=got_qty) if order_type == 'sell' and not sell_verified: order_process.update_rate(method='sell') if use_stop_loss and order_status == 'FILLED' and order_type == 'buy': curr_rate = float(api.tickerPrice(symbol=pair)['price']) buy_price = order.obj.buy_price, if (1 - curr_rate / buy_price[0]) * 100 >= stop_loss: logger( description= f"{pair} Цена упала до стоплосс (покупали по {buy_price}, сейчас {curr_rate}),\ пора продавать, процент для продажи {stop_loss}", log_type='info') buy_amount = order_process.get_qty() order_process.create_order(side='SELL', quantity=buy_amount, recvWindow=15000) for order in get_running_orders(): del all_pairs[order.pair] if all_pairs: logger( description= f'Найдены пары, по которым нет неисполненных ордеров: {all_pairs.keys()}', log_type='debug') for pair, pair_obj in all_pairs.items(): timeframe = get_timeframe() klines_limits = get_klines_limits() klines = api.klines(symbol=pair.upper(), interval=timeframe, limit=klines_limits) order_process = OrderProcess( order_id=None, pair=pair, order_data=None, ) spend_sum = pair_obj['spend_sum'] base_currency = pair_obj['base'] top_price = order_process.get_ask_price() CURR_LIMITS = order_process.get_limit() stepSize = CURR_LIMITS['filters'][2]['stepSize'] minQty = CURR_LIMITS['filters'][2]['minQty'] minNotional = CURR_LIMITS['filters'][3]['minNotional'] if not analysis(klines=klines): continue balances = { balance['asset']: float(balance['free']) for balance in api.account()['balances'] if balance['asset'] in [pair_obj['base'], pair_obj['quote']] } logger(description=f"Баланс {balances}", log_type='debug') if balances[base_currency] >= spend_sum: my_amount = adjust_to_step(spend_sum / top_price, stepSize) if my_amount < float(stepSize) or my_amount < float( minQty): logger( description= "Покупка невозможна, выход. Увеличьте размер ставки", log_type='warning') continue trade_am = top_price * my_amount if trade_am < float(minNotional): raise Exception( """меньше допустимого по паре {min_am:0.8f}. минимальная сумма торгов {incr}""" .format(trade_am=trade_am, min_am=float(minNotional), incr=minNotional)) order_process.create_order(recvWindow=5000, side='BUY', quantity=my_amount, price=top_price)