Работа с API Binance: описание, код и примеры

Андрей К…
Последнее изменение:
153
2
0

Вступление

Биржа binance, как и многие другие биржи, предоставляет API - программный интерфейс для автоматизации торговли. В этой статье рассмотрены методы и приведены примеры кода для работы с ними.
Официальное описание API (на английском) - здесь. Бот для Binance - здесь. Как получить API ключи - тут.


Вводная информация


В отличии от многих других бирж, Binance лимитирует не только количество запросов к API, но и "вес" запросов. Причем, это не какие-то фиксированные единицы, но целый комплекс (как они заявляют, англ). Например, если вы постоянно запрашиваете свечи но не торгуете, то ваш вес накапливается и вас могут забанить. И вообще они суровые - если вы постоянно перебиваете лучшую цену на минимальную ставку, или создаете/отменяете ордера но не покупаете и продаете и т.п. то вас настигнут санкции. Так что будьте аккуратны при тестировании ботов. Впрочем, пока я тестировал, ничего плохого не случилось, хотя я порой и жестил.


Если биржа захочет вам намекнуть, что пора бы снизить пыл, она вернет 429 ответ сервера. Если вы будете игнорировать этот ответ и ломиться в закрытую дверь, то вас забанят по IP на срок от 2 минут до 3 дней.


Подключение к API биржи идет через https://api.binance.com, для авторизованных запросов нужно отправлять ключ в заголовке X-MBX-APIKEY, и подписывать тело запроса SHA256.


Что бы вы не заморачивались с этим, я написал код, который позволяет все указанные запросы выполнять. Для его работы нужно установить Python версии 3.6+ с официального сайта, потом в командной строке выполнить pip install requests. Создайте папку (для удобства), создайте новый файл binance_api.py, и вставьте туда этот код:

import ssl
import time
import json
import urllib
import hmac, hashlib
import requests

from urllib.parse import urlparse, urlencode
from urllib.request import Request, urlopen

class Binance():

    methods = {
            # public methods
            'ping':             {'url':'api/v1/ping', 'method': 'GET', 'private': False},
            'time':             {'url':'api/v1/time', 'method': 'GET', 'private': False},
            'exchangeInfo':     {'url':'api/v1/exchangeInfo', 'method': 'GET', 'private': False},
            'depth':            {'url': 'api/v1/depth', 'method': 'GET', 'private': False},
            'trades':           {'url': 'api/v1/trades', 'method': 'GET', 'private': False},
            'historicalTrades': {'url': 'api/v1/historicalTrades', 'method': 'GET', 'private': False},
            'aggTrades':        {'url': 'api/v1/aggTrades', 'method': 'GET', 'private': False},
            'klines':           {'url': 'api/v1/klines', 'method': 'GET', 'private': False},
            'ticker24hr':       {'url': 'api/v1/ticker/24hr', 'method': 'GET', 'private': False},
            'tickerPrice':      {'url': 'api/v3/ticker/price', 'method': 'GET', 'private': False},
            'tickerBookTicker': {'url': 'api/v3/ticker/bookTicker', 'method': 'GET', 'private': False},
            # private methods
            'createOrder':      {'url': 'api/v3/order', 'method': 'POST', 'private': True},
            'testOrder':        {'url': 'api/v3/order/test', 'method': 'POST', 'private': True},
            'orderInfo':        {'url': 'api/v3/order', 'method': 'GET', 'private': True},
            'cancelOrder':      {'url': 'api/v3/order', 'method': 'DELETE', 'private': True},
            'openOrders':       {'url': 'api/v3/openOrders', 'method': 'GET', 'private': True},
            'allOrders':        {'url': 'api/v3/allOrders', 'method': 'GET', 'private': True},
            'account':          {'url': 'api/v3/account', 'method': 'GET', 'private': True},
            'myTrades':         {'url': 'api/v3/myTrades', 'method': 'GET', 'private': True},
            # wapi
            'depositAddress':   {'url': 'wapi/v3/depositAddress.html', 'method':'GET', 'private':True},
            'withdraw':   {'url': 'wapi/v3/withdraw.html', 'method':'POST', 'private':True},
            'depositHistory': {'url': 'wapi/v3/depositHistory.html', 'method':'GET', 'private':True},
            'withdrawHistory': {'url': 'wapi/v3/withdrawHistory.html', 'method':'GET', 'private':True},
            'assetDetail': {'url': 'wapi/v3/assetDetail.html', 'method':'GET', 'private':True},
            'tradeFee': {'url': 'wapi/v3/tradeFee.html', 'method':'GET', 'private':True},
            'accountStatus': {'url': 'wapi/v3/accountStatus.html', 'method':'GET', 'private':True},
            'systemStatus': {'url': 'wapi/v3/systemStatus.html', 'method':'GET', 'private':True},
            'assetDust': {'url': 'sapi/v1/asset/dust', 'method':'POST', 'private':True},
            'dustLog': {'url': 'wapi/v3/userAssetDribbletLog.html', 'method':'GET', 'private':True},
            'assetAssetDividend': {'url': 'sapi/v1/asset/assetDividend', 'method':'GET', 'private':True},
            #sapi
            'marginTransfer': {'url': 'sapi/v1/margin/transfer', 'method': 'POST', 'private':True},
            'marginLoan': {'url': 'sapi/v1/margin/loan', 'method': 'POST', 'private': True},
            'marginLoanGet': {'url': 'sapi/v1/margin/loan', 'method': 'GET', 'private': True},
            'marginRepay': {'url': 'sapi/v1/margin/repay', 'method': 'POST', 'private': True},
            'marginRepayGet': {'url': 'sapi/v1/margin/repay', 'method': 'GET', 'private': True},
            'marginCreateOrder': {'url': 'sapi/v1/margin/order', 'method': 'POST', 'private':True},
            'marginCancelOrder': {'url': 'sapi/v1/margin/order', 'method': 'DELETE', 'private':True},
            'marginOrderInfo': {'url': 'sapi/v1/margin/order', 'method': 'GET', 'private':True},
            'marginAccount': {'url': 'sapi/v1/margin/account', 'method': 'POST', 'private':True},
            'marginOpenOrders': {'url': 'sapi/v1/margin/openOrders', 'method': 'GET', 'private':True},
            'marginAllOrders': {'url': 'sapi/v1/margin/allOrders', 'method': 'GET', 'private':True},
            'marginAsset': {'url': 'sapi/v1/margin/asset', 'method': 'POST', 'private':True},
            'marginPair': {'url': 'sapi/v1/margin/pair', 'method': 'POST', 'private':True},
            'marginPriceIndex': {'url': 'sapi/v1/margin/priceIndex', 'method': 'POST', 'private':True},
            'marginMyTrades': {'url': 'sapi/v1/margin/myTrades', 'method': 'GET', 'private':True},
            'marginMaxBorrowable': {'url': 'sapi/v1/margin/maxBorrowable', 'method': 'GET', 'private':True},
            'marginmaxTransferable': {'url': 'sapi/v1/margin/maxTransferable', 'method': 'GET', 'private':True},
            #futures
            'futuresExchangeInfo': {'url': 'fapi/v1/exchangeInfo', 'method': 'GET', 'private': False, 'futures': True},
            'futuresKlines': {'url': 'fapi/v1/klines', 'method': 'GET', 'private': False, 'futures': True},
            'futuresCreateOrder':      {'url': 'fapi/v1/order', 'method': 'POST', 'private': True, 'futures': True},
            'futuresAccount':      {'url': 'fapi/v1/account', 'method': 'POST', 'private': True, 'futures': True},
            'futuresBalance':      {'url': 'fapi/v1/balance', 'method': 'GET', 'private': True, 'futures': True},
            'futuresSymbolPriceTicker': {'url': 'fapi/v1/ticker/price', 'method': 'GET', 'private': True, 'futures': True},
            'futuresOrderInfo': {'url': 'fapi/v1/order', 'method': 'GET', 'private': True, 'futures': True},
            'futuresCancelOrder':      {'url': 'fapi/v1/order', 'method': 'DELETE', 'private': True, 'futures': True},
   }
    
    def __init__(self, API_KEY, API_SECRET):
        self.API_KEY = API_KEY
        self.API_SECRET = bytearray(API_SECRET, encoding='utf-8')
        self.shift_seconds = 0

    def __getattr__(self, name):
        def wrapper(*args, **kwargs):
            kwargs.update(command=name)
            return self.call_api(**kwargs)
        return wrapper

    def set_shift_seconds(self, seconds):
        self.shift_seconds = seconds
        
    def call_api(self, **kwargs):

        command = kwargs.pop('command')

        base_url ='https://api.binance.com/' 
        if self.methods[command].get('futures'):
            base_url = 'https://fapi.binance.com/' 
        api_url = base_url  + self.methods[command]['url']

        payload = kwargs
        headers = {}
        
        payload_str = urllib.parse.urlencode(payload)
        if self.methods[command]['private']:
            payload.update({'timestamp': int(time.time() + self.shift_seconds - 1) * 1000})
            payload_str = urllib.parse.urlencode(payload).encode('utf-8')
            sign = hmac.new(
                key=self.API_SECRET,
                msg=payload_str,
                digestmod=hashlib.sha256
            ).hexdigest()

            payload_str = payload_str.decode("utf-8") + "&signature="+str(sign) 
            headers = {"X-MBX-APIKEY": self.API_KEY, "Content-Type":"application/x-www-form-urlencoded"}

        if self.methods[command]['method'] == 'GET' or self.methods[command]['url'].startswith('sapi'):
            api_url += '?' + payload_str

        response = requests.request(method=self.methods[command]['method'], url=api_url, data="" if self.methods[command]['method'] == 'GET' else payload_str, headers=headers)
            
        if 'code' in response.text:
            raise Exception(response.text)

        return response.json()

 

Для тестирования методов, создайте в этой же папке второй файл, например, binance_test.py, туда вставьте вот такой код (подставьте свои API ключи):

from binance_api import Binance
bot = Binance(
    API_KEY='D7...Ejj',
    API_SECRET='gwQ...u3A'
)
print('account', bot.account())

(Или возьмите с гитхаба)

После этого код можно запускать. К примеру, если вы только установили Python и не знаете, что делать, найдите редактор Idle (он устанавливается вместе с питоном), в нем File -> Open, откройте файл binance_test.py и нажмите F5. Код, представленный выше, вернет информацию по вашему аккаунту - подробности ниже.


Еще немного общей информации: практически во всех подписанных запросах необходимо указывать параметр timestamp - это текущее unix-время в милиосекундах. Но, так как некоторые сети бывают перегружены, то ваш запрос может заблудиться и придти позже. Поэтому биржа предоставляет вам временное окно (по умолчанию 5000 милисекунд). Если у вас запросы не успевают придти в это окно, вы можете его расширить с помощью параметра recvWindow. Но, думаю, это мало кому понадобится.


Реклама



Публичные запросы


Проверка связи - /api/v1/ping 


Метод для проверки работы API. 
Возвращает пустой словарь

{}


Ссылка для просмотра в браузере https://api.binance.com/api/v1/ping.
Вес - 1
Код для проверки:

from binance_api import Binance
bot = Binance(
    API_KEY='D7...Ejj',
    API_SECRET='gwQ...u3A'
)
print(bot.ping())

 


Получение времени биржи - /api/v1/time


Ссылка для просмотра в браузере https://api.binance.com/api/v1/time
Вес - 1
Возвращает словарь с текущим временем:

{
  "serverTime": 1499827319559
}


Код для проверки:

from binance_api import Binance
bot = Binance(
    API_KEY='D7...Ejj',
    API_SECRET='gwQ...u3A'
)
print(bot.time())

 


Настройки и лимиты биржи - /api/v1/exchangeInfo


Ссылка для просмотра в браузере https://api.binance.com/api/v1/exchangeInfo
Вес - 1
Возвращает структуру данных:

{
  "timezone": "UTC",
  "serverTime": 1508631584636,
  "rateLimits": [{
      "rateLimitType": "REQUESTS",
      "interval": "MINUTE",
      "limit": 1200
    },
    {
      "rateLimitType": "ORDERS",
      "interval": "SECOND",
      "limit": 10
    },
    {
      "rateLimitType": "ORDERS",
      "interval": "DAY",
      "limit": 100000
    }
  ],
  "exchangeFilters": [],
  "symbols": [{
    "symbol": "ETHBTC",
    "status": "TRADING",
    "baseAsset": "ETH",
    "baseAssetPrecision": 8,
    "quoteAsset": "BTC",
    "quotePrecision": 8,
    "orderTypes": ["LIMIT", "MARKET"],
    "icebergAllowed": false,
    "filters": [{
      "filterType": "PRICE_FILTER",
      "minPrice": "0.00000100",
      "maxPrice": "100000.00000000",
      "tickSize": "0.00000100"
    }, {
      "filterType": "LOT_SIZE",
      "minQty": "0.00100000",
      "maxQty": "100000.00000000",
      "stepSize": "0.00100000"
    }, {
      "filterType": "MIN_NOTIONAL",
      "minNotional": "0.00100000"
    }]
  }]
}


