def CancelObsoleteOpenBuyOrders(self): """Cancel all open buy orders which are older than 'ORDER_TIMEOUT_MIN' """ open_orders = ExecuteApiCall(self.__api.get_open_orders()) cancelled_buy_orders_timeout = [] if open_orders["success"]: for order in open_orders["result"]: try: open_time = datetime.strptime(order["Opened"], '%Y-%m-%dT%H:%M:%S.%f') except ValueError: open_time = datetime.strptime(order["Opened"], '%Y-%m-%dT%H:%M:%S') if (datetime.now() - open_time).seconds >= ( ORDER_TIMEOUT_MIN * 60): # TODO: check if times are in same time zone if "LIMIT_BUY" == order["OrderType"]: ticker = ExecuteApiCall( self.__api.get_ticker(order["Exchange"])) if ticker["success"]: filled_quantity = order["Quantity"] - order[ "QuantityRemaining"] """Only cancel buy orders if the filled quantity is greater than MIN_ORDER_SIZE""" if (0.0 == filled_quantity) or \ (MIN_ORDER_SIZE < (filled_quantity * ticker["result"]["Last"])): cancelled_order = ExecuteApiCall( self.__api.cancel(order["OrderUuid"])) if cancelled_order["success"]: cancelled_buy_orders_timeout.append( order["Exchange"]) return cancelled_buy_orders_timeout
def CancelOpenOrdersAtTrigger(self, market_name): """ This function cancels all open orders for the selected market if the amount of money involved is above MIN_ORDER_SIZE. """ open_orders = ExecuteApiCall(self.__api.get_open_orders(market_name)) cancelled_orders = [] if open_orders["success"]: for order in open_orders["result"]: ticker = ExecuteApiCall(self.__api.get_ticker(market_name)) if ticker["success"]: if "LIMIT_BUY" == order["OrderType"]: filled_quantity = order["Quantity"] - order[ "QuantityRemaining"] """Only cancel buy orders if the filled quantity is greater than MIN_ORDER_SIZE""" if (0.0 == filled_quantity) or ( MIN_ORDER_SIZE < (filled_quantity * ticker["result"]["Last"])): cancelled_order = ExecuteApiCall( self.__api.cancel(order["OrderUuid"])) if cancelled_order["success"]: cancelled_orders.append("buy-" + market_name) elif "LIMIT_SELL" == order["OrderType"]: """Only cancel sell orders if the remaining quantity is greater than 50K satoshis""" if MIN_ORDER_SIZE < (order["QuantityRemaining"] * ticker["result"]["Last"]): cancelled_order = ExecuteApiCall( self.__api.cancel(order["OrderUuid"])) if cancelled_order["success"]: cancelled_orders.append("sell-" + market_name) return cancelled_orders
def Buy(self, market_name, amount_to_buy, rate): """Places a limit buy order on the selected market""" base_currency_balance = ExecuteApiCall( self.__api.get_balance(BASE_CURRENCY)) buy = {"success": False} if (base_currency_balance["success"]) and \ (base_currency_balance["result"]["Available"] >= amount_to_buy * rate): buy = ExecuteApiCall( self.__api.buy_limit(market_name, amount_to_buy, rate)) return buy
def Sell(self, market_name, rate, amount_to_sell): """Places a limit sell order on the selected market""" sell = {"success": False} if amount_to_sell * rate >= MIN_SELL_SIZE: sell = ExecuteApiCall( self.__api.sell_limit(market_name, amount_to_sell, rate)) return sell
def Run(self, price_charts): balances = ExecuteApiCall(self.__api.get_balances()) balance_all = 0.0 # sum of all balances converted to base currency base_currency_balance = 0.0 # actual balance of base currency if balances["success"]: """Filling log balances""" for result in balances["result"]: market_name = BASE_CURRENCY + '-' + result["Currency"] if BASE_CURRENCY == result["Currency"]: balance_all += result["Balance"] base_currency_balance = result["Balance"] elif (result["Balance"] > 0.0) and \ (market_name in price_charts) and (price_charts[market_name][-1] > 0.0): balance_all += result["Balance"] * price_charts[market_name][-1] \ * ASK_COEFFICIENT * FEE_COEFFICIENT with open(PROJECT_LOCATION + "Log/Logging.csv", 'a', newline='') as csvfile: logfilewriter = csv.writer(csvfile) logfilewriter.writerow([str(datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')[:-4]), " Full balance in " + BASE_CURRENCY + ": " + str(format(balance_all, '.6f'))]) logfilewriter.writerow([BASE_CURRENCY + ' balance: ' + str(format(base_currency_balance, '.6f'))]) logfilewriter.writerow('\n') csvfile.close() LogOutput(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')[:-4]) + ': ' + BASE_CURRENCY + ' balance: ' + str(format(base_currency_balance, '.6f')) + ', Full balance in ' + BASE_CURRENCY + ': ' + str(format(balance_all, '.6f')) + '\n')
def RefreshPendingOrders(self): """Refreshes pending orders: this function makes limit orders behave as market orders""" open_orders = ExecuteApiCall(self.__api.get_open_orders()) refreshed_orders = [] if open_orders["success"]: for order in open_orders["result"]: market_name = order["Exchange"] ticker = ExecuteApiCall(self.__api.get_ticker(market_name)) if ticker["success"]: if "LIMIT_BUY" == order["OrderType"]: filled_quantity = order["Quantity"] - order[ "QuantityRemaining"] """Only cancel buy orders if the filled quantity is greater than MIN_ORDER_SIZE""" if (0.0 == filled_quantity) or ( MIN_ORDER_SIZE < (filled_quantity * ticker["result"]["Last"])): cancelled_order = ExecuteApiCall( self.__api.cancel(order["OrderUuid"])) if cancelled_order["success"]: rate = self.GetBuyRate(ticker) buy = self.Buy(market_name, order["QuantityRemaining"], rate) if buy["success"]: refreshed_orders.append("buy-" + market_name) elif "LIMIT_SELL" == order["OrderType"]: """Only cancel sell orders if the remaining quantity is greater than MIN_ORDER_SIZE""" if MIN_ORDER_SIZE < (order["QuantityRemaining"] * ticker["result"]["Last"]): cancelled_order = ExecuteApiCall( self.__api.cancel(order["OrderUuid"])) if cancelled_order["success"]: rate = self.GetSellRate(ticker) balance = ExecuteApiCall( self.__api.get_balance( market_name[BASE_CURRENCY_LEN + 1:])) if balance["success"]: sell = self.Sell( market_name, rate, balance["result"]["Balance"]) if sell["success"]: refreshed_orders.append("sell-" + market_name) return refreshed_orders
def GetBalances(self): """ Returns the account balances for each currency output structure: ret["<currency name>"] refers to a float number """ ret = dict() balances = ExecuteApiCall(self.__api.get_balances()) if balances["success"]: for result in balances["result"]: ret[result["Currency"]] = result["Available"] return ret
def CollectData(self): """ This function collects market data by API. """ """init self.__market_sum_last_valid""" try: if self.__market_sum["success"]: pass except KeyError: self.__market_sum_last_valid = { "success": False, "result": [], "message": None } """Get the new data""" self.__market_sum = ExecuteApiCall(self.__api.get_market_summaries()) """Update last valid values""" if self.__market_sum["success"]: self.__market_sum_last_valid = self.__market_sum
def Run(self, trigger_queue: TriggerQueue): """ This is the main function, it is called periodically. It places and logs buy and sell orders at triggers and refreshes pending orders. """ buy_orders = [] sell_orders = [] invalidity_sell_orders = [] cancelled_orders = [] # refreshed_orders = [] buy_triggers = [] sell_triggers = [] """Refreshing orders""" refreshed_orders = self.RefreshPendingOrders() """Calculating position size""" base_currency_balance = ExecuteApiCall( self.__api.get_balance(BASE_CURRENCY)) if base_currency_balance["success"]: position_size = base_currency_balance["result"][ "Available"] * POSITION_SIZE_COEFFICIENT / NUM_OF_POSITIONS if position_size > MAX_POSITION_SIZE: position_size = MAX_POSITION_SIZE elif position_size < MIN_POSITION_SIZE: position_size = MIN_POSITION_SIZE else: position_size = MIN_POSITION_SIZE """Creating new list without redundant triggers""" for market_name in trigger_queue.buy: if market_name not in buy_triggers: buy_triggers.append(market_name) """Placing buy orders""" for market_name in buy_triggers: ticker = ExecuteApiCall(self.__api.get_ticker(market_name)) if ticker["success"]: cancel = self.CancelOpenOrdersAtTrigger(market_name) if cancel: cancelled_orders.append(cancel) rate = self.GetBuyRate(ticker) amount_to_buy = position_size / rate buy = self.Buy(market_name, amount_to_buy, rate) if buy["success"]: buy_orders.append(market_name) buy_triggers.remove(market_name) """Creating new list without redundant triggers""" for market_name in trigger_queue.sell: if market_name not in sell_triggers: sell_triggers.append(market_name) """Placing sell orders""" balances = self.GetBalances() for coin in balances: if balances[coin] > 0.0: market_name = BASE_CURRENCY + "-" + coin if market_name in sell_triggers: ticker = ExecuteApiCall(self.__api.get_ticker(market_name)) if ticker["success"]: cancel = self.CancelOpenOrdersAtTrigger(market_name) if cancel: cancelled_orders.append(cancel) rate = self.GetSellRate(ticker) sell = self.Sell(market_name, rate, balances[coin]) if sell["success"]: sell_orders.append(market_name) sell_triggers.remove(market_name) if market_name in trigger_queue.invalidity_sell: invalidity_sell_orders.append(market_name) """Log the orders to file""" date = str(datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')[:-4]) with open(PROJECT_LOCATION + "Log/Orders.csv", 'a', newline='') as csvfile: logfilewriter = csv.writer(csvfile) logfilewriter.writerow([date]) logfilewriter.writerow( ['Cancelled orders: ' + str(cancelled_orders)]) logfilewriter.writerow( ['Refreshed orders: ' + str(refreshed_orders)]) logfilewriter.writerow(['Buy orders: ' + str(buy_orders)]) logfilewriter.writerow(['Sell orders: ' + str(sell_orders)]) logfilewriter.writerow([ 'Sell orders because of invalidity: ' + str(invalidity_sell_orders) ]) logfilewriter.writerow('\n') csvfile.close() """Log the orders to console""" if cancelled_orders: LogOutput(date + ': Cancelled orders: ' + str(cancelled_orders)) if refreshed_orders: LogOutput(date + ': Refreshed orders: ' + str(refreshed_orders)) if buy_orders: LogOutput(date + ': Buy orders: ' + str(buy_orders)) if sell_orders: LogOutput(date + ': Sell orders: ' + str(sell_orders)) if invalidity_sell_orders: LogOutput(date + ': Sell orders because of invalidity: ' + str(invalidity_sell_orders))
def Run(self, trigger_queue: TriggerQueue, charts: Data): """ This is the main function, it is called periodically. It places buy and sell simulated orders at triggers, and logs them. """ buy_orders = [] sell_orders = [] invalidity_sell_orders = [] buy_triggers = [] sell_triggers = [] """Init balances""" for market_name in charts.last: coin = market_name[BASE_CURRENCY_LEN + 1:] if coin not in self.__balances: self.__balances[coin] = 0.0 """Calculating position size""" self.__position_size = self.__base_currency_balance * POSITION_SIZE_COEFFICIENT / TEST_NUM_OF_POSITIONS if self.__position_size > TEST_MAX_POSITION_SIZE: self.__position_size = TEST_MAX_POSITION_SIZE elif self.__position_size < TEST_MIN_POSITION_SIZE: self.__position_size = TEST_MIN_POSITION_SIZE """Creating new list without redundant triggers""" for market_name in trigger_queue.buy: if market_name not in buy_triggers: buy_triggers.append(market_name) """Placing buy orders""" for market_name in buy_triggers: ticker = ExecuteApiCall(self.__api.get_ticker(market_name)) if ticker["success"]: rate = self.GetBuyRate(ticker) buy = self.Buy(market_name, rate) if buy: buy_orders.append(market_name) """Creating new list without redundant triggers""" for market_name in trigger_queue.sell: if market_name not in sell_triggers: sell_triggers.append(market_name) """Placing sell orders""" for market_name in sell_triggers: coin = market_name[BASE_CURRENCY_LEN + 1:] if self.__balances[coin] > 0.0: ticker = ExecuteApiCall(self.__api.get_ticker(market_name)) if ticker["success"]: rate = self.GetSellRate(ticker) sell = self.Sell(market_name, rate) if sell: sell_orders.append(market_name) if market_name in trigger_queue.invalidity_sell: invalidity_sell_orders.append(market_name) """Log the orders to console""" date = str(datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')[:-4]) if buy_orders: LogOutput(date + ': Buy orders: ' + str(buy_orders)) if sell_orders: LogOutput(date + ': Sell orders: ' + str(sell_orders)) if invalidity_sell_orders: LogOutput(date + ': Sell orders because of invalidity: ' + str(invalidity_sell_orders)) LogOutput( str(datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')[:-4]) + ': ' + BASE_CURRENCY + ' balance: ' + str(format(self.__base_currency_balance, '.6f')) + ', Full balance in ' + BASE_CURRENCY + ': ' + str(format(self.CalculateBalanceAll(charts), '.6f')) + '\n')