aboutsummaryrefslogtreecommitdiff
path: root/portfolio.py
diff options
context:
space:
mode:
authorIsmaël Bouya <ismael.bouya@normalesup.org>2018-01-21 15:17:48 +0100
committerIsmaël Bouya <ismael.bouya@normalesup.org>2018-01-21 15:37:24 +0100
commitdeb8924cc60f0d64575657399f4fe112ff1cfb31 (patch)
tree66dbef501b99f962882fce9ac0f67855650674cd /portfolio.py
parentf0e4f1828138f86cee54d9f8c4414228840207aa (diff)
downloadTrader-deb8924cc60f0d64575657399f4fe112ff1cfb31.tar.gz
Trader-deb8924cc60f0d64575657399f4fe112ff1cfb31.tar.zst
Trader-deb8924cc60f0d64575657399f4fe112ff1cfb31.zip
Add compute value lambdas for currency conversion
Diffstat (limited to 'portfolio.py')
-rw-r--r--portfolio.py51
1 files changed, 39 insertions, 12 deletions
diff --git a/portfolio.py b/portfolio.py
index 4991dce..5211dd8 100644
--- a/portfolio.py
+++ b/portfolio.py
@@ -89,14 +89,14 @@ class Amount:
89 self.ticker_cache = {} 89 self.ticker_cache = {}
90 self.ticker_cache_timestamp = time.time() 90 self.ticker_cache_timestamp = time.time()
91 91
92 def in_currency(self, other_currency, market, action="average"): 92 def in_currency(self, other_currency, market, action=None, compute_value="average"):
93 if other_currency == self.currency: 93 if other_currency == self.currency:
94 return self 94 return self
95 asset_ticker = Trade.get_ticker(self.currency, other_currency, market) 95 asset_ticker = Trade.get_ticker(self.currency, other_currency, market)
96 if asset_ticker is not None: 96 if asset_ticker is not None:
97 return Amount( 97 return Amount(
98 other_currency, 98 other_currency,
99 self.value * asset_ticker[action], 99 self.value * Trade.compute_value(asset_ticker, action, compute_value=compute_value),
100 linked_to=self, 100 linked_to=self,
101 ticker=asset_ticker) 101 ticker=asset_ticker)
102 else: 102 else:
@@ -175,12 +175,12 @@ class Balance:
175 return cls(currency, hash_["total"], hash_["free"], hash_["used"]) 175 return cls(currency, hash_["total"], hash_["free"], hash_["used"])
176 176
177 @classmethod 177 @classmethod
178 def in_currency(cls, other_currency, market, action="average", type="total"): 178 def in_currency(cls, other_currency, market, compute_value="average", type="total"):
179 amounts = {} 179 amounts = {}
180 for currency in cls.known_balances: 180 for currency in cls.known_balances:
181 balance = cls.known_balances[currency] 181 balance = cls.known_balances[currency]
182 other_currency_amount = getattr(balance, type)\ 182 other_currency_amount = getattr(balance, type)\
183 .in_currency(other_currency, market, action=action) 183 .in_currency(other_currency, market, compute_value=compute_value)
184 amounts[currency] = other_currency_amount 184 amounts[currency] = other_currency_amount
185 return amounts 185 return amounts
186 186
@@ -213,16 +213,34 @@ class Balance:
213 return amounts 213 return amounts
214 214
215 @classmethod 215 @classmethod
216 def prepare_trades(cls, market, base_currency="BTC"): 216 def prepare_trades(cls, market, base_currency="BTC", compute_value=None):
217 cls.fetch_balances(market) 217 cls.fetch_balances(market)
218 values_in_base = cls.in_currency(base_currency, market) 218 values_in_base = cls.in_currency(base_currency, market)
219 total_base_value = sum(values_in_base.values()) 219 total_base_value = sum(values_in_base.values())
220 new_repartition = cls.dispatch_assets(total_base_value) 220 new_repartition = cls.dispatch_assets(total_base_value)
221 Trade.compute_trades(values_in_base, new_repartition, market=market) 221 # Recompute it in case we have new currencies
222 values_in_base = cls.in_currency(base_currency, market)
223 Trade.compute_trades(values_in_base, new_repartition, market=market, compute_value=compute_value)
222 224
223 def __repr__(self): 225 def __repr__(self):
224 return "Balance({} [{}/{}/{}])".format(self.currency, str(self.free), str(self.used), str(self.total)) 226 return "Balance({} [{}/{}/{}])".format(self.currency, str(self.free), str(self.used), str(self.total))
225 227
228class Computation:
229 def average_inverse(ticker, action):
230 if ticker["inverted"]:
231 return 1/ticker["original"]["average"]
232 else:
233 return ticker["average"]
234
235 computations = {
236 "default": lambda x, y: x[y],
237 "average_inverse": average_inverse,
238 "average": lambda x, y: x["average"],
239 "bid": lambda x, y: x["bid"],
240 "ask": lambda x, y: x["ask"],
241 }
242
243
226class Trade: 244class Trade:
227 trades = {} 245 trades = {}
228 246
@@ -282,7 +300,7 @@ class Trade:
282 return cls.get_ticker(c1, c2, market) 300 return cls.get_ticker(c1, c2, market)
283 301
284 @classmethod 302 @classmethod
285 def compute_trades(cls, values_in_base, new_repartition, market=None): 303 def compute_trades(cls, values_in_base, new_repartition, market=None, compute_value=None):
286 base_currency = sum(values_in_base.values()).currency 304 base_currency = sum(values_in_base.values()).currency
287 for currency in Balance.currencies(): 305 for currency in Balance.currencies():
288 if currency == base_currency: 306 if currency == base_currency:
@@ -293,7 +311,8 @@ class Trade:
293 currency, 311 currency,
294 market=market 312 market=market
295 ) 313 )
296 cls.trades[currency].prepare_order() 314 if compute_value is not None:
315 cls.trades[currency].prepare_order(compute_value=compute_value)
297 return cls.trades 316 return cls.trades
298 317
299 @property 318 @property
@@ -314,7 +333,7 @@ class Trade:
314 else: 333 else:
315 return "bid" if not inverted else "ask" 334 return "bid" if not inverted else "ask"
316 335
317 def prepare_order(self): 336 def prepare_order(self, compute_value="default"):
318 if self.action is None: 337 if self.action is None:
319 return 338 return
320 ticker = self.value_from.ticker 339 ticker = self.value_from.ticker
@@ -322,7 +341,9 @@ class Trade:
322 341
323 if not inverted: 342 if not inverted:
324 value_from = self.value_from.linked_to 343 value_from = self.value_from.linked_to
325 value_to = self.value_to.in_currency(self.currency, self.market) 344 # The ticker will most probably be inverted, but we want the average
345 # of the initial value
346 value_to = self.value_to.in_currency(self.currency, self.market, compute_value="average_inverse")
326 delta = abs(value_to - value_from) 347 delta = abs(value_to - value_from)
327 currency = self.base_currency 348 currency = self.base_currency
328 else: 349 else:
@@ -330,11 +351,17 @@ class Trade:
330 delta = abs(self.value_to - self.value_from) 351 delta = abs(self.value_to - self.value_from)
331 currency = self.currency 352 currency = self.currency
332 353
333 rate = ticker[self.order_action(inverted)] 354 rate = Trade.compute_value(ticker, self.order_action(inverted), compute_value=compute_value)
334 355
335 self.orders.append(Order(self.order_action(inverted), delta, rate, currency)) 356 self.orders.append(Order(self.order_action(inverted), delta, rate, currency))
336 357
337 @classmethod 358 @classmethod
359 def compute_value(cls, ticker, action, compute_value="default"):
360 if type(compute_value) == str:
361 compute_value = Computation.computations[compute_value]
362 return compute_value(ticker, action)
363
364 @classmethod
338 def all_orders(cls): 365 def all_orders(cls):
339 return sum(map(lambda v: v.orders, cls.trades.values()), []) 366 return sum(map(lambda v: v.orders, cls.trades.values()), [])
340 367
@@ -401,7 +428,7 @@ class Order:
401 return self.status 428 return self.status
402 429
403def print_orders(market, base_currency="BTC"): 430def print_orders(market, base_currency="BTC"):
404 Balance.prepare_trades(market, base_currency=base_currency) 431 Balance.prepare_trades(market, base_currency=base_currency, compute_value="average")
405 for currency, balance in Balance.known_balances.items(): 432 for currency, balance in Balance.known_balances.items():
406 print(balance) 433 print(balance)
407 for currency, trade in Trade.trades.items(): 434 for currency, trade in Trade.trades.items():