Бот для liqui

Кстати говоря да, у меня же есть код бота для liqui.io..

Работает абсолютно идентично боту для эксмо.. Тот же алгоритм и тот же, фактически код.

На этом статья окончена :) Вставляйте API ключи и играйте.

Вот код:

import urllib, http.client
import os
import time
import json
# эти модули нужны для генерации подписи API
import hmac, hashlib

# ключи API, которые предоставила liqui
API_KEY = ''
# обратите внимание, что добавлена 'b' перед строкой
API_SECRET = b''

# Тонкая настройка
CURRENCY_1 = 'ltc' 
CURRENCY_2 = 'btc'

CURRENCY_1_MIN_QUANTITY = 0.0001 # минимальная сумма ставки 

ORDER_LIFE_TIME = 3 # через сколько минут отменять неисполненный ордер на покупку CURRENCY_1
STOCK_FEE = 0.002 # Комиссия, которую берет биржа (0.002 = 0.2%)
AVG_PRICE_PERIOD = 90 # За какой период брать среднюю цену
CAN_SPEND = 0.0002 # Сколько тратить CURRENCY_2 каждый раз при покупке CURRENCY_1
PROFIT_MARKUP = 0.001 # Какой навар нужен с каждой сделки? (0.001 = 0.1%)
DEBUG = True# True - выводить отладочную информацию, False - писать как можно меньше

STOCK_TIME_OFFSET = 0 # Если расходится время биржи с текущим 
NONCE = 1
CURR_DIR = os.path.dirname(os.path.abspath(__file__))

# базовые настройки
API_URL = 'api.liqui.io'
API_VERSION = 'api/3'

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

Реклама:


pass CURRENT_PAIR = (CURRENCY_1 + '_' + CURRENCY_2).lower() # все обращения к API проходят через эту функцию def call_api(api_method, http_method="POST", public=True, **kwargs): payload = {} if not public: try: nonce_file = open(CURR_DIR + "/nonce", "r+") except FileNotFoundError: nonce_file = open(CURR_DIR + "/nonce", "w+") try: nonce = int(nonce_file.read()) except ValueError: nonce = 0 nonce = (NONCE if not nonce else nonce)+1 nonce_file.close() nonce_file = open(CURR_DIR + "/nonce", "w") nonce_file.write(str(nonce)) nonce_file.close() payload = {'nonce': nonce} if kwargs: payload.update(kwargs) payload = urllib.parse.urlencode(payload) #print("payload", payload) H = hmac.new(key=API_SECRET, digestmod=hashlib.sha512) H.update(payload.encode('utf-8')) sign = H.hexdigest() headers = {"Content-type": "application/x-www-form-urlencoded", "Key":API_KEY, "Sign":sign} conn = http.client.HTTPSConnection(API_URL) conn.request(http_method, ("" if public else '/tapi') + ("/"+API_VERSION if public else '') + ("/"+ api_method if public else ''), payload, headers) response = conn.getresponse().read() #print("response", response) conn.close() try: obj = json.loads(response.decode('utf-8')) if 'error' in obj and obj['error']: raise ScriptError(obj['error']) return obj except json.decoder.JSONDecodeError: raise ScriptError('Ошибка анализа возвращаемых данных, получена строка', response) # Реализация алгоритма def main_flow(): try: # Получаем список активных ордеров try: opened_orders_dict = call_api(api_method="", http_method="POST", public=False, method="ActiveOrders", pair=CURRENT_PAIR )['return']### opened_orders = [] for order in opened_orders_dict: curr_order = opened_orders_dict[order] curr_order['order_id'] = order opened_orders.append(curr_order) except (KeyError, ScriptError): if DEBUG: print('Открытых ордеров нет') opened_orders = [] sell_orders = [] # Есть ли неисполненные ордера на продажу CURRENCY_1? for order in opened_orders: if order['type'] == 'sell': # Есть неисполненные ордера на продажу CURRENCY_1, выход raise ScriptQuitCondition('Выход, ждем пока не исполнятся/закроются все ордера на продажу (один ордер может быть разбит биржей на несколько и исполняться частями)') else: # Запоминаем ордера на покупку CURRENCY_1 sell_orders.append(order) # Проверяем, есть ли открытые ордера на покупку CURRENCY_1 if sell_orders: # открытые ордера есть for order in sell_orders: # Проверяем, есть ли частично исполненные if DEBUG: print('Проверяем, что происходит с отложенным ордером', order['order_id']) order_history = call_api(api_method="", http_method="POST", public=False, method="OrderInfo", order_id=order['order_id'])['return'][order['order_id']] if order_history['status'] == 0 and order_history['start_amount'] != order_history['amount']: # по ордеру уже есть частичное выполнение, выход raise ScriptQuitCondition('По ордеру уже есть частичное выполнение, выход, продолжаем надеяться докупить валюту по тому курсу, по которому уже купили часть') else: if DEBUG: print('Частично исполненных ордеров нет') time_passed = time.time() + STOCK_TIME_OFFSET*60*60 - int(order['timestamp_created']) if time_passed > ORDER_LIFE_TIME * 60: # Ордер уже давно висит, никому не нужен, отменяем call_api(api_method="", http_method="POST", public=False, method="CancelOrder", order_id=order['order_id']) raise ScriptQuitCondition('Отменяем ордер -за ' + str(ORDER_LIFE_TIME) + ' минут не удалось купить '+ str(CURRENCY_1)) else: raise ScriptQuitCondition('Выход, продолжаем надеяться купить валюту по указанному ранее курсу') else: # Открытых ордеров нет balances = call_api(api_method="", http_method="POST", public=False, method="getInfo")['return']['funds'] if float(balances[CURRENCY_1]) >= CURRENCY_1_MIN_QUANTITY: # Есть ли в наличии CURRENCY_1, которую можно продать? """ Высчитываем курс для продажи. Нам надо продать всю валюту, которую купили, на сумму, за которую купили + немного навара и минус комиссия биржи При этом важный момент, что валюты у нас меньше, чем купили - бирже ушла комиссия 0.00134345 1.5045 """ wanna_get = "%.8f" % (CAN_SPEND + CAN_SPEND * (STOCK_FEE+PROFIT_MARKUP)) # сколько хотим получить за наше кол-во rate = "%.8f" % (float(wanna_get)/float(balances[CURRENCY_1])) print('sell', balances[CURRENCY_1], wanna_get, rate) new_order = call_api(api_method="", http_method="POST", public=False, method="Trade", pair=CURRENT_PAIR, type="sell", rate=rate, amount="%.8f" % (float(balances[CURRENCY_1]) - 0.0000001))['return'] print(new_order) if DEBUG: print('Создан ордер на продажу', CURRENCY_1, new_order['order_id']) else: # CURRENCY_1 нет, надо докупить # Достаточно ли денег на балансе в валюте CURRENCY_2 (Баланс >= CAN_SPEND) if float(balances[CURRENCY_2]) >= CAN_SPEND: # Узнать среднюю цену за AVG_PRICE_PERIOD, по которой продают CURRENCY_1 deals = call_api(api_method="trades/"+CURRENT_PAIR) prices = [] for deal in deals[CURRENT_PAIR]: time_passed = time.time() + STOCK_TIME_OFFSET*60*60 - int(deal['timestamp']) if time_passed < AVG_PRICE_PERIOD*60: prices.append(float(deal['price'])) try: avg_price = sum(prices)/len(prices) """ Посчитать, сколько валюты CURRENCY_1 можно купить. На сумму CAN_SPEND за минусом STOCK_FEE, и с учетом PROFIT_MARKUP ( = ниже средней цены рынка, с учетом комиссии и желаемого профита) """ # купить больше, потому что биржа потом заберет кусок my_need_price = avg_price + avg_price * (STOCK_FEE+PROFIT_MARKUP) my_amount = CAN_SPEND/my_need_price print('buy', my_amount, my_need_price) # Допускается ли покупка такого кол-ва валюты (т.е. не нарушается минимальная сумма сделки) if my_amount >= CURRENCY_1_MIN_QUANTITY: new_order = call_api(api_method="", http_method="POST", public=False, method="Trade", pair=CURRENT_PAIR, type="buy", rate=my_need_price, amount=round(my_amount,8))['return'] print(new_order) if DEBUG: print('Создан ордер на покупку', new_order['order_id']) else: # мы можем купить слишком мало на нашу сумму raise ScriptQuitCondition('Выход, не хватает денег на создание ордера') except ZeroDivisionError: print('Не удается вычислить среднюю цену', prices) else: raise ScriptQuitCondition('Выход, не хватает денег') except ScriptError as e: print(e) except ScriptQuitCondition as e: if DEBUG: print(e) pass while(True): main_flow() print('*'*80) time.sleep(1)

 

Тэги: