Skip to content

Commit 98bdb7d

Browse files
committed
v1.1.3 - Order book and trade history functions
- Added `order_history` and `get_orderbook` to `SteemEngineToken` for getting both historic, and currently open trades. - Created new data objects `SETrade` and `SEOrder` to represent the data returned by get_orderbook and order_history - `ObjBase` now aliases `__repr__()` to `__str__()` for child classes. - Updated documentation to show the new methods and objects.
1 parent 21d6ed0 commit 98bdb7d

9 files changed

+209
-3
lines changed

docs/source/code/privex.steemengine.SteemEngineToken.SteemEngineToken.rst

+2
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,13 @@ SteemEngineToken
1919
~SteemEngineToken.custom_beem
2020
~SteemEngineToken.find_steem_tx
2121
~SteemEngineToken.get_balances
22+
~SteemEngineToken.get_orderbook
2223
~SteemEngineToken.get_token
2324
~SteemEngineToken.get_token_balance
2425
~SteemEngineToken.issue_token
2526
~SteemEngineToken.list_tokens
2627
~SteemEngineToken.list_transactions
28+
~SteemEngineToken.order_history
2729
~SteemEngineToken.send_token
2830

2931

docs/source/code/privex.steemengine.objects.rst

+2
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ Data Objects (Token/SEBalance etc.)
1717
ObjBase
1818
SEBalance
1919
SETransaction
20+
SETrade
21+
SEOrder
2022
Token
2123
TokenMetadata
2224

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
SteemEngineToken.get\_orderbook
2+
===================================================================
3+
4+
.. currentmodule:: privex.steemengine.SteemEngineToken
5+
6+
.. automethod:: SteemEngineToken.get_orderbook
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
SteemEngineToken.order\_history
2+
===================================================================
3+
4+
.. currentmodule:: privex.steemengine.SteemEngineToken
5+
6+
.. automethod:: SteemEngineToken.order_history
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
objects.SEOrder
2+
==================================
3+
4+
.. currentmodule:: privex.steemengine.objects
5+
6+
.. autoclass:: SEOrder
7+
8+
9+
.. automethod:: __init__
10+
11+
12+
.. rubric:: Methods
13+
14+
.. autosummary::
15+
16+
~SEOrder.__init__
17+
~SEOrder.from_list
18+
19+
20+
21+
22+
23+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
objects.SETrade
2+
==================================
3+
4+
.. currentmodule:: privex.steemengine.objects
5+
6+
.. autoclass:: SETrade
7+
8+
9+
.. automethod:: __init__
10+
11+
12+
.. rubric:: Methods
13+
14+
.. autosummary::
15+
16+
~SETrade.__init__
17+
~SETrade.from_list
18+
19+
20+
21+
22+
23+

privex/steemengine/SteemEngineToken.py

+68-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from privex.jsonrpc import SteemEngineRPC
55
from privex.steemengine import exceptions
66
from privex.steemengine.SteemEngineHistory import SteemEngineHistory
7-
from privex.steemengine.objects import SEBalance, SETransaction, Token
7+
from privex.steemengine.objects import SEBalance, SETransaction, Token, SETrade, SEOrder
88
from privex.helpers import empty
99

1010
log = logging.getLogger(__name__)
@@ -198,6 +198,73 @@ def list_tokens(self, limit=1000, offset=0) -> List[Token]:
198198
limit=limit, offset=offset
199199
)))
200200

