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

Бесплатный бот для Poloniex


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

По сути в данный момент  - это просто адаптация старинного бота из блога Андрея под пакет от s4w3d0ff.

Бот околонулевой, но для тех кто впервые хочет разобраться с темой подойдет.

Оригинальный код убавился на 200 строк python 3.9

"""
    Original bot https://bablofil.com/bot-dlya-birjy-poloniex/
    Adapted to the package https://github.com/s4w3d0ff/python-poloniex

"""
import os
import time
import sqlite3
import poloniex

from config import PRIVATE
from statistics import median
from datetime import datetime

PAIRS = {
    'USDT_BTC': {
        'ORDER_AMOUNT': '2',  # Сколько валюты 1 использовать в ордере ( в данном случае, 0.002 Btc),
        'ORDER_LIFE_TIME': 3,  # через сколько минут отменять неисполненный ордер на покупку CURR_1
        'PROFIT_MARKUP_DOWN': 0.001,
        # Какой навар нужен с каждой сделки при покупке (поверх комиссии)? (0.001 = 0.1%). Можно ставить 0
        'PROFIT_MARKUP_UP': 0.002,  # Какой навар нужен с каждой сделки при продаже (поверх комиссии)? (0.002 = 0.2%)
        'MED_PRICE_PERIOD': 15,  # За какой период брать среднюю цену (в минутах)
    }
}
STOCK_FEE = 0.00125  # Минимальная комиссия, которую берет биржа (0.002 = 0.2%)
DEBUG = True  # True - выводить отладочную информацию, False - писать как можно меньше

CURR_DIR = os.path.dirname(os.path.abspath(__file__))

LOG_FILE = CURR_DIR + '/log.txt'

polo = poloniex.Poloniex(key=PRIVATE['key'], secret=PRIVATE['secret'])


def log(*args):
    log_f = open(LOG_FILE, 'a')
    print(datetime.now(), *args)
    print(datetime.now(), *args, file=log_f)
    log_f.close()


# Свой класс исключений
class ScriptError(Exception):
    pass


class ScriptQuitCondition(Exception):
    pass


