Перейти к публикации
Форум ботоводов

stop loss и бинанс


Рекомендованные сообщения

Здравствуйте, в одном из комментариев на https://bablofil.ru/bot-dlya-binance/ некто Антон П  задал вопрос- " Можно ли сделать так, чтобы после срабатывания stop loss прекращалась подача новых ордеров, а именно останавливалась торговля? ". Хотел бы присоединиться, с тем же вопросом. Так-как во время слива при включенном stop loss бот закупался-бы в убыток себе, а данная функция оградила бы бинанс бота от убытков. Спасибо.

Ссылка на комментарий
Поделиться на других сайтах

Добрый день,

Добавил параметры active и stop_after_sl в настройки пары, ну и там сям в коде.

Скачайте обычного бота, и файл binance_bot.py замените. 

В любом случае дайте обратную связь, пожалуйста.

"""
    Подробная информация о боте на сайте bablofil.ru/bot-dlya-binance
"""
import sqlite3
import logging
import time
import os

from datetime import datetime

from binance_api import Binance
bot = Binance(
    API_KEY='',
    API_SECRET=''
)

"""
    Пропишите пары, на которые будет идти торговля.
    base - это базовая пара (BTC, ETH,  BNB, USDT) - то, что на бинансе пишется в табличке сверху
    quote - это квотируемая валюта. Например, для торгов по паре NEO/USDT базовая валюта USDT, NEO - квотируемая
"""


pairs = [
   {
        'base': 'BTC',
        'quote': 'EOS',
        'offers_amount': 5, # Сколько предложений из стакана берем для расчета средней цены
                            # Максимум 1000. Допускаются следующие значения:[5, 10, 20, 50, 100, 500, 1000]
        'spend_sum': 0.0015,  # Сколько тратить base каждый раз при покупке quote
        'profit_markup': 0.005, # Какой навар нужен с каждой сделки? (0.001 = 0.1%)
        'active': True, # True - по паре будет торговля
        'use_stop_loss': False, # Нужно ли продавать с убытком при падении цены
        'stop_loss': 1, # 1% - На сколько должна упасть цена, что бы продавать с убытком
        'stop_after_sl': True, # True - если сработал stop-loss, то прекратить торговлю по паре
    }, {
        'base': 'USDT',
        'quote': 'NEO',
        'offers_amount': 5, # Сколько предложений из стакана берем для расчета средней цены
                            # Максимум 1000. Допускаются следующие значения:[5, 10, 20, 50, 100, 500, 1000]
        'spend_sum': 11,  # Сколько тратить base каждый раз при покупке quote
        'profit_markup': 0.005, # Какой навар нужен с каждой сделки? (0.001 = 0.1%)
        'active': True, # True - по паре будет торговля
        'use_stop_loss': False, # Нужно ли продавать с убытком при падении цены
        'stop_loss': 2, # 2%  - На сколько должна упасть цена, что бы продавать с убытком
        'stop_after_sl': True, # True - если сработал stop-loss, то прекратить торговлю по паре

    }
]



BUY_LIFE_TIME_SEC = 180 # Сколько (в секундах) держать ордер на продажу открытым

STOCK_FEE = 0.00075  # Комиссия, которую берет биржа (0.001 = 0.1%)

# Если вы решите не платить комиссию в BNB, то установите в False. Обычно делать этого не надо
USE_BNB_FEES = True

# Получаем ограничения торгов по всем парам с биржи
local_time = int(time.time())
limits = bot.exchangeInfo()
server_time = int(limits['serverTime'])//1000

# Ф-ция, которая приводит любое число к числу, кратному шагу, указанному биржей
# Если передать параметр increase=True то округление произойдет к следующему шагу
def adjust_to_step(value, step, increase=False):
   return ((int(value * 100000000) - int(value * 100000000) % int(
        float(step) * 100000000)) / 100000000)+(float(step) if increase else 0)

# Подключаем логирование
logging.basicConfig(
    format="%(asctime)s [%(levelname)-5.5s] %(message)s",
    level=logging.DEBUG,
    handlers=[
        logging.FileHandler("{path}/logs/{fname}.log".format(path=os.path.dirname(os.path.abspath(__file__)), fname="binance")),
        logging.StreamHandler()
    ])

log = logging.getLogger('')

# Бесконечный цикл программы

shift_seconds = server_time-local_time
bot.set_shift_seconds(shift_seconds)

