]> git.immae.eu Git - perso/Immae/Projets/Cryptomonnaies/Cryptoportfolio/Trader.git/blob - script.py
Add order processing functions
[perso/Immae/Projets/Cryptomonnaies/Cryptoportfolio/Trader.git] / script.py
1 import ccxt
2 # Put your poloniex api key in market.py
3 from market import market
4
5 def static_var(varname, value):
6 def decorate(func):
7 setattr(func, varname, value)
8 return func
9 return decorate
10
11 max_digits = 18
12
13 repartition_pertenthousand = {
14 "BTC": 2857,
15 "ZEC": 3701,
16 "DOGE": 1805,
17 "DGB": 1015,
18 "SC": 623,
19 }
20
21
22 def formatted_price(value):
23 return round(value / 10**max_digits, 8)
24
25 @static_var("cache", {})
26 def get_ticker(c1, c2, market):
27 def invert(ticker):
28 return {
29 "inverted": True,
30 "bid": float(1/ticker["ask"]),
31 "ask": float(1/ticker["bid"]),
32 "bidA": float(1/ticker["askA"]),
33 "askA": float(1/ticker["bidA"]),
34 }
35 def augment_ticker(ticker):
36 # FIXME: need to do better than just a multiplier
37 ticker.update({
38 "inverted": False,
39 "bidA": ticker["bid"] * 0.99,
40 "askA": ticker["ask"] * 1.01,
41 })
42
43 if (c1, c2, market.__class__) in get_ticker.cache:
44 return get_ticker.cache[(c1, c2, market.__class__)]
45 if (c2, c1, market.__class__) in get_ticker.cache:
46 return invert(get_ticker.cache[(c2, c1, market.__class__)])
47
48 try:
49 get_ticker.cache[(c1, c2, market.__class__)] = market.fetch_ticker("{}/{}".format(c1, c2))
50 augment_ticker(get_ticker.cache[(c1, c2, market.__class__)])
51 except ccxt.ExchangeError:
52 try:
53 get_ticker.cache[(c2, c1, market.__class__)] = market.fetch_ticker("{}/{}".format(c2, c1))
54 augment_ticker(get_ticker.cache[(c2, c1, market.__class__)])
55 except ccxt.ExchangeError:
56 get_ticker.cache[(c1, c2, market.__class__)] = None
57 return get_ticker(c1, c2, market)
58
59 def fetch_balances(market):
60 balances = {}
61 fetched_balance = market.fetch_balance()
62 for key, value in fetched_balance["total"].items():
63 if value > 0:
64 balances[key] = int(value * 10**max_digits)
65 return balances
66
67 def assets_value(assets, market, base_currency="BTC"):
68 repartition_in_base_currency = {}
69 for currency, asset_value in assets.items():
70 if currency == base_currency:
71 repartition_in_base_currency[currency] = asset_value
72 else:
73 asset_ticker = get_ticker(currency, base_currency, market)
74 if asset_ticker is None:
75 raise Exception("This asset is not available in the chosen market")
76 repartition_in_base_currency[currency] = int(asset_ticker["bidA"] * asset_value)
77 return repartition_in_base_currency
78
79 def dispatch_assets(base_currency_value, repartition_pertenthousand, market, base_currency="BTC"):
80 sum_pertenthousand = sum([v for k, v in repartition_pertenthousand.items()])
81 repartition_in_base_currency = {}
82 for currency, ptt in repartition_pertenthousand.items():
83 repartition_in_base_currency[currency] = int(ptt * base_currency_value / sum_pertenthousand)
84 return repartition_in_base_currency
85
86 def compute_moves(current_assets, repartition_pertenthousand, market, base_currency="BTC"):
87 value_in_base = assets_value(current_assets, market, base_currency=base_currency)
88 total_base_value = sum([ v for k, v in value_in_base.items()])
89
90 new_repartition = dispatch_assets(total_base_value, repartition_pertenthousand, market, base_currency=base_currency)
91 mouvements = {}
92
93 for key in set(value_in_base.keys()).union(set(new_repartition.keys())):
94 mouvements[key] = value_in_base.get(key, 0) - new_repartition.get(key, 0)
95
96 return mouvements
97
98 def compute_order(currency, value, market, base_currency="BTC"):
99 if currency == base_currency or value == 0:
100 return [None, 0, False]
101
102 asset_ticker = get_ticker(currency, base_currency, market)
103 if asset_ticker["inverted"]:
104 asset_ticker = get_ticker(base_currency, currency, market)
105 if value > 0:
106 rate = asset_ticker["askA"]
107 return ["buy", rate, True]
108 else:
109 rate = asset_ticker["bidA"]
110 return ["sell", rate, True]
111 else:
112 if value > 0:
113 rate = asset_ticker["bidA"]
114 return ["sell", rate, False]
115 else:
116 rate = asset_ticker["askA"]
117 return ["buy", rate, False]
118
119 def make_order(currency, value, market, base_currency="BTC"):
120 action, rate, inverted = compute_order(currency, value, market, base_currency=base_currency)
121 amount = formatted_price(abs(value))
122 if not inverted:
123 symbol = "{}/{}".format(currency, base_currency)
124 else:
125 symbol = "{}/{}".format(base_currency, currency)
126 return market.create_order(symbol, 'limit', action, amount, price=rate)
127
128 def make_orders(current_assets, repartition_pertenthousand, market, base_currency="BTC"):
129 mouvements = compute_moves(
130 current_assets,
131 repartition_pertenthousand,
132 market,
133 base_currency=base_currency)
134
135 results = []
136 for currency, value in sorted(mouvements.items(), key=lambda x: x[1]):
137 # FIXME: wait for sales to finish
138 results.append(make_order(currency, value, market, base_currency=base_currency))
139 return results
140
141 def print_assets(assets, indent="", market=None, base_currency="BTC"):
142 if market is not None:
143 format_string = "{}{} {} ({} {})"
144 else:
145 format_string = "{}{} {}"
146 base_currency_price = 0
147
148 for currency, value in assets.items():
149 if market is not None:
150 asset_ticker = get_ticker(currency, base_currency, market)
151 base_currency_price = asset_ticker["bidA"] * value
152 print(format_string.format(
153 indent,
154 formatted_price(value),
155 currency,
156 formatted_price(base_currency_price),
157 base_currency))
158
159 def print_orders(current_assets, repartition_pertenthousand, market, base_currency="BTC"):
160 mouvements = compute_moves(
161 current_assets,
162 repartition_pertenthousand,
163 market,
164 base_currency=base_currency)
165
166 for currency, value in mouvements.items():
167 action, rate, inverted = compute_order(
168 currency,
169 value,
170 market,
171 base_currency=base_currency)
172 if action is not None:
173 currency_price = int(value / rate)
174
175 if not inverted:
176 c1, c2 = [base_currency, currency]
177 v1, v2 = [value, currency_price]
178 else:
179 c1, c2 = [currency, base_currency]
180 v1, v2 = [currency_price, value]
181
182 print("need to {} {} {}'s worth of {}, i.e. {} {}".format(
183 action,
184 formatted_price(abs(v1)), c1,
185 c2,
186 formatted_price(abs(v2)), c2))
187
188 current_assets = fetch_balances(market)
189 print_orders(current_assets, repartition_pertenthousand, market)