while True:
    try:
        conn = sqlite3.connect('local.db')
        cursor = conn.cursor()

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

              buy_order_id NUMERIC,
              buy_initial_amount REAL,
              buy_initial_price REAL,
              buy_created DATETIME,
              buy_finished DATETIME,
              buy_cancelled DATETIME,

              sell_order_id NUMERIC,
              sell_amount REAL,
              sell_initial_price REAL,
              sell_created DATETIME,
              sell_finished DATETIME
            );
        """
        cursor.execute(orders_q)

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

        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_initial_price,  strftime('%s',buy_created), buy_initial_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_initial_price': row[4], 'buy_created': row[5], 'curr_rate': row[6]}
        if orders_info:
            log("Получены неисполненные ордера из БД:", [order for order in orders_info])

            stock_orders = polo.returnOpenOrders()

            log("Получена информация по ордерам с биржи", [(order, stock_orders[order]) for order in stock_orders if len(stock_orders[order])])
            for order in orders_info:
                finished = True
                for stock_order in stock_orders[orders_info[order]['order_pair']]:
                    if stock_order['orderNumber'] == order:
                        finished = False
                        log('Ордер %s всё еще не выполнен' % order)
                        break

                if orders_info[order]['order_type'] == 'buy':
                    if finished:
                        log('Ордер %s выполнен, создаем ордер на продажу' % order)

                        order_trades = polo.returnOrderTrades(order)

                        got_amount = 0
                        max_fee = STOCK_FEE

                        for trade in order_trades:
                            got_amount += float(trade['amount']) - float(trade['amount'])*float(trade['fee'])
                            max_fee = max(max_fee, float(trade['fee']))

                        if max_fee != STOCK_FEE:
                            sell_price = float(orders_info[order]['curr_rate']) + float(orders_info[order]['curr_rate'])*float(max_fee+PAIRS[orders_info[order]['order_pair']]['PROFIT_MARKUP_UP'])
                            log("Комиссия не совпадает с расчетной, объем торгов изменился. Комиссия: %s, объем: %s" % (max_fee, got_amount))
                            new_order = polo.sell(currencyPair=orders_info[order]['order_pair'], rate=sell_price, amount=got_amount)

                            sell_amount = got_amount
                            sell_initial_price = sell_price
                        else:
                            new_order = polo.sell(currencyPair=orders_info[order]['order_pair'], rate=orders_info[order]['sell_initial_price'], amount=orders_info[order]['sell_amount'])

                            sell_amount = orders_info[order]['sell_amount']
                            sell_initial_price = orders_info[order]['sell_initial_price']

                        if not 'error' in new_order:
                            log("Создан ордер на продажу", 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_initial_price = :sell_initial_price
                                  WHERE
                                    buy_order_id = :buy_order_id

                                """, {
                                    'buy_order_id': order,
                                    'sell_order_id': new_order['orderNumber'],
                                    'sell_amount': sell_amount,
                                    'sell_initial_price': sell_initial_price
                                }
                            )
                            conn.commit()

                        else:
                            log("Не удалось создать ордер на продажу", new_order)

                    else:
                        order_created = int(orders_info[order]['buy_created'])
                        time_passed = time.time() - order_created
                        if time_passed > PAIRS[orders_info[order]['order_pair']]['ORDER_LIFE_TIME'] * 60:
                            log("Ордер по покупку не выполнен за %s секунд, отменяем" % time_passed)
                            cancel = polo.cancelOrder(order)
                            if 'success' in cancel and cancel['success'] == 1:
                                log("Ордер %s был успешно отменен" % order)
                                cursor.execute(
                                    """
                                      UPDATE orders
                                      SET
                                        buy_cancelled = datetime()
                                      WHERE
                                        buy_order_id = :buy_order_id

                                    """, {
                                        'buy_order_id': order
                                    }
                                )
                                conn.commit()
                            else:
                                log('Какие-то проблемы при отмене ордера', cancel)

                if finished and orders_info[order]['order_type'] == 'sell':
                    log("$"*80)
                    log("#========== Ордер на продажу %s выполнен" % order)
                    log("$"*80)
                    cursor.execute(
                        """
                          UPDATE orders
                          SET
                            sell_finished = datetime()
                          WHERE
                            sell_order_id = :sell_order_id

                        """, {
                            'sell_order_id': order
                        }
                    )
                    conn.commit()
        else:
            log("Неисполненных ордеров в БД нет")

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

        all_pairs = [pair for pair in PAIRS]

        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):
            all_pairs.remove(row[0])

        if all_pairs:
            log('Найдены пары, по которым нет неисполненных ордеров:', all_pairs)
            for pair in all_pairs:
                log("Работаем с парой", pair)

                end_time = time.time()
                start_time = end_time - float(PAIRS[pair]['MED_PRICE_PERIOD'])*60

                log("Получаем результаты последних торгов для определения цены за период с %s по %s" % (start_time, end_time))

                trades = polo.returnTradeHistory(pair, start_time, end_time)
                log("Получено %s записей" % len(trades))

                buy_prices = []

                for trade in trades:
                    if trade['type'] == 'buy':
                        buy_prices.append(float(trade['rate']))

                if not buy_prices:
                    log('Не удалось получить цены продаж за период (не было сделок на покупку), пропускаем пару')
                else:
                    buy_price = median(buy_prices)
                    curr_rate = buy_price + buy_price*float(STOCK_FEE-PAIRS[pair]['PROFIT_MARKUP_DOWN'])
                    buy_amount = float(PAIRS[pair]['ORDER_AMOUNT'])/curr_rate
                    sell_amount = buy_amount - buy_amount * STOCK_FEE
                    sell_price = curr_rate + curr_rate*float(STOCK_FEE+PAIRS[pair]['PROFIT_MARKUP_UP'])

                    log(
                        'Медианная цена покупки = %0.8f, с наценкой %s и комиссией биржи %s курс составит %0.8f'
                        %
                        (
                            buy_price,
                            PAIRS[pair]['PROFIT_MARKUP_DOWN'],
                            STOCK_FEE,
                            curr_rate
                        )
                    )
                    log(
                        """Итого собираемся купить %0.8f %s по курсу %0.8f.
                           После вычета комиссии останется %0.8f %s, которые продадим по курсу %0.8f.
                           Итого на баланс упадет %0.8f %s
                           """
                        %
                        (
                            buy_amount,
                            pair.split('_')[1],
                            curr_rate,
                            sell_amount,
                            pair.split('_')[1],
                            sell_price,
                            sell_amount * sell_price - buy_amount*curr_rate,
                            pair.split('_')[0],
                        )
                    )

                    new_order = polo.buy(currencyPair=pair, rate=curr_rate, amount=buy_amount)
                    if not 'error' in new_order:
                        log("Создан ордер на покупку", new_order)
                        cursor.execute(
                            """
                              INSERT INTO orders(
                                  order_type,
                                  order_pair,
                                  buy_order_id,
                                  buy_initial_amount,
                                  buy_initial_price,
                                  buy_created,
                                  sell_amount,
                                  sell_initial_price

                              ) Values (
                                'buy',
                                :order_pair,
                                :order_id,
                                :buy_order_amount,
                                :buy_initial_price,
                                datetime(),
                                :sell_amount,
                                :sell_initial_price
                              )
                            """, {
                                'order_pair': pair,
                                'order_id': new_order['orderNumber'],
                                'buy_order_amount': buy_amount,
                                'buy_initial_price': curr_rate,
                                'sell_amount': sell_amount,
                                'sell_initial_price': sell_price
                            }
                        )
                        conn.commit()
                    else:
                        log("Не удалось создать ордер", new_order)

        else:
            log('По всем парам есть неисполненные ордера')

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

 

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

  • 2 months later...

Отличный шаблон, вынес работу с базой в отдельные функции, сделал закупку и продажу по ema с трейлингом, сделал выставление ордера на продажу по принципу покупки (если не продалось - перевыставление ордера на продажу по новой цене). Еще бывают траблы с частичной продажей и зависшим ордером (редко, не чинил пока). Пока закупает хорошо, осталось научиться продавать хорошо)) Еще раз спасибо за шаблон!

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

Join the conversation

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

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

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

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

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

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

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

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