log.debug("""
    Текущее время: {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
))

while True:
    try:
        # Устанавливаем соединение с локальной базой данных
        conn = sqlite3.connect('binance.db')
        cursor = conn.cursor()

        # Если не существует таблиц, их нужно создать (первый запуск)
        orders_q = """
          create table if not exists
            orders (
              order_type TEXT,
              order_pair TEXT,

              buy_order_id NUMERIC,
              buy_amount REAL,
              buy_price REAL,
              buy_created DATETIME,
              buy_finished DATETIME NULL,
              buy_cancelled DATETIME NULL,

              sell_order_id NUMERIC NULL,
              sell_amount REAL NULL,
              sell_price REAL NULL,
              sell_created DATETIME NULL,
              sell_finished DATETIME NULL,
              force_sell INT DEFAULT 0
            );
        """
        cursor.execute(orders_q)

        log.debug("Получаем все неисполненные ордера по БД")

        orders_q = """
            SELECT
              CASE WHEN order_type='buy' THEN buy_order_id ELSE sell_order_id END order_id
              , order_type
              , order_pair
              , sell_amount
              , sell_price
              ,  strftime('%s',buy_created)
              , buy_amount
              , buy_price
            FROM
              orders
            WHERE
              buy_cancelled IS NULL AND CASE WHEN order_type='buy' THEN buy_finished IS NULL ELSE sell_finished IS NULL END
        """
        orders_info = {}


        for row in cursor.execute(orders_q):
            orders_info[str(row[0])] = {'order_type': row[1], 'order_pair': row[2], 'sell_amount': row[3], 'sell_price': row[4],
                                         'buy_created': row[5], 'buy_amount': row[6], 'buy_price': row[7] }
        # формируем словарь из указанных пар, для удобного доступа
        all_pairs = {pair['quote'].upper() + pair['base'].upper():pair for pair in pairs}
        if not [p for p in pairs if p['active']]:
           log.debug('Больше нет активных пар')
           break
        
        if orders_info:
            log.debug("Получены неисполненные ордера из БД: {orders}".format(orders=[(order, orders_info[order]['order_pair']) for order in orders_info]))

            # Проверяем каждый неисполненный по базе ордер
            for order in orders_info:
                # Получаем по ордеру последнюю информацию по бирже
                stock_order_data = bot.orderInfo(symbol=orders_info[order]['order_pair'], orderId=order)

                order_status = stock_order_data['status']
                log.debug("Состояние ордера {order} - {status}".format(order=order, status=order_status))
                if order_status == 'NEW':
                    log.debug('Ордер {order} всё еще не выполнен'.format(order=order))

                # Если ордер на покупку
                if orders_info[order]['order_type'] == 'buy':
                    # Если ордер уже исполнен
                    if order_status == 'FILLED':
                        log.info("""
                            Ордер {order} выполнен, получено {exec_qty:0.8f}.
                            Создаем ордер на продажу
                        """.format(
                            order=order, exec_qty=float(stock_order_data['executedQty'])
                        ))

                        # смотрим, какие ограничения есть для создания ордера на продажу
                        for elem in limits['symbols']:
                            if elem['symbol'] == orders_info[order]['order_pair']:
                                CURR_LIMITS = elem
                                break
                        else:
                            raise Exception("Не удалось найти настройки выбранной пары " + pair_name)

                        # Рассчитываем данные для ордера на продажу

                        # Имеющееся кол-во на продажу
                        has_amount = orders_info[order]['buy_amount']*((1-STOCK_FEE) if not USE_BNB_FEES else 1)
                        # Приводим количество на продажу к числу, кратному по ограничению
                        sell_amount = adjust_to_step(has_amount, CURR_LIMITS['filters'][2]['stepSize'])
                        # Рассчитываем минимальную сумму, которую нужно получить, что бы остаться в плюсе
                        need_to_earn = orders_info[order]['buy_amount']*orders_info[order]['buy_price']*(1+all_pairs[stock_order_data['symbol']]['profit_markup'])
                        # Рассчитываем минимальную цену для продажи
                        min_price = (need_to_earn/sell_amount)/((1-STOCK_FEE) if not USE_BNB_FEES else 1)
                        # Приводим к нужному виду, если цена после срезки лишних символов меньше нужной, увеличиваем на шаг
                        cut_price = max(
                            adjust_to_step(min_price, CURR_LIMITS['filters'][0]['tickSize'], increase=True),
                            adjust_to_step(min_price, CURR_LIMITS['filters'][0]['tickSize'])
                        )
                        # Получаем текущие курсы с биржи
                        curr_rate = float(bot.tickerPrice(symbol=orders_info[order]['order_pair'])['price'])
                        # Если текущая цена выше нужной, продаем по текущей
                        need_price = max(cut_price, curr_rate)

                        log.info("""
                            Изначально было куплено {buy_initial:0.8f}, за вычетом комиссии {has_amount:0.8f},
                            Получится продать только {sell_amount:0.8f}
                            Нужно получить как минимум {need_to_earn:0.8f} {curr}
                            Мин. цена (с комиссией) составит {min_price}, после приведения {cut_price:0.8f}
                            Текущая цена рынка {curr_rate:0.8f}
                            Итоговая цена продажи: {need_price:0.8f}
                        """.format(
                            buy_initial=orders_info[order]['buy_amount'], has_amount=has_amount,sell_amount=sell_amount,
                            need_to_earn=need_to_earn, curr=all_pairs[orders_info[order]['order_pair']]['base'],
                            min_price=min_price, cut_price=cut_price, need_price=need_price,
                            curr_rate=curr_rate
                        ))

                        # Если итоговая сумма продажи меньше минимума, ругаемся и не продаем
                        if (need_price*has_amount) <float(CURR_LIMITS['filters'][3]['minNotional']):
                            raise Exception("""
                                Итоговый размер сделки {trade_am:0.8f} меньше допустимого по паре {min_am:0.8f}. """.format(
                                trade_am=(need_price*has_amount), min_am=float(CURR_LIMITS['filters'][3]['minNotional'])
                            ))

                        log.debug(
                            'Рассчитан ордер на продажу: кол-во {amount:0.8f}, курс: {rate:0.8f}'.format(
                                amount=sell_amount, rate=need_price)
                        )

                        # Отправляем команду на создание ордера с рассчитанными параметрами
                        new_order = bot.createOrder(
                            symbol=orders_info[order]['order_pair'],
                            recvWindow=5000,
                            side='SELL',
                            type='LIMIT',
                            timeInForce='GTC',  # Good Till Cancel
                            quantity="{quantity:0.{precision}f}".format(
                                quantity=sell_amount, precision=CURR_LIMITS['baseAssetPrecision']
                            ),
                            price="{price:0.{precision}f}".format(
                                price=need_price, precision=CURR_LIMITS['baseAssetPrecision']
                            ),
                            newOrderRespType='FULL'
                        )
                        # Если ордер создался без ошибок, записываем данные в базу данных
                        if 'orderId' in new_order:
                            log.info("Создан ордер на продажу {new_order}".format(new_order=new_order))
                            cursor.execute(
                                """
                                  UPDATE orders
                                  SET
                                    order_type = 'sell',
                                    buy_finished = datetime(),
                                    sell_order_id = :sell_order_id,
                                    sell_created = datetime(),
                                    sell_amount = :sell_amount,
                                    sell_price = :sell_initial_price
                                  WHERE
                                    buy_order_id = :buy_order_id

                                """, {
                                    'buy_order_id': order,
                                    'sell_order_id': new_order['orderId'],
                                    'sell_amount': sell_amount,
                                    'sell_initial_price': need_price
                                }
                            )
                            conn.commit()
                        # Если были ошибки при создании, выводим сообщение
                        else:
                            log.warning("Не удалось создать ордер на продажу {new_order}".format(new_order=new_order))

                    # Ордер еще не исполнен, частичного исполнения нет, проверяем возможность отмены
                    elif order_status == 'NEW':
                        order_created = int(orders_info[order]['buy_created'])
                        time_passed = int(time.time()) - order_created
                        log.debug("Прошло времени после создания {passed:0.2f}".format(passed=time_passed))
                        # Прошло больше времени, чем разрешено держать ордер
                        if time_passed > BUY_LIFE_TIME_SEC:
                            log.info("""Ордер {order} пора отменять, прошло {passed:0.1f} сек.""".format(
                                order=order, passed=time_passed
                            ))
                            # Отменяем ордер на бирже
                            cancel = bot.cancelOrder(
                                symbol=orders_info[order]['order_pair'],
                                orderId=order
                            )
                            # Если удалось отменить ордер, скидываем информацию в БД
                            if 'orderId' in cancel:
                                
                                log.info("Ордер {order} был успешно отменен".format(order=order))
                                cursor.execute(
                                    """
                                      UPDATE orders
                                      SET
                                        buy_cancelled = datetime()
                                      WHERE
                                        buy_order_id = :buy_order_id
                                    """, {
                                        'buy_order_id': order
                                    }
                                 )
                                
                                conn.commit()
                            else:
                                log.warning("Не удалось отменить ордер: {cancel}".format(cancel=cancel))
                    elif order_status == 'PARTIALLY_FILLED':
                        log.debug("Ордер {order} частично исполнен, ждем завершения".format(order=order))

                # Если это ордер на продажу, и он исполнен
                if order_status == 'FILLED' and orders_info[order]['order_type'] == 'sell':
                    log.debug("Ордер {order} на продажу исполнен".format(
                        order=order
                    ))
                    # Обновляем информацию в БД
                    cursor.execute(
                        """
                          UPDATE orders
                          SET
                            sell_finished = datetime()
                          WHERE
                            sell_order_id = :sell_order_id

                        """, {
                            'sell_order_id': order
                        }
                    )
                    conn.commit()
                if all_pairs[orders_info[order]['order_pair']]['use_stop_loss']:
                   
                   if order_status == 'NEW' and orders_info[order]['order_type'] == 'sell':
                     curr_rate = float(bot.tickerPrice(symbol=orders_info[order]['order_pair'])['price'])
                     
                     if (1 - curr_rate/orders_info[order]['buy_price'])*100 >= all_pairs[orders_info[order]['order_pair']]['stop_loss']:
                        log.debug("{pair} Цена упала до стоплосс (покупали по {b:0.8f}, сейчас {s:0.8f}), пора продавать".format(
                           pair=orders_info[order]['order_pair'],
                           b=orders_info[order]['buy_price'],
                           s=curr_rate
                        ))
                        # Отменяем ордер на бирже
                        cancel = bot.cancelOrder(
                          symbol=orders_info[order]['order_pair'],
                             orderId=order
                         )
                        # Если удалось отменить ордер, скидываем информацию в БД
                        if 'orderId' in cancel:
                           log.info("Ордер {order} был успешно отменен, продаем по рынку".format(order=order))
                           new_order = bot.createOrder(
                                  symbol=orders_info[order]['order_pair'],
                                  recvWindow=15000,
                                  side='SELL',
                                  type='MARKET',
                                  quantity=orders_info[order]['sell_amount'],
                            )
                           if not new_order.get('code'):
                              log.info("Создан ордер на продажу по рынку " + str(new_order))
                              cursor.execute(
                                 """
                                   DELETE FROM orders
                                   WHERE
                                     sell_order_id = :sell_order_id
                                 """, {
                                     'sell_order_id': order
                                 }
                              )
                              conn.commit()
                              if all_pairs[orders_info[order]['order_pair']]['stop_after_sl']:
                                  all_pairs[orders_info[order]['order_pair']]['active'] = False
                        else:
                           log.warning("Не удалось отменить ордер: {cancel}".format(cancel=cancel))
                     else:
                         log.debug("{pair} (покупали по {b:0.8f}, сейчас {s:0.8f}), расхождение {sl:0.4f}%, panic_sell = {ps:0.4f}% ({ps_rate:0.8f}), продажа с профитом: {tp:0.8f}".format(
                           pair=orders_info[order]['order_pair'],
                           b=orders_info[order]['buy_price'],
                           s=curr_rate,
                           sl=(1 - curr_rate/orders_info[order]['buy_price'])*100,
                           ps=all_pairs[orders_info[order]['order_pair']]['stop_loss'],
                           ps_rate=orders_info[order]['buy_price']/100 * (100-all_pairs[orders_info[order]['order_pair']]['stop_loss']),
                           tp=orders_info[order]['sell_price']
                        ))
                   
                   elif order_status == 'CANCELED' and orders_info[order]['order_type'] == 'sell':
                     # На случай, если после отмены произошел разрыв связи
                     new_order = bot.createOrder(
                                  symbol=orders_info[order]['order_pair'],
                                  recvWindow=15000,
                                  side='SELL',
                                  type='MARKET',
                                  quantity=orders_info[order]['sell_amount'],
                            )
                     if not new_order.get('code'):
                        log.info("Создан ордер на продажу по рынку " + str(new_order))
                        cursor.execute(
                           """
                             DELETE FROM orders
                             WHERE
                               sell_order_id = :sell_order_id
                           """, {
                               'sell_order_id': order
                           }
                        )
                        conn.commit()
        else:
            log.debug("Неисполненных ордеров в БД нет")

        log.debug('Получаем из настроек все пары, по которым нет неисполненных ордеров')

        orders_q = """
            SELECT
              distinct(order_pair) pair
            FROM
              orders
            WHERE
              buy_cancelled IS NULL AND CASE WHEN order_type='buy' THEN buy_finished IS NULL ELSE sell_finished IS NULL END
        """
        # Получаем из базы все ордера, по которым есть торги, и исключаем их из списка, по которому будем создавать новые ордера
        for row in cursor.execute(orders_q):
            del all_pairs[row[0]]

        all_pairs = {k:v for k,v in all_pairs.items() if v['active']}

        # Если остались пары, по которым нет текущих торгов
        if all_pairs:
            log.debug('Найдены пары, по которым нет неисполненных ордеров: {pairs}'.format(pairs=list(all_pairs.keys())))
            for pair_name, pair_obj in all_pairs.items():
                try:
                   log.debug("Работаем с парой {pair}".format(pair=pair_name))

                   # Получаем лимиты пары с биржи
                   for elem in limits['symbols']:
                       if elem['symbol'] == pair_name:
                           CURR_LIMITS = elem
                           break
                   else:
                       raise Exception("Не удалось найти настройки выбранной пары " + pair_name)

                   # Получаем балансы с биржи по указанным валютам
                   balances = {
                       balance['asset']: float(balance['free']) for balance in bot.account()['balances']
                       if balance['asset'] in [pair_obj['base'], pair_obj['quote']]
                   }
                   log.debug("Баланс {balance}".format(balance=["{k}:{bal:0.8f}".format(k=k, bal=balances[k]) for k in balances]))
                   # Если баланс позволяет торговать - выше лимитов биржи и выше указанной суммы в настройках
                   if balances[pair_obj['base']] >= pair_obj['spend_sum']:
                       # Получаем информацию по предложениям из стакана, в кол-ве указанном в настройках
                       offers = bot.depth(
                           symbol=pair_name,
                           limit=pair_obj['offers_amount']
                       )

                       # Берем цены покупок (для цен продаж замените bids на asks)
                       prices = [float(bid[0]) for bid in offers['bids']]

                       try:
                           # Рассчитываем среднюю цену из полученных цен
                           avg_price = sum(prices) / len(prices)
                           # Среднюю цену приводим к требованиям биржи о кратности
                           my_need_price = adjust_to_step(avg_price, CURR_LIMITS['filters'][0]['tickSize'])
                           # Рассчитываем кол-во, которое можно купить, и тоже приводим его к кратному значению
                           my_amount = adjust_to_step(pair_obj['spend_sum']/ my_need_price, CURR_LIMITS['filters'][2]['stepSize'])
                           # Если в итоге получается объем торгов меньше минимально разрешенного, то ругаемся и не создаем ордер
                           if my_amount < float(CURR_LIMITS['filters'][2]['stepSize']) or my_amount < float(CURR_LIMITS['filters'][2]['minQty']):
                               log.warning("""
                                   Минимальная сумма лота: {min_lot:0.8f}
                                   Минимальный шаг лота: {min_lot_step:0.8f}
                                   На свои деньги мы могли бы купить {wanted_amount:0.8f}
                                   После приведения к минимальному шагу мы можем купить {my_amount:0.8f}
                                   Покупка невозможна, выход. Увеличьте размер ставки
                               """.format(
                                   wanted_amount=pair_obj['spend_sum']/ my_need_price,
                                   my_amount=my_amount,
                                   min_lot=float(CURR_LIMITS['filters'][2]['minQty']),
                                   min_lot_step=float(CURR_LIMITS['filters'][2]['stepSize'])
                               ))
                               continue

                           # Итоговый размер лота
                           trade_am = my_need_price*my_amount
                           log.debug("""
                                   Средняя цена {av_price:0.8f}, 
                                   после приведения {need_price:0.8f}, 
                                   объем после приведения {my_amount:0.8f},
                                   итоговый размер сделки {trade_am:0.8f}
                                   """.format(
                               av_price=avg_price, need_price=my_need_price, my_amount=my_amount, trade_am=trade_am
                           ))
                           # Если итоговый размер лота меньше минимального разрешенного, то ругаемся и не создаем ордер
                           if trade_am < float(CURR_LIMITS['filters'][3]['minNotional']):
                               raise Exception("""
                                   Итоговый размер сделки {trade_am:0.8f} меньше допустимого по паре {min_am:0.8f}. 
                                   Увеличьте сумму торгов (в {incr} раз(а))""".format(
                                   trade_am=trade_am, min_am=float(CURR_LIMITS['filters'][3]['minNotional']),
                                   incr=float(CURR_LIMITS['filters'][3]['minNotional'])/trade_am
                               ))
                           log.debug(
                               'Рассчитан ордер на покупку: кол-во {amount:0.8f}, курс: {rate:0.8f}'.format(amount=my_amount, rate=my_need_price)
                           )
                           # Отправляем команду на бирже о создании ордера на покупку с рассчитанными параметрами
                           new_order = bot.createOrder(
                               symbol=pair_name,
                               recvWindow=5000,
                               side='BUY',
                               type='LIMIT',
                               timeInForce='GTC',  # Good Till Cancel
                               quantity="{quantity:0.{precision}f}".format(
                                   quantity=my_amount, precision=CURR_LIMITS['baseAssetPrecision']
                               ),
                               price="{price:0.{precision}f}".format(
                                   price=my_need_price, precision=CURR_LIMITS['baseAssetPrecision']
                               ),
                               newOrderRespType='FULL'
                           )
                           # Если удалось создать ордер на покупку, записываем информацию в БД
                           if 'orderId' in new_order:
                               log.info("Создан ордер на покупку {new_order}".format(new_order=new_order))
                               cursor.execute(
                                   """
                                     INSERT INTO orders(
                                         order_type,
                                         order_pair,
                                         buy_order_id,
                                         buy_amount,
                                         buy_price,
                                         buy_created

                                     ) Values (
                                       'buy',
                                       :order_pair,
                                       :order_id,
                                       :buy_order_amount,
                                       :buy_initial_price,
                                       datetime()
                                     )
                                   """, {
                                       'order_pair': pair_name,
                                       'order_id': new_order['orderId'],
                                       'buy_order_amount': my_amount,
                                       'buy_initial_price': my_need_price
                                   }
                               )
                               conn.commit()
                           else:
                               log.warning("Не удалось создать ордер на покупку! {new_order}".format(new_order=str(new_order)))

                       except ZeroDivisionError:
                           log.debug('Не удается вычислить среднюю цену: {prices}'.format(prices=str(prices)))
                   else:
                       log.warning('Для создания ордера на покупку нужно минимум {min_qty:0.8f} {curr}, выход'.format(
                           min_qty=pair_obj['spend_sum'], curr=pair_obj['base']
                       ))
                except Exception as e:
                   log.exception(e)
        else:
            log.debug('По всем парам есть неисполненные ордера')

    except Exception as e:
        log.exception(e)
    finally:
        conn.close()

 

binance_bot.py

Ссылка на комментарий
Поделиться на других сайтах

Огромное спасибо Вам Senior Андрей за то, что занимаетесь этим, и отвечаете многим порой на глупые вопросы, помогаете оперативно при возникновении проблем в ваших проектах, и за то что вы есть. Благодаря Вам познакомился с питоном, заодно потихоньку PHP, HTML, QT и многим другим. До баблофила лет пять бесплодных попыток сделать скучный калькулятор на визуал бейсик.нет. Сейчас уже успешно помогаю новичкам на киберфоруме(в свободное время). Хотел добавить, если вдруг у Вас будет время для новой статьи, неплохим вариантом как мне кажется был бы разбор на пальцах кода binance_api(я об него все зубы сломал, хотя в принципе вроде бы все понятно),с его кваргсами, и магическими атрибутами. Но Вам конечно виднее. Еще я заметил, разницу бинанс бота до обвала криптовалют, и нынешнего. Теперешний работает стабильно(тьфу-тьфу),появились новые фишки(стоп лосс в частности). А на странице загрузки у Вас версия 1.0.0 для всех изменений.Но все это ИМХО. Еще раз спасибо, начинаю тестировать, о результатах отпишусь.

Ссылка на комментарий
Поделиться на других сайтах

Подскажите также возможно ли в код вставить что-то типа(с периодическим выводом в консоль):

log.debug("По паре{pair}сработал стоп-лос,и она отключена".format(pair=pair_name))

если возможно, то в какой строке? Спасибо.

Ссылка на комментарий
Поделиться на других сайтах

Конечно, вот сюда

if all_pairs[orders_info[order]['order_pair']]['stop_after_sl']:
    all_pairs[orders_info[order]['order_pair']]['active'] = False
    log.debug("Сработал Stop-Loss по паре {pair}, она отключена".format(pair=orders_info[order]['order_pair']))

Кстати говоря, продажа по стоп-лоссу состоит из двух частей - сначала отменяется выставленный sell, потом выставляется sell по рынку на то же кол-во.

Так вот, пара будет выключена после того, как сработали оба этих шага.

Вы можете изменить логику так, что бы срабатывало после отмены, если это требуется - сдвиньте эти строки влево на 4 пробела..

Ссылка на комментарий
Поделиться на других сайтах

А может не совсем отключать пару а скажем на час? Это я так понимаю надо через БД делать или переменную создать на настоящее время и в цикле проверять есть ли такие переменные и прошло ли у них время с начала их создания, а по истечению срока,  флаг active обратно ставить True? Не, не вариант? ))

Ссылка на комментарий
Поделиться на других сайтах

Ну примерно так, надо тогда в настройках пары добавлять что-то вроде  

'reactivate_pair':True,
'reactivate_pair_after_sec': 3600,
'deactivation_time': 0,

Потом тут 

if all_pairs[orders_info[order]['order_pair']]['stop_after_sl']:
    all_pairs[orders_info[order]['order_pair']]['active'] = False

Добавить строку, будет так

if all_pairs[orders_info[order]['order_pair']]['stop_after_sl']:
    all_pairs[orders_info[order]['order_pair']]['active'] = False
    all_pairs[orders_info[order]['order_pair']]['deactivation_time'] = int(time.time())

Потом вот это

if not [p for p in pairs if p['active']]:
   log.debug('Больше нет активных пар')
   break

Заменить на это:

# Если пара не активна и допускается реактивация
for p in [p for p in pairs if p['reactivate_pair'] and not p['active']]:
    # Если прошло больше указанного времени
    if (int(time.time()) - p['deactivation_time']) >= p['reactivate_pair_after_sec']:
        # Активировать пару
        all_pairs[p['quote'].upper() + p['base'].upper()]['Active'] = True

 

Ссылка на комментарий
Поделиться на других сайтах

по результатам  тестирования данной модернизации был замечен ордер не полностью отработавший,  пара же успешно отключилась.

Также не нашел в логах сообщений о выключенной паре(может плохо искал). Так как сообщение необходимо постоянно выводить в консоль передвинул строку на 1 таб влево, для выхода из условия. Тестирую дальше. Еще в сети есть некто Герчик, который разработал целую стратегию, так у него есть утверждение " Если limit order не открылся и акция прошла 2 стопа (по закрытию бара), то сделка отменяется ". В принципе тоже можно прикрутить. Продолжаю тестировать.

if all_pairs[orders_info[order]['order_pair']]['stop_after_sl']:
	all_pairs[orders_info[order]['order_pair']]['active'] = False
log.debug("Сработал Stop-Loss по паре {pair}, она отключена".format(pair=orders_info[order]['order_pair']))

 

Ссылка на комментарий
Поделиться на других сайтах

  • 3 months later...

Добрый день. Подскажите пожалуйста почему возникает ошибка?

2019-05-10 10:26:40,145 [ERROR] 'reactivate_pair_after_sec'
Traceback (most recent call last):
  File "H:\БОТ в Разр\16  binance_bot\16binance_bot.py", line 321, in <module>
    if (int(time.time()) - p['deactivation_time']) >= p['reactivate_pair_after_sec']:
KeyError: 'reactivate_pair_after_sec'

Ссылка на комментарий
Поделиться на других сайтах

 
 
 
10.05.2019 в 10:55, bros3670 сказал:

Добрый день. Подскажите пожалуйста почему возникает ошибка?

2019-05-10 10:26:40,145 [ERROR] 'reactivate_pair_after_sec'
Traceback (most recent call last):
  File "H:\БОТ в Разр\16  binance_bot\16binance_bot.py", line 321, in <module>
    if (int(time.time()) - p['deactivation_time']) >= p['reactivate_pair_after_sec']:
KeyError: 'reactivate_pair_after_sec'

Где то в настройках какой-то пары не указан параметр

'reactivate_pair_after_sec': 3600,
Ссылка на комментарий
Поделиться на других сайтах

  • 3 weeks later...
21.01.2019 в 03:01, admin сказал:

Добрый день,

Добавил параметры active и stop_after_sl в настройки пары, ну и там сям в коде.

Скачайте обычного бота, и файл binance_bot.py замените. 

В любом случае дайте обратную связь, пожалуйста.


"""
    Подробная информация о боте на сайте bablofil.ru/bot-dlya-binance
"""
import sqlite3
import logging
import time
import os

from datetime import datetime

from binance_api import Binance
bot = Binance(
    API_KEY='',
    API_SECRET=''
)

"""
    Пропишите пары, на которые будет идти торговля.
    base - это базовая пара (BTC, ETH,  BNB, USDT) - то, что на бинансе пишется в табличке сверху
    quote - это квотируемая валюта. Например, для торгов по паре NEO/USDT базовая валюта USDT, NEO - квотируемая
"""


pairs = [
   {
        'base': 'BTC',
        'quote': 'EOS',
        'offers_amount': 5, # Сколько предложений из стакана берем для расчета средней цены
                            # Максимум 1000. Допускаются следующие значения:[5, 10, 20, 50, 100, 500, 1000]
        'spend_sum': 0.0015,  # Сколько тратить base каждый раз при покупке quote
        'profit_markup': 0.005, # Какой навар нужен с каждой сделки? (0.001 = 0.1%)
        'active': True, # True - по паре будет торговля
        'use_stop_loss': False, # Нужно ли продавать с убытком при падении цены
        'stop_loss': 1, # 1% - На сколько должна упасть цена, что бы продавать с убытком
        'stop_after_sl': True, # True - если сработал stop-loss, то прекратить торговлю по паре
    }, {
        'base': 'USDT',
        'quote': 'NEO',
        'offers_amount': 5, # Сколько предложений из стакана берем для расчета средней цены
                            # Максимум 1000. Допускаются следующие значения:[5, 10, 20, 50, 100, 500, 1000]
        'spend_sum': 11,  # Сколько тратить base каждый раз при покупке quote
        'profit_markup': 0.005, # Какой навар нужен с каждой сделки? (0.001 = 0.1%)
        'active': True, # True - по паре будет торговля
        'use_stop_loss': False, # Нужно ли продавать с убытком при падении цены
        'stop_loss': 2, # 2%  - На сколько должна упасть цена, что бы продавать с убытком
        'stop_after_sl': True, # True - если сработал stop-loss, то прекратить торговлю по паре

    }
]



BUY_LIFE_TIME_SEC = 180 # Сколько (в секундах) держать ордер на продажу открытым

STOCK_FEE = 0.00075  # Комиссия, которую берет биржа (0.001 = 0.1%)

# Если вы решите не платить комиссию в BNB, то установите в False. Обычно делать этого не надо
USE_BNB_FEES = True

# Получаем ограничения торгов по всем парам с биржи
local_time = int(time.time())
limits = bot.exchangeInfo()
server_time = int(limits['serverTime'])//1000

# Ф-ция, которая приводит любое число к числу, кратному шагу, указанному биржей
# Если передать параметр increase=True то округление произойдет к следующему шагу
def adjust_to_step(value, step, increase=False):
   return ((int(value * 100000000) - int(value * 100000000) % int(
        float(step) * 100000000)) / 100000000)+(float(step) if increase else 0)

# Подключаем логирование
logging.basicConfig(
    format="%(asctime)s [%(levelname)-5.5s] %(message)s",
    level=logging.DEBUG,
    handlers=[
        logging.FileHandler("{path}/logs/{fname}.log".format(path=os.path.dirname(os.path.abspath(__file__)), fname="binance")),
        logging.StreamHandler()
    ])

log = logging.getLogger('')

# Бесконечный цикл программы

shift_seconds = server_time-local_time
bot.set_shift_seconds(shift_seconds)

log.debug("""
    Текущее время: {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
))