Ключ rateLimits ведет на массив с лимитами - сколько запросов в секунду/минуту/день можно делать. 
Ключ symbols содержит настройки для каждой пары - рассмотрим одну, ETHBTC

{
  "symbol": "ETHBTC",
  "status": "TRADING",
  "baseAsset": "ETH",
  "baseAssetPrecision": 8,
  "quoteAsset": "BTC",
  "quotePrecision": 8,
  "orderTypes": [
    "LIMIT",
    "LIMIT_MAKER",
    "MARKET",
    "STOP_LOSS_LIMIT",
    "TAKE_PROFIT_LIMIT"
  ],
  "icebergAllowed": true,
  "filters": [
    {
      "filterType": "PRICE_FILTER",
      "minPrice": "0.00000100",
      "maxPrice": "100000.00000000",
      "tickSize": "0.00000100"
    },
    {
      "filterType": "LOT_SIZE",
      "minQty": "0.00100000",
      "maxQty": "100000.00000000",
      "stepSize": "0.00100000"
    },
    {
      "filterType": "MIN_NOTIONAL",
      "minNotional": "0.00100000"
    }
  ]
}


symbol - непосредственно пара
status - TRADING  -разрешена торговля
baseAsset - базовая валюта
baseAssetPrecision - требуемое количество символов базовой валюты после запятой при создании ордера (для цены и количества)
quoteAsset - квотируемая валюта
quotePrecision - требуемое количество символов квотируемой валюты после запятой при создании ордера (для цены и количества)
"orderTypes": [
    "LIMIT",
    "LIMIT_MAKER",
    "MARKET",
    "STOP_LOSS_LIMIT",
    "TAKE_PROFIT_LIMIT"
  ] - допустимые виды ордеров по паре
icebergAllowed - разрешено ли создание айсбергов (ордеров с невидимой частью)
filters - ограничение ордеров
    PRICE_FILTER - ограничение цены создаваемого ордера. Цена ордера должна быть в диапазоне min_price и max_price, и шаг торговли должен быть кратен tickSize. Да да, тут нельзя ставить ордера с произвольной ценой.
    LOT_SIZE - ограничение объема создаваемого ордера. Объем должен быть в диапазоне minQty и maxQty, и быть кратен stepSize.
    MIN_NOTIONAL - итоговая сумма ордера (объем*цена) должна быть выше minNotional.
Код для проверки:

from binance_api import Binance
bot = Binance(
    API_KEY='D7...Ejj',
    API_SECRET='gwQ...u3A'
)
print(bot.exchangeInfo())

 


Открытые ордера на бирже - /api/v1/depth


Метод позволяет получить книгу ордеров. 
Принимает параметры:
Обязательные:
symbol - пара 
Необязательные:
limit - кол-во возвращаемых записей от 5 до 1000 (по умолчанию 100). Допустимые значения: 5, 10, 20, 50, 100, 500, 1000. Еще можно указать 0, но он может вернуть большое кол-во данных.
Вес зависит от параметра limit. При лимите от 5 до 100 вес будет равен 1. Для параметра 500 вес составит 5. Для параметра 1000 вес будет 10.
Ссылка для просмотра в браузере: https://api.binance.com/api/v1/depth?symbol=ETHBTC
Возвращает значения:

{
  "lastUpdateId": 1027024,
  "bids": [
    [
      "4.00000000",     // PRICE
      "431.00000000",   // QTY
      []                // Ignore.
    ]
  ],
  "asks": [
    [
      "4.00000200",
      "12.00000000",
      []
    ]
  ]
}


bids - это списки цен/объемов на покупку, asks - на продажу.
Пример кода:

from binance_api import Binance
bot = Binance(
    API_KEY='D7...Ejj',
    API_SECRET='gwQ...u3A'
)
print('depth', bot.depth(
    symbol='BNBBTC',
    limit=5
))

 


Последние (чужие) сделки - /api/v1/trades


Принимает параметры:
Обязательные:
symbol - пара 
Необязательные:
limit - кол-во возвращаемых записей (максимум 500, по умолчанию 500).
Вес - 1
Ссылка для просмотра в браузере: https://api.binance.com/api/v1/trades?symbol=ETHBTC
Пример ответа:

[
  {
    "id": 28457,
    "price": "4.00000100",
    "qty": "12.00000000",
    "time": 1499865549590,
    "isBuyerMaker": true,
    "isBestMatch": true
  }
]


id - id сделки
price - цена
qty - количество
time - время сделки
isBuyerMaker - была ли покупка по указанной покупателем цене, 
isBestMatch - была ли встречная сделка
Пример кода:

from binance_api import Binance
bot = Binance(
    API_KEY='D7...Ejj',
    API_SECRET='gwQ...u3A'
)
print('trades', bot.trades(
    symbol='BNBBTC',
    limit=1
))

 


Сжатая история сделок - /api/v1/aggTrades


Метод позволяет получить суммарную историю сделок. Сделки, выполненные в одно время по одному ордеру и по одной цене будут представлены одной строкой с объединенным количеством.
Вес - 1
Ссылка для просмотра в браузере: https://api.binance.com/api/v1/aggTrades?symbol=ETHBTC
Принимает параметры:
Обязательные:
symbol - пара
Необязательные:
fromID - показывать начиная со сделки № (включительно)
startTime - начиная с какого времени (включительно)
endTime - заканчивая каким временем (включительно)
limit - Кол-во записей (максимум 500, по умолчанию 500)
Возвращает данные:

[
  {
    "a": 26129,         //  tradeId строки
    "p": "0.01633102",  // Цена
    "q": "4.70443515",  // Количество
    "f": 27781,         // Первая tradeId
    "l": 27781,         // Последняя tradeId
    "T": 1498793709153, // Время
    "m": true,          // Was the buyer the maker?
    "M": true           // Was the trade the best price match?
  }
]


Пример кода:

from binance_api import Binance
bot = Binance(
    API_KEY='D7...Ejj',
    API_SECRET='gwQ...u3A'
)
print('aggTrades', bot.aggTrades(
    symbol='BNBBTC',
    limit=1
))

 


Данные по свечам – /api/v1/klines


Вес – 1
Ссылка для просмотра в браузере https://api.binance.com/api/v1/klines?symbol=LTCBTC&interval=5m
Параметры:
Обязательные:
symbol – пара
interval – период свечи
    Допустимые интервалы:
    •    1m     // 1 минута
    •    3m     // 3 минуты
    •    5m    // 5 минут
    •    15m  // 15 минут
    •    30m    // 30 минут
    •    1h    // 1 час
    •    2h    // 2 часа
    •    4h    // 4 часа
    •    6h    // 6 часов
    •    8h    // 8 часов
    •    12h    // 12 часов
    •    1d    // 1 день
    •    3d    // 3 дня
    •    1w    // 1 неделя
    •    1M    // 1 месяц

Необязательные:
limit – кол-во свечей (максимум 500, по умолчанию 500)
startTime – время начала построения
endTime – окончание периода
Если не указаны параметры startTime и endTime, то возвращаются самые последние свечи.
Пример ответа:

[
  [
    1499040000000,      // Время открытия
    "0.01634790",       // Цена открытия (Open)
    "0.80000000",       // Максимальная цена (High)
    "0.01575800",       // Минимальная цена (Low)
    "0.01577100",       // Цена закрытия (Close)
    "148976.11427815",  // Объем
    1499644799999,      // Время закрытия
    "2434.19055334",    // Объем квотируемой валюты
    308,                // Кол-во сделок
    "1756.87402397",    // Taker buy base asset volume
    "28.46694368",      // Taker buy quote asset volume
    "17928899.62484339" // Ignore
  ]
]

 

Пример кода:

from binance_api import Binance
bot = Binance(
    API_KEY='D7...Ejj',
    API_SECRET='gwQ...u3A'
)
print('klines', bot.klines(
    symbol='BNBBTC',
    interval='5m',
    limit=1
))

 


Статистика за 24 часа - /api/v1/ticker/24hr


Вес – 1, если указана пара, иначе вес равен (количеству всех торгуемых пар)/2.
Ссылка для просмотра в браузере: https://api.binance.com/api/v1/ticker/24hr?symbol=BNBBTC
Параметры:
Необязательные:
symbol – пара
Если symbol не указан, возвращаются данные по всем парам. В этом случае, считается, что вы сделали столько запросов к бирже, сколько вернулось пар.
Пример ответа:

{
  "symbol": "BNBBTC", // пара
  "priceChange": "-94.99999800", // изменение цены за сутки 
  "priceChangePercent": "-95.960", // изменение цены за сутки %
  "weightedAvgPrice": "0.29628482", //Средневзвешенная цена
  "prevClosePrice": "0.10002000", // Предыдущая цена закрытия
  "lastPrice": "4.00000200",     // Последняя цена
  "lastQty": "200.00000000",    // Последний объем
  "bidPrice": "4.00000000",    // Цена покупки
  "askPrice": "4.00000200",    // Цена продажи
  "openPrice": "99.00000000",    // Цена открытия
  "highPrice": "100.00000000",    // Самая высокая цена
  "lowPrice": "0.10000000",    // Самая низкая цена
  "volume": "8913.30000000",    // Объем торгов базовой валюты
  "quoteVolume": "15.30000000",    // Объем торгов квотируемой
  "openTime": 1499783499040,    // Время открытия
  "closeTime": 1499869899040,    // Время закрытия
  "fristId": 28385,   // Id первой сделки
  "lastId": 28460,    // Id последней сделки
  "count": 76         // Кол-во сделок
}

 

Если пар несколько, то такие словари вкладываются в массив, вот так:

[
  {
    "symbol": "BNBBTC",
    
  },
  {
    "symbol": "LTCBTC",
    
  },
]

 

Пример кода:

from binance_api import Binance
bot = Binance(
    API_KEY='D7...Ejj',
    API_SECRET='gwQ...u3A'
)
print('ticker/24hr', bot.ticker24hr(
    symbol='BNBBTC'
))

 


Последняя цена по паре (или парам) - /api/v3/ticker/price


Вес - 1
Параметры:
Необязательные:
symbol – пара
Если параметр symbol не указан, то возвращаются цены по всем парам.
Ссылка для просмотра в браузере: https://api.binance.com/api/v3/ticker/price?symbol=BNBBTC
Пример ответа:

{
  "symbol": "LTCBTC",
  "price": "4.00000200"
}


Или (если не указан параметр)

[
  {
    "symbol": "LTCBTC",
    "price": "4.00000200"
  },
  {
    "symbol": "ETHBTC",
    "price": "0.07946600"
  }
]

 

Пример кода:

from binance_api import Binance
bot = Binance(
    API_KEY='D7...Ejj',
    API_SECRET='gwQ...u3A'
)
print('ticker/price', bot.tickerPrice(
    symbol='BNBBTC'
))

 


Лучшие цены покупки/продажи - /api/v3/ticker/bookTicker


Вес 1
Параметры:
Необязательные:
symbol – пара
Если параметр symbol не указан, возвращаются данные по всем парам.
Ссылка для просмотра в браузере: https://api.binance.com/api/v3/ticker/bookTicker?symbol=BNBBTC
Пример ответа:

{
  "symbol": "LTCBTC",
  "bidPrice": "4.00000000", //Лучшая цена покупки
  "bidQty": "431.00000000", // Кол-во к покупке
  "askPrice": "4.00000200", // Лучшая цена продажи
  "askQty": "9.00000000"       // Кол-во к продаже    
}

 

Или (если не указан параметр):

[
  {
    "symbol": "LTCBTC",
    "bidPrice": "4.00000000",
    "bidQty": "431.00000000",
    "askPrice": "4.00000200",
    "askQty": "9.00000000"
  },
  {
    "symbol": "ETHBTC",
    "bidPrice": "0.07946700",
    "bidQty": "9.00000000",
    "askPrice": "100000.00000000",
    "askQty": "1000.00000000"
  }
]


Пример кода:

from binance_api import Binance
bot = Binance(
    API_KEY='D7...Ejj',
    API_SECRET='gwQ...u3A'
)
print('ticker/bookTicker', bot.tickerBookTicker(
    symbol='BNBBTC'
))

Реклама


 


