def createSafeTrades(self, orders: List[Order], updateBookKeeper: bool = True): """ Given a list of trades, will convert them to safe trades -> AKA trades that: - Below our maximum - Make sure we have enough assets to complete the trade """ safe_orders = [] max_vol = min([VirtualMarket.instance().convertCurrency( exch=order.exchange, amt=order.volume, start=order.pair[0], end=Currency.USDT ) for order in orders]) max_vol = min(max_vol, float(SafetyValues.MaximumOrderValueUSD.value)) for order in orders: required_currency = None if order.buyOrSell == BS.BUY: required_currency = order.pair[1] elif order.buyOrSell == BS.SELL: required_currency = order.pair[0] available_assets = BookKeeper.instance().getValuePairOfCurrencyInExchange( exch=order.exchange, curr=required_currency, ) max_vol = min(max_vol, available_assets.amt_usd * 0.8) if max_vol < SafetyValues.MinimumOrderValueUSD.value: print("Max Vol: {}".format(max_vol)) return None max_vol = VirtualMarket.instance().convertCurrency( exch=order.exchange, amt=max_vol, start=Currency.USDT, end=order.pair[0] ) max_vol = float(self._binance.amount_to_precision("{0}/{1}".format(order.pair[0].value, order.pair[1].value), max_vol)) for order in orders: safe_orders.append( Order( exchange=order.exchange, buyOrSell=order.buyOrSell, orderType=order.orderType, pair=order.pair, price=(order.price*0.999), volume=max_vol, ) ) return safe_orders
def run(): exchanges, pairs = initializeEverything() searchForOpportunities = True while searchForOpportunities: try: marketData = {} for exchange in exchanges: marketData[exchange] = MarketEngine.instance().fetchTickers( exch=exchange, pairs=pairs) VirtualMarket.instance().updateMarket(marketData=marketData) ArbitrageEngine.instance().updateGraph() ArbitrageEngine.instance()._graph.print() arbitrage_path = ArbitrageEngine.instance().findArbitrage( graph=ArbitrageEngine.instance()._graph, src=Currency.USDT, ) if arbitrage_path: percentGrowth = ArbitrageEngine.instance().verifyArbitrage(path=arbitrage_path) if percentGrowth >= SafetyValues.MinimumOpportunity.value: orders = ArbitrageEngine.instance().pathToOrders( path=arbitrage_path, graph=ArbitrageEngine.instance()._graph) pprint(orders) safe_orders = MarketEngine.instance().createSafeTrades(orders) if safe_orders: print('\n{0}Safe Orders:{1}'.format('\033[92m', '\033[0m')) pprint(safe_orders) print('\n\n') for order in safe_orders: pprint(MarketEngine.instance().makeUnsafeTrade(order=order)) print("Executed Order: {}".format(order.toStringShort())) pprint(BookKeeper.instance()._balances) else: print("{0}No arbitrage opportunity found!{1}\n".format('\033[91m','\033[0m')) sleep(5) except Exception as e: pprint(e) break
def reportOrder(self, order=Order): """ Given an order, updates the positions for that exchange """ exch = order.exchange if not exch in self._balances: raise TypeError( 'Exchange is not in the balances map, please add it before trying to add a currency to it' ) acq_curr = order.pair[0] acq_amt = order.volume los_curr = order.pair[1] los_amt = order.volume * order.price if order.buyOrSell == BS.SELL: acq_amt = acq_amt * -1 else: los_amt = los_amt * -1 new_acq_amt = acq_amt + self._balances[exch][acq_curr].amt new_los_amt = los_amt + self._balances[exch][los_curr].amt new_acq_amt_usd = VirtualMarket.instance().convertCurrency( exch=order.exchange, amt=new_acq_amt, start=acq_curr, end=Currency.USDT, ) self._balances[exch][acq_curr] = ValuePair( amt=new_acq_amt, amt_usd=new_acq_amt_usd, ) new_los_amt_usd = VirtualMarket.instance().convertCurrency( exch=order.exchange, amt=new_los_amt, start=los_curr, end=Currency.USDT, ) self._balances[exch][los_curr] = ValuePair( amt=new_los_amt, amt_usd=new_los_amt_usd, )
def initializeEverything(): currencies = [ Currency.BTC, Currency.ETH, Currency.LTC, Currency.XRP, ] exchanges = [ Exchange.BINANCE, Exchange.KRAKEN ] MarketEngine.initialize(currencies, exchanges, None) pairs = MarketEngine.instance().supportedCurrencyPairs() ArbitrageEngine.initialize(currencies, exchanges, pairs) BookKeeper.initialize(currencies, exchanges) VirtualMarket.initialize(currencies, exchanges, pairs) try: marketData = {} for exchange in exchanges: marketData[exchange] = MarketEngine.instance().fetchTickers( exch=exchange, pairs=pairs) VirtualMarket.instance().updateMarket(marketData=marketData) print("Market Initialized!") for key,value in VirtualMarket.instance()._market.items(): pprint(value.print()) for exchange in exchanges: MarketEngine.instance().fetchBalance(exch=exchange) print("Book Keeper Initialized!") pprint(BookKeeper.instance()._balances) except Exception as e: print("Initialization failed!") pprint(e) return return (exchanges, pairs)
def _fetchBinanceBalance(self): """ Makes an API POST request to the Binance API instance asking for our account balances Example response: { "makerCommission": 15, "takerCommission": 15, "buyerCommission": 0, "sellerCommission": 0, "canTrade": true, "canWithdraw": true, "canDeposit": true, "updateTime": 123456789, "balances": [ { "asset": "BTC", "free": "4723846.89208129", <= USD? "locked": "0.00000000" }, { "asset": "LTC", "free": "4763368.68006011", <= USD? "locked": "0.00000000" } ] } """ if not self._binance: raise AttributeError('Binance API instance has not been instanciated') resp = self._binance.privateGetAccount() if not 'balances' in resp: raise ApiError('binance api did not return a correct response') else: balances = resp['balances'] position = {} supported_currencies_string = self.supportedCurrenciesString() for entry in balances: if entry['asset'] in supported_currencies_string: currency = Currency[entry['asset']] amount = float(entry['free']) usd_amount = VirtualMarket.instance().convertCurrency( exch=Exchange.BINANCE, amt=amount, start=currency, end=Currency.USDT ) position[currency] = ValuePair(amount, usd_amount) BookKeeper.instance().updateBalance( exch=Exchange.BINANCE, balance=position ) return position
def updateGraph(self): """ Public method to update our internal graph with data from the market. Requests ticker data for every supported pair on every supported exchange, and then updates the graph. """ for exchange in self._supported_exchanges: marketData = VirtualMarket.instance().getMarketData( exch=exchange) for src, dest, edge in marketData.getEdges(): self._graph.addEdge(src, dest, edge.xrate, edge.weight, edge.vol, edge.vol_sym, edge.pair, edge.ab, edge.exch, edge.timestamp)
def _fetchKrakenBalance(self): """ Makes an API POST request to the Kraken API instance asking for our account balances Example Response: { 'error': [], 'result': { 'XETH': '0.0998591200', } } """ if not self._kraken: raise AttributeError('Kraken API instance has not been instanciated') resp = self._kraken.privatePostBalance() if resp['error']: raise ApiError('kraken api did not return a correct response') else: balances = resp['result'] position = {} supported_currencies_string = list(map(lambda x: nTOk[x.value], self._supportedCurrencies)) for (curr, amt) in balances.items(): if curr in supported_currencies_string: currency = Currency[kTOn[curr]] amount = float(amt) usd_amount = VirtualMarket.instance().convertCurrency( exch=Exchange.KRAKEN, amt=amount, start=currency, end=Currency.USDT ) position[currency] = ValuePair(amount, usd_amount) BookKeeper.instance().updateBalance( exch=Exchange.KRAKEN, balance=position ) return position