while True:
    try:
        # Устанавливаем соединение с локальной базой данных
        conn = sqlite3.connect('binance.db')
        cursor = conn.cursor()

        # Если не существует таблиц, их нужно создать (первый запуск)
        orders_q = """
          create table if not exists
            orders (
              order_type TEXT,
              order_pair TEXT,

              buy_order_id NUMERIC,
              buy_amount REAL,
              buy_price REAL,
              buy_created DATETIME,
              buy_finished DATETIME NULL,
              buy_cancelled DATETIME NULL,

              sell_order_id NUMERIC NULL,
              sell_amount REAL NULL,
              sell_price REAL NULL,
              sell_created DATETIME NULL,
              sell_finished DATETIME NULL,
              force_sell INT DEFAULT 0
            );
        """
        cursor.execute(orders_q)

        log.debug("Получаем все неисполненные ордера по БД")

        orders_q = """
            SELECT
              CASE WHEN order_type='buy' THEN buy_order_id ELSE sell_order_id END order_id
              , order_type
              , order_pair
              , sell_amount
              , sell_price
              ,  strftime('%s',buy_created)
              , buy_amount
              , buy_price
            FROM
              orders
            WHERE
              buy_cancelled IS NULL AND CASE WHEN order_type='buy' THEN buy_finished IS NULL ELSE sell_finished IS NULL END
        """
        orders_info = {}


        for row in cursor.execute(orders_q):
            orders_info[str(row[0])] = {'order_type': row[1], 'order_pair': row[2], 'sell_amount': row[3], 'sell_price': row[4],
                                         'buy_created': row[5], 'buy_amount': row[6], 'buy_price': row[7] }
        # формируем словарь из указанных пар, для удобного доступа
        all_pairs = {pair['quote'].upper() + pair['base'].upper():pair for pair in pairs}
        if not [p for p in pairs if p['active']]:
           log.debug('Больше нет активных пар')
           break
        
        if orders_info:
            log.debug("Получены неисполненные ордера из БД: {orders}".format(orders=[(order, orders_info[order]['order_pair']) for order in orders_info]))

            # Проверяем каждый неисполненный по базе ордер
            for order in orders_info:
                # Получаем по ордеру последнюю информацию по бирже
                stock_order_data = bot.orderInfo(symbol=orders_info[order]['order_pair'], orderId=order)

                order_status = stock_order_data['status']
                log.debug("Состояние ордера {order} - {status}".format(order=order, status=order_status))
                if order_status == 'NEW':
                    log.debug('Ордер {order} всё еще не выполнен'.format(order=order))

                # Если ордер на покупку
                if orders_info[order]['order_type'] == 'buy':
                    # Если ордер уже исполнен
                    if order_status == 'FILLED':
                        log.info("""
                            Ордер {order} выполнен, получено {exec_qty:0.8f}.
                            Создаем ордер на продажу
                        """.format(
                            order=order, exec_qty=float(stock_order_data['executedQty'])
                        ))

                        # смотрим, какие ограничения есть для создания ордера на продажу
                        for elem in limits['symbols']:
                            if elem['symbol'] == orders_info[order]['order_pair']:
                                CURR_LIMITS = elem
                                break
                        else:
                            raise Exception("Не удалось найти настройки выбранной пары " + pair_name)

                        # Рассчитываем данные для ордера на продажу

                        # Имеющееся кол-во на продажу
                        has_amount = orders_info[order]['buy_amount']*((1-STOCK_FEE) if not USE_BNB_FEES else 1)
                        # Приводим количество на продажу к числу, кратному по ограничению
                        sell_amount = adjust_to_step(has_amount, CURR_LIMITS['filters'][2]['stepSize'])
                        # Рассчитываем минимальную сумму, которую нужно получить, что бы остаться в плюсе
                        need_to_earn = orders_info[order]['buy_amount']*orders_info[order]['buy_price']*(1+all_pairs[stock_order_data['symbol']]['profit_markup'])
                        # Рассчитываем минимальную цену для продажи
                        min_price = (need_to_earn/sell_amount)/((1-STOCK_FEE) if not USE_BNB_FEES else 1)
                        # Приводим к нужному виду, если цена после срезки лишних символов меньше нужной, увеличиваем на шаг
                        cut_price = max(
                            adjust_to_step(min_price, CURR_LIMITS['filters'][0]['tickSize'], increase=True),
                            adjust_to_step(min_price, CURR_LIMITS['filters'][0]['tickSize'])
                        )
                        # Получаем текущие курсы с биржи
                        curr_rate = float(bot.tickerPrice(symbol=orders_info[order]['order_pair'])['price'])
                        # Если текущая цена выше нужной, продаем по текущей
                        need_price = max(cut_price, curr_rate)

                        log.info("""
                            Изначально было куплено {buy_initial:0.8f}, за вычетом комиссии {has_amount:0.8f},
                            Получится продать только {sell_amount:0.8f}
                            Нужно получить как минимум {need_to_earn:0.8f} {curr}
                            Мин. цена (с комиссией) составит {min_price}, после приведения {cut_price:0.8f}
                            Текущая цена рынка {curr_rate:0.8f}
                            Итоговая цена продажи: {need_price:0.8f}
                        """.format(
                            buy_initial=orders_info[order]['buy_amount'], has_amount=has_amount,sell_amount=sell_amount,
                            need_to_earn=need_to_earn, curr=all_pairs[orders_info[order]['order_pair']]['base'],
                            min_price=min_price, cut_price=cut_price, need_price=need_price,
                            curr_rate=curr_rate
                        ))

                        # Если итоговая сумма продажи меньше минимума, ругаемся и не продаем
                        if (need_price*has_amount) <float(CURR_LIMITS['filters'][3]['minNotional']):
                            raise Exception("""
                                Итоговый размер сделки {trade_am:0.8f} меньше допустимого по паре {min_am:0.8f}. """.format(
                                trade_am=(need_price*has_amount), min_am=float(CURR_LIMITS['filters'][3]['minNotional'])
                            ))

                        log.debug(
                            'Рассчитан ордер на продажу: кол-во {amount:0.8f}, курс: {rate:0.8f}'.format(
                                amount=sell_amount, rate=need_price)
                        )

                        # Отправляем команду на создание ордера с рассчитанными параметрами
                        new_order = bot.createOrder(
                            symbol=orders_info[order]['order_pair'],
                            recvWindow=5000,
                            side='SELL',
                            type='LIMIT',
                            timeInForce='GTC',  # Good Till Cancel
                            quantity="{quantity:0.{precision}f}".format(
                                quantity=sell_amount, precision=CURR_LIMITS['baseAssetPrecision']
                            ),
                            price="{price:0.{precision}f}".format(
                                price=need_price, precision=CURR_LIMITS['baseAssetPrecision']
                            ),
                            newOrderRespType='FULL'
                        )
                        # Если ордер создался без ошибок, записываем данные в базу данных
                        if 'orderId' in new_order:
                            log.info("Создан ордер на продажу {new_order}".format(new_order=new_order))
                            cursor.execute(
                                """
                                  UPDATE orders
                                  SET
                                    order_type = 'sell',
                                    buy_finished = datetime(),
                                    sell_order_id = :sell_order_id,
                                    sell_created = datetime(),
                                    sell_amount = :sell_amount,
                                    sell_price = :sell_initial_price
                                  WHERE
                                    buy_order_id = :buy_order_id

                                """, {
                                    'buy_order_id': order,
                                    'sell_order_id': new_order['orderId'],
                                    'sell_amount': sell_amount,
                                    'sell_initial_price': need_price
                                }
                            )
                            conn.commit()
                        # Если были ошибки при создании, выводим сообщение
                        else:
                            log.warning("Не удалось создать ордер на продажу {new_order}".format(new_order=new_order))

                    # Ордер еще не исполнен, частичного исполнения нет, проверяем возможность отмены
                    elif order_status == 'NEW':
                        order_created = int(orders_info[order]['buy_created'])
                        time_passed = int(time.time()) - order_created
                        log.debug("Прошло времени после создания {passed:0.2f}".format(passed=time_passed))
                        # Прошло больше времени, чем разрешено держать ордер
                        if time_passed > BUY_LIFE_TIME_SEC:
                            log.info("""Ордер {order} пора отменять, прошло {passed:0.1f} сек.""".format(
                                order=order, passed=time_passed
                            ))
                            # Отменяем ордер на бирже
                            cancel = bot.cancelOrder(
                                symbol=orders_info[order]['order_pair'],
                                orderId=order
                            )
                            # Если удалось отменить ордер, скидываем информацию в БД
                            if 'orderId' in cancel:
                                
                                log.info("Ордер {order} был успешно отменен".format(order=order))
                                cursor.execute(
                                    """
                                      UPDATE orders
                                      SET
                                        buy_cancelled = datetime()
                                      WHERE
                                        buy_order_id = :buy_order_id
                                    """, {
                                        'buy_order_id': order
                                    }
                                 )
                                
                                conn.commit()
                            else:
                                log.warning("Не удалось отменить ордер: {cancel}".format(cancel=cancel))
                    elif order_status == 'PARTIALLY_FILLED':
                        log.debug("Ордер {order} частично исполнен, ждем завершения".format(order=order))

                # Если это ордер на продажу, и он исполнен
                if order_status == 'FILLED' and orders_info[order]['order_type'] == 'sell':
                    log.debug("Ордер {order} на продажу исполнен".format(
                        order=order
                    ))
                    # Обновляем информацию в БД
                    cursor.execute(
                        """
                          UPDATE orders
                          SET
                            sell_finished = datetime()
                          WHERE
                            sell_order_id = :sell_order_id

                        """, {
                            'sell_order_id': order
                        }
                    )
                    conn.commit()
                if all_pairs[orders_info[order]['order_pair']]['use_stop_loss']:
                   
                   if order_status == 'NEW' and orders_info[order]['order_type'] == 'sell':
                     curr_rate = float(bot.tickerPrice(symbol=orders_info[order]['order_pair'])['price'])
                     
                     if (1 - curr_rate/orders_info[order]['buy_price'])*100 >= all_pairs[orders_info[order]['order_pair']]['stop_loss']:
                        log.debug("{pair} Цена упала до стоплосс (покупали по {b:0.8f}, сейчас {s:0.8f}), пора продавать".format(
                           pair=orders_info[order]['order_pair'],
                           b=orders_info[order]['buy_price'],
                           s=curr_rate
                        ))
                        # Отменяем ордер на бирже
                        cancel = bot.cancelOrder(
                          symbol=orders_info[order]['order_pair'],
                             orderId=order
                         )
                        # Если удалось отменить ордер, скидываем информацию в БД
                        if 'orderId' in cancel:
                           log.info("Ордер {order} был успешно отменен, продаем по рынку".format(order=order))
                           new_order = bot.createOrder(
                                  symbol=orders_info[order]['order_pair'],
                                  recvWindow=15000,
                                  side='SELL',
                                  type='MARKET',
                                  quantity=orders_info[order]['sell_amount'],
                            )
                           if not new_order.get('code'):
                              log.info("Создан ордер на продажу по рынку " + str(new_order))
                              cursor.execute(
                                 """
                                   DELETE FROM orders
                                   WHERE
                                     sell_order_id = :sell_order_id
                                 """, {
                                     'sell_order_id': order
                                 }
                              )
                              conn.commit()
                              if all_pairs[orders_info[order]['order_pair']]['stop_after_sl']:
                                  all_pairs[orders_info[order]['order_pair']]['active'] = False
                        else:
                           log.warning("Не удалось отменить ордер: {cancel}".format(cancel=cancel))
                     else:
                         log.debug("{pair} (покупали по {b:0.8f}, сейчас {s:0.8f}), расхождение {sl:0.4f}%, panic_sell = {ps:0.4f}% ({ps_rate:0.8f}), продажа с профитом: {tp:0.8f}".format(
                           pair=orders_info[order]['order_pair'],
                           b=orders_info[order]['buy_price'],
                           s=curr_rate,
                           sl=(1 - curr_rate/orders_info[order]['buy_price'])*100,
                           ps=all_pairs[orders_info[order]['order_pair']]['stop_loss'],
                           ps_rate=orders_info[order]['buy_price']/100 * (100-all_pairs[orders_info[order]['order_pair']]['stop_loss']),
                           tp=orders_info[order]['sell_price']
                        ))
                   
                   elif order_status == 'CANCELED' and orders_info[order]['order_type'] == 'sell':
                     # На случай, если после отмены произошел разрыв связи
                     new_order = bot.createOrder(
                                  symbol=orders_info[order]['order_pair'],
                                  recvWindow=15000,
                                  side='SELL',
                                  type='MARKET',
                                  quantity=orders_info[order]['sell_amount'],
                            )
                     if not new_order.get('code'):
                        log.info("Создан ордер на продажу по рынку " + str(new_order))
                        cursor.execute(
                           """
                             DELETE FROM orders
                             WHERE
                               sell_order_id = :sell_order_id
                           """, {
                               'sell_order_id': order
                           }
                        )
                        conn.commit()
        else:
            log.debug("Неисполненных ордеров в БД нет")

        log.debug('Получаем из настроек все пары, по которым нет неисполненных ордеров')

        orders_q = """
            SELECT
              distinct(order_pair) pair
            FROM
              orders
            WHERE
              buy_cancelled IS NULL AND CASE WHEN order_type='buy' THEN buy_finished IS NULL ELSE sell_finished IS NULL END
        """
        # Получаем из базы все ордера, по которым есть торги, и исключаем их из списка, по которому будем создавать новые ордера
        for row in cursor.execute(orders_q):
            del all_pairs[row[0]]

        all_pairs = {k:v for k,v in all_pairs.items() if v['active']}

        # Если остались пары, по которым нет текущих торгов
        if all_pairs:
            log.debug('Найдены пары, по которым нет неисполненных ордеров: {pairs}'.format(pairs=list(all_pairs.keys())))
            for pair_name, pair_obj in all_pairs.items():
                try:
                   log.debug("Работаем с парой {pair}".format(pair=pair_name))

                   # Получаем лимиты пары с биржи
                   for elem in limits['symbols']:
                       if elem['symbol'] == pair_name:
                           CURR_LIMITS = elem
                           break
                   else:
                       raise Exception("Не удалось найти настройки выбранной пары " + pair_name)

                   # Получаем балансы с биржи по указанным валютам
                   balances = {
                       balance['asset']: float(balance['free']) for balance in bot.account()['balances']
                       if balance['asset'] in [pair_obj['base'], pair_obj['quote']]
                   }
                   log.debug("Баланс {balance}".format(balance=["{k}:{bal:0.8f}".format(k=k, bal=balances[k]) for k in balances]))
                   # Если баланс позволяет торговать - выше лимитов биржи и выше указанной суммы в настройках
                   if balances[pair_obj['base']] >= pair_obj['spend_sum']:
                       # Получаем информацию по предложениям из стакана, в кол-ве указанном в настройках
                       offers = bot.depth(
                           symbol=pair_name,
                           limit=pair_obj['offers_amount']
                       )

                       # Берем цены покупок (для цен продаж замените bids на asks)
                       prices = [float(bid[0]) for bid in offers['bids']]

                       try:
                           # Рассчитываем среднюю цену из полученных цен
                           avg_price = sum(prices) / len(prices)
                           # Среднюю цену приводим к требованиям биржи о кратности
                           my_need_price = adjust_to_step(avg_price, CURR_LIMITS['filters'][0]['tickSize'])
                           # Рассчитываем кол-во, которое можно купить, и тоже приводим его к кратному значению
                           my_amount = adjust_to_step(pair_obj['spend_sum']/ my_need_price, CURR_LIMITS['filters'][2]['stepSize'])
                           # Если в итоге получается объем торгов меньше минимально разрешенного, то ругаемся и не создаем ордер
                           if my_amount < float(CURR_LIMITS['filters'][2]['stepSize']) or my_amount < float(CURR_LIMITS['filters'][2]['minQty']):
                               log.warning("""
                                   Минимальная сумма лота: {min_lot:0.8f}
                                   Минимальный шаг лота: {min_lot_step:0.8f}
                                   На свои деньги мы могли бы купить {wanted_amount:0.8f}
                                   После приведения к минимальному шагу мы можем купить {my_amount:0.8f}
                                   Покупка невозможна, выход. Увеличьте размер ставки
                               """.format(
                                   wanted_amount=pair_obj['spend_sum']/ my_need_price,
                                   my_amount=my_amount,
                                   min_lot=float(CURR_LIMITS['filters'][2]['minQty']),
                                   min_lot_step=float(CURR_LIMITS['filters'][2]['stepSize'])
                               ))
                               continue

                           # Итоговый размер лота
                           trade_am = my_need_price*my_amount
                           log.debug("""
                                   Средняя цена {av_price:0.8f}, 
                                   после приведения {need_price:0.8f}, 
                                   объем после приведения {my_amount:0.8f},
                                   итоговый размер сделки {trade_am:0.8f}
                                   """.format(
                               av_price=avg_price, need_price=my_need_price, my_amount=my_amount, trade_am=trade_am
                           ))
                           # Если итоговый размер лота меньше минимального разрешенного, то ругаемся и не создаем ордер
                           if trade_am < float(CURR_LIMITS['filters'][3]['minNotional']):
                               raise Exception("""
                                   Итоговый размер сделки {trade_am:0.8f} меньше допустимого по паре {min_am:0.8f}. 
                                   Увеличьте сумму торгов (в {incr} раз(а))""".format(
                                   trade_am=trade_am, min_am=float(CURR_LIMITS['filters'][3]['minNotional']),
                                   incr=float(CURR_LIMITS['filters'][3]['minNotional'])/trade_am
                               ))
                           log.debug(
                               'Рассчитан ордер на покупку: кол-во {amount:0.8f}, курс: {rate:0.8f}'.format(amount=my_amount, rate=my_need_price)
                           )
                           # Отправляем команду на бирже о создании ордера на покупку с рассчитанными параметрами
                           new_order = bot.createOrder(
                               symbol=pair_name,
                               recvWindow=5000,
                               side='BUY',
                               type='LIMIT',
                               timeInForce='GTC',  # Good Till Cancel
                               quantity="{quantity:0.{precision}f}".format(
                                   quantity=my_amount, precision=CURR_LIMITS['baseAssetPrecision']
                               ),
                               price="{price:0.{precision}f}".format(
                                   price=my_need_price, precision=CURR_LIMITS['baseAssetPrecision']
                               ),
                               newOrderRespType='FULL'
                           )
                           # Если удалось создать ордер на покупку, записываем информацию в БД
                           if 'orderId' in new_order:
                               log.info("Создан ордер на покупку {new_order}".format(new_order=new_order))
                               cursor.execute(
                                   """
                                     INSERT INTO orders(
                                         order_type,
                                         order_pair,
                                         buy_order_id,
                                         buy_amount,
                                         buy_price,
                                         buy_created

                                     ) Values (
                                       'buy',
                                       :order_pair,
                                       :order_id,
                                       :buy_order_amount,
                                       :buy_initial_price,
                                       datetime()
                                     )
                                   """, {
                                       'order_pair': pair_name,
                                       'order_id': new_order['orderId'],
                                       'buy_order_amount': my_amount,
                                       'buy_initial_price': my_need_price
                                   }
                               )
                               conn.commit()
                           else:
                               log.warning("Не удалось создать ордер на покупку! {new_order}".format(new_order=str(new_order)))

                       except ZeroDivisionError:
                           log.debug('Не удается вычислить среднюю цену: {prices}'.format(prices=str(prices)))
                   else:
                       log.warning('Для создания ордера на покупку нужно минимум {min_qty:0.8f} {curr}, выход'.format(
                           min_qty=pair_obj['spend_sum'], curr=pair_obj['base']
                       ))
                except Exception as e:
                   log.exception(e)
        else:
            log.debug('По всем парам есть неисполненные ордера')

    except Exception as e:
        log.exception(e)
    finally:
        conn.close()

 