Реклама


Авторизованные запросы:

 


Создание ордера - /api/v3/order

Для тех, кто будет писать свою библиотеку – обратите внимание, что адрес один и тот же /api/v3/order, но отличается метод – если отправлять данные через POST, это будет создание ордера, через GET – получение информации об ордере, DELETE – отмена ордера. Параметры, соответственно, разные.


Вес – 1
Метод: POST
Параметры:
Обязательные:
symbol – пара
side – тип ордера (BUY либо SELL)
type – тип ордера (LIMIT, MARKET, STOP_LOSS, STOP_LOSS_LIMIT, TAKE_PROFIT, TAKE_PROFIT_LIMIT, LIMIT_MAKER) 
quantity – количество к покупке
timestamp – текущее время в миллисекундах (в коде, выложенном здесь, проставляется автоматически, указывать не надо. 
Необязательные:
timeInForce – (GTC, IOC, FOK). По умолчанию GTC. Расшифрую.
    GTC (Good Till Cancelled) – ордер будет висеть до тех пор, пока его не отменят.
    IOC (Immediate Or Cancel) – Будет куплено то количество, которое можно купить немедленно. Все, что не удалось купить, будет отменено.
   FOK (Fill-Or-Kill) – Либо будет куплено все указанное количество немедленно, либо не будет куплено вообще ничего, ордер отменится.

price – цена
newClientOrderId – Идентификатор ордера, который вы сами придумаете (строка). Если не указан, генерится автоматически.
stopPrice – стоп-цена, можно указывать если тип ордера STOP_LOSS, STOP_LOSS_LIMIT, TAKE_PROFIT, или TAKE_PROFIT_LIMIT.
icebergQty – кол-во для ордера-айсберга, можно указывать, если тип ордера LIMIT, STOP_LOSS_LIMIT, and TAKE_PROFIT_LIMIT
recvWindow – кол-во миллисекунд, которое прибавляется к timestamp и формирует окно действия запроса (см. выше). По умолчанию 5000.
newOrderRespType –какую информацию возвращать, если удалось создать ордер. Допустимые значения ACK, RESULT, или FULL, по умолчанию RESULT. Подробности ниже.


В зависимости от типа ордера, некоторые поля становятся обязательными:

Тип ордера                    Обязательные поля
LIMIT                         timeInForce, quantity, price
MARKET                        quantity
STOP_LOSS                     quantity, stopPrice
STOP_LOSS_LIMIT               timeInForce, quantity, price, stopPrice
TAKE_PROFIT                   quantity, stopPrice
TAKE_PROFIT_LIMIT             timeInForce, quantity, price, stopPrice
LIMIT_MAKER                   quantity, price


Ордера типа LIMIT_MAKER – это ордера типа обычного LIMIT, но они отклонятся, если ордер при выставлении может выполниться по рынку. Другими словами, вы никогда не будете тейкером, ордер либо выставится выше/ниже рынка, либо не выставится вовсе.
Ордера типа STOP_LOSS и TAKE_PROFIT исполнятся по рынку (ордер типа MARKET), как только будет достигнута цена stopPrice.
Любые ордера LIMIT или LIMIT_MAKER могут формировать ордер-айсберг, установив параметр icebergQty.
Если установлен параметр icebergQty, то параметр timeInForce ОБЯЗАТЕЛЬНО должен иметь значение GTC.

Для того, что бы выставлять цены, противоположные текущим для ордеров типов MARKET и LIMIT:
Цена выше рыночной: STOP_LOSS BUY, TAKE_PROFIT SELL
Цена ниже рыночной: STOP_LOSS SELL, TAKE_PROFIT BUY


При создании ордера вернется ответ, в зависимости от параметра newOrderRespType:


newOrderRespType == ACK:

{
  "symbol": "BTCUSDT",
  "orderId": 28,
  "clientOrderId": "6gCrw2kRUAF9CvJDGP16IP",
  "transactTime": 1507725176595
}


newOrderRespType == RESULT:

{
  "symbol": "BTCUSDT",
  "orderId": 28,
  "clientOrderId": "6gCrw2kRUAF9CvJDGP16IP",
  "transactTime": 1507725176595,
  "price": "0.00000000",
  "origQty": "10.00000000",
  "executedQty": "10.00000000",
  "status": "FILLED",
  "timeInForce": "GTC",
  "type": "MARKET",
  "side": "SELL"
}


newOrderRespType == FULL:

{
  "symbol": "BTCUSDT",
  "orderId": 28,
  "clientOrderId": "6gCrw2kRUAF9CvJDGP16IP",
  "transactTime": 1507725176595,
  "price": "0.00000000",
  "origQty": "10.00000000",
  "executedQty": "10.00000000",
  "status": "FILLED",
  "timeInForce": "GTC",
  "type": "MARKET",
  "side": "SELL",
  "fills": [
    {
      "price": "4000.00000000",
      "qty": "1.00000000",
      "commission": "4.00000000",
      "commissionAsset": "USDT"
    },
    {
      "price": "3999.00000000",
      "qty": "5.00000000",
      "commission": "19.99500000",
      "commissionAsset": "USDT"
    },
    {
      "price": "3998.00000000",
      "qty": "2.00000000",
      "commission": "7.99600000",
      "commissionAsset": "USDT"
    },
    {
      "price": "3997.00000000",
      "qty": "1.00000000",
      "commission": "3.99700000",
      "commissionAsset": "USDT"
    },
    {
      "price": "3995.00000000",
      "qty": "1.00000000",
      "commission": "3.99500000",
      "commissionAsset": "USDT"
    }
  ]
}


Пример кода:

from binance_api import Binance
bot = Binance(
    API_KEY='D7...Ejj',
    API_SECRET='gwQ...u3A'
)
# Создать отложенный ордер на покупку 0.1 LTC за BTC
# По курсу 0.1
print('createOrder', bot.createOrder(
    symbol='LTCBTC',
    recvWindow=5000,
    side='BUY',
    type='LIMIT',
    timeInForce='GTC',
    quantity=0.1,
    price=0.1
))

 


Тестирование создания ордера: /api/v3/order/test


Вес: 1
Метод: POST
Метод позволяет протестировать создание ордера – например, проверить, правильно ли настроены временные рамки. По факту такой ордер никогда не будет исполнен, и средства на его создание затрачены не будут.
Параметры такие же, как при создании ордера.
Возвращает пустой словарь:

{}


Пример кода:

from binance_api import Binance
bot = Binance(
    API_KEY='D7...Ejj',
    API_SECRET='gwQ...u3A'
)
# Протестировать отложенный ордер на покупку 0.1 LTC за BTC
# По курсу 0.1
print('testOrder', bot.testOrder(
    symbol='LTCBTC',
    recvWindow=5000,
    side='BUY',
    type='LIMIT',
    timeInForce='GTC',
    quantity=0.1,
    price=0.1
))

 


Получить информацию по созданному ордеру - /api/v3/order


Вес – 1
Метод – GET
Параметры:
Обязательные:
symbol – пара
orderId – ID ордера, назначенный биржей
ИЛИ origClientOrderId – ID ордера, назначенный пользователем или сгенерированный (см. создание ордера)
Либо orderId либо origClientOrderId необходимо предоставить.
timestamp – текущее время (в представленном коде проставляется автоматически, указывать не надо)
Необязательные:
recvWindow – окно валидности запроса.

Возвращаемое значение:

{
  "symbol": "LTCBTC",
  "orderId": 1,
  "clientOrderId": "myOrder1",
  "price": "0.1",
  "origQty": "1.0",     // исходное указанное кол-во на покупку/продажу
  "executedQty": "0.0",  // текущее исполненное кол-во
  "status": "NEW",
  "timeInForce": "GTC",
  "type": "LIMIT",
  "side": "BUY",
  "stopPrice": "0.0",
  "icebergQty": "0.0",
  "time": 1499827319559,
  "isWorking": true
}

Пример кода:

from binance_api import Binance
bot = Binance(
    API_KEY='D7...Ejj',
    API_SECRET='gwQ...u3A'
)
print('orderInfo', bot.orderInfo(
    orderId=123123,
    symbol='LTCBTC',
))

 


Отмена ордера - /api/v3/order


Вес – 1
Метод – DELETE
Параметры:
Обязательные:
symbol – пара

orderId – ID ордера, назначенный биржей
ИЛИ origClientOrderId – ID ордера, назначенный пользователем или сгенерированный (см. создание ордера)
Либо orderId либо origClientOrderId необходимо предоставить.

timestamp – текущее время (в представленном коде проставляется автоматически, указывать не надо)
Не обязательные:
 
newClientOrderId – позволяет однозначно определить отмену, если не указано, генерируется автоматически
recvWindow – окно валидности запроса.
Возвращает:

{
  "symbol": "LTCBTC",
  "origClientOrderId": "myOrder1",
  "orderId": 1,
  "clientOrderId": "cancelMyOrder1"
}

 

Пример кода:

from binance_api import Binance
bot = Binance(
    API_KEY='D7...Ejj',
    API_SECRET='gwQ...u3A'
)
print('cancelOrder', bot.cancelOrder(
    orderId=123123,
    symbol='LTCBTC',
))

 


Текущие открытые пользователем ордера - /api/v3/openOrders


Вес – 1 если указана пара, либо (количество всех открытых для торгов пар) / 2.
Метод – GET
Параметры:
Обязательные:
timestamp – текущее время (в представленном коде проставляется автоматически, указывать не надо)
Не обязательные:
Не обязательные:
symbol – пара
recvWindow – окно валидности запроса.

Если параметр symbol не указан, возвращаются все открытые ордера по всем парам в массиве. В этом случае количество запросов к API считается равным количеству открытых для торговли пар.
Возвращает:

[
  {
    "symbol": "LTCBTC",
    "orderId": 1,
    "clientOrderId": "myOrder1",
    "price": "0.1",
    "origQty": "1.0",
    "executedQty": "0.0",
    "status": "NEW",
    "timeInForce": "GTC",
    "type": "LIMIT",
    "side": "BUY",
    "stopPrice": "0.0",
    "icebergQty": "0.0",
    "time": 1499827319559,
    "isWorking": trueO
  }
]


Пример кода:

from binance_api import Binance
bot = Binance(
    API_KEY='D7...Ejj',
    API_SECRET='gwQ...u3A'
)

# Все открытые ордера по паре
print('openOrders', bot.openOrders(
    symbol='LTCBTC',
))

# Все открытые ордера по всем парам
print('openOrders', bot.openOrders())

 


Все ордера пользователя вообще - /api/v3/allOrders


Метод позволяет получить вообще все ордера пользователя – открытые, исполненные или отмененные.
Вес – 5
Метод – GET
Параметры:
Обязательные:
symbol – пара
timestamp – текущее время (в представленном коде проставляется автоматически, указывать не надо)
Не обязательные:
orderId – Если указан, то вернутся все ордера, которые >= указанному. Если не указан, вернутся самые последние.
limit – кол-во возвращаемых ордеров (максимум 500, по умолчанию 500)
recvWindow – окно валидности запроса.
Возвращает:

[
  {
    "symbol": "LTCBTC",
    "orderId": 1,
    "clientOrderId": "myOrder1",
    "price": "0.1",
    "origQty": "1.0",
    "executedQty": "0.0",
    "status": "NEW",
    "timeInForce": "GTC",
    "type": "LIMIT",
    "side": "BUY",
    "stopPrice": "0.0",
    "icebergQty": "0.0",
    "time": 1499827319559,
    "isWorking": true
  }
]

 

Пример кода:

from binance_api import Binance
bot = Binance(
    API_KEY='D7...Ejj',
    API_SECRET='gwQ...u3A'
)

# Все ордера по паре
print('allOrders', bot.allOrders(
    symbol='LTCBTC',
))

 


Информация по аккаунту - /api/v3/account


Вес – 5
Метод – GET
Параметры:
Обязательные:
timestamp – текущее время (в представленном коде проставляется автоматически, указывать не надо)
Не обязательные:
recvWindow – окно валидности запроса.
Возвращает:

{
  "makerCommission": 15,
  "takerCommission": 15,
  "buyerCommission": 0,
  "sellerCommission": 0,
  "canTrade": true,
  "canWithdraw": true,
  "canDeposit": true,
  "updateTime": 123456789,
  "balances": [
    {
      "asset": "BTC",
      "free": "4723846.89208129",
      "locked": "0.00000000"
    },
    {
      "asset": "LTC",
      "free": "4763368.68006011",
      "locked": "0.00000000"
    }
  ]
}


Пример кода:

from binance_api import Binance
bot = Binance(
    API_KEY='D7...Ejj',
    API_SECRET='gwQ...u3A'
)

print('account', bot.account())

 


Список сделок пользователя - /api/v3/myTrades


Метод позволяет получить историю торгов авторизованного пользователя по указанной паре.
Вес – 5.
Параметры:
Обязательные:
symbol – пара
timestamp – текущее время (в представленном коде проставляется автоматически, указывать не надо)
Не обязательные:
limit – кол-во возвращаемых сделок (максимум 500, по умолчанию 500)
fromId – с какой сделки начинать вывод. По умолчанию выводятся самые последние.
recvWindow – окно валидности запроса.
Возвращает:

[
  {
    "id": 28457,
    "orderId": 100234,
    "price": "4.00000100",
    "qty": "12.00000000",
    "commission": "10.10000000",
    "commissionAsset": "BNB",
    "time": 1499865549590,
    "isBuyer": true,
    "isMaker": false,
    "isBestMatch": true
  }
]


Пример кода:

from binance_api import Binance
bot = Binance(
    API_KEY='D7...Ejj',
    API_SECRET='gwQ...u3A'
)

print('myTrades', bot.myTrades(
    symbol='LTCBTC'
))

Реклама


WAPI

Ввод и вывод средств

Подробное описание будет чуть позже, пока что примеры с комментариями

from binance_api import Binance
bot = Binance(
    API_KEY='D7F...Ejj',
    API_SECRET='gwQ...u3A'
)

# Получение адреса для депозита
print(bot.depositAddress(asset='BTC'))

# Вывод средств
print(bot.withdraw(asset='XRP', address='1wsdsr234234242', amount=12))

# История пополнений
print(bot.depositHistory(asset='BTC'))
print(bot.depositHistory())

# История выводов
print(bot.withdrawHistory())
print(bot.withdrawHistory(asset='ETH'))

# Узнать комиссию за вывод
print(bot.withdrawFee(asset='BTC'))

# Состояние аккаунта
print(bot.accountStatus())

# Состояние биржи
print(bot.systemStatus())

 

Это статья из цикла "Популярно о бирже"

Комментарии: (153)
15.02.2018 22:40
Здравствуйте! Что-то у меня не в порядке с первым примером. Выдает ошибку : {'msg',: 'Invalid API-key, IP, or permission for action.', 'code': -2015}. API ключ я взял настоящий действующий.
16.02.2018 02:01
Временами выдает {'code': -1022, 'msg': 'Signature for this request is not valid.'}". Прочел что это связано с recWindow. Непонятно как этого избегать.
16.02.2018 05:03
Проверьте настройки безопасности - возможно, нужно добавить IP в белый список. Так же убедитесь, что стоят нужные галки в настройках ключа - для первого примера нужен флаг Read Info, но вообще поставьте Enable Trading тоже - что бы можно было выставлять ордера
16.02.2018 05:07
Это значит, что пакет данных от вас до Binance идет долго, дольше чем 5000 мс. 
Просто увеличьте это окно, например

from binance_api import Binance
bot = Binance(
    API_KEY='D7...Ejj',
    API_SECRET='gwQ...u3A'
)

print('account', bot.account(recvWindow=15000))

Этот параметр можно в любом приватном методе использовать
16.02.2018 16:13
Я поробовал добавит IP в белый список н это не помогло. Впрочем это видимо вопрос не к Вам, а к админам биржи. Спасибо за ответ!
16.02.2018 16:12
print('account', bot.account(recvWindow=15000)) выдает ошибку 
{'msg',:"Not all sent parameters were read; 'read' '2' parameter(s) but was sent '3'.", 'code': -1104}
18.02.2018 13:00
Увеличил параметр до 25000 - и все равно. Насколько надо его увеличить? Работает примерно в половине случаев...
16.02.2018 17:48
Проверил только что, взял код с сайта и вашего примера, отлично отработало.
Проверьте свой код - такая ошибка говорит о том, что какой-то параметр не распознался, возможно написан с опечаткой
18.02.2018 13:08
Скорее всего, вам стоит проверить синхронизацию времени на своем компьютере, мне кажется у вас расхождение с мировым на несколько секунд, отсюда все проблемы. 25000 это и так довольно много.
18.02.2018 12:56
Вы правы, опечатка!
18.02.2018 14:26
Прошу прощения за глупый вопрос : а как это проверить и какое время должно быть? (Ubuntu 16.04 LTS). Вроде секунды в порядке...
18.02.2018 17:52
Начните с  команды timedatectl
Вот, можете по шагам пройти, установить ntp и всё, что надо https://www.digitalocean.com/community/tutorials/how-to-set-up-time-synchronization-on-ubuntu-16-04
18.02.2018 19:35
Спасибо за ссылку, я все это проделал и лучше не стало. Опытным путем видно что где-то 55000 оптимальное число,но все равно 1 раз из десяти происходит сбой. Меньше и больше - сбоев больше : 2 - 3 из 10.
04.03.2018 12:26
Здравствуйте!  При попытке выставить ордер на покупку по паре 'ADABTC' получаю ответ биржи:        {'code': -1100, 'msg': "Illegal characters found in parameter 'price'; legal range is '^([0-9]{1,20})(\\.[0-9]{1,20})?$'."}
возможно это связано с тем, что цена ADA низкая в  BTC? Кусок кода :
    #цену приводим к требованиям биржи о кратности
    my_need_price = adjust_to_step(bid_price, data_big[pair][1]['filters'][0]['tickSize'])
 # Рассчитываем кол-во, которое можно купить, и тоже приводим его к кратному значению
    my_amount = adjust_to_step(amount/ my_need_price, data_big[pair][1]['filters'][1]['stepSize'])
    my_need_price = float(my_need_price)
    my_need_price = round(my_need_price,8)
    print ('my_need_price =',my_need_price , 'my_amount=',my_amount)
    with open(CURR_DIR+'/SL/LOG/'+'log_buy.txt', 'a') as f:
        print(datetime.now(),'***338РЕШЕНИЕ О ПОКУПКЕ***', pair)
        print(datetime.now(),'***339РЕШЕНИЕ О ПОКУПКЕ***', pair,'data_big[pair][0]=',data_big[pair][0], file=f)
        print(datetime.now(),'my_need_price =',my_need_price , 'my_amount=',my_amount, file=f)        
        print(datetime.now(),'***Ордер на покупку***', pair, 'bid_price=', bid_price, 'amount=', amount, file=f)    
 # Отправляем команду на бирже о создании ордера на покупку с рассчитанными параметрами
    new_order = bot.createOrder(
                                symbol=pair,
                                recvWindow=15000,
                                side='BUY',
                                type='LIMIT',
                                timeInForce='GTC',  # Good Till Cancel
                                quantity=my_amount,
                                price=my_need_price,
                                newOrderRespType='FULL'
                               )
    time.sleep(1)
     # Если удалось создать ордер на покупку
    if 'orderId' in new_order:
        print("Создан ордер на покупку", new_order) 
        print ('orderId=', new_order['orderId'])
        data_big[pair][0] = 1    
        data_big[pair].append(new_order['orderId'])

        with open(CURR_DIR+'/SL/LOG/'+'log_buy.txt', 'a') as f:
            print(datetime.now(), pair,'362создан ордер на покупку', new_order, file=f)
            print(datetime.now(), pair,'создан ордер на покупку data_big[pair] =', data_big[pair], file=f)
        
    else :
        data_big[pair][0] = 0 
        with open(CURR_DIR+'/SL/LOG/'+'log_buy.txt', 'a') as f:
            print(datetime.now(), pair,'368ОШИБКА не создан ордер на покупку', new_order, file=f)
            print(datetime.now(), pair,'ОШИБКА не создан ордер на покупку data_big[pair] =', data_big[pair], file=f)
    with open(CURR_DIR+'/SL/LOG/'+'log_buy.txt', 'a') as f:
        print(datetime.now(), pair,'318 Выход call_buy data_big[pair] =', data_big[pair], file=f)
А дальше лог, который выдает этот код:
2018-03-04 21:24:08.254604 ***339РЕШЕНИЕ О ПОКУПКЕ*** ADABTC data_big[pair][0]= 0
2018-03-04 21:24:08.254604 my_need_price = 2.3e-05 my_amount= 52.0
2018-03-04 21:24:08.254604 ***Ордер на покупку*** ADABTC bid_price= 2.3e-05 amount= 0.0012
2018-03-04 21:24:09.431604 ADABTC 368ОШИБКА не создан ордер на покупку {'code': -1100, 'msg': "Illegal characters found in parameter 'price'; legal range is '^([0-9]{1,20})(\\.[0-9]{1,20})?$'."}
2018-03-04 21:24:09.431604 ADABTC ОШИБКА не создан ордер на покупку data_big[pair] = [0, {'symbol': 'ADABTC', 'status': 'TRADING', 'baseAsset': 'ADA', 'baseAssetPrecision': 8, 'quoteAsset': 'BTC', 'quotePrecision': 8, 'orderTypes': ['LIMIT', 'LIMIT_MAKER', 'MARKET', 'STOP_LOSS_LIMIT', 'TAKE_PROFIT_LIMIT'], 'icebergAllowed': True, 'filters': [{'filterType': 'PRICE_FILTER', 'minPrice': '0.00000001', 'maxPrice': '100000.00000000', 'tickSize': '0.00000001'}, {'filterType': 'LOT_SIZE', 'minQty': '1.00000000', 'maxQty': '90000000.00000000', 'stepSize': '1.00000000'}, {'filterType': 'MIN_NOTIONAL', 'minNotional': '0.00100000'}]}]
2018-03-04 21:24:09.431604 ADABTC 318 Выход call_buy data_big[pair] = [0, {'symbol': 'ADABTC', 'status': 'TRADING', 'baseAsset': 'ADA', 'baseAssetPrecision': 8, 'quoteAsset': 'BTC', 'quotePrecision': 8, 'orderTypes': ['LIMIT', 'LIMIT_MAKER', 'MARKET', 'STOP_LOSS_LIMIT', 'TAKE_PROFIT_LIMIT'], 'icebergAllowed': True, 'filters': [{'filterType': 'PRICE_FILTER', 'minPrice': '0.00000001', 'maxPrice': '100000.00000000', 'tickSize': '0.00000001'}, {'filterType': 'LOT_SIZE', 'minQty': '1.00000000', 'maxQty': '90000000.00000000', 'stepSize': '1.00000000'}, {'filterType': 'MIN_NOTIONAL', 'minNotional': '0.00100000'}]}]

Т.е. значения   my_need_price = 2.3e-05    my_amount= 52.0  приводят к такому результату, я уже думал что дело в букве е в цене, но как победить это я не знаю, может подскажите?
05.03.2018 20:27
Добрый день!
Вам нужно отправлять как-то так:
price="{price:0.8f}".format(price=my_need_price)

Так же они лимитируют precision - сколько знаков после запятой для пары допускается, советую посмотреть эту статью и взять код оттуда https://bablofil.ru/bot-dlya-binance/ - там эти моменты решены
06.03.2018 13:38
Спасибо, просто я не профессиональный программист, а самоучка и не понимаю всего кода из https://bablofil.ru/bot-dlya-binance/ , но теперь я примерно понял, а вообще я делал на основе этой вашей статьи, просто те моменты где я не понимал код я не использовал, сделаю отпишусь.
07.03.2018 11:59
Спасибо, просто вставил вашу строку        price="{price:0.8f}".format(price=my_need_price)
и все заработало, просто как чудо, до этого неделю голову ломал
12.03.2018 19:05
Добрый день. Обнаружил, что в API отсутствует возможность связать заявку и сделку. Через WebSocket в режиме активных торгов эта информация поступает, но есть сценарий, когда возникает проблема. Пример. Робот выставил заявку, она выставилась, висит активная. Я записал ID транзакции и Id заявки у себя. Все нормально. Далее, закрываю робота и на бирже моя заявка срабатывает. Я открываю робота, вызываю "GetAccountTrades" (в API возможно по-другому называется, я использую C# и BinanceDotNet), получаю список сделок, но в нем нет OrderId. Получается, робот не может понять, что произошло с заявкой. Тем более, она может пройти частично или несколько сделок будут входить в одну заявку. Я не первый, кто заметил этот недочет, люди советуют обратиться к разработчикам биржи. Вам не приходилось обходить подобный момент?
14.03.2018 12:08
Метод API myTrades возвращает ID ордера 
[
  {
    "id": 28457,
    "orderId": 100234,
    "price": "4.00000100",
    "qty": "12.00000000",
    "commission": "10.10000000",
    "commissionAsset": "BNB",
    "time": 1499865549590,
    "isBuyer": true,
    "isMaker": false,
    "isBestMatch": true
  }
]
Видимо, библиотека которой вы пользуетесь это игнорирует, или нужно использовать другой метод
14.03.2018 13:34
Действительно, в API есть такое поле. Видимо наткнулся на устаревшую информацию (месячной давности) и не перепроверил сам. Благодарю за наводку!
15.03.2018 06:06
Добрый день, Андрей
Можно попросить вас, выложить код бота  binance с индикатором MACD 
В заранее благодарю.
17.03.2018 19:35
Всем доброго времени суток. Пишу бота, который собирает открытую статистику (без API KEY) агрегированных сделок на бирже через websocket. Создаю количество потоков равное количеству валютных пар, например XXXETH. Но через несколько часов работы сервер биржи перестает предоставлять статистику по некоторым валютам (примерно половина) или даже в момент пампа. При этом на клиентском сокете не могу отловить этот момент, чтобы пересоздать соединение. Кто как решает эту проблему?
18.03.2018 10:42
Пробую получить свечки за большой промежуток времени и не получается - отдаются только свечи за последнее время, остальное игнорируется.
Это ограничение бинанса?
Есть вариант обойти?
18.03.2018 17:28
Ограничение бинанса - последние 500 записей. Поэтому приходиться собирать статистику через websocket (свечи, агрегированные сделки) и хранить у себя.
21.03.2018 17:26
Добры вечер всем! Подскажите пожалуйста как по API узнать цену ордера исполненного по маркету? В "orderInfo" не нашел значения.
21.03.2018 18:32
Спасибо! Решился вопрос.
27.03.2018 14:09
Здравствуйте. Подскажите из-за чего возникает эта ошибка?
Traceback (most recent call last):
  File "C:\1\binance_test.py", line 6, in <module>
    print('account', bot.account())
  File "C:\1\binance_api.py", line 43, in wrapper
    return self.call_api(**kwargs)
  File "C:\1\binance_api.py", line 70, in call_api
    return response.json()
  File "C:\Program Files\Python36\lib\site-packages\requests\models.py", line 892, in json
    return complexjson.loads(self.text, **kwargs)
  File "C:\Program Files\Python36\lib\json\__init__.py", line 354, in loads
    return _default_decoder.decode(s)
  File "C:\Program Files\Python36\lib\json\decoder.py", line 339, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
  File "C:\Program Files\Python36\lib\json\decoder.py", line 357, in raw_decode
    raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)</module>
27.03.2018 17:23
Биржа на что-то ругается, может быть время не синхронизировано, или сетевой сбой какой то. Попробуйте передать и указать параметр recvWindow побольше
27.03.2018 19:21
Роман, такая же ошибка. Вчера все нормально работало. Если нашли в чем причина отпишитесь пожалуйста.
27.03.2018 19:23
Не помогает(
28.03.2018 08:06
Да, изменился немного механизм работы API
Я изменил код в статье, можно дальше пользоваться
28.03.2018 20:34
Спасибо!
28.03.2018 18:03
Здравствуйте, подскажите пожалуйста, почему не можно API Binance https://api.binance.com/api/v1/ticker/24hr?symbol=BNBBTC отредактировать в программе http://jsoneditoronline.org/,  как API exmo? Урок брал в Вашей статьи https://bablofil.ru/exmo-api/#add_comment_form
16.04.2018 14:45
Здравствуйте.
Если вы откроете ссылку  https://api.binance.com/api/v1/ticker/24hr?symbol=BNBBTC в браузере, скопируете текст и вставите в jsoneditoronline, то все получится. Но если вы попробуете ссылку открыть в самом jsoneditoronline, то он не сможет её скачать т.к. бинанс будет думать что это какой-то робот ломится
02.04.2018 13:39
Здравствуйте, подскажите пожалуйста. Как одним запросом извлечь 4 разных пар свечь c API Binance. я могу извлечь только одну пару
16.04.2018 14:54
Добрый день.
Так, к сожалению, нельзя, но можно вытащить что-то похожее, за сутки, отсюда - https://api.binance.com/api/v1/ticker/24hr?symbol=BNBBTC
07.04.2018 18:00
Здравствуйте, а как получить текущую свечу одной пары?
16.04.2018 14:56
Добрый день,
Что, в вашем понимании, текущая - вы же можете строить свечи за любой период - минута, сутки, 11 секунд, год... 
Вы можете брать последние свечи методом klines, можете брать последние сделки по паре и строить свою свечу, можете брать тикер (https://api.binance.com/api/v1/ticker/24hr?symbol=BNBBTC) и получать самые последние данные + объемы за сутки
09.04.2018 05:54
Добрый день. Подскажите, как получить с Бинансе информацию о имеющихся парах? Нужно что-то типа https://wex.nz/api/3/info
16.04.2018 14:57
Добрый день,
я беру отсюда - https://api.binance.com/api/v1/exchangeInfo
В цикле по symbols, берем symbol
24.04.2018 12:17
спасибо,
Ещё вопросик проясните пожалуйста-
можно ли публичные запросы (depth, например) сделать на несколько пар одновременно?
например на Yobite: Depth: https://yobit.net/api/3/depth/ltc_btc-nmc_btc
а то как бы не нарушить их лимиты, при обновлении цен на все пары...(интересует при сравнении бирж - 30-40 пар обычно)
26.04.2018 08:31
Можно, смотря какая информация нужна
Например, вот последняя цена по каждой паре
https://api.binance.com/api/v3/ticker/price
Везде, где symbol необязательное поле, просто убирайте его, и получите полный список.
Вообще можно 1200 запросов в минуту, если не превышать то не банят
26.04.2018 08:58
спасибо. прайс использую. просто когда арбитражную ситуацию оцениваешь нужны стаканы. Но если 1200 запросов... вопросов нет. На некоторых биржах столкнулся на 1-2 запроса в секунду и менее. Там этот вопрос актуален.
25.04.2018 04:01
Андрей, поменялось похоже еще что-то на Бинансе( Такая ошибка вылетает на bot.account():
{'code': -1021, 'msg': "Timestamp for this request was 1000ms ahead of the server's time."}
26.04.2018 08:32
Это означает, что у вас время опережает мировое
Нужно настроить синхронизацию времени на вашем устройстве, боты сейчас работают, я проверил
26.04.2018 17:32
Спасибо! Я видел сообщение ошибки, но подумал что что-то другое) Синхронизация не помогала, пока не поменял сервер синхронизации. А не подскажите из Питона нельзя запускать синхронизацию времени винды? А то у меня сутки нормально все было. Опять эта ошибка. Синхронизировался-хорошо все.
28.04.2018 12:00
Из питона можно вызывать команды командной строки, один способ это модуль subprocess, второй - os.system(..), можно вызывать команды синхронизации
Но посмотрите код бота https://bablofil.ru/bot-dlya-binance/ - там я беру время сервера binance, текущее время, беру разницу и в дальнейшем отправляю запросы за учетом этой разницы, ничего синхронизировать не надо.
06.05.2018 11:21
простите, а как из сжатой истории чужих сделок (/api/v1/aggTrades) определить была ли это покупка или продажа?
  {
    "a": 26129,         //  tradeId строки
    "p": "0.01633102",  // Цена
    "q": "4.70443515",  // Количество
    "f": 27781,         // Первая tradeId
    "l": 27781,         // Последняя tradeId
    "T": 1498793709153, // Время
    "m": true,          // Was the buyer the maker?
    "M": true           // Was the trade the best price match?
  }
если "m" true, то сделка Sell, а если false, то Buy?
15.05.2018 11:07
Если один купил а другой продал, то это buy или sell?
Отвечу так: в истории торгов binance зеленым подсвечиваются сделки, у которых isBuyerMaker == false, и маджентой - у кого true
16.05.2018 15:27
ну это понятно, что для кого-то Buy, а для кого-то Sell ))
имел ввиду, конечно, отображение на бирже ... спасибо за ответ
15.05.2018 06:33
Возник вопрос, а как достать баланс доступный для определённой валюты и в дальнейшем без проблем использовать его для рассчётов ?
15.05.2018 11:14
Добрый день!
Как то так:

from binance_api import Binance
bot = Binance(
    API_KEY='D7...Ejj',
    API_SECRET='gwQ...u3A'
)
NEED_ASSET = "BTC"

need_balance = 0
for struct in bot.account()["balances"]:
    if struct["asset"] == NEED_ASSET:
        need_balance = float(struct["free"])
        break

print(need_balance)
17.05.2018 08:30
Здравствуйте, с  неделю начала вылазить ошибка.
/ $
/ $ cd '/data/user/0/ru.iiec.pydroid3/files/project/binance_calc_invest' ; export PYTHTraceback (most recent call last):           File "/data/user/0/ru.iiec.pydroid3/files/accomp_files/iiec_run/iiec_run.py", line 31, in <module>                                 start(fakepyfile,mainpyfile)             File "/data/user/0/ru.iiec.pydroid3/files/accomp_files/iiec_run/iiec_run.py", line 30, in start                                    exec(open(mainpyfile).read(),  __main__.__dict__)                                   File "<string>", line 12, in <module>      File "/data/user/0/ru.iiec.pydroid3/files/project/binance_calc_invest/binance_api.py", line 46, in wrapper                         return self.call_api(**kwargs)           File "/data/user/0/ru.iiec.pydroid3/files/project/binance_calc_invest/binance_api.py", line 73, in call_api                        return response.json()
  File "/data/user/0/ru.iiec.pydroid3/files/arm-linux-androideabi/lib/python3.6/site-packages/requests/models.py", line 892, in json
    return complexjson.loads(self.text, **kwargs)
  File "/data/user/0/ru.iiec.pydroid3/files/arm-linux-androideabi/lib/python3.6/json/__init__.py", line 354, in loads
    return _default_decoder.decode(s)
  File "/data/user/0/ru.iiec.pydroid3/files/arm-linux-androideabi/lib/python3.6/json/decoder.py", line 339, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
  File "/data/user/0/ru.iiec.pydroid3/files/arm-linux-androideabi/lib/python3.6/json/decoder.py", line 357, in raw_decode
    raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

[Program finished]</module></string></module>
17.05.2018 08:55
Добрый день, видимо не может подключиться к бирже по какой то причине (связь? ростелеком?) или получает какой то неожиданный ответ.

добавьте перед 
return response.json()
строку
print response.text
и посмотрите, что там возвращается

А так код у меня, например, по прежнему работает
17.05.2018 12:23
<title>ERROR: The request could not be satisfied</title>                              <body>                              <h1>403 ERROR</h1>                         <h2>The request could not be satisfied.</h2>                                          <hr noshade="" size="1px"/>                    Bad request.                               <br clear="all"/>                           <hr noshade="" size="1px"/>                                                    Generated by cloudfront (CloudFront)       Request ID: rgfqfSbdvbhh_m2xQZHBQ146vm1UvVzMnLx4ZV6ACkQZTQvl8k9Nsw==</body>
17.05.2018 14:18
Я такое правил уже, когда трафик бинанса пошел через сервера амазона...
Вам нужно скачать обновленную версию либо с этой статьи, либо с этой: https://bablofil.ru/bot-dlya-binance/, должно все работать
21.05.2018 09:47
Добрый день, у меня при работе моего самописного бота тоже такая ошибка появляется, подскажите как вы решили эту проблему?
21.05.2018 09:54
В общем если запрос идет через GET и через сервера CloudFront то тело запроса должно быть пустым (только заголовки)
21.05.2018 10:37
ok, спасибо.
17.05.2018 12:16
Да кстати это началось после ковровых блокировок роскомпозора
17.05.2018 15:43
Спасибо все заработало
23.05.2018 12:17
ДОбрый день. Подскажите пожалуйста, как через апи бинанс получать данные о пополнении баланса и выводе средств с биржи? По идее должна быть такая возможность, но у Вас тут я к сожалению, не нашел. Заранее спасибо
23.05.2018 20:43
Добрый день
Обновил статью: код binance_api (вначале) и в конце статьи добавил несколько примеров.
Более подробно распишу позже, но вроде бы и так всё наглядно
Если что спецификацию можно почитать на английском https://github.com/binance-exchange/binance-official-api-docs/blob/master/wapi-api.md
23.05.2018 12:41
Здравствуйте.

Подскажите пожалуйста, как можно скачать историю котировок криптовалют с биржи Binance для создания своей базы данных?
01.06.2018 08:34
Здравствуйте, непосредственно бинанс дает скачать максимум 500 записей, если нужна история торгов за длительный период лучше поискать сторонние аггрегаторы
28.05.2018 20:29
Здравствуйте.
подскажите как подключиться в Binance с использованием вебсокета ?
10.06.2018 10:55
Здравствуйте, вообще есть такое (чье-то) решение https://github.com/sammchardy/python-binance
pip install python-binance
Умеет коннектиться из коробки
А я попозже постараюсь выложить простой способ работы с сокетами
Официальное описание API - тут https://github.com/binance-exchange/binance-official-api-docs/blob/master/web-socket-streams.md
Имейте в виду, что сокеты отправляют информацию раз в секунду, в то время как rest запросы отвечают за 0.3 - 0.8 секунды
08.06.2018 12:48
Здравствуйте Андрей. Большая благодарность Вам за качественное объяснение и примеры. Очень понятно и доходчиво!
Есть вопрос - не могу найти информацию по купленным и проданным ордерам за единицу времени, например за последнюю секунду (имею ввиду не пользователя а вообще по бирже по определённому токену). Знаю что бинанс предоставляет эту информацию, но не могу найти как это сделать, Вы не интересовались этим вопросом?
10.06.2018 10:59
Добрый день.
Посмотрите метод aggTrades - можно указать период с разницей в секунду, получите до 500 сделок
Так же можно просто trades - последние 500 сделок, но там придется самому время выбирать из полученных данных
17.06.2018 12:46
Андрей, спасибо большое!
13.06.2018 17:51
Добрый вечер! Спасибо за подробный разбор работы апи биржи. 
Подскажите, есть ли способ скачать историю движения цен в orderbook (стакане) ? Или же остаётся только подписываться на вэбсокет и сохранять инфо в БД?
18.06.2018 07:53
Добрый день
Боюсь, что именно придется собирать самому (или обращаться к тем, кто уже собирает)
26.06.2018 04:25
Добрый день Андрей, большая просьба подсказать как определить объёмы покупок и объёмы продаж за 1 час методом trades. 
Просто не совсем понимаю описание этого метода.

{
  "e": "trade",     // Event type
  "E": 123456789,   // Event time
  "s": "BNBBTC",    // Symbol
  "t": 12345,       // Trade ID
  "p": "0.001",     // Price
  "q": "100",       // Quantity
  "b": 88,          // Buyer order Id
  "a": 50,          // Seller order Id
  "T": 123456785,   // Trade time
  "m": true,        // Is the buyer the market maker?
  "M": true         // Ignore.
}

Запутался в терминологии.
Судя по описанию с github https://github.com/binance-exchange/binance-official-api-docs/blob/master/web-socket-streams.md (Trade Streams)
за это отвечает значение "isBuyerMaker" ("m": true,        // Is the buyer the market maker?). 
Т.е. если это значение true, то это покупка (покупатель создал ордер на покупку), и соответственно если false то это продажа?
isBestMatch ("M": true         // Ignore.) тоже не понятен - имеется ввиду что сделка выполнена?

Заранее благодарю, Иван.
26.06.2018 20:54
Добрый день
Насчет isBuyerMaker - по сути это означает, что тот, кто хотел купить, выставил по ценам ниже рынка, и тот, кто продавал, откликнулся на это (покупатель - мейкер, продавец - тейкер). А вот покупка это или продажа - это как посмотреть. Обсуждали в комментариях в комментариях выше, биржа подсвечивает зеленым, если isBuyerMaker - false. 
Сделка в любом случае выполнена, если попала в историю сделок.
isBestMatch - они писали на реддит, кажется, что это поле никогда не меняется и оставлено для совместимости.
27.06.2018 05:37
Андрей, благодарю.
30.06.2018 23:25
Здравствуйте, Андрей. Вы пишете "Да да, тут нельзя ставить ордера с произвольной ценой.", я зашёл на https://api.binance.com/api/v1/exchangeInfo, и там можно увидеть по всем парам такую картину: 

[{"filterType":"PRICE_FILTER","minPrice":"0.00000100","maxPrice":"100000.00000000","tickSize":"0.00000100"}

то есть фактически максимальная и минимальная цена не ограничены (пока), просто в теории эти значения могут быть изменены биржей до каких-то более узких значений. Я правильно понимаю?
01.07.2018 10:13
Здравствуйте
Под невозможностью произвольной цены я имел в первую очередь не мин/макс, а именно шаг - tickSize.
Если он, например равен 0.01000000, то нельзя поставить 0.01100000 или 0.01000001 или еще как-то, все цены, которые вы ставите по этой паре, должны быть кратны 0.01000000. Биржа не даст поставить ордера ни руками, ни через апи, если не выполняется это условие.
Ну, и если посмотреть внимательнее, не у всех пар значения одинаковые, хотя большей частью совпадают
BTCUSDT
,"minPrice":"0.01000000","maxPrice":"10000000.00000000","tickSize":"0.01000000"
NEOUSDT
,"minPrice":"0.00100000","maxPrice":"10000000.00000000","tickSize":"0.00100000"
LSKBNB
"minPrice": "0.00010000", "maxPrice":"100000.00000000","tickSize": "0.00010000"
Ну и да, биржа в любой момент может изменить эти ограничения, особенно когда (и если) цены начнут скакать и изменяться в несколько раз.
06.07.2018 13:00
Спасибо за уточнение! :)
28.07.2018 14:41
Здравствуйте, Андрей! При запуске print(bot.withdraw(asset='XRP', address='адресс моего кошелька', amount='точное кол-во')) выходит эта ошибка: {'msg': 'Name is empty.', 'success': False}.  Не могли бы Вы подсказать в чём может быть проблема?
01.08.2018 10:01
Добрый день, странно, поле name необязательно к заполнению, это описание обычное
Вы можете его указать, например 
print(bot.withdraw(asset='XRP', address='адресс моего кошелька', amount='точное кол-во', name='for_me')) 
Ну и еще для XRP можно указать addressTag, если требуется
01.08.2018 17:39
Благодарю, эту проблему уже решил) Техподдержка ничего дельного не отвечала, в итоге в "Withdrawal Address Management" я подключил "Whitelist", добавил кошель, намеренно создал имя, уже его вписал и бинго: эта ошибка пропала (если просто указать имя в коде - увы не работает). Только вот заместо одной ошибки появилась другая: {'msg': 'Address verification failed.', 'success': False}. Я начал тестировать на другой валюте что бы исключить возможные проблемы с "addressTag", но пока не могу понять в связи с чем выходит ошибка. Все остальные функции прекрасно работают с API ключами, а на указанный в коде адрес кошелька через браузер средства выводятся без намёка на какую либо проблему. Техподдержка сейчас просит прислать им код в формате "POST 'https://www.binance.com/wapi/v3/withdraw.html?asset=waves&address=0x**************** -d 'amount=1&recvWindow=5000&name=addressName&timestamp=1510903211000&signature=************************", только вот не совсем понимаю зачем в таком формате, да ещё и с "timestamp" "recvWindow", а что такое "signature" и где этот показатель брать, так и вообще не знаю. Возможно если эти параметры вписать - эта ошибка так же как и предыдущая пропадёт :D
07.08.2018 10:50
Добавьте в моем коде перед

response = requests.request(method=self.methods[command]['method'], url=api_url, data="" if self.methods[command]['method'] == 'GET' else payload_str, headers=headers)

print(api_url)
print("" if self.methods[command]['method'] == 'GET' else payload_str)
print(headers)

там будут все эти параметры, они рассчитываются
20.08.2018 04:59
Как поставить ордер понятно а как сделать что бы при его срабатывании ставился TAKE_PROFIT по определенной цене и объему
17.10.2018 12:05
Отслеживать его состояние и выставлять новый при срабатывании.
Можете посмотреть, как это сделано здесь: https://bablofil.ru/bot-dlya-binance
16.09.2018 14:49
кто нибудь знает какой вес имеет запрос /api/v3/ticker/price если не указывать конкретную пару ?
17.10.2018 12:08
Увы.. Техподдержка наверное только. Да и то, они эксперементируют с машинным обучением, если вы торгуете то ничего не будет, а если только лишнюю нагрузку создаете, то будет.
03.10.2018 13:55
Существует ли опция получить список всех ордеров в стакане?
17.10.2018 12:10
Нет, и более того - то, что вы видите в стакане не всегда является истинным. Есть ордера айсберги - в стакане отображается только видимая (мелкая часть), а при покупке всплывает остальное.
07.10.2018 05:17
Вылетает ошибка раз в день примерно:
Exception: {"code":-1021,"msg":"Timestamp for this request is outside of the recvWindow."}

Помогите пожалуйста синхронизировать время. Сейчас пробую делать так:
        subprocess.call("net start w32time", shell=True)
        subprocess.call("w32tm /resync", shell=True)
        # Настраиваю синхронизацию времени
        limits = bot.exchangeInfo()
        local_time = int(time.time())
        server_time = int(limits['serverTime'])//1000
        shift_seconds = server_time-local_time
        bot.set_shift_seconds(shift_seconds)

Не помогает(
07.10.2018 16:24
Эту настройку через каждую минуту делаю. Для надежности и время синхронизирую на компьютере и устанавливаю как в боте Андрея поправку.
17.10.2018 12:13
Может пакет какой-то сетевой заблудился, может оборудование провайдера на чердаке барахлит или еще что-то, бывает такое.. 
Можете попробовать в этой строке payload.update({'timestamp': int(time.time() + self.shift_seconds - 1) * 1000})
убрать единичку или увеличить её, может быть пореже будет вылетать ошибка
15.11.2018 18:39
когда от сервера приходит 429 ответ, на сколько времени нужно отправить бота в сон? и можно ли обойти это с помощью прокси?
16.11.2018 13:55
и ещё вопросы:
ограничения идут на IP или на 1 ключ? если я например сделаю бота в котором будет несколько людей торговать
и если вылетает 429 ответ, он вылетает на IP или на аккаунт
17.11.2018 17:12
Сначала возвращается 429 код несколько раз, потом, если не успокоиться и продолжать долбить, банят по IP на несколько минут и возвращают код 418, если и тут не успокоиться то увеличивают срок бана.
Я бы советовал после получения 429 использовать замедление с увеличением - т.е. грубо говоря на 1 сек сделать паузу, если опять вернулось 429 то уже паузу на 3 сек, потом на 9 например.. При получении 418 сразу минут на 5 тормозить.
Прокси могут помочь, но до этого проще не доводить, все же 1200 запросов в минуту допускается, причем можно всякие курсы и свечи получать по сокетам без ограничений вообще - остается только управлять выставлением ордеров. Более того, по сокетам можно и обновления по своим ордерам получать. В общем, при грамотной архитектуре взаимодейтсвия бана не будет и при сотне клиентов с одного IP
16.11.2018 10:11
Доброго времени суток!
У меня при выполнении:
new_order = bot.createOrder(
                                       symbol=pair,
                                       recvWindow=15000,
                                       side='SELL',
                                       type='LIMIT',
                                       quantity="{quantity:0.{precision}f}".format(quantity=my_amount, precision=CURR_LIMITS['baseAssetPrecision']),
                                       price="{price:0.{precision}f}".format(price=0.01, precision=CURR_LIMITS['baseAssetPrecision']),
                                       newOrderRespType='FULL')

Вылетает ошибка:
2018-11-16 13:16:48,274 [ERROR] Timeout value connect was quantity=0.16000000&price=0.01000000&recvWindow=15000&newOrderRespType=FULL&side=SELL&symbol=LTCBTC&timestamp=1542363406000&type=LIMIT&signature=8d859dc16d56a4de0c60c14dd2a7860ded374f7d5724838793b72c6f4063cbec, but it must be an int, float or None.
Traceback (most recent call last):
  File "C:\Python35\lib\site-packages\urllib3\util\timeout.py", line 124, in _validate_timeout
    float(value)
ValueError: could not convert string to float: 'quantity=0.16000000&price=0.01000000&recvWindow=15000&newOrderRespType=FULL&side=SELL&symbol=LTCBTC&timestamp=1542363406000&type=LIMIT&signature=8d859dc16d56a4de0c60c14dd2a7860ded374f7d5724838793b72c6f4063cbec'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Users\uia\Desktop\infoB\MACD_bot.py", line 882, in <module>
    newOrderRespType='FULL')
  File "C:\Users\uia\Desktop\infoB\binance_api.py", line 52, in wrapper
    return self.call_api(**kwargs)
  File "C:\Users\uia\Desktop\infoB\binance_api.py", line 82, in call_api
    response = requests.request(method=self.methods[command]['method'], url=api_url, data="", timeout=30 if self.methods[command]['method'] == 'GET' else payload_str, headers=headers)
  File "C:\Python35\lib\site-packages\requests\api.py", line 60, in request
    return session.request(method=method, url=url, **kwargs)
  File "C:\Python35\lib\site-packages\requests\sessions.py", line 533, in request
    resp = self.send(prep, **send_kwargs)
  File "C:\Python35\lib\site-packages\requests\sessions.py", line 646, in send
    r = adapter.send(request, **kwargs)
  File "C:\Python35\lib\site-packages\requests\adapters.py", line 435, in send
    timeout = TimeoutSauce(connect=timeout, read=timeout)
  File "C:\Python35\lib\site-packages\urllib3\util\timeout.py", line 94, in __init__
    self._connect = self._validate_timeout(connect, 'connect')
  File "C:\Python35\lib\site-packages\urllib3\util\timeout.py", line 127, in _validate_timeout
    "int, float or None." % (name, value))
ValueError: Timeout value connect was quantity=0.16000000&price=0.01000000&recvWindow=15000&newOrderRespType=FULL&side=SELL&symbol=LTCBTC&timestamp=1542363406000&type=LIMIT&signature=8d859dc16d56a4de0c60c14dd2a7860ded374f7d5724838793b72c6f4063cbec, but it must be an int, float or None.

Уже всю голову сломал - в чём может быть проблема?</module>
16.11.2018 10:40
Разобрался
18.11.2018 20:21
Андрей К. спасибо за отличную инструкцию) Только ей и пользуюсь. 
Есть вопрос. Существует ли вообще способ, вытащить с биржи объёмы покупок и объёмы продаж (по конкретной паре) за временной промежуток меньше минуты? то есть, некий аналог метода klines, но для времени меньше минуты?
18.11.2018 20:51
Нет, надо самому накапливать, через сокеты ну или обычные запросы в цикле
11.12.2018 05:37
Андрей доброго времени суток
Выходит вот такая ошибка 

