Давайте что-нибудь проанализируем.. Например, историю торгов? Это и в принципе полезно, и скиллы набьются полезные… В общем план такой – научиться вытаскивать нужные данные с биржи, экспортировать в Excel, ну и что-нибудь с ними делать. Понятно, что не руками :) Поехали!
Подготовка.
Нам потребуется
а) Установленный питон с модулем requests (как установить читайте тут)
б) Установленный модуль openpyxl – но тут всё просто, запустите командную строку и вбейте pip install openpyxl
Проверка
После того, как вы все установили, давайте проверим, создаются ли валидные Excel файлы. Простейший пример (взятый с официального сайта) показывает, как создать новую книгу, внести туда данные и сохранить:
from openpyxl import Workbook
wb = Workbook()
# Выбрать активную книгу
ws = wb.active
# Запишем число 42 в ячейку А1
ws['A1'] = 42
# Добавим строку с данными
ws.append([1, 2, 3])
# В поле А2 запишем текущую дату и время
import datetime
ws['A2'] = datetime.datetime.now()
# Сохраним файл рядом со скриптом
import os
wb.save(os.path.dirname(os.path.abspath(__file__)) + "/sample.xlsx")
Копируем этот код, вставляем в IDLE (опять же, подробности тут), сохраняем под каким-нибудь именем (у меня это excel_test.py) и запускаем (F5). В папке рядом со скриптом должен появиться файл sample.xlsx.
Можно открыть его экселем и посмотреть, что внутри:
История торгов из Exmo в Excel
Ок, работает, писать данные можем. Теперь давайте попробуем забрать с exmo.me всю историю торгов. Точнее не так – всю историю Эксмо не дает, а дает максимум 10 000 последних торгов по паре.
Вот код – вставим в IDLE, сохраним как exmo_excel.py и запустим (о том, что такое API и как работать с ним на Exmo читайте в других статьях цикла – ссылки в конце статьи, над комментариями).
import urllib, http.client
import os
import time
import json
# эти модули нужны для генерации подписи API
import hmac, hashlib
from openpyxl import Workbook
from datetime import datetime, timezone
# ключи API, которые предоставила exmo
API_KEY = 'K-...'
# обратите внимание, что добавлена 'b' перед строкой
API_SECRET = b'S-...'
# базовые настройки
API_URL = 'api.exmo.com'
API_VERSION = 'v1'
# Свой класс исключений
class ScriptError(Exception):
pass
class ScriptQuitCondition(Exception):
pass
# все обращения к API проходят через эту функцию
def call_api(**kwargs):
payload = {'nonce': int(round(time.time()*1000))}
if kwargs:
payload.update(kwargs)
payload = urllib.parse.urlencode(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, timeout=60)
conn.request("POST", "/"+API_VERSION + "/" + kwargs['method'], payload, headers)
response = conn.getresponse().read()
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)
# Получим список всех пар, по которым торгует биржа
pairs_list = []
pairs = call_api(method='pair_settings')
for pair in pairs:
pairs_list.append(pair) # сложим их в словарь
pairs_str = ','.join(pairs_list) # из словаря создадим строку, с парами, разделенными запятыми
# Получим историю торгов по всем парам
trades = call_api(method='user_trades', pair=pairs_str, limit=10000)
for pair in trades: # пройдемся по каждой паре
if not trades[pair]: #пропускаем пары, по которым не было торгов
continue
# Теперь проходим по всем торгам этой пары
print(pair, len(trades[pair]))
Должны увидеть список пар, по которым торговали, и кол-во полученных сделок по каждой их них. У меня это выглядит так:
Не лишним будет упомянуть, что есть торги по сути. Когда вы выставляете ордер на продажу, например 1 BTC, биржа подбирает для вас покупателей. Ваш ордер может быть исполнен в одну сделку – если кто-то сразу купит ваш биткоин целиком, либо в несколько – когда ваш биткойн раскупят по частям. Так вот, история торгов – это история именно таких сделок.
Вообще, стоило бы сравнить с историей торгов на сайте Эксмо, но там как будто специально неудобно сделано.. В общем, похоже на правду, на этом и остановимся пока. Если что, историю торгов можно смотреть тут (раздел сделки):
Теперь, собственно, нужно объединить оба скрипта, что бы получить историю торгов и выгрузить в эксель. Немного магии и вуаля:
import urllib, http.client
import os
import time
import json
# эти модули нужны для генерации подписи API
import hmac, hashlib
from openpyxl import Workbook
from datetime import datetime, timezone
# ключи API, которые предоставила exmo
API_KEY = 'K-...'
# обратите внимание, что добавлена 'b' перед строкой
API_SECRET = b'S-...'
# базовые настройки
API_URL = 'api.exmo.com'
API_VERSION = 'v1'
# Свой класс исключений
class ScriptError(Exception):
pass
class ScriptQuitCondition(Exception):
pass
# все обращения к API проходят через эту функцию
def call_api(**kwargs):
payload = {'nonce': int(round(time.time()*1000))}
if kwargs:
payload.update(kwargs)
payload = urllib.parse.urlencode(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, timeout=60)
conn.request("POST", "/"+API_VERSION + "/" + kwargs['method'], payload, headers)
response = conn.getresponse().read()
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)
# Получим список всех пар, по которым торгует биржа
pairs_list = []
pairs = call_api(method='pair_settings')
for pair in pairs:
pairs_list.append(pair) # сложим их в словарь
pairs_str = ','.join(pairs_list) # из словаря создадим строку, с парами, разделенными запятыми
# Создадим Excel файл
wb = Workbook()
ws = wb.active
# Вставим заголовки
ws.append(["Дата сделки", "Пара сделки", "ID ордера", "ID сделки", "Тип сделки", "Кол-во по сделке", "Цена сделки", "Сумма сделки"])
# Получим историю торгов по всем парам
trades = call_api(method='user_trades', pair=pairs_str, limit=10000)
for pair in trades: # пройдемся по каждой паре
if not trades[pair]: #пропускаем пары, по которым не было торгов
continue
# Теперь проходим по всем торгам этой пары
for trade in trades[pair]:
# Мы бы могли использовать метод dict.values(), но нам нужны данные в определенном порядке, причем каждый раз для каждого массива, так что немного усложним код
# Форматируем и вставляем строку с данными в Excel
ws.append([
datetime.fromtimestamp(trade['date'], timezone.utc), # дата сделки
pair, # Пара сделки
trade['order_id'], # ID ордера
trade['trade_id'], # ID сделки
'Покупка' if trade['type'] == 'buy' else 'Продажа',
float(trade['quantity']), # Кол-во по сделке
float(trade['price']), # Цена сделки
float(trade['amount']) * (-1 if trade['type'] == 'buy' else 0.998), # сумма сделки, если buy то отрицательная - так удобнее считать потом
])
# Сохраняем файл
wb.save(os.path.dirname(os.path.abspath(__file__)) + "/exmo_excel.xlsx")
print('Работу закончил')
Вставляем этот код в IDLE, сохраняем, запускаем.. У вас должен появиться Excel-файл exmo_excel.xlsx рядом со скриптом. Откроем, посмотрим.
Я поставил фильтр по паре LTC_RUB, что бы еще раз акцентировать внимание на сделках, так в файле все торги по всем парам (точнее, последние 10 000 торгов). В первой колонке время сделки (по времени биржи), в остальных вроде понятно, объясню про ID ордера и ID сделки.
Смотреть стоит по времени, т.е. снизу вверх. 14 августа я на почти 150р купил 0, 618LTC по курсу 242,38. Для этого я создавал отложенный ордер (52466257), который был исполнен в рамках одной сделки (5227092).
После этого я, видимо, выставил отложенный ордер на продажу купленного (52466294), который исполнился опять же одной сделкой.
После этого я создал отложенный ордер на покупку (62752648), который был исполнен частями –обратите внимание, что тут две строки с одним и тем же номером ордера и одной и той же ценой, но разными суммами, временем и id сделки. Т.е. сначала кто-то купил почти всё, а потом кто-то еще докупил, что осталось.
Ну а потом сработала еще одна продажа купленного.
Если сложить все суммы сделки (вот почему покупку мы делали отрицательной), то получим сальдо или как там его – мне больше нравится слово профит, хотя и «прибыль» тоже ничего. В данном случае вроде бы 63 копейки прибыли, но….. Тут, насколько я вижу, хотя надо бы и проверить, сумма указывается ДО вычета комиссии биржи – 0.2%.
Если еще раз обратите внимание, то первую сделку я провел за 150 рублей, купив 0,618LTC, а продаю 0,617LTC – потому что часть купленного в LTC съела комиссия (рубли не псотрадали). Когда же я продаю купленное, комиссия берется с рублей – но тут я не вижу, что бы это отражалось. Поэтому, наверное, более точно было считать так (дополнил столбец руками):
Для положительных сумм сделок мы вычитаем комиссию 0.2% (формула видна на рисунке), отрицательные считаем как есть – так правильно. Итого, профит составил 2,8 копейки, юхууу))
Не помню, что я тестил на этой паре год назад, и какие настройки прибыльности стояли, но в общем имейте в виду такую выдачу инфы, что через API, что на сайте.
Если хотите, можете сразу выводить в эксель прибыль за вычетом комиссии. Для этого строку
float(trade['amount']) * (-1 if trade['type'] == 'buy' else 1),
нужно заменить на
float(trade['amount']) * (-1 if trade['type'] == 'buy' else 0.998),
итог будет правильным:
В общем, делайте с экселем теперь что хотите, стройте графики или сводные таблицы, инструмент для получения данных у вас есть.
История торгов из Yobit в Excel
Ну и как бонус давайте сделаем тоже самое для биржи yobit.net. Тут уже будет меньше комментариев, т.к. по сути ничего не меняется, только немного кода. Более детально о том, как работать с API yobit, читайте так же по ссылкам в конце статьи.
В общем, вот код, вбивайте свои ключи, запускайте.. Он будет работать мучительно долго, т.к. во первых очень много пар, а во вторых, после каждой пары добавлено time.sleep(1), что бы вас Yobit не забанил.. Хотя, он может быть и так не забанит, так что можете удалить эту строку и все пойдет шустрее, но это на свой страх и риск.
import os
import json
import requests
import math
import time
import urllib, http.client
import hmac, hashlib
from openpyxl import Workbook
from datetime import datetime, timezone
# Вписываем свои ключи
API_KEY = '...'
API_SECRET = b'...'
"""
Каждый новый запрос к серверу должен содержать увеличенное число в диапазоне 1-2147483646
Поэтому храним число в файле поблизости, каждый раз обновляя его
"""
nonce_file = "./nonce"
if not os.path.exists(nonce_file):
with open(nonce_file, "w") as out:
out.write('1')
# Будем перехватывать все сообщения об ошибках с биржи
class YobitException(Exception):
pass
def call_api(**kwargs):
# При каждом обращении к торговому API увеличиваем счетчик nonce на единицу
with open(nonce_file, 'r+') as inp:
nonce = int(inp.read())
inp.seek(0)
inp.write(str(nonce+1))
inp.truncate()
payload = {'nonce': nonce}
if kwargs:
payload.update(kwargs)
payload = urllib.parse.urlencode(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("yobit.net", timeout=60)
conn.request("POST", "/tapi/", payload, headers)
response = conn.getresponse().read()
conn.close()
try:
obj = json.loads(response.decode('utf-8'))
if 'error' in obj and obj['error']:
raise YobitException(obj['error'])
return obj
except json.decoder.JSONDecodeError:
raise YobitException('Ошибка анализа возвращаемых данных, получена строка', response)
res = requests.get('https://yobit.net/api/3/info') # получаем данные info
res_obj = json.loads(res.text) # переводим полученный текст в объект с данными
pairs = [pair for pair in res_obj['pairs']] # создадим массив названий пар
# Создадим Excel файл
wb = Workbook()
ws = wb.active
# Вставим заголовки
ws.append(["Дата сделки", "Пара сделки", "ID ордера", "ID сделки", "Тип сделки", "Цена сделки", "Сумма сделки"])
for pair in pairs:
try:
print ('Получаем историю торгов по паре %s' % pair, '*'*30)
data = call_api(method="TradeHistory", pair=pair)
if(data.get('return')):
for t in data['return']:
trade = data['return'][t]
ws.append([
datetime.fromtimestamp(int(trade['timestamp']), timezone.utc), # дата сделки
pair, # Пара сделки
trade['order_id'], # ID ордера
t, # ID сделки
'Покупка' if trade['type'] == 'buy' else 'Продажа',
float(trade['rate']), # Цена сделки
float(trade['amount']) * (-1 if trade['type'] == 'buy' else 1), # сумма сделки, если buy то отрицательная - так удобнее считать потом
])
else:
print('Торгов не было')
#time.sleep(1)
except YobitException as e:
print("Облом:", e)
wb.save(os.path.dirname(os.path.abspath(__file__)) + "/yobit_excel.xlsx")
print('Работу закончил')
Когда оно всё доработает, рядом с файлом появится файл yobit_excel.xslx, можете открывать и делать выводы. Опять же, если нужно вычитать комиссию, то воспользуйтесь советом выше, для эксмо. Если что-то не будет работать или будет работать не так, пишите, поправим.
Удачи!
При каждом запросе к АПИ передается nonce - некоторое число, которое должно увеличиваться с каждым запросом.
В коде я начинаю с единицы - 1,2,3 и т.п. Соответственно, если вы уже использовали API для работы с каким-нибудь ботом, в мобильном приложении и т.п., то они тоже передавали какие-то значения, и явно они выше единицы. Даже если вы запускали этот код, то увеличивали счетчик.
В общем, самое простое решение будет пересоздать API ключи на бирже - для каждых новых ключей отсчет начинается заново.
Так же в процессе работы в папке с кодом создается файлик nonce, в который записывается последнее использованное кодом значение.
Если пересоздавать ключи API неудобно, то можно открыть этот файл блокнотом, записать туда например 1000000, сохранить, что бы постараться опередить уже использованное ранее значение.
Торгов не было
Получаем историю торгов по паре rad_usd ******************************
Торгов не было
Получаем историю торгов по паре rpc_usd ******************************
Торгов не было
Получаем историю торгов по паре xcre_rur ******************************
Торгов не было
Получаем историю торгов по паре limx_waves ******************************
Торгов не было
Получаем историю торгов по паре hdg_btc ******************************
Торгов не было
Кстати, нашел кое-что в коде, поправил статью, скачайте новый код. Но к nonce оно не относится. Есть еще вариант что у вас два экземпляра запущено, проверьте в диспетчере задач, сколько раз python.exe встречается. Может прав нет у питона писать в этот файл (nonce) в текущей директории? Тогда нужно от админа запустить
Исправил
ПС или может как то похожее можно на ексел реализовать? я там примерно логику действий отрабатываю.. но это все в статике.. а потом это надо как то через апи в онлайн..
Попробуйте переустановить питон, поставьте все галочки - пусть он установится в C:\Program Files...
У waves длина названия больше, поэтому, если собирать их по 50 штук, выходит слишком длинная строка запроса, нужно уменьшить кол-во. Я обновил пример в статье, теперь там 30 записей за раз берется, waves работает
1. Когда создается новый файл "питоном", как у Вас, то старый затирается, это не есть хорошо, нужно открывать уже существующий файл и в него добавлять эти таблички, т.к. в том файле уже может быть создан расчет, а он просто затирается новым файлом.
2. Научите нас пожалуйста вставлять сформированную таблицу в питоне начиная с конкретную ячейки, допустим "Н8", конкретного листа эксельки, а не как сейчас по умолчанию всё таблицы вставляются по умолчанию в ячейку "А1", то же на примере.
3. Так как биржа Yobit все цифры формирует с точкой после значащего знака "." (пример 0.12345678), а в эксельки все расчеты с цифрами можно производить только с запятой (пример 0,12345678), то научите как "питоном" менять все точки в цифрах на запятые, что бы загруженная в файл табличка была сразу готова для полноценной работы с ней, это очень важно.
Буду премного благодарен за такой ликбез, спасибо.