binance_bot.py 34 \u041a\u0411 · 17 downloads

БОТ почему то не выставляет STOP LOSS... Может я делаю что не так? Он покупает и выставляет ордер на продажу с наваром, но когда достигает -1% (когда пора STOP LOSS ставить) он не отменяет предыдущий ордер и не ставит стоп лосс ...

А можно ли сделать таким образом, чтобы бот не выставлял цену с наваром вообще, а просто отслеживал ТЕКУЩУЮ ЦЕНУ после покупки и вне зависимости от того на сколько подскочила монета, при падении на 1% от текущей цены ставился бы стоп лосс???

Ссылка на комментарий
Поделиться на других сайтах

  • 4 weeks later...
24.06.2019 в 01:46, admin сказал:

Бот для Binance с индикаторамиКонечно можно, смотрите нового бота, там есть такие моменты, можете скомбинировать

К сожалению сам найти не смог нужную настройку( Помогите пожалуйста, если Вас не затруднит... 2 вечера код просматривал=)

Ссылка на комментарий
Поделиться на других сайтах

  • 2 months later...
22.01.2019 в 19:10, admin сказал:

Ну примерно так, надо тогда в настройках пары добавлять что-то вроде  


'reactivate_pair':True,
'reactivate_pair_after_sec': 3600,
'deactivation_time': 0,