2018-12-11 14:42:06,744 [ERROR] 'stepSize'
Traceback (most recent call last):
  File "./binance_bot.py", line 455, in <module>
    my_amount = adjust_to_step(pair_obj['spend_sum']/ my_need_price, CURR_LIMITS['filters'][1]['stepSize'])
KeyError: 'stepSize'

вот полный лог  
2018-12-11 14:44:56,707 [DEBUG] 
    Текущее время: 2018-12-11 14:44:55 1544507095
    Время сервера: 2018-12-11 14:44:57 1544507097
    Разница: 2.00000000 
    Бот будет работать, как будто сейчас: 2018-12-11 14:44:57 1544507097

2018-12-11 14:44:56,710 [DEBUG] Получаем все неисполненные ордера по БД
2018-12-11 14:44:56,710 [DEBUG] Неисполненных ордеров в БД нет
2018-12-11 14:44:56,711 [DEBUG] Получаем из настроек все пары, по которым нет неисполненных ордеров
2018-12-11 14:44:56,711 [DEBUG] Найдены пары, по которым нет неисполненных ордеров: ['BTCUSDT', 'NEOUSDT']
2018-12-11 14:44:56,712 [DEBUG] Работаем с парой BTCUSDT
2018-12-11 14:44:56,714 [DEBUG] Starting new HTTPS connection (1): api.binance.com:443
2018-12-11 14:44:57,878 [DEBUG] https://api.binance.com:443 "GET /api/v3/account?timestamp=1544507097000&signature=f5f9eac5713109a0d89d3f00dff70d6cfd3cdb9d27ce993baccd9f571963aeed HTTP/1.1" 200 None
2018-12-11 14:44:57,880 [DEBUG] Баланс ['BTC:0.00268876', 'USDT:30.20181458']
2018-12-11 14:44:57,882 [DEBUG] Starting new HTTPS connection (1): api.binance.com:443
2018-12-11 14:44:58,887 [DEBUG] https://api.binance.com:443 "GET /api/v1/depth?symbol=BTCUSDT&limit=5 HTTP/1.1" 200 None
2018-12-11 14:44:58,889 [ERROR] 'stepSize'
Traceback (most recent call last):
  File "./binance_bot.py", line 455, in <module>
    my_amount = adjust_to_step(pair_obj['spend_sum']/ my_need_price, CURR_LIMITS['filters'][1]['stepSize'])