201+
def order_history(self, symbol, limit=30, offset=0, indexes: List[dict] = None) -> List[SETrade]:
202+
"""
203+
Get a list of recent Steem Engine orders for a given symbol.
204+
205+
**Example:**
206+
207+
>>> o = SteemEngineToken().order_history('ENG')
208+
>>> o[0]
209+
<SETrade type='buy' price='0.99' symbol='ENG' quantity='0.80405854'>
210+
>>> o[0].timestamp
211+
'2019-07-27 01:06:09'
212+
213+
:param str symbol: The symbol to get historic orders for
214+
:param int limit: Amount of orders to retrieve
215+
:param int offset: Offset selection by this many rows (for pagination)
216+
:param list indexes: A list of dictionary indexes, e.g. ``[dict(descending=False, index='timestamp')]``
217+
:return List[SETrade] orders: A list of :py:class:`.SETrade` objects
218+
"""
219+
indexes = [dict(descending=False, index='timestamp')] if empty(indexes) else indexes
220+
return list(SETrade.from_list(self.rpc.find(
221+
contract='market',
222+
table='tradesHistory',
223+
query=dict(symbol=symbol),
224+
indexes=indexes,
225+
limit=limit, offset=offset
226+
)))
227+
228+
def get_orderbook(self, symbol, direction='buy', user=None, limit=200, offset=0,
229+
indexes: list = None) -> List[SEOrder]:
230+
"""
231+
Get a list of open Steem Engine orders for a given symbol, by default will display ``'buy'`` orders unless
232+
you set ``direction`` to ``'sell'``
233+
234+
**Example:**
235+
236+
>>> o = SteemEngineToken().get_orderbook('ENG', direction='sell')
237+
>>> o[0]
238+
<SEOrder account='someguy123' price='0.99' symbol='ENG' quantity='885.40249121'>
239+
>>> str(o[0].timestamp)
240+
'2019-07-26 10:46:18'
241+
242+
243+
:param str symbol: The symbol to get the open orders for
244+
:param int limit: Amount of orders to retrieve
245+
:param int offset: Offset selection by this many rows (for pagination)
246+
:param list indexes: A list of dictionary indexes, e.g. ``[dict(descending=False, index='timestamp')]``
247+
:param str user: If ``None`` , get all orders, otherwise only get orders by this user. Default: ``None``
248+
:param str direction: The direction of orders to get, either ``buy`` or ``sell`` Default: ``buy``
249+
:return List[SEOrder] orders: A list of :py:class:`.SEOrder` objects
250+
"""
251+
direction = direction.lower()
252+
if direction not in ['buy', 'sell']:
253+
raise AttributeError('get_orderbook direction must be either "buy" or "sell"')
254+
255+
indexes = [dict(descending=direction == 'sell', index='price')] if empty(indexes) else indexes
256+
257+
q = dict(symbol=symbol)
258+
if not empty(user):
259+
q['account'] = user
260+
return list(SEOrder.from_list(self.rpc.find(
261+
contract='market',
262+
table=f'{direction.lower()}Book',
263+
query=q,
264+
indexes=indexes,
265+
limit=limit, offset=offset
266+
)))
267+
201268
def find_steem_tx(self, tx_data: dict, last_blocks=15) -> dict:
202269
"""
203270
Used internally to get the transaction ID after a Steem transaction has been broadcasted.

privex/steemengine/objects.py

+78-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
import json
2+
from datetime import datetime
23
from typing import Union, List, Generator
34
from decimal import Decimal
45
from privex.helpers import empty
56

7+
AnyNum = Union[Decimal, float, str]
8+
9+
610
class ObjBase:
711
"""
812
A base class to be extended by data storage classes, allowing their attributes to be
@@ -50,6 +54,10 @@ def from_list(cls, obj_list: List[dict]):
5054
for tx in obj_list:
5155
yield cls(**tx)
5256

57+
def __repr__(self):
58+
return self.__str__()
59+
60+
5361
class TokenMetadata(ObjBase):
5462
"""
5563
Represents the ``metadata`` field on a token object on SteemEngine
@@ -132,7 +140,6 @@ def __str__(self):
132140
return f"<SETransaction symbol='{self.symbol}' sender='{self.sender}' to='{self.to}' quantity='{self.quantity}'>"
133141

134142

135-
136143
class SEBalance(ObjBase):
137144
"""
138145
Represents an account token balance on SteemEngine
@@ -150,4 +157,74 @@ def __str__(self):
150157
return f"<SEBalance account='{self.account}' symbol='{self.symbol}' balance='{self.balance}'>"
151158