Потом тут 


if all_pairs[orders_info[order]['order_pair']]['stop_after_sl']:
    all_pairs[orders_info[order]['order_pair']]['active'] = False

Добавить строку, будет так


if all_pairs[orders_info[order]['order_pair']]['stop_after_sl']:
    all_pairs[orders_info[order]['order_pair']]['active'] = False
    all_pairs[orders_info[order]['order_pair']]['deactivation_time'] = int(time.time())

Потом вот это


if not [p for p in pairs if p['active']]:
   log.debug('Больше нет активных пар')
   break

Заменить на это:


# Если пара не активна и допускается реактивация
for p in [p for p in pairs if p['reactivate_pair'] and not p['active']]:
    # Если прошло больше указанного времени
    if (int(time.time()) - p['deactivation_time']) >= p['reactivate_pair_after_sec']:
        # Активировать пару
        all_pairs[p['quote'].upper() + p['base'].upper()]['Active'] = True

 

пара замораживается....при достижении времени разморозки  появляется такое

  File "./binance_bot.py", line 357, in <module>
    all_pairs[p['quote'].upper() + p['base'].upper()]['Active'] = True
KeyError: 'WANBTC'
2019-09-13 22:09:24,082 [DEBUG] Получаем все неисполненные ордера по БД
2019-09-13 22:09:24,086 [ERROR] 'WANBTC'
Traceback (most recent call last):
  File "./binance_bot.py", line 357, in <module>
    all_pairs[p['quote'].upper() + p['base'].upper()]['Active'] = True
KeyError: 'WANBTC'
2019-09-13 22:09:24,096 [DEBUG] Получаем все неисполненные ордера по БД
2019-09-13 22:09:24,099 [ERROR] 'WANBTC'
Traceback (most recent call last):
  File "./binance_bot.py", line 357, in <module>
    all_pairs[p['quote'].upper() + p['base'].upper()]['Active'] = True
KeyError: 'WANBTC'
2019-09-13 22:09:24,109 [DEBUG] Получаем все неисполненные ордера по БД
2019-09-13 22:09:24,113 [ERROR] 'WANBTC'
Traceback (most recent call last):
  File "./binance_bot.py", line 357, in <module>
    all_pairs[p['quote'].upper() + p['base'].upper()]['Active'] = True
KeyError: 'WANBTC'
2019-09-13 22:09:24,121 [DEBUG] Получаем все неисполненные ордера по БД
2019-09-13 22:09:24,126 [ERROR] 'WANBTC'
Traceback (most recent call last):
  File "./binance_bot.py", line 357, in <module>
    all_pairs[p['quote'].upper() + p['base'].upper()]['Active'] = True
KeyError: 'WANBTC

при перезапуске бота-пара разморожена... опять работает....что не так?

Изменено пользователем Theankud
Ссылка на комментарий
Поделиться на других сайтах

                                   'buy_created': row[5], 'buy_amount': row[6], 'buy_price': row[7] }
        # формируем словарь из указанных пар, для удобного доступа
        #all_pairs = {pair['quote'].upper() + pair['base'].upper():pair for pair in pairs}
        all_pairs = {pair['quote'].upper() + pair['base'].upper():pair for pair in pairs}
        # Если пара не активна и допускается реактивация
        for p in [p for p in pairs if p['reactivate_pair'] and not p['active']]:

            # Если прошло больше указанного времени
            if (int(time.time()) - p['deactivation_time']) >= p['reactivate_pair_after_sec']:
                
                 
                # Активировать пару
                all_pairs[p['quote'].upper() + p['base'].upper()]['Active'] = True
                log.info('Реактивируем пару {pair}'.format(pair=pair_name))
        if orders_info:
            log.debug("Получены неисполненные ордера из БД: {orders}".format(orders=[(order, orders_info[order]['order_pair']) for order in orders_info]))

            # Проверяем каждый неисполненный по базе ордер
            for order in orders_info:
                # Получаем по ордеру последнюю информацию по бирже
                stock_order_data = bot.orderInfo(symbol=orders_info[order]['order_pair'], orderId=order)

                order_status = stock_order_data['status']

 

замораживает, но не размораживает.....

Ссылка на комментарий
Поделиться на других сайтах

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Гость
Ответить в тему...

×   Вставлено в виде отформатированного текста.   Вставить в виде обычного текста

  Разрешено не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отобразить как ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставить изображения напрямую. Загрузите или вставьте изображения по ссылке.

×
×
  • Создать...