forked from dantimofte/aiokraken
-
Notifications
You must be signed in to change notification settings - Fork 0
/
example.py
203 lines (148 loc) · 7.34 KB
/
example.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
import time
from datetime import timedelta
from decimal import Decimal, localcontext, DefaultContext
import aiohttp
import asyncio
import signal
from aiokraken import Markets, Balance, OHLC
from aiokraken.utils import get_kraken_logger, get_nonce
from aiokraken.rest.api import Server, API
from aiokraken.rest.client import RestClient
from aiokraken.model.timeframe import KTimeFrameModel
LOGGER = get_kraken_logger(__name__)
# Stupid bot
@asyncio.coroutine
def ask_exit(sig_name):
print("got signal %s: exit" % sig_name)
yield from asyncio.sleep(1.0)
asyncio.get_event_loop().stop()
# TODO : related to the command design pattern?
# Ref for coroutine execution flow...
# https://stackoverflow.com/questions/30380110/mutually-recursive-coroutines-with-asyncio
# class Box:
#
# start: Event # an event is a signal that has been triggered: it has happened
# stop: Event
# low: decimal.Decimal
# high: decimal.Decimal
#
#
#
# def square_bull(ohlc: OHLC, start: Signal, stop: Signal):
#
# boxes = []
#
# # TODO : extract boxes from ohlc dataframe
#
#
# return boxes
async def basicbot(assets_allowed, assets_forbidden, markets_allowed, markets_forbidden, loop):
from aiokraken.config import load_api_keyfile
keystruct = load_api_keyfile()
# public
pub_client = RestClient(server=Server())
# TODO : use interface client (REST + WS) when ready
priv_client = RestClient(server=Server(
key=keystruct.get('key'),
secret=keystruct.get('secret')
))
markets = Markets(restclient = priv_client)
# Note : now that self.restclient has markets has trades and orders, we need to use private client...
markets.filter(whitelist=markets_allowed, blacklist=markets_forbidden)
balance = Balance(restclient = priv_client)
balance.filter(whitelist=assets_allowed, blacklist=assets_forbidden)
try:
# update the different markets to find suitable ones
await markets()
while True:
# get balance to find out tradable pairs
await balance()
print(balance)
# get tradable markets without leverage
tradables = {t: m for t, m in markets.details.items() if m.base in balance}
print(tradables)
flat_markets = list() # not interesting ones
for m, data in {m: d for m, d in markets.items() if m in tradables}.items():
# TODO : context manager for timeframe ?
mdata = await data(KTimeFrameModel.one_minute) # update at specific timeframe to find interesting markets
if (mdata.tf_ohlc[KTimeFrameModel.one_minute].high == mdata.tf_ohlc[KTimeFrameModel.one_minute].low):
# nothing happened there, drop it
print(f"{m} looks flat. Dropping it.")
flat_markets.append(m)
else:
# TODO : maybe check trend via open/close onf the whole ohlc ?
# TODO : maybe each strategy has its preconditions to validate before even attempting it...
pivot = mdata.tf_ohlc[KTimeFrameModel.one_minute].pivot(before=timedelta(days=1))
# TODO : maybe figure out best timeframe to compute resistance/ supports based on ohlc ???
print(f"Resistances / Supports for {m}: {pivot}")
# select markets based on pivot data:
if pivot.R1 - pivot.S1 < pivot.pivot * 0.0025: # check if the interval is bigger than fees
flat_markets.append(m)
print(f"{m} Support Resistance interval data too flat to cover fees. Dropping it.")
# TODO : put signals in place to re-add it to the list of interesting markets if interval increase...
else:
# TODO : maybe lazy update of data only when required ? how to keep managing async control ?
# Think multiple agents, one per strategy... ( can access one or more markets... )
# NB: they might use the (immutable or time-updated only -> deterministic) data,
# even if requested by another...
ohlc = mdata.tf_ohlc[KTimeFrameModel.one_minute].ema(name="EMA_12", length=12).ema(name="EMA_26", length=26)
# TODO : simplify accessor...
# get last EMA value
print(f" Last EMAs for {m}: {ohlc.indicators['ema'].model.timedataframe.iloc[-1]}")
# STRATEGIES
# Daytrade -> FIRST FOCUS : restart every night. no point in keeping data for long.
# TODO : adjust timeframe.
# Position -> NEXT
# swing -> later
# scalping -> later
# Day trading strats :
# - pivot / support / resistance DONE !
# - trend TODO
# - fibonnacci levels TODo
# - breakout https://tradingsim.com/blog/day-trading-breakouts/
# - reversal https://www.investopedia.com/terms/r/reversal.asp
# - momentum
# TODO : Automated trading plan https://www.investopedia.com/terms/t/trading-plan.asp
# Setup Tradesignals
#TODO
# if ohlc[m]
#
#
# def obv_crossover():
# raise NotImplementedError
#
# def r1_crossover():
# raise NotImplementedError
#
# ohlc[m].obv.crossover(obv_crossover)
# ohlc[m].R1.crossover(r1_crossover)
# Ref : https://tradingstrategyguides.com/best-bitcoin-trading-strategy/
# Ref : https://tradingstrategyguides.com/support-and-resistance-strategy/
# TODO: On combination of signal : setup orders + setup signals on order filled.
if flat_markets:
markets.filter(blacklist=flat_markets) # adding flat markets to blacklist for next loop
except Exception as e:
LOGGER.error(f"Exception caught : {e}. Terminating...", exc_info=True)
raise
# TODO : backtest on previous day before implementing on current day... => need candles from Day -2
# Goal : choose markets that are likely to be profitable (given fee calculations).
if __name__ == '__main__':
from configparser import ConfigParser
config = ConfigParser()
config.read("example.ini")
# TODO : simplified version that can be run anytime :
# check balance compared to config. propose buy/sell actions to user
# based on analysis since last time it was used.
loop = asyncio.get_event_loop()
for signame in ('SIGINT', 'SIGTERM'):
loop.add_signal_handler(
getattr(signal, signame),
lambda: asyncio.ensure_future(ask_exit(signame))
)
loop.run_until_complete(basicbot(
assets_allowed=config["assets"]['whitelist'].split(),
assets_forbidden=config["assets"]["blacklist"].split(),
markets_allowed=config["markets"]["whitelist"].split(),
markets_forbidden=config["markets"]["blacklist"].split(),
loop=loop
))