diff options
author | Ismaël Bouya <ismael.bouya@normalesup.org> | 2018-01-16 00:44:20 +0100 |
---|---|---|
committer | Ismaël Bouya <ismael.bouya@normalesup.org> | 2018-01-16 01:56:04 +0100 |
commit | dd359bc0617a915909efb2ef37048192c0639836 (patch) | |
tree | 0d9eb997f313ab883e584ae7c68f2584deb63710 /script.py | |
parent | b2dab3acfb8cb23bdb54298c88aecfb7042fb8d5 (diff) | |
download | Trader-dd359bc0617a915909efb2ef37048192c0639836.tar.gz Trader-dd359bc0617a915909efb2ef37048192c0639836.tar.zst Trader-dd359bc0617a915909efb2ef37048192c0639836.zip |
Complete refactor of the script to use classesjl/dev
Diffstat (limited to 'script.py')
-rw-r--r-- | script.py | 218 |
1 files changed, 0 insertions, 218 deletions
diff --git a/script.py b/script.py deleted file mode 100644 index 187ff73..0000000 --- a/script.py +++ /dev/null | |||
@@ -1,218 +0,0 @@ | |||
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 | "bidE": float(1/ticker["askE"]), | ||
35 | "askE": float(1/ticker["bidE"]), | ||
36 | } | ||
37 | def augment_ticker(ticker): | ||
38 | bid_factor = 1.01 | ||
39 | ask_factor = 0.99 | ||
40 | fees = fetch_fees(market) | ||
41 | # FIXME: need to do better than just a multiplier | ||
42 | ticker.update({ | ||
43 | "inverted": False, | ||
44 | # Adjusted | ||
45 | "bidA": ticker["bid"] * bid_factor, | ||
46 | "askA": ticker["ask"] * ask_factor, | ||
47 | # Expected in the end | ||
48 | "bidE": ticker["bid"] * bid_factor * (1 - fees["maker"]), | ||
49 | "askE": ticker["ask"] * ask_factor * (1 - fees["maker"]), | ||
50 | # fees | ||
51 | "bidF": ticker["bid"] * bid_factor * fees["maker"], | ||
52 | "askF": ticker["ask"] * ask_factor * fees["maker"], | ||
53 | }) | ||
54 | |||
55 | if (c1, c2, market.__class__) in get_ticker.cache: | ||
56 | return get_ticker.cache[(c1, c2, market.__class__)] | ||
57 | if (c2, c1, market.__class__) in get_ticker.cache: | ||
58 | return invert(get_ticker.cache[(c2, c1, market.__class__)]) | ||
59 | |||
60 | try: | ||
61 | get_ticker.cache[(c1, c2, market.__class__)] = market.fetch_ticker("{}/{}".format(c1, c2)) | ||
62 | augment_ticker(get_ticker.cache[(c1, c2, market.__class__)]) | ||
63 | except ccxt.ExchangeError: | ||
64 | try: | ||
65 | get_ticker.cache[(c2, c1, market.__class__)] = market.fetch_ticker("{}/{}".format(c2, c1)) | ||
66 | augment_ticker(get_ticker.cache[(c2, c1, market.__class__)]) | ||
67 | except ccxt.ExchangeError: | ||
68 | get_ticker.cache[(c1, c2, market.__class__)] = None | ||
69 | return get_ticker(c1, c2, market) | ||
70 | |||
71 | def fetch_balances(market): | ||
72 | balances = {} | ||
73 | fetched_balance = market.fetch_balance() | ||
74 | for key, value in fetched_balance["total"].items(): | ||
75 | if value > 0: | ||
76 | balances[key] = int(value * 10**max_digits) | ||
77 | return balances | ||
78 | |||
79 | @static_var("cache", {}) | ||
80 | def fetch_fees(market): | ||
81 | if market.__class__ not in fetch_fees.cache: | ||
82 | fetch_fees.cache[market.__class__] = market.fetch_fees() | ||
83 | return fetch_fees.cache[market.__class__] | ||
84 | |||
85 | def assets_value(assets, market, base_currency="BTC"): | ||
86 | repartition_in_base_currency = {} | ||
87 | for currency, asset_value in assets.items(): | ||
88 | if currency == base_currency: | ||
89 | repartition_in_base_currency[currency] = [asset_value, 0] | ||
90 | else: | ||
91 | asset_ticker = get_ticker(currency, base_currency, market) | ||
92 | if asset_ticker is None: | ||
93 | raise Exception("This asset is not available in the chosen market") | ||
94 | repartition_in_base_currency[currency] = [ | ||
95 | int(asset_ticker["bidE"] * asset_value), | ||
96 | int(asset_ticker["bidF"] * asset_value) | ||
97 | ] | ||
98 | |||
99 | return repartition_in_base_currency | ||
100 | |||
101 | def dispatch_assets(base_currency_value, repartition_pertenthousand, market, base_currency="BTC"): | ||
102 | sum_pertenthousand = sum([v for k, v in repartition_pertenthousand.items()]) | ||
103 | repartition_in_base_currency = {} | ||
104 | for currency, ptt in repartition_pertenthousand.items(): | ||
105 | repartition_in_base_currency[currency] = int(ptt * base_currency_value / sum_pertenthousand) | ||
106 | return repartition_in_base_currency | ||
107 | |||
108 | def compute_moves(current_assets, repartition_pertenthousand, market, no_fees=True, base_currency="BTC"): | ||
109 | value_in_base = assets_value(current_assets, market, base_currency=base_currency) | ||
110 | total_base_value = sum([ v[0] for k, v in value_in_base.items()]) | ||
111 | |||
112 | new_repartition = dispatch_assets(total_base_value, repartition_pertenthousand, market, base_currency=base_currency) | ||
113 | mouvements = {} | ||
114 | |||
115 | if no_fees: | ||
116 | for key in set(value_in_base.keys()).union(set(new_repartition.keys())): | ||
117 | mouvements[key] = value_in_base.get(key, [0, 0])[0] - new_repartition.get(key, 0) | ||
118 | else: | ||
119 | for key in set(value_in_base.keys()).union(set(new_repartition.keys())): | ||
120 | value, fee = value_in_base.get(key, [0, 0]) | ||
121 | mouvements[key] = [value - new_repartition.get(key, 0), fee] | ||
122 | |||
123 | return mouvements | ||
124 | |||
125 | def compute_order(currency, value, market, base_currency="BTC"): | ||
126 | if currency == base_currency or value == 0: | ||
127 | return [None, 0, False] | ||
128 | |||
129 | asset_ticker = get_ticker(currency, base_currency, market) | ||
130 | if asset_ticker["inverted"]: | ||
131 | asset_ticker = get_ticker(base_currency, currency, market) | ||
132 | if value > 0: | ||
133 | rate = asset_ticker["askA"] | ||
134 | return ["buy", rate, True] | ||
135 | else: | ||
136 | rate = asset_ticker["bidA"] | ||
137 | return ["sell", rate, True] | ||
138 | else: | ||
139 | if value > 0: | ||
140 | rate = asset_ticker["bidA"] | ||
141 | return ["sell", rate, False] | ||
142 | else: | ||
143 | rate = asset_ticker["askA"] | ||
144 | return ["buy", rate, False] | ||
145 | |||
146 | def make_order(currency, value, market, base_currency="BTC"): | ||
147 | action, rate, inverted = compute_order(currency, value, market, base_currency=base_currency) | ||
148 | amount = formatted_price(abs(value)) | ||
149 | if not inverted: | ||
150 | symbol = "{}/{}".format(currency, base_currency) | ||
151 | else: | ||
152 | symbol = "{}/{}".format(base_currency, currency) | ||
153 | return market.create_order(symbol, 'limit', action, amount, price=rate) | ||
154 | |||
155 | def make_orders(current_assets, repartition_pertenthousand, market, base_currency="BTC"): | ||
156 | mouvements = compute_moves( | ||
157 | current_assets, | ||
158 | repartition_pertenthousand, | ||
159 | market, | ||
160 | base_currency=base_currency) | ||
161 | |||
162 | results = [] | ||
163 | for currency, value in sorted(mouvements.items(), key=lambda x: x[1]): | ||
164 | # FIXME: wait for sales to finish | ||
165 | results.append(make_order(currency, value, market, base_currency=base_currency)) | ||
166 | return results | ||
167 | |||
168 | def print_assets(assets, indent="", market=None, base_currency="BTC"): | ||
169 | if market is not None: | ||
170 | format_string = "{}{} {} ({} {})" | ||
171 | else: | ||
172 | format_string = "{}{} {}" | ||
173 | base_currency_price = 0 | ||
174 | |||
175 | for currency, value in assets.items(): | ||
176 | if market is not None: | ||
177 | asset_ticker = get_ticker(currency, base_currency, market) | ||
178 | base_currency_price = asset_ticker["bidE"] * value | ||
179 | print(format_string.format( | ||
180 | indent, | ||
181 | formatted_price(value), | ||
182 | currency, | ||
183 | formatted_price(base_currency_price), | ||
184 | base_currency)) | ||
185 | |||
186 | def print_orders(current_assets, repartition_pertenthousand, market, base_currency="BTC"): | ||
187 | mouvements = compute_moves( | ||
188 | current_assets, | ||
189 | repartition_pertenthousand, | ||
190 | market, | ||
191 | no_fees=False, | ||
192 | base_currency=base_currency) | ||
193 | |||
194 | for currency, [value, fee] in mouvements.items(): | ||
195 | action, rate, inverted = compute_order( | ||
196 | currency, | ||
197 | value, | ||
198 | market, | ||
199 | base_currency=base_currency) | ||
200 | if action is not None: | ||
201 | currency_price = int(value / rate) | ||
202 | |||
203 | if not inverted: | ||
204 | c1, c2 = [base_currency, currency] | ||
205 | v1, v2 = [value, currency_price] | ||
206 | else: | ||
207 | c1, c2 = [currency, base_currency] | ||
208 | v1, v2 = [currency_price, value] | ||
209 | |||
210 | print("need to {} {} {}'s worth of {}, i.e. {} {} ( + {} {} fee)".format( | ||
211 | action, | ||
212 | formatted_price(abs(v1)), c1, | ||
213 | c2, | ||
214 | formatted_price(abs(v2)), c2, | ||
215 | formatted_price(fee), c2)) | ||
216 | |||
217 | current_assets = fetch_balances(market) | ||
218 | print_orders(current_assets, repartition_pertenthousand, market) | ||