Skip to content

Commit 753c06f

Browse files
author
Sam McHardy
committed
Add aggregate trade iterator and documentation
1 parent 70e459b commit 753c06f

3 files changed

Lines changed: 114 additions & 0 deletions

File tree

binance/client.py

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,16 @@ class Client(object):
6363
ORDER_RESP_TYPE_RESULT = 'RESULT'
6464
ORDER_RESP_TYPE_FULL = 'FULL'
6565

66+
# For accessing the data returned by Client.aggregate_trades().
67+
AGG_ID = 'a'
68+
AGG_PRICE = 'p'
69+
AGG_QUANTITY = 'q'
70+
AGG_FIRST_TRADE_ID = 'f'
71+
AGG_LAST_TRADE_ID = 'l'
72+
AGG_TIME = 'T'
73+
AGG_BUYER_MAKES = 'm'
74+
AGG_BEST_MATCH = 'M'
75+
6676
def __init__(self, api_key, api_secret, requests_params=None):
6777
"""Binance API Client constructor
6878
@@ -565,6 +575,77 @@ def get_aggregate_trades(self, **params):
565575
"""
566576
return self._get('aggTrades', data=params)
567577

578+
def aggregate_trade_iter(self, symbol, start_str=None, last_id=None):
579+
"""Iterate over aggregate trade data from (start_time or last_id) to
580+
the end of the history so far.
581+
582+
If start_time is specified, start with the first trade after
583+
start_time. Meant to initialise a local cache of trade data.
584+
585+
If last_id is specified, start with the trade after it. This is meant
586+
for updating a pre-existing local trade data cache.
587+
588+
Only allows start_str or last_id—not both. Not guaranteed to work
589+
right if you're running more than one of these simultaneously. You
590+
will probably hit your rate limit.
591+
592+
See dateparser docs for valid start and end string formats http://dateparser.readthedocs.io/en/latest/
593+
594+
If using offset strings for dates add "UTC" to date string e.g. "now UTC", "11 hours ago UTC"
595+
596+
:param symbol: Symbol string e.g. ETHBTC
597+
:type symbol: str
598+
:param start_str: Start date string in UTC format. The iterator will
599+
return the first trade occurring later than this time.
600+
:type start_str: str
601+
:param last_id: aggregate trade ID of the last known aggregate trade.
602+
Not a regular trade ID. See https://github.com/binance-exchange/binance-official-api-docs/blob/master/rest-api.md#compressedaggregate-trades-list.
603+
604+
:returns: an iterator of JSON objects, one per trade. The format of
605+
each object is identical to Client.aggregate_trades().
606+
607+
:type last_id: int
608+
"""
609+
if start_str is not None and last_id is not None:
610+
raise ValueError(
611+
'start_time and last_id may not be simultaneously specified.')
612+
613+
# If there's no last_id, get one.
614+
if last_id is None:
615+
# Without a last_id, we actually need the first trade. Normally,
616+
# we'd get rid of it. See the next loop.
617+
if start_str is None:
618+
trades = self.get_aggregate_trades(symbol=symbol, fromId=0)
619+
else:
620+
# It doesn't matter what the end time is, as long as it's less
621+
# than a day and the result set contains at least one trade.
622+
# A half a day should be fine.
623+
start_ts = date_to_milliseconds(start_str)
624+
trades = self.get_aggregate_trades(
625+
symbol=symbol,
626+
startTime=start_ts,
627+
endTime=start_ts + (1000 * 3600))
628+
for t in trades:
629+
yield t
630+
last_id = trades[-1][self.AGG_ID]
631+
632+
while True:
633+
# There is no need to wait between queries, to avoid hitting the
634+
# rate limit. We're using blocking IO, and as long as we're the
635+
# only thread running calls like this, Binance will automatically
636+
# add the right delay time on their end, forcing us to wait for
637+
# data. That really simplifies this function's job. Binance is
638+
# fucking awesome.
639+
trades = self.get_aggregate_trades(symbol=symbol, fromId=last_id)
640+
# fromId=n returns a set starting with id n, but we already have
641+
# that one. So get rid of the first item in the result set.
642+
trades = trades[1:]
643+
if len(trades) == 0:
644+
return
645+
for t in trades:
646+
yield t
647+
last_id = trades[-1][self.AGG_ID]
648+
568649
def get_klines(self, **params):
569650
"""Kline/candlestick bars for a symbol. Klines are uniquely identified by their open time.
570651

docs/constants.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,16 @@ Binance requires specific string constants for Order Types, Order Side, Time in
5050
ORDER_RESP_TYPE_RESULT = 'RESULT'
5151
ORDER_RESP_TYPE_FULL = 'FULL'
5252
53+
# For accessing the data returned by Client.aggregate_trades().
54+
AGG_ID = 'a'
55+
AGG_PRICE = 'p'
56+
AGG_QUANTITY = 'q'
57+
AGG_FIRST_TRADE_ID = 'f'
58+
AGG_LAST_TRADE_ID = 'l'
59+
AGG_TIME = 'T'
60+
AGG_BUYER_MAKES = 'm'
61+
AGG_BEST_MATCH = 'M'
62+
5363
5464
For Websocket Depth these are found on `binance.websockets.BinanceSocketManager`
5565

docs/market_data.rst

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,29 @@ Market Data Endpoints
3030
3131
trades = client.get_aggregate_trades(symbol='BNBBTC')
3232
33+
`Aggregate Trade Iterator <binance.html#binance.client.Client.aggregate_trade_iter>`_
34+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
35+
36+
Iterate over aggregate trades for a symbol from a given date or a given order id.
37+
38+
.. code:: python
39+
40+
agg_trades = client.aggregate_trade_iter(symbol='ETHBTC', start_str='30 minutes ago UTC')
41+
42+
# iterate over the trade iterator
43+
for trade in agg_trades:
44+
print(trade)
45+
# do something with the trade data
46+
47+
# convert the iterator to a list
48+
# note: generators can only be iterated over once so we need to call it again
49+
agg_trades = client.aggregate_trade_iter(symbol='ETHBTC', '30 minutes ago UTC')
50+
agg_trade_list = list(agg_trades)
51+
52+
# example using last_id value
53+
agg_trades = client.aggregate_trade_iter(symbol='ETHBTC', last_id=23380478)
54+
agg_trade_list = list(agg_trades)
55+
3356
3457
`Get Kline/Candlesticks <binance.html#binance.client.Client.get_klines>`_
3558
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

0 commit comments

Comments
 (0)