KeyError: 'stepSize'</module></module>
11.12.2018 07:41
Здравствуйте,
Скачайте обновленную версию бота
19.12.2018 23:22
Скажите, я правильно понимаю?
Если при запросе к /api/v1/klines, данных больше, чем limit, то биржа возвращает часть запрашиваемых данных, начиная со startTime. Т.е. последние данные не возвращаются!
А /api/v1/aggTrades возвращает последние данные? Т.е. наоборот?! В документации ничего не сказано об этом.

Как в таком случае получить все данные, допустим, за месяц? Особенно, если хочется получать их в порядке от startTime, до endTime?
Надо как-то получить id первого трейда, в моем временном диапазоне?!
Как это правильнее сделать? Можно получить все трейды за одну секунду? Но возможно так, что в эту секунду не было трейдов (из-за малой ликвидности или биржа просто упала).
Что посоветуете?
20.12.2018 13:40
Во-первых, свечи это свечи а торги это торги - это в принципе разные наборы данных.
Всегда можно заранее посчитать, сколько минутных или там часовых свечей будет или было на интервале.
С торгами тоже не так сложно, сначала получить торги на нужном интервале, узнать минимальный First tradeId, после чего получать торги с параметром fromId (без времени) пачками по 1000 шт, до тех пор, пока время исполнения этих торгов не превысит максимальное.
20.12.2018 14:01
Окей, опустим случай, когда на каком-то промежутке времени может не быть трейдов.
Тогда получаем один последний трейд, который предшествует моему startTime и берем его Aggregate tradeId. А потом получаем все трейды после нашего Aggregate tradeId.
Только я не понял причем тут First tradeId? Если я правильно понимаю, то это ссылка на обычные (не агрегированные) трейды. Мне они не нужны. Или не так?
20.12.2018 14:48
Это сами решайте, что вам нужно а что нет.
Я ответил вот на эти вопросы
>>> Как в таком случае получить все данные, допустим, за месяц? Особенно, если хочется получать их в порядке от startTime, до endTime?
18.02.2019 07:05
Добрый день! Спасибо за то, что выкладываете такие полезные материалы. Я только только начал изучение Python с его практическим применением в криптотрейдинге. Написал свою первую "программу"