152159

160+
class SETrade(ObjBase):
161+
"""
162+
Represents a past trade on the SE market.
163+
164+
:ivar str symbol: The symbol this order is for
165+
:ivar Decimal quantity: The amount of tokens being bought/sold
166+
:ivar Decimal price: The price per token ( :py:attr:`.symbol` ) in STEEM
167+
:ivar datetime timestamp: The date/time which the order was placed
168+
:ivar str direction: The type of order as a string, either ``'buy'`` or ``'sell'``
169+
:ivar str type: Alias for ``direction`` - either ``'buy'`` or ``'sell'``
170+
"""
171+
172+
def __init__(self, symbol: str, quantity: AnyNum, price: AnyNum, timestamp: int, volume: AnyNum,
173+
direction: str = None, **kwargs):
174+
175+
direction = kwargs.get('type') if not direction else direction
176+
self.raw_data = {
177+
**kwargs,
178+
**dict(symbol=symbol, quantity=quantity, price=price, timestamp=timestamp,
179+
volume=volume, direction=direction)
180+
}
181+
self.volume = Decimal(volume)
182+
self.price = Decimal(price)
183+
self.quantity = Decimal(quantity)
184+
self.timestamp = datetime.utcfromtimestamp(int(timestamp))
185+
self.symbol = symbol.upper()
186+
self.direction = self.type = direction.lower()
187+
if self.type not in ['buy', 'sell']:
188+
raise AttributeError('SEOrder.type must be either buy or sell')
189+
190+
def __str__(self):
191+
return f"<SETrade type='{self.type}' price='{self.price}' symbol='{self.symbol}' quantity='{self.quantity}'>"
192+
193+
194+
class SEOrder(ObjBase):
195+
"""
196+
Represents an open order on the SE market.
197+
198+
:ivar str symbol: The symbol this order is for
199+
:ivar Decimal quantity: The amount of tokens being bought/sold
200+
:ivar Decimal price: The price per token ( :py:attr:`.symbol` ) in STEEM
201+
:ivar Decimal tokens_locked: The amount of STEEM locked into the order
202+
:ivar Decimal tokensLocked: Alias of ``tokens_locked``
203+
:ivar datetime timestamp: The date/time which the order was placed
204+
:ivar datetime expiration: ?????
205+
:ivar str account: The username of the person who placed the order
206+
:ivar str txid: The transaction ID of the order
207+
"""
208+
def __init__(self, symbol: str, quantity: AnyNum, price: AnyNum, timestamp: int, account: str, expiration: int,
209+
txid: str = None, tokens_locked: AnyNum = None, **kwargs):
210+
txid = kwargs.get('txId') if not txid else txid
211+
tokens_locked = kwargs.get('tokensLocked') if not tokens_locked else tokens_locked
212+
self.raw_data = {
213+
**kwargs,
214+
**dict(symbol=symbol, quantity=quantity, price=price, timestamp=timestamp, account=account,
215+
tokens_locked=tokens_locked, expiration=expiration, txid=txid)
216+
}
217+
self.tokens_locked = self.tokensLocked = None if not tokens_locked else Decimal(tokens_locked)
218+
self.price = Decimal(price)
219+
self.quantity = Decimal(quantity)
220+
self.timestamp = datetime.utcfromtimestamp(int(timestamp))
221+
self.expiration = datetime.utcfromtimestamp(int(expiration))
222+
self.symbol = symbol.upper()
223+
self.account = str(account).lower()
224+
self.txid = str(txid)
225+
226+
pass
227+
228+
def __str__(self):
229+
return f"<SEOrder account='{self.account}' price='{self.price}' symbol='{self.symbol}' quantity='{self.quantity}'>"
153230

setup.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
setup(
4343
name='privex_steemengine',
4444

45-
version='1.1.0',
45+
version='1.1.3',
4646

4747
description='A small library for querying and interacting with the SteemEngine network (https://steem-engine.com)',
4848
long_description=long_description,

0 commit comments

Comments
 (0)