Skip to content

Commit e322e5e

Browse files
committed
basic bot: add real-time price trailer (task) that keeps bid price 0.0005% below last clear value
1 parent de87b5c commit e322e5e

File tree

1 file changed

+92
-10
lines changed

1 file changed

+92
-10
lines changed

examples/basic_order_bot.py

Lines changed: 92 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,29 @@
1+
from pprint import pformat
2+
from functools import partial
3+
from decimal import Decimal
4+
from typing import Callable
5+
16
import tractor
27
import trio
38
from uuid import uuid4
49

10+
from piker.accounting import dec_digits
511
from piker.clearing import (
612
open_ems,
713
OrderClient,
814
)
9-
1015
# TODO: we should probably expose these top level in this subsys?
1116
from piker.clearing._messages import (
1217
Order,
1318
Status,
1419
BrokerdPosition,
1520
)
21+
from piker.data import (
22+
Flume,
23+
open_feed,
24+
Feed,
25+
ShmArray,
26+
)
1627

1728

1829
async def wait_for_order_status(
@@ -66,25 +77,24 @@ async def bot_main():
6677

6778
ll: str = 'info'
6879

69-
# open an order ctl client
80+
# open an order ctl client, live data feed, trio nursery for
81+
# spawning an order trailer task
7082
client: OrderClient
7183
trades_stream: tractor.MsgStream
84+
feed: Feed
7285
accounts: list[str]
7386

7487
fqme: str = 'btcusdt.usdtm.perp.binance'
7588

7689
async with (
7790

91+
# TODO: do this implicitly inside `open_ems()` ep below?
7892
# init and sync actor-service runtime
7993
maybe_open_pikerd(
8094
loglevel=ll,
81-
debug_mode=False,
95+
debug_mode=True,
8296

8397
),
84-
tractor.wait_for_actor(
85-
'pikerd',
86-
),
87-
8898
open_ems(
8999
fqme,
90100
mode='paper', # {'live', 'paper'}
@@ -97,14 +107,81 @@ async def bot_main():
97107
_, # positions
98108
accounts,
99109
_, # dialogs
100-
)
110+
),
111+
112+
open_feed(
113+
fqmes=[fqme],
114+
loglevel=ll,
115+
116+
# TODO: if you want to throttle via downsampling
117+
# how many tick updates your feed received on
118+
# quote streams B)
119+
# tick_throttle=10,
120+
) as feed,
121+
122+
trio.open_nursery() as tn,
101123
):
102124
print(f'Loaded binance accounts: {accounts}')
103125

104-
price: float = 30e3 # non-clearable
126+
flume: Flume = feed.flumes[fqme]
127+
min_tick = Decimal(flume.mkt.price_tick)
128+
min_tick_digits: int = dec_digits(min_tick)
129+
price_round: Callable = partial(
130+
round,
131+
ndigits=min_tick_digits,
132+
)
133+
134+
quote_stream: trio.abc.ReceiveChannel = feed.streams['binance']
135+
136+
137+
clear_margin: float = 0.9995
138+
139+
async def trailer(
140+
order: Order,
141+
):
142+
# ref shm OHLCV array
143+
s_shm: ShmArray = flume.rt_shm
144+
m_shm: ShmArray = flume.hist_shm
145+
146+
# NOTE: if you wanted to frame ticks by type like the
147+
# the quote throttler does.
148+
# from piker.data._sampling import frame_ticks
149+
150+
async for quotes in quote_stream:
151+
for fqme, quote in quotes.items():
152+
for tick in quote.get('ticks', ()):
153+
print(
154+
f'{fqme} ticks:\n{pformat(tick)}\n\n'
155+
f'last 1s OHLC:\n{s_shm.array[-1]}\n'
156+
f'last 1m OHLC:\n{m_shm.array[-1]}\n'
157+
)
158+
159+
# always keep live limit 2% below last
160+
# clearing price
161+
if tick['type'] == 'trade':
162+
await client.update(
163+
uuid=order.oid,
164+
price=price_round(
165+
clear_margin
166+
*
167+
tick['price']
168+
),
169+
)
170+
msgs, pps = await wait_for_order_status(
171+
trades_stream,
172+
oid,
173+
'open'
174+
)
175+
176+
177+
# setup order dialog via first msg
105178
size: float = 0.01
179+
price: float = price_round(
180+
clear_margin
181+
*
182+
flume.first_quote['last']
183+
)
106184
oid: str = str(uuid4())
107-
108185
order = Order(
109186
exec_mode='live', # {'dark', 'live', 'alert'}
110187
action='buy', # TODO: remove this from our schema?
@@ -116,6 +193,7 @@ async def bot_main():
116193
price=price,
117194
brokers=['binance'],
118195
)
196+
119197
await client.send(order)
120198

121199
msgs, pps = await wait_for_order_status(
@@ -127,6 +205,9 @@ async def bot_main():
127205
assert not pps
128206
assert msgs[-1].oid == oid
129207

208+
# start "trailer task" which tracks rt quote stream
209+
tn.start_soon(trailer, order)
210+
130211
try:
131212
# wait for ctl-c from user..
132213
await trio.sleep_forever()
@@ -138,6 +219,7 @@ async def bot_main():
138219
oid,
139220
'canceled'
140221
)
222+
raise
141223

142224

143225
if __name__ == '__main__':

0 commit comments

Comments
 (0)