import calendar
import time
import datetime

print("Введите год:")
a = int(input())

print("Введите месяц:")
b = int(input())

print("Введите дату:")
c = int(input())

d_now = datetime.datetime(a, b, c)

endTimeR = calendar.timegm(d_now.timetuple()) - 86400
startTimeR = calendar.timegm(d_now.timetuple()) - 1

endDate = time.ctime(endTimeR)
startDate = time.ctime(startTimeR)

endTimeRR = endTimeR * 1000
startTimeRR = startTimeR * 1000 - 1

print("Ваш startTime:", endTimeRR, "Ваш startDate:", endDate
      )

print("Ваш endTime:", startTimeRR, "Ваш endDate:", startDate
      )

Она рассчитывает количество секунд от начала эпохи за предыдущий вводу день. Подскажите пожалуйста как ее правильно внедрить в ваш скрипт. Такая конструкция не работает(( Выдает пустое значение klines [] https://s.mail.ru/MjUj/yBSJ7oEF8 

import calendar
import time
import datetime

from binance_api import Binance
bot = Binance(
    API_KEY='z1sw***zrE',
    API_SECRET='Svs***IpPL'
)

print("Введите год:")
a = int(input())

print("Введите месяц:")
b = int(input())

print("Введите дату:")
c = int(input())

d_now = datetime.datetime(a, b, c)

endTimeR = calendar.timegm(d_now.timetuple()) - 86400
startTimeR = calendar.timegm(d_now.timetuple()) - 1

endDate = time.ctime(endTimeR)
startDate = time.ctime(startTimeR)

endTimeRR = endTimeR * 1000
startTimeRR = startTimeR * 1000 - 1

print('klines', bot.klines(
    symbol='ELFBTC',
    interval='1d',
    startTime=startTimeRR,
    endTime=endTimeRR,
    limit=1
))
18.02.2019 12:42
Полученные даты вы можете смотреть например тут https://www.unixtimestamp.com/index.php
Вводите свои данные в поле Enter a Timestamp (например endTimeRR), и смотрите, какое время получилось
endTimeRR раньше чем startTimeRR  - должно быть наоборот
Ну и разница в секунду, а вы запрашиваете суточные свечи, оно может и будет работать но есть сомнения в правильности такого решения
18.02.2019 13:20
Спасибо!!!
06.03.2019 07:26
Почему получаю ошибку при запросе истории вывода? Спасибо
Traceback (most recent call last):
  File "C:\Users\-\Desktop\1.py", line 6, in <module>
    print(bot.withdrawFee(asset='BTC'))
  File "C:\Users\-\Desktop\binance_api.py", line 52, in wrapper
    return self.call_api(**kwargs)
  File "C:\Users\-\Desktop\binance_api.py", line 82, in call_api
    return response.json()
  File "C:\Users\-\AppData\Local\Programs\Python\Python36\lib\site-packages\requests\models.py", line 897, in json
    return complexjson.loads(self.text, **kwargs)
  File "C:\Users\-\AppData\Local\Programs\Python\Python36\lib\json\__init__.py", line 354, in loads
    return _default_decoder.decode(s)
  File "C:\Users\-\AppData\Local\Programs\Python\Python36\lib\json\decoder.py", line 339, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
  File "C:\Users\-\AppData\Local\Programs\Python\Python36\lib\json\decoder.py", line 357, in raw_decode
    raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)</module>
10.03.2019 14:57
Оказывается, поменялись методы, теперь withdrawFee не существует, зато добавились 

print(bot.tradeFee())
print(bot.assetDetail())

Я обновил код, скопируйте по новой
07.03.2019 19:58
Как-то смутно понимаю в чем разница между StopLoss и TakeProfit ордерами. Оба могут же купить\продать при достижении stopPrice?
Я правильно понимаю следующие?
StopLoss купит\продаст, когда цена упадет до\ниже stopPrice? Т.е. stopPrice должен быть меньше текущей цены (иначе сразу сработает).
TakeProfit купит\продаст, когда цена поднимется до\выше stopPrice? Т.е. stopPrice должен быть выше текущей цены (иначе сразу сработает).
10.03.2019 14:29
Ну в общем да, когда last price на бирже достигнет stop price, будет выставлен ордер, либо по рынку, либо по указанной цене, если выбран лимит.
Насчет почему так не знаю, это не они придумали (
Наверное не самая удачная терминология, более того, если играть на понижение то takeProfit`ом станет падение цены а не её рост а stopLoss как раз должен будет работать в случае роста - иначе будут убытки.
09.04.2019 15:30
Не, не правильно я понимал. Если сейчас я все правильно понял, то оно должно работать по следующим правилам:
if StopLoss && Buy then триггер срабатывает, когда цена > текущей (цена выросла)
if StopLoss && Sell then триггер срабатывает, когда цена < текущей (цена упала)
if TakeProfit && Buy then триггер срабатывает, когда цена < текущей (цена упала)
if TakeProfit && Sell then триггер срабатывает, когда цена > текущей (цена выросла)
11.04.2019 07:11
Если сейчас курс 100, и вы выставляете тейт-профит со стоп-ценой 103 и ценой 105, то 
1. У вас не выставляется ордер, у вас появляется указание начать торговать когда цена достигнет 103
2. Когда и если цена достигает 103 (стоп-цена), выставляется обычный лимитный ордер (и попадает в стакан) с ценой 105.

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

Вы можете подробнее узнать тут https://support.binance.com/hc/en-us/articles/115003372072-How-to-use-Stop-Limit-Function
02.04.2019 21:45
Прощу прощения, наверно глупый вопрос. У меня никак не получается перевести время в милисекундах. в человеческую форму. От какого времени эти милисекунды отсчитываются?

Спасибо
03.04.2019 11:33
От первого января 1970 года.
Но вам не надо самому пересчитывать, т.к. там есть часовые пояса, коррекционные секунды и т.п., лучше взять готовый метод и пересчитать в нём
Если хотите посмотреть глазами, можно сделать на этом сайте https://www.unixtimestamp.com/, только дату от бинанса нужно будет разделить на 1000
Если локально, в коде, то вот пример

>>> from datetime import datetime
>>> print(datetime.fromtimestamp(1554291055))
2019-04-03 14:30:55
03.04.2019 14:25
Спасибо за ответ! 

А как конвертировать время в ответе от :

from binance_api import Binance
bot = Binance(
    API_KEY='D7...Ejj',
    API_SECRET='gwQ...u3A'
)
print('trades', bot.trades(
    symbol='BNBBTC',
    limit=1
))

?
03.04.2019 16:26
Так же

from datetime import datetime
from binance_api import Binance

bot = Binance(
    API_KEY='D7...Ejj',
    API_SECRET='gwQ...u3A'
)
for trade in bot.trades(symbol='BNBBTC', limit=1):
     print(datetime.fromtimestamp(trade['time']//1000), trade)
17.04.2019 10:20
Приветствую! Друзья, подскажите пожалуйста:
     my = bot.trades(symbol='BNBBTC', limit=1)
     print(my)
Тут на выходе в переменной my у нас получается следующее:
     [{'id': 42225656, 'price': '0.00378370', 'qty': '268.24000000', 'quoteQty': '1.01493968', 'time': 1555496218647, 'isBuyerMaker': False, 'isBestMatch': True}]
Как я могу получить доступ, например отдельно к цене и записать ее значение в переменную?
18.04.2019 10:42
my = bot.trades(symbol='BNBBTC', limit=1)
print(my) #все записи
print(my[0]) #Одна запись, первая

first_record = my[0] # Для удобства
print("qty", first_record['qty'])
myQuoteQty = first_record['quoteQty']
print(myQuoteQty)
price = first_record['price']
price_as_float = float(first_record['price'])
print(price, price_as_float)

Обратите внимание, что  '0.00378370' в кавычках, это значит что это - строка. Строку нельзя делить, прибавлять числа и т.п. 
Что бы можно было использовать строку как число, используйте float(), в примере выше это есть
13.06.2019 11:25
Добрый день!
Не могу понять почему выдает ошибку:

Traceback (most recent call last):
  File "C:\Users\ermakov\Desktop\БОТ\ban.py", line 1, in <module>
    from binance_api import Binance
  File "C:\Users\ermakov\Desktop\БОТ\binance_api.py", line 5, in <module>
    import requests
ModuleNotFoundError: No module named 'requests'

Ставлю этот код:

from binance_api import Binance
bot = Binance(
    API_KEY='D7...Ejj',
    API_SECRET='gwQ...u3A'
)
print('account', bot.account())

</module></module>
13.06.2019 12:18
Разобрался!
16.08.2019 02:46
Ребятушки Бинанс изменил условия API, теперь надо recvWindow = 6000 вместо recvWindow = 5000 
Куда прописатьв скрипт API Binance? чтобы не прописывать в каждый ордер?
17.08.2019 07:45
Если не указывать его вообще, то берется значение по умолчанию (5000, не смог найти упоминание про 6000)
Максимальное значение теперь 60 000, раньше можно было любое
recvWindow cannot exceed 60000.
В скрипт можно прописать ну примерно так, после строки 
payload.update({'timestamp': int(time.time() + self.shift_seconds - 1) * 1000})
добавить такую же
payload.update({'recvWindow ': 6000})
тогда это будет работать для подписанных запросов
17.08.2019 11:00
так не работает, выдает ошибку
{"code":-1104,"msg":"Not all sent parameters were read; read '2' parameter(s) but was sent '3'."}
17.08.2019 11:02
помогает если в коде бота прописать :
bot.createOrder(
                symbol=self.symbol,
                recvWindow=60000,
                side='BUY',
                type='LIMIT',
 и 
 bot.account(recvWindow=60000)
17.08.2019 15:52
Так зачем его вообще прописывать? Оно не везде требуется
Уберите его и будет работать
А если не будет, то нужно синхронизировать своё время с мировым
16.08.2019 08:54
2019-08-16
In Q4 2017, the following endpoints were deprecated and removed from the API documentation. They have been permanently removed from the API as of this version. We apologize for the omission from the original changelog:

GET api/v1/order
GET api/v1/openOrders
POST api/v1/order
DELETE api/v1/order
GET api/v1/allOrders
GET api/v1/account
GET api/v1/myTrades
Streams, endpoints, parameters, payloads, etc. described in the documents in this repository are considered official and supported. The use of any other streams, endpoints, parameters, or payloads, etc. is not supported; use them at your own risk and with no guarantees.
17.08.2019 07:13
Этими методами мы и не пользовались вроде, они, судя по описанию, устарели еще до полноценного запуска биржи )
Но тем не менее спасибо, информация важная
21.09.2019 08:54
в коде ошибка в тайм штампе

    def timepi(self):
        return int(int(requests.get('https://api.binance.com/api/v1/time').json()['serverTime'])-time.time()*1000)
        .......................
            payload.update({'timestamp': int((time.time()*1000)+self.timepi())})

так небудет ошибки
24.09.2019 09:05
Ошибка не в таймстампе, а в синхронизации времени.
Если посмотреть код бота (https://bablofil.ru/bot-dlya-binance/), то он на старте берет время с сервера, корректирует его через метод set_shift_seconds, и дальше работает со сдвигом относительно биржи.
Но если системное время все время расходится с мировым (а это часто бывает, особенно на Windows), то имеет смысл либо время от времени корректировать это расхождение, либо да, пользоваться вашим решением (но понимать, что с каждым запросом к API происходит еще одно обращение, уменьшая лимиты и немного увеличивая время работы запросов)
04.12.2019 14:24
Отличный робот, спасибо большое.
Подскажите, плз что здесь надо изменить для создания маржинального ордера, может ещё какойто параметр?

bot.createOrder(
    symbol='LTCUSDT',
    recvWindow=5000,
    side='BUY',
    type='LIMIT',
    timeInForce='GTC',
    quantity=1,
    price=50
)
07.12.2019 13:39
Для маржинального другая команда, не createOrder а marginCreateOrder, а так параметры все правильные, вроде
06.02.2020 18:09
Андрей, можно ли отвязаться от локального времени ПК?
Тоже получал на bot.account()  -  {'code': -1021, 'msg': "Timestamp for this request was 1000ms ahead of the server's time."}
и на bot.accountStatus()  -  {'msg': 'Timestamp for this request is outside of the recvWindow.', 'success': False}
Решилось подкручиванием вручную на +5сек от реального, но со временем может получиться что Бот встанет из-за рассинхронизации времени.
06.02.2020 18:15
Вот опять.... подкучиваю.
06.02.2020 19:47
Видимо у Винды точность синхронизации - минута.
Установил SP TimeSync посмотрим будут ли ошибки.
Возможно все-таки прийдется в каждом вызове указывать параметр recvWindow - минуту, две:
      #print(bot.depositHistory())
      print(bot.depositHistory(recvWindow=100000))
Или написать класс-обвертку, который будет подставлять recvWindow автоматом.
06.02.2020 19:58
Сервер сказал, что recvWindow - может быть максимум 60000.
Точного времени все-равно не хватает уложиться в 5000, поэтому по-любому recvWindow=60000
07.02.2020 05:56
Так же насколько я понимаю в "def __init__(self, API_KEY, API_SECRET)" можно подкрутить:
        self.shift_seconds = 0
01.03.2020 09:02
А вы давно бота скачивали?
В этом боте есть второй независимый поток, который время от времени берет время с биржи и корректирует локальное в боте
https://bablofil.ru/bot-dlya-binance-s-indikatorami/
Даже если пользуетесь другим, можете посмотреть как там код написан
07.02.2020 06:14
Андрей, можно Вас попросить показать на примерах для "тупеньких" как отпралять запросы GET POST без наворотов, как в Вашем binance_api.py.   Возможно это мне ничего не даст как другим на практике, но возможно что-то даст для понимания.   Поскольку глядя на Ваш код в общем понятно, что получаются аргументы, потом парсятся, потом еще что-то, потом передается в request.   Но я не могу всё это дешифровать в простой вид.   Спасибо!
01.03.2020 09:05
Да, хорошо, я постараюсь отдельную статью подготовить, пошаговую
26.02.2020 14:09
Конвертация миллисекунд в datetime:

import datetime

milliseconds = 1581714066222
dt=datetime.datetime.fromtimestamp( milliseconds/1000 )                  
print( dt )                                                            # '2020-02-15 00:01:06.222000'
print( dt.strftime("%B %d, %Y %I:%M:%S") )    # 'February 14, 2020 11:01:06'
19.03.2020 19:28
Добрый день! Подскажите, пожалуйста: Пытаюсь использовать Ваш бот в сфере маржинальной торговли. Обычные команды для спотовой работают (ордера не пытался открыть, но та же функция account() работает). А с маржинальной получается вот что:

bot = Binance(
    API_KEY='***',
    API_SECRET='***'
)
bot.marginAccount()

Выдаёт ошибку:
{"code":-1000,"msg":"An unknown error occurred while processing the request."}

Маржинальную торговлю разрешил. Забросил туда доллар.
Заранее спасибо!
19.03.2020 21:45
Этот, кстати, работает (https://python-binance.readthedocs.io/en/latest/overview.html). Но моих знаний пока не хватает, чтобы разобрать разницу :(
12.04.2020 17:28
А тут все просто, Владимир. Нужно просто заменить POST на GET в исходном коде.
Не знаю как сюда выложить этот кусок кода, фото тоже не вставляет. Вобщем, вот ссыль:
https://skr.sh/s1ea2bqpGuv?a
13.04.2020 14:14
А вот это я не могу понять.

tt = bot.marginTransfer(
    asset=spot_wall['asset'],
    amount=1.000,
    recvWindow=5000,
    type=1)
Вобщем, пытаюсь перебросить валюту со спотового кошелька на маржинальный.
А Бинанс мне такой: "code":-1002,"msg":"You are not authorized to execute this request."
Т.е. он мне говорит, что у меня нет АПИ ключей и предлагает их прикрепить к запросу?
Они есть. Все запросы выполняются. Ну кроме этого.
27.04.2020 22:30
Всем доброго времени суток! Подскажите, пожалуйста, как получить данные по свечам с Бинанс Фьючерс. Заранее благодарю!
17.08.2020 16:59
Автору нудно двигаться дальше - статьи по API к ММВБ (Тинькоф и тд), к Yahoo Finance и тд.
23.08.2020 18:15
а можно на бинансе по этому подобию сделать?
# -*- coding: utf-8 -*-
import sys
import http.client
import urllib
import json
import hashlib
import hmac
import time

class ExmoAPI:
    def __init__(self, API_KEY, API_SECRET, API_URL = 'api.exmo.me', API_VERSION = 'v1'):
        self.API_URL = API_URL
        self.API_VERSION = API_VERSION
        self.API_KEY = ''
        self.API_SECRET = bytes('')

    def sha512(self, data):
        H = hmac.new(key = self.API_SECRET, digestmod = hashlib.sha512)
        H.update(data.encode('utf-8'))
        return H.hexdigest()

    def api_query(self, api_method, params = {}):
        params['nonce'] = int(round(time.time() * 1000))
        params =  urllib.parse.urlencode(params)

        sign = self.sha512(params)
        headers = {
            "Content-type": "application/x-www-form-urlencoded",
            "Key": self.API_KEY,
            "Sign": sign
        }
        conn = http.client.HTTPSConnection(self.API_URL)
        conn.request("POST", "/" + self.API_VERSION + "/" + api_method, params, headers)
        response = conn.getresponse().read()

        conn.close()

        obj = json.loads(response) # .decode('utf-8'))
        return obj

ExmoAPI_instance = ExmoAPI('YOUR API KEY', 'YOUR API SECRET')
14.04.2021 12:33
Как при помощи marginCreateOrder создать ордер на покупку с плечом x20???
19.06.2021 13:31
Админ добавь в статью, чтобы скрипт работал, необходима библиотека pip install python-binance , даже стандартный скрипт, выдает ошибку пока библиотеку не установишь
05.07.2021 19:58
Какую ошибку? Для работы достаточно кода, указанного в статье, или его более поздней версии 
https://github.com/Bablofil/binance-api/blob/master/binance_api.py
02.09.2021 09:28
Добрый день. Подскажите пожалуйста, как это все подключить к тестовой сети binance? Не первую неделю ищу ответы) Хотелось бы протестировать бота не на реальных деньгах. Вот код подключения к тестовой сети (работает)


# Загрузка ключей из файла config
config = configparser.ConfigParser()
config.read_file(open(r'D:/проекты/криптобот/secret.cfg'))
test_api_key = config.get('BINANCE', 'TEST_API_KEY')
test_secret_key = config.get('BINANCE', 'TEST_SECRET_KEY')

client = Client(test_api_key, test_secret_key)

client.API_URL = 'https://testnet.binance.vision/api

 Но как правильно изменить url в вашем коде (binance_api.py) на тестовый не пойму т.к. в программировании почти 0. 

Буду благодарен любой помощи! Спасибо.
Пожалуйста, Авторизуйтесь что бы оставить свой комментарий