def buyCoin(coin): my_bittrex = Bittrex('******', '####') market = 'BTC-' + coin price_btc = my_bittrex.get_ticker(market)['result']['Ask'] finance = finances.Finances() size = (finance.getBuyAmount() / price_btc) #size = ((profits*0.92)/(price_btc)) my_bittrex.buy_limit(market, size, price_btc) print('BOUGHT', coin) ledger_list.append({'coin': coin, 'price': price_btc, 'size': size}) print(ledger_list) f = open('ledger.txt', 'w+') f.write(str(ledger_list)) # updateProfitsSpent(profits*0.92) f.close()
class TestBittrexMarketAPI(unittest.TestCase): def setUp(self): self.bittrex = Bittrex() def test_secret_and_key(self): try: os.environ['BITTREX_KEY'] os.environ['BITTREX_SECRET'] except KeyError: self.fail("Requires BITTREX_KEY and BITTREX_SECRET env variables") def test_buy_limit(self): self.assertRaises(TypeError, self.bittrex.buy_limit) actual = self.bittrex.buy_limit('BTC-LTC', 1, 1) test_response_structure(self, actual, 'buy_limit') def test_sell_limit(self): self.assertRaises(TypeError, self.bittrex.buy_limit) actual = self.bittrex.sell_limit('BTC-LTC', 1, 1) test_response_structure(self, actual, 'sell_limit') def test_cancel(self): self.assertRaises(TypeError, self.bittrex.cancel) # provide invalid uuid but test the json structure actual = self.bittrex.cancel('BTC-LTC') test_response_structure(self, actual, 'cancel') def test_open_orders(self): invalid_actual = self.bittrex.get_open_orders('Invalid Market') no_param_actual = self.bittrex.get_open_orders() actual = self.bittrex.get_open_orders('BTC-LTC') test_failed_response(self, invalid_actual, 'get_open_orders') test_basic_response(self, no_param_actual, 'get_open_orders') test_basic_response(self, actual, 'get_open_orders')
class BittrexWrapper(object): def __init__(self, apiKey, apiSecret): self.apiKey = apiKey self.apiSecret = apiSecret self.api = Bittrex(self.apiKey, self.apiSecret) self.failure = (False, 0, 0) def get_price(self, market_code, base_code='BTC'): self.currency_code = '%s-%s' % (base_code, market_code) price_ticker = bittrex_api.get_ticker(currency_code) if price_ticker['success']: return price_ticker else: return {} def get_address(self): deposit_address_query = self.api.get_deposit_address(base_code) if deposit_address_query['success'] == False and deposit_address_query['message'] == 'ADDRESS_GENERATING': time.sleep(10) deposit_address_query = self.api.get_deposit_address(base_code) def buy_coins(self, market_code, price, base_code='BTC'): currency_code = '%s-%s' % (base_code, market_code) price_ticker = self.api.get_ticker(currency_code) if price_ticker['success']: ask_price = price_ticker['result']['Ask'] else: return self.failure quantity = price / ask_price sell_market_query = self.api.buy_limit(currency_code, quantity, ask_price) if sell_market_query['success']: order_uuid = sell_market_query['result']['uuid'] elif not sell_market_query['success']: return self.Failure # Sleep for long enough for bittrex to process the order time.sleep(30) # 4) Check the Order order_status_query = bittrex_api.get_order(order_uuid) if order_status_query['success']: aOrder = dict() aOrder['price'] = order_status_query['result']['Price'] aOrder['Quantity'] = order_status_query['result']['Quantity'] aOrder['Exchange'] = order_status_query['result']['Exchange'] aOrder['completed'] = True return aOrder['completed'], aOrder['price'], aOrder['Quantity'] else: return self.Failure
class Trader(object): """ Used for handling all trade functionality """ def __init__(self, secrets): self.trade_params = secrets["tradeParameters"] self.pause_params = secrets["pauseParameters"] self.Bittrex = Bittrex(secrets) self.Messenger = Messenger(secrets) self.Database = Database() def initialise(self): """ Fetch the initial coin pairs to track and to print the header line """ try: if len(self.Database.app_data["coinPairs"]) < 1: self.Database.store_coin_pairs(self.get_markets("BTC")) self.Messenger.print_header( len(self.Database.app_data["coinPairs"])) except ConnectionError as exception: self.Messenger.print_exception_error("connection") logger.exception(exception) exit() def analyse_pauses(self): """ Check all the paused buy and sell pairs and reactivate the necessary ones """ if self.Database.check_resume(self.pause_params["buy"]["pauseTime"], "buy"): self.Database.store_coin_pairs(self.get_markets("BTC")) self.Messenger.print_resume_pause( len(self.Database.app_data["coinPairs"]), "buy") if self.Database.check_resume(self.pause_params["sell"]["pauseTime"], "sell"): self.Messenger.print_resume_pause( self.Database.app_data["pausedTrackedCoinPairs"], "sell") self.Database.resume_sells() def analyse_buys(self): """ Analyse all the un-paused coin pairs for buy signals and apply buys """ trade_len = len(self.Database.trades["trackedCoinPairs"]) pause_trade_len = len(self.Database.app_data["pausedTrackedCoinPairs"]) if (trade_len < 1 or pause_trade_len == trade_len ) and trade_len < self.trade_params["buy"]["maxOpenTrades"]: for coin_pair in self.Database.app_data["coinPairs"]: self.buy_strategy(coin_pair) def analyse_sells(self): """ Analyse all the un-paused tracked coin pairs for sell signals and apply sells """ for coin_pair in self.Database.trades["trackedCoinPairs"]: if coin_pair not in self.Database.app_data[ "pausedTrackedCoinPairs"]: self.sell_strategy(coin_pair) def buy_strategy(self, coin_pair): """ Applies the buy checks on the coin pair and handles the results appropriately :param coin_pair: Coin pair market to check (ex: BTC-ETH, BTC-FCT) :type coin_pair: str """ if (len(self.Database.trades["trackedCoinPairs"]) >= self.trade_params["buy"]["maxOpenTrades"] or coin_pair in self.Database.trades["trackedCoinPairs"]): return rsi = self.calculate_RSI(coin_pair=coin_pair, period=14, unit=self.trade_params["tickerInterval"]) day_volume = self.get_current_24hr_volume(coin_pair) current_buy_price = self.get_current_price(coin_pair, "ask") if self.check_buy_parameters(rsi, day_volume, current_buy_price): buy_stats = {"rsi": rsi, "24HrVolume": day_volume} self.buy(coin_pair, self.trade_params["buy"]["btcAmount"], current_buy_price, buy_stats) elif rsi is not None and rsi <= self.pause_params["buy"][ "rsiThreshold"]: self.Messenger.print_no_buy(coin_pair, rsi, day_volume, current_buy_price) elif rsi is not None: self.Messenger.print_pause(coin_pair, rsi, self.pause_params["buy"]["pauseTime"], "buy") self.Database.pause_buy(coin_pair) def sell_strategy(self, coin_pair): """ Applies the sell checks on the coin pair and handles the results appropriately :param coin_pair: Coin pair market to check (ex: BTC-ETH, BTC-FCT) :type coin_pair: str """ if (coin_pair in self.Database.app_data["pausedTrackedCoinPairs"] or coin_pair not in self.Database.trades["trackedCoinPairs"]): return rsi = self.calculate_RSI(coin_pair=coin_pair, period=14, unit=self.trade_params["tickerInterval"]) current_sell_price = self.get_current_price(coin_pair, "bid") profit_margin = self.Database.get_profit_margin( coin_pair, current_sell_price) if self.check_sell_parameters(rsi, profit_margin): sell_stats = {"rsi": rsi, "profitMargin": profit_margin} self.sell(coin_pair, current_sell_price, sell_stats) elif rsi is not None and profit_margin >= self.pause_params["sell"][ "profitMarginThreshold"]: self.Messenger.print_no_sell(coin_pair, rsi, profit_margin, current_sell_price) elif rsi is not None: self.Messenger.print_pause(coin_pair, profit_margin, self.pause_params["sell"]["pauseTime"], "sell") self.Database.pause_sell(coin_pair) def check_buy_parameters(self, rsi, day_volume, current_buy_price): """ Used to check if the buy conditions have been met :param rsi: The coin pair's current RSI :type rsi: float :param day_volume: The coin pair's current 24 hour volume :type day_volume: float :param current_buy_price: The coin pair's current price :type current_buy_price: float :return: Boolean indicating if the buy conditions have been met :rtype : bool """ return ( rsi is not None and rsi <= self.trade_params["buy"]["rsiThreshold"] and day_volume >= self.trade_params["buy"]["24HourVolumeThreshold"] and current_buy_price > self.trade_params["buy"]["minimumUnitPrice"]) def check_sell_parameters(self, rsi, profit_margin): """ Used to check if the sell conditions have been met :param rsi: The coin pair's current RSI :type rsi: float :param profit_margin: The coin pair's current profit margin :type profit_margin: float :return: Boolean indicating if the sell conditions have been met :rtype : bool """ return ((rsi is not None and rsi >= self.trade_params["sell"]["rsiThreshold"] and profit_margin > self.trade_params["sell"]["minProfitMarginThreshold"]) or profit_margin > self.trade_params["sell"]["profitMarginThreshold"]) def buy(self, coin_pair, btc_quantity, price, stats, trade_time_limit=2): """ Used to place a buy order to Bittrex. Wait until the order is completed. If the order is not filled within trade_time_limit minutes cancel it. :param coin_pair: String literal for the market (ex: BTC-LTC) :type coin_pair: str :param btc_quantity: The amount of BTC to buy with :type btc_quantity: float :param price: The price at which to buy :type price: float :param stats: The buy stats object :type stats: dict :param trade_time_limit: The time in minutes to wait fot the order before cancelling it :type trade_time_limit: float """ buy_data = self.Bittrex.buy_limit(coin_pair, btc_quantity / price, price) if not buy_data["success"]: return logger.error( "Failed to buy on {} market.".format(coin_pair)) self.Database.store_initial_buy(coin_pair, buy_data["result"]["uuid"]) buy_order_data = self.get_order(buy_data["result"]["uuid"], trade_time_limit * 60) self.Database.store_buy(buy_order_data["result"], stats) self.Messenger.send_buy_email(buy_order_data["result"], stats) self.Messenger.print_buy(coin_pair, price, stats["rsi"], stats["24HrVolume"]) self.Messenger.play_sw_imperial_march() def sell(self, coin_pair, price, stats, trade_time_limit=2): """ Used to place a sell order to Bittrex. Wait until the order is completed. If the order is not filled within trade_time_limit minutes cancel it. :param coin_pair: String literal for the market (ex: BTC-LTC) :type coin_pair: str :param price: The price at which to buy :type price: float :param stats: The buy stats object :type stats: dict :param trade_time_limit: The time in minutes to wait fot the order before cancelling it :type trade_time_limit: float """ trade = self.Database.get_open_trade(coin_pair) sell_data = self.Bittrex.sell_limit(coin_pair, trade["quantity"], price) if not sell_data["success"]: return logger.error( "Failed to sell on {} market. Bittrex error message: {}". format(coin_pair, sell_data["message"])) sell_order_data = self.get_order(sell_data["result"]["uuid"], trade_time_limit * 60) # TODO: Handle partial/incomplete sales. self.Database.store_sell(sell_order_data["result"], stats) self.Messenger.send_sell_email(sell_order_data["result"], stats) self.Messenger.print_sell(coin_pair, price, stats["rsi"], stats["profitMargin"]) self.Messenger.play_sw_theme() def get_markets(self, main_market_filter=None): """ Gets all the Bittrex markets and filters them based on the main market filter :param main_market_filter: Main market to filter on (ex: BTC, ETH, USDT) :type main_market_filter: str :return: All Bittrex markets (with filter applied, if any) :rtype : list """ markets = self.Bittrex.get_markets() if not markets["success"]: logger.error("Failed to fetch Bittrex markets") exit() markets = markets["result"] if main_market_filter is not None: market_check = main_market_filter + "-" markets = py_.filter_( markets, lambda market: market_check in market["MarketName"]) markets = py_.map_(markets, lambda market: market["MarketName"]) return markets def get_current_price(self, coin_pair, price_type): """ Gets current market price for a coin pair :param coin_pair: Coin pair market to check (ex: BTC-ETH, BTC-FCT) :type coin_pair: str :param price_type: The type of price to get (one of: 'ask', 'bid') :type price_type: str :return: Coin pair's current market price :rtype : float """ coin_summary = self.Bittrex.get_market_summary(coin_pair) if not coin_summary["success"]: logger.error( "Failed to fetch Bittrex market summary for the {} market". format(coin_pair)) return None if price_type == "ask": return coin_summary["result"][0]["Ask"] if price_type == "bid": return coin_summary["result"][0]["Bid"] return coin_summary["result"][0]["Last"] def get_current_24hr_volume(self, coin_pair): """ Gets current 24 hour market volume for a coin pair :param coin_pair: Coin pair market to check (ex: BTC-ETH, BTC-FCT) :type coin_pair: str :return: Coin pair's current 24 hour market volume :rtype : float """ coin_summary = self.Bittrex.get_market_summary(coin_pair) if not coin_summary["success"]: logger.error( "Failed to fetch Bittrex market summary for the {} market". format(coin_pair)) return None return coin_summary["result"][0]["BaseVolume"] def get_closing_prices(self, coin_pair, period, unit): """ Returns closing prices within a specified time frame for a coin pair :param coin_pair: String literal for the market (ex: BTC-LTC) :type coin_pair: str :param period: Number of periods to query :type period: int :param unit: Ticker interval (one of: 'oneMin', 'fiveMin', 'thirtyMin', 'hour', 'week', 'day', and 'month') :type unit: str :return: Array of closing prices :rtype : list """ historical_data = self.Bittrex.get_historical_data( coin_pair, period, unit) closing_prices = [] for i in historical_data: closing_prices.append(i["C"]) return closing_prices def get_order(self, order_uuid, trade_time_limit): """ Used to get an order from Bittrex by it's UUID. First wait until the order is completed before retrieving it. If the order is not completed within trade_time_limit seconds, cancel it. :param order_uuid: The order's UUID :type order_uuid: str :param trade_time_limit: The time in seconds to wait fot the order before cancelling it :type trade_time_limit: float :return: Order object :rtype : dict """ start_time = time.time() order_data = self.Bittrex.get_order(order_uuid) while time.time() - start_time <= trade_time_limit and order_data[ "result"]["IsOpen"]: time.sleep(10) order_data = self.Bittrex.get_order(order_uuid) if order_data["result"]["IsOpen"]: error_str = self.Messenger.print_order_error( order_uuid, trade_time_limit, order_data["result"]["Exchange"]) logger.error(error_str) if order_data["result"]["Type"] == "LIMIT_BUY": self.Bittrex.cancel(order_uuid) return order_data return order_data def calculate_RSI(self, coin_pair, period, unit): """ Calculates the Relative Strength Index for a coin_pair If the returned value is above 75, it's overbought (SELL IT!) If the returned value is below 25, it's oversold (BUY IT!) :param coin_pair: String literal for the market (ex: BTC-LTC) :type coin_pair: str :param period: Number of periods to query :type period: int :param unit: Ticker interval (one of: 'oneMin', 'fiveMin', 'thirtyMin', 'hour', 'week', 'day', and 'month') :type unit: str :return: RSI :rtype : float """ closing_prices = self.get_closing_prices(coin_pair, period * 3, unit) count = 0 change = [] # Calculating price changes for i in closing_prices: if count != 0: change.append(i - closing_prices[count - 1]) count += 1 if count == 15: break # Calculating gains and losses advances = [] declines = [] for i in change: if i > 0: advances.append(i) if i < 0: declines.append(abs(i)) average_gain = (sum(advances) / 14) average_loss = (sum(declines) / 14) new_avg_gain = average_gain new_avg_loss = average_loss for _ in closing_prices: if 14 < count < len(closing_prices): close = closing_prices[count] new_change = close - closing_prices[count - 1] add_loss = 0 add_gain = 0 if new_change > 0: add_gain = new_change if new_change < 0: add_loss = abs(new_change) new_avg_gain = (new_avg_gain * 13 + add_gain) / 14 new_avg_loss = (new_avg_loss * 13 + add_loss) / 14 count += 1 if new_avg_loss == 0: return None rs = new_avg_gain / new_avg_loss new_rs = 100 - 100 / (1 + rs) return new_rs
class TradeBot(): def __init__(self, key=None, secret=None, **kwargs): self.exchange = Bittrex(key, secret) self.orders = [] # Default config config = { 'base_currency': 'ETH', 'min_order': 0.001, 'max_order': 0.05, 'sleep_time': 60, 'profit': 2, 'min_volume': 75, 'max_units': 100 } # Update config from object constructor config.update(kwargs) # Set attributes based on config for attr in config.keys(): setattr(self, attr, config[attr]) def get_markets(self): logging.info(f'Getting markets for {self.base_currency}') all_markets = self.exchange.get_markets()['result'] markets = set() for mkt in all_markets: if mkt['BaseCurrency'] == self.base_currency: markets.add(mkt['MarketName']) return markets def get_coins_with_open_orders(self): open_orders = self.exchange.get_open_orders()['result'] if len(open_orders) == 0: return [] else: return [x['Exchange'] for x in open_orders] def get_market_data(self): mkt_data = [] for mkt in self.markets: logging.info(f'Getting market data for {mkt}') data = self.exchange.get_marketsummary(mkt)['result'][0] data['Change'] = calculate_change(data['Last'], data['Low']) mkt_data.append(data) return mkt_data def has_balance_to_buy(self): logging.info('checking if we have some balance to buy') q = self.exchange.get_balance(self.base_currency) # balance_adjustment to avoid INSUFFICIENT FUNDS MESSAGE balance_adjustment = 0.0005 self.balance = q['result']['Available'] - balance_adjustment logging.debug(f'{self.balance}{self.base_currency} available') if self.balance >= self.min_order: return True else: return False def get_market_to_buy(self): self.update() mkt = [ m for m in self.market_data if m['BaseVolume'] >= self.min_volume ] sorted_mkt = sorted(mkt, key=lambda x: x['BaseVolume'], reverse=True) while sorted_mkt[0]['MarketName'] in self.coins_with_open_orders: sorted_mkt.pop(0) return sorted_mkt[0] def buy(self, mkt): coin = mkt['MarketName'] # get a price between ask and bid price = (mkt['Ask'] + mkt['Bid']) / 2 if self.balance > self.max_order: qnt = self.max_order / price else: qnt = self.balance / price if qnt > self.max_units: qnt = self.max_units if (qnt * price) < self.min_order: qnt = self.min_order / price logging.info(f'BUY {qnt} {coin} - price {price}, total {price * qnt}') order = self.exchange.buy_limit(coin, qnt, price) if order['success']: self.orders.append(order['result']['uuid']) else: logging.error(f'BUY FAIL - {order}') return (order) def sell(self): for order in self.orders: order_info = self.exchange.get_order(order)['result'] if order_info['Closed']: coin = order_info['Exchange'] qnt = order_info['Quantity'] price = profit(order_info['PricePerUnit'], self.profit) sell_order = self.exchange.sell_limit(coin, qnt, price) self.orders.remove(order) logging.info(f'SELL {order} {sell_order}') def update(self): logging.info('Updating data') self.markets = self.get_markets() self.market_data = self.get_market_data() self.coins_with_open_orders = self.get_coins_with_open_orders() def do_trade(self): if self.has_balance_to_buy(): self.buy(self.get_market_to_buy()) if len(self.orders) > 0: self.sell() logging.info(f'Sleeping for {self.sleep_time} seconds') sleep(self.sleep_time) def run(self): logging.info('Starting Bot') while True: self.do_trade()
class CryptoArb(object): """ Integration tests for the Bittrex Account API. * These will fail in the absence of an internet connection or if bittrex API goes down. * They require a valid API key and secret issued by Bittrex. * They also require the presence of a JSON file called secrets.json. It is structured as such: { "key": "12341253456345", "secret": "3345745634234534" } """ def setUp(self): with open("secrets.json") as secrets_file: self.secrets = json.load(secrets_file) secrets_file.close() self.bittrex = Bittrex(self.secrets['key'], self.secrets['secret']) def test(self): desiredResult = .95 ## ETHEREUM btcResult = 0 LoopNumber = 1 while btcResult < desiredResult: markets = self.bittrex.get_market_summaries() marketCount = len(markets["result"]) print("Start - " + str(LoopNumber)) btcCount = 0 ethCount = 0 ### ~~ Filling the BTC-ALT Matrix ~~ ### # Counting the number of BTC Currency Pairs btcLoopCount = 0 while btcLoopCount < marketCount: if "BTC-" in markets["result"][btcLoopCount]["MarketName"]: btcCount = btcCount + 1 btcLoopCount = btcLoopCount + 1 # Creating the BTC pair-exchange matrix btcCol, btcRow = 2, btcCount BTCMatrix = [[0 for x in range(btcCol)] for y in range(btcRow)] # Filling the BTC Matrix btcLoopCount = 0 btcMatrixRowCount = 0 while btcLoopCount < marketCount: if "BTC-" in markets["result"][btcLoopCount]["MarketName"]: BTCMatrix[btcMatrixRowCount][0] = markets["result"][ btcLoopCount]["MarketName"] BTCMatrix[btcMatrixRowCount][1] = markets["result"][ btcLoopCount]["Ask"] btcMatrixRowCount = btcMatrixRowCount + 1 btcLoopCount = btcLoopCount + 1 ### ~~ Filling the ETH-ALT Matrix ~~ ### # Counting the number of ETH Currency Pairs ethLoopCount = 0 while ethLoopCount < marketCount: if "ETH-" in markets["result"][ethLoopCount]["MarketName"]: ethCount = ethCount + 1 ethLoopCount = ethLoopCount + 1 # Creating the ETH pair-exchange matrix ethCol, ethRow = 2, ethCount ETHMatrix = [[0 for x in range(ethCol)] for y in range(ethRow)] # Filling the ETH Matrix ethLoopCount = 0 ethMatrixRowCount = 0 while ethLoopCount < marketCount: if "ETH-" in markets["result"][ethLoopCount]["MarketName"]: ETHMatrix[ethMatrixRowCount][0] = markets["result"][ ethLoopCount]["MarketName"] ETHMatrix[ethMatrixRowCount][1] = markets["result"][ ethLoopCount]["Bid"] ethMatrixRowCount = ethMatrixRowCount + 1 ethLoopCount = ethLoopCount + 1 btc_ethTick = self.bittrex.get_ticker("BTC-ETH") btc_eth_BTC = btc_ethTick["result"]["Bid"] # ~~~ Comparing Bitcoin Arbitrage Returns ~~~ # arbBTCPairs = [] arbBTCReturn = [] arbBTCTestReturn = [] arbBTCRow = 0 for btcAlt in BTCMatrix: for ethAlt in ETHMatrix: if ethAlt[0][4:] == btcAlt[0][4:]: btcResult = 0 #arbBTCPairs.append(str(btcAlt[0]) + " > " + str(ethAlt[0]) + " > BTC_ETH") arbPath = str(btcAlt[0]) + " > " + str( ethAlt[0]) + " > BTC_ETH" btcAltDiff = 0.0000007 altEthDiff = -0.0000002 ethBtcDiff = -0.000001 # Forumla to check returns print("BTC -> Alt: " + str(btcAlt[1])) btc_altX = float(btcAlt[1] + btcAltDiff) print("Alt -> ETH: " + str(ethAlt[1])) eth_altX = float(ethAlt[1] + altEthDiff) print("ETH -> BTC: " + str(btc_eth_BTC)) btc_ethX = float(btc_eth_BTC + ethBtcDiff) #test1 = float(btcAlt[1] - 0.00000001) #test2 = float(ethAlt[1] - 0.00000001) #test3 = float(btc_eth_BTC - 0.0000004) print( str(btcAlt[0]) + " > " + str(ethAlt[0]) + " > BTC_ETH") btcUnits = 1 print("BTC = " + str(btcUnits)) altUnits = round(((btcUnits / 1.0025) / btc_altX), 8) #testaltUnits = round(((btcUnits / 1.0025) / test1), 8) print("Alt Units = " + str(altUnits) + " (" + str(btc_altX) + ")") #print("Test Alt Units = " + str(testaltUnits) + " (" + str(test1) + ")") ethUnits = round( ((altUnits - (altUnits * 0.0025)) * eth_altX), 8) #testethUnits = round(((testaltUnits - (testaltUnits * 0.0025)) * test2), 8) print("ETH Units = " + str(ethUnits) + " (" + str(eth_altX) + ")") #print("Test ETH Units = " + str(testethUnits) + " (" + str(test2) + ")") btcResult = round( ((ethUnits - (ethUnits * 0.0025)) * btc_ethX), 8) #testbtcResult = round(((testethUnits - (testethUnits * 0.0025)) * test3), 8) print("BTC Result = " + str(btcResult) + " (" + str(btc_ethX) + ")") #print("Test BTC Result = " + str(testbtcResult) + " (" + str(test3) + ")") print("") #arbBTCReturn.append(btcResult) #arbBTCTestReturn.append(testbtcResult) print(btcAlt[0]) if (btcResult ) >= desiredResult and btcAlt[0] != "BTC-SALT": print("!! Desired Result Reached !!") break arbBTCRow = arbBTCRow + 1 if (btcResult) >= desiredResult and btcAlt[0] != "BTC-SALT": break print("") # If desired result is not reached empty the lists to start again if btcResult <= desiredResult: BTCMatrix[:] = [] ETHMatrix[:] = [] arbBTCPairs[:] = [] arbBTCReturn[:] = [] LoopNumber = LoopNumber + 1 # Loops if return isn't good enough i.e. > 1.005 # Loop has been exited because return is good enough # If statement is final check to make sure return is good enough if float(btcResult) > desiredResult and btcAlt[0] != "BTC-SALT": print("Arb Return = " + str(btcResult)) print("begin timer") startTime = time.time() # Path of the arb which yiels return i.e. BTC -> ALT -> ETH -> BTC #print(arbPath) # Getting name of Alt if len(arbPath) == 25: alt = arbPath[4:6] print("Alt = " + alt) elif len(arbPath) == 27: alt = arbPath[4:7] print("Alt = " + alt) elif len(arbPath) == 29: alt = arbPath[4:8] print("Alt = " + alt) elif len(arbPath) == 31: alt = arbPath[4:9] print("Alt = " + alt) else: print("Wrong Number Letters " + len(arbPath)) print("Time elapsed " + str(time.time() - startTime)) # Begin Buy Process orderBTCALTBook = self.bittrex.get_orderbook( "BTC-" + str(alt), "sell") print("") #BTCBal = self.bittrex.get_balance("BTC") #if str(BTCBal["result"]["Balance"]) == "None": # principle = 0 #else: # principle = float(BTCBal["result"]["Balance"]) principle = 0.00065 print("Principle = " + str(principle)) AltQuantity = 0 ETHQuantity = 0 BTCQuantity = 0 market = "BTC-" + alt print("Market = " + market) print("") actBtcAltRate = 0 actAltEthRate = 0 actEthBtcRate = 0 btcOrderCount = 0 while principle > 0: print("BTC -> " + str(alt) + " Order " + str(btcOrderCount + 1) + ": Principle = " + str(principle)) askQuantity = orderBTCALTBook["result"][btcOrderCount][ "Quantity"] askRate = orderBTCALTBook["result"][btcOrderCount]["Rate"] askTotal = askQuantity * askRate print("-- Order Details: --") print("---- Ask Quantity = " + str(askQuantity)) print("---- Ask Rate = " + str(askRate)) print("---- Ask Total = " + str(askTotal)) print("---- Principle = " + str(principle)) print("") if askTotal > principle: print("---- Executing full final trade...") tradeQuantity = math.floor( ((principle / 1.0025) / askRate) * 100000000) / 100000000 print("---- Trade Quantity = " + str(tradeQuantity) + " (" + str(principle / 1.0025) + " / " + str(askRate) + ")") # Execute full or remainder of trade AltQuantity = AltQuantity + tradeQuantity print("---- BUY " + str(AltQuantity) + " " + str(alt) + " @ " + str(askRate) + "BTC = " + str(round((AltQuantity * askRate), 8))) altBuy = self.bittrex.buy_limit(market, AltQuantity, askRate) print("---- " + str(altBuy)) actBtcAltRate = askRate # I can delete this because I have a more accurate below from get_order_history altBuy = True break else: # Execute a portion of the trade print("---- Partial Trade - CANCEL ... ") print("---- BUY " + str(askQuantity) + str(alt) + " @ " + str(askRate) + " BTC = " + str(round((askQuantity * askRate), 8))) AltQuantity = AltQuantity + askQuantity principle = principle - askTotal break #buy = self.bittrex.buy_limit(market, askQuantity, askRate) #print(buy) #principle = (principle * 0.9975) - askTotal # execute trade btcOrderCount = btcOrderCount + 1 print("") print(str(alt) + " Quantity = " + str(AltQuantity)) firstTrade = time.time() - startTime secondTrade = 0 finalTrade = 0 print("Time since arb calc = " + str(firstTrade)) print("") if altBuy == True: orderETHALTBook = self.bittrex.get_orderbook( "ETH-" + str(alt), "buy") market = "ETH-" + alt ogAltQuantity = AltQuantity altOrderCount = 0 while AltQuantity > 0: print( str(alt) + " -> ETH Order " + str(altOrderCount + 1) + ": Principle = " + str(AltQuantity)) bidQuantity = orderETHALTBook["result"][altOrderCount][ "Quantity"] bidRate = orderETHALTBook["result"][altOrderCount]["Rate"] bidTotal = bidQuantity * bidRate print("-- Order Details: --") print("---- Bid Quantity = " + str(bidQuantity)) print("---- Bid Rate = " + str(bidRate)) print("---- Bid Total = " + str(bidTotal)) print("---- Alt Quantity = " + str(AltQuantity)) print("") if bidQuantity > AltQuantity: print("Executing full final trade...") tradeQuantity = math.floor( ((AltQuantity * 0.9975) * bidRate) * 100000000) / 100000000 print("---- Trade Quantity = " + str(tradeQuantity) + " (" + str(AltQuantity) + " * " + str(bidRate) + ")") # Execute full or remainder of trade print("---- SELL " + str(ogAltQuantity) + " " + str(alt) + " @ " + str(bidRate) + "ETH = " + str(tradeQuantity)) ETHQuantity = ETHQuantity + tradeQuantity altSell = self.bittrex.sell_limit( market, ogAltQuantity, bidRate) print("---- " + str(altSell)) actAltEthRate = bidRate # I can delete this because I have a more accurate below from get_order_history altSell = True break else: # Execute a portion of the trade print("---- Executing partial trade... " + str(bidQuantity) + str(alt) + " @ " + str(bidRate) + "ETH = " + str(bidQuantity * bidRate)) ETHQuantity = (ETHQuantity + bidTotal) * 0.9975 sell = self.bittrex.sell_limit(market, bidQuantity, bidRate) print(sell) AltQuantity = AltQuantity - bidQuantity # execute trade print("") altOrderCount = altOrderCount + 1 if altSell == True: print("") print("ETH Quantity = " + str(ETHQuantity)) secondTrade = time.time() - startTime print("Time since arb calc = " + str(secondTrade)) print("") orderBTCETHBook = self.bittrex.get_orderbook( "BTC-ETH", "buy") ogETHQuantity = ETHQuantity market = "BTC-ETH" ethOrderCount = 0 while ETHQuantity > 0: print("ETH -> BTC Order " + str(ethOrderCount + 1) + ": Principle = " + str(ETHQuantity)) bidQuantity = orderBTCETHBook["result"][ethOrderCount][ "Quantity"] bidRate = orderBTCETHBook["result"][ethOrderCount][ "Rate"] bidTotal = bidQuantity * bidRate print("-- Order Details: --") print("---- Bid Quantity = " + str(bidQuantity)) print("---- Bid Rate = " + str(bidRate)) print("---- Bid Total = " + str(bidTotal)) print("---- ETH Quantity = " + str(ETHQuantity)) print("") if bidQuantity > ETHQuantity: print("---- Executing full final trade...") tradeQuantity = math.floor( ((ETHQuantity * 0.9975) * bidRate) * 100000000) / 100000000 print("---- Trade Quantity = " + str(tradeQuantity) + " (" + str(ETHQuantity) + " * " + str(bidRate) + ")") # Execute full or remainder of trade print("---- SELL " + str(ogETHQuantity) + " ETH @ " + str(bidRate) + "BTC = " + str(tradeQuantity)) BTCQuantity = BTCQuantity + tradeQuantity sell = self.bittrex.sell_limit( market, ogETHQuantity, bidRate) print("---- " + str(sell)) actEthBtcRate = bidRate # I can delete this because I have a more accurate below from get_order_history break else: # Execute a portion of the trade print("---- Executing partial trade... " + str(bidQuantity) + "ETH @ " + str(bidRate) + "BTC = " + str(bidQuantity * bidRate)) BTCQuantity = BTCQuantity + bidTotal sell = self.bittrex.sell_limit( market, bidQuantity, bidRate) print(sell) ETHQuantity = ETHQuantity - bidQuantity # execute trade ethOrderCount = ethOrderCount + 1 print(BTCQuantity) finalTrade = time.time() - startTime print("Time since arb calc = " + str(finalTrade)) btcAltMarket = self.bittrex.get_market_summary("BTC-" + str(alt)) btcAltVolume = btcAltMarket["result"][0]["Volume"] altEthMarket = self.bittrex.get_market_summary("ETH-" + str(alt)) altEthVolume = altEthMarket["result"][0]["Volume"] ethBtcMarket = self.bittrex.get_market_summary("BTC-ETH") ethBtcVolume = ethBtcMarket["result"][0]["Volume"] # Grab bittrex Trade Details # 1 - BTC-ALT #tradeDetails = self.bittrex.get_order_history() tradeDetails = self.bittrex.get_order_history() tradeOne = tradeDetails["result"][2] tradeTwo = tradeDetails["result"][1] tradeThree = tradeDetails["result"][0] # Actual Arb Return tradeOneActualValue = tradeOne["Price"] + tradeOne[ "Commission"] tradeThreeActualValue = tradeThree["Price"] + tradeThree[ "Commission"] actualArbReturn = tradeThreeActualValue / tradeOneActualValue # Actual Rates tradeOneActualRate = tradeOne["PricePerUnit"] tradeTwoActualRate = tradeTwo["PricePerUnit"] tradeThreeActualRate = tradeThree["PricePerUnit"] with open('Trade Tracker.csv', 'a', newline='') as csvfile: tracker = csv.writer(csvfile, delimiter=',', quotechar='|', quoting=csv.QUOTE_MINIMAL) tracker.writerow([ arbPath, datetime.datetime.now().strftime( "%Y-%m-%d %H:%M:%S.%f")[:-3], btcResult, actualArbReturn, str(btcAlt[1]), str(btcAltDiff), btcAlt[1] + btcAltDiff, tradeOneActualRate, str(btcAlt[1] - tradeOneActualRate), str(( (btcAlt[1] - tradeOneActualRate) / btcAlt[1]) * 100), str(firstTrade), str(btcAltVolume), str(ethAlt[1]), str(altEthDiff), str(ethAlt[1] + altEthDiff), tradeTwoActualRate, str(ethAlt[1] - tradeTwoActualRate), str(( (ethAlt[1] - tradeTwoActualRate) / ethAlt[1]) * 100), str(secondTrade), str(altEthVolume), str(btc_eth_BTC), str(ethBtcDiff), str(btc_eth_BTC + ethBtcDiff), tradeThreeActualRate, str(btc_eth_BTC - tradeThreeActualRate), str(((btc_eth_BTC - tradeThreeActualRate) / btc_eth_BTC) * 100), str(finalTrade), str(ethBtcVolume) ]) print("Excel Save Successful") db = firebase.database() data = { "Arb Path": arbPath, "Date Time": datetime.datetime.now().strftime( "%Y-%m-%d %H:%M:%S.%f")[:-3], "Principle": principle, "Actual Return": BTCQuantity, "Expected Arb Return": btcResult, "Actual Arb Return": actualArbReturn, "Trade 1 Quoted Rate": str(btcAlt[1]), "Trade 1 Adjustment": str(btcAltDiff), "Trade 1 Adjusted Quote": btcAlt[1] + btcAltDiff, "Trade 1 Actual Rate": tradeOneActualRate, "Trade 1 Actual-Quote Diff": str(btcAlt[1] - tradeOneActualRate), "Trade 1 Actual-Quote % Diff": str(((btcAlt[1] - tradeOneActualRate) / btcAlt[1]) * 100), "Trade 1 Time From Quote": str(firstTrade), "Trade 1 Market Volume": str(btcAltVolume), "Trade 2 Quoted Rate": str(ethAlt[1]), "Trade 2 Adjustment": str(altEthDiff), "Trade 2 Adjusted Quote": str(ethAlt[1] + altEthDiff), "Trade 2 Actual Rate": tradeTwoActualRate, "Trade 2 Actual-Quote Diff": str(ethAlt[1] - tradeTwoActualRate), "Trade 2 Actual-Quote % Diff": str(((ethAlt[1] - tradeTwoActualRate) / ethAlt[1]) * 100), "Trade 2 Time From Quote": str(secondTrade), "Trade 2 Market Volume": str(altEthVolume), "Trade 3 Quoted Rate": str(btc_eth_BTC), "Trade 3 Adjustment": str(ethBtcDiff), "Trade 3 Adjusted Quote": str(btc_eth_BTC + ethBtcDiff), "Trade 3 Actual Rate": tradeThreeActualRate, "Trade 3 Actual-Quote Diff": str(btc_eth_BTC - tradeThreeActualRate), "Trade 3 Actual-Quote % Diff Rate": str(((btc_eth_BTC - tradeThreeActualRate) / btc_eth_BTC) * 100), "Trade 3 Time From Quote": str(finalTrade), "Trade 3 Market Volume": str(ethBtcVolume) } db.child("Successful Transactions").push(data) else: print("ALT -> ETH Fail") else: print("BTC -> ALT Fail")
class bittrex_private: def __init__(self): # self.bittrex_public = Bittrex(None, None) # 公開情報を扱うBittrexオブジェクト self.bittrex_private = Bittrex(KEY, SECRET) # 個人の情報を扱うBittrexオブジェクト # トレード履歴を取得 def get_order_history(self): response = self.bittrex_private.get_order_history() pprint(response) return response # 買い注文を出す # marketに通貨ペア、quantityに注文する量、rateに価格を指定 def buy_alt_coin(self, market, quantity, rate): response = self.bittrex_private.buy_limit(market=market, quantity=quantity, rate=rate) # 成功なら注文id、失敗ならfalseを返す if response['success'] is False: print(response) return False else: return response['result']['uuid'] # 売り注文を出す # marketに通貨ペア、quantityに注文する量、rateに価格を指定 def sell_alt_coin(self, market, quantity, rate): response = self.bittrex_private.sell_limit(market=market, quantity=quantity, rate=rate) # 成功なら注文id、失敗ならfalseを返す if response['success'] is False: print(response) return False else: return response['result']['uuid'] # 注文をキャンセルする def order_cancel(self, uuid): response = self.bittrex_private.cancel(uuid=uuid) # 成功ならtrue、失敗ならfalseを返す print(response) return response['success'] # 注文一覧を取得する def get_orders(self): order_list = [] response = self.bittrex_private.get_open_orders() if response['success'] is False: print(response) return False else: # 注文が1件もない場合 if len(response['result']) == 0: return None for item in response['result']: # 通貨の種類と量、注文IDを抜き出す balance = {} balance['market'] = item['Exchange'] balance['quantity'] = item['Quantity'] balance['uuid'] = item['OrderUuid'] order_list.append(balance) return order_list # 所有している通貨をList型で返す def get_balances(self): balance_list = [] response = self.bittrex_private.get_balances() if response['success'] is False: print(response) return False else: for item in response['result']: # 利用可能な通貨量が0の場合はスキップする if item['Available'] == 0: continue # 通貨の種類と量を抜き出す balance = {} balance['currency'] = item['Currency'] balance['available'] = item['Available'] balance_list.append(balance) return balance_list
class Trader(object): """ Used for handling all trade functionality """ def __init__(self, secrets): self.trade_params = secrets["tradeParameters"] self.pause_params = secrets["pauseParameters"] self.Bittrex = Bittrex(secrets) self.Messenger = Messenger(secrets) self.Database = Database() def initialise(self): """ Fetch the initial coin pairs to track and to print the header line """ try: if len(self.Database.app_data["coinPairs"]) < 1: self.Database.store_coin_pairs(self.get_markets("BTC")) self.Messenger.print_header(len(self.Database.app_data["coinPairs"])) except ConnectionError as exception: self.Messenger.print_exception_error("connection") logger.exception(exception) exit() def analyse_pauses(self): """ Check all the paused buy and sell pairs and reactivate the necessary ones """ if self.Database.check_resume(self.pause_params["buy"]["pauseTime"], "buy"): self.Database.store_coin_pairs(self.get_markets("BTC")) self.Messenger.print_resume_pause(len(self.Database.app_data["coinPairs"]), "buy") if self.Database.check_resume(self.pause_params["sell"]["pauseTime"], "sell"): self.Messenger.print_resume_pause(self.Database.app_data["pausedTrackedCoinPairs"], "sell") self.Database.resume_sells() def analyse_buys(self): """ Analyse all the un-paused coin pairs for buy signals and apply buys """ trade_len = len(self.Database.trades["trackedCoinPairs"]) pause_trade_len = len(self.Database.app_data["pausedTrackedCoinPairs"]) if (trade_len < 1 or pause_trade_len == trade_len) and trade_len < self.trade_params["buy"]["maxOpenTrades"]: for coin_pair in self.Database.app_data["coinPairs"]: self.buy_strategy(coin_pair) def analyse_sells(self): """ Analyse all the un-paused tracked coin pairs for sell signals and apply sells """ for coin_pair in self.Database.trades["trackedCoinPairs"]: if coin_pair not in self.Database.app_data["pausedTrackedCoinPairs"]: self.sell_strategy(coin_pair) def buy_strategy(self, coin_pair): """ Applies the buy checks on the coin pair and handles the results appropriately :param coin_pair: Coin pair market to check (ex: BTC-ETH, BTC-FCT) :type coin_pair: str """ if (len(self.Database.trades["trackedCoinPairs"]) >= self.trade_params["buy"]["maxOpenTrades"] or coin_pair in self.Database.trades["trackedCoinPairs"]): return rsi = self.calculate_RSI(coin_pair=coin_pair, period=14, unit=self.trade_params["tickerInterval"]) day_volume = self.get_current_24hr_volume(coin_pair) current_buy_price = self.get_current_price(coin_pair, "ask") if self.check_buy_parameters(rsi, day_volume, current_buy_price): buy_stats = { "rsi": rsi, "24HrVolume": day_volume } self.buy(coin_pair, self.trade_params["buy"]["btcAmount"], current_buy_price, buy_stats) elif rsi is not None and rsi <= self.pause_params["buy"]["rsiThreshold"]: self.Messenger.print_no_buy(coin_pair, rsi, day_volume, current_buy_price) elif rsi is not None: self.Messenger.print_pause(coin_pair, rsi, self.pause_params["buy"]["pauseTime"], "buy") self.Database.pause_buy(coin_pair) def sell_strategy(self, coin_pair): """ Applies the sell checks on the coin pair and handles the results appropriately :param coin_pair: Coin pair market to check (ex: BTC-ETH, BTC-FCT) :type coin_pair: str """ if (coin_pair in self.Database.app_data["pausedTrackedCoinPairs"] or coin_pair not in self.Database.trades["trackedCoinPairs"]): return rsi = self.calculate_RSI(coin_pair=coin_pair, period=14, unit=self.trade_params["tickerInterval"]) current_sell_price = self.get_current_price(coin_pair, "bid") profit_margin = self.Database.get_profit_margin(coin_pair, current_sell_price) if self.check_sell_parameters(rsi, profit_margin): sell_stats = { "rsi": rsi, "profitMargin": profit_margin } self.sell(coin_pair, current_sell_price, sell_stats) elif rsi is not None and profit_margin >= self.pause_params["sell"]["profitMarginThreshold"]: self.Messenger.print_no_sell(coin_pair, rsi, profit_margin, current_sell_price) elif rsi is not None: self.Messenger.print_pause(coin_pair, profit_margin, self.pause_params["sell"]["pauseTime"], "sell") self.Database.pause_sell(coin_pair) def check_buy_parameters(self, rsi, day_volume, current_buy_price): """ Used to check if the buy conditions have been met :param rsi: The coin pair's current RSI :type rsi: float :param day_volume: The coin pair's current 24 hour volume :type day_volume: float :param current_buy_price: The coin pair's current price :type current_buy_price: float :return: Boolean indicating if the buy conditions have been met :rtype : bool """ return (rsi is not None and rsi <= self.trade_params["buy"]["rsiThreshold"] and day_volume >= self.trade_params["buy"]["24HourVolumeThreshold"] and current_buy_price > self.trade_params["buy"]["minimumUnitPrice"]) def check_sell_parameters(self, rsi, profit_margin): """ Used to check if the sell conditions have been met :param rsi: The coin pair's current RSI :type rsi: float :param profit_margin: The coin pair's current profit margin :type profit_margin: float :return: Boolean indicating if the sell conditions have been met :rtype : bool """ return ((rsi is not None and rsi >= self.trade_params["sell"]["rsiThreshold"] and profit_margin > self.trade_params["sell"]["minProfitMarginThreshold"]) or profit_margin > self.trade_params["sell"]["profitMarginThreshold"]) def buy(self, coin_pair, btc_quantity, price, stats, trade_time_limit=2): """ Used to place a buy order to Bittrex. Wait until the order is completed. If the order is not filled within trade_time_limit minutes cancel it. :param coin_pair: String literal for the market (ex: BTC-LTC) :type coin_pair: str :param btc_quantity: The amount of BTC to buy with :type btc_quantity: float :param price: The price at which to buy :type price: float :param stats: The buy stats object :type stats: dict :param trade_time_limit: The time in minutes to wait fot the order before cancelling it :type trade_time_limit: float """ buy_data = self.Bittrex.buy_limit(coin_pair, btc_quantity / price, price) if not buy_data["success"]: return logger.error("Failed to buy on {} market.".format(coin_pair)) self.Database.store_initial_buy(coin_pair, buy_data["result"]["uuid"]) buy_order_data = self.get_order(buy_data["result"]["uuid"], trade_time_limit * 60) self.Database.store_buy(buy_order_data["result"], stats) self.Messenger.print_buy(coin_pair, price, stats["rsi"], stats["24HrVolume"]) self.Messenger.send_buy_slack(coin_pair, stats["rsi"], stats["24HrVolume"]) self.Messenger.send_buy_gmail(buy_order_data["result"], stats) self.Messenger.play_sw_imperial_march() def sell(self, coin_pair, price, stats, trade_time_limit=2): """ Used to place a sell order to Bittrex. Wait until the order is completed. If the order is not filled within trade_time_limit minutes cancel it. :param coin_pair: String literal for the market (ex: BTC-LTC) :type coin_pair: str :param price: The price at which to buy :type price: float :param stats: The buy stats object :type stats: dict :param trade_time_limit: The time in minutes to wait fot the order before cancelling it :type trade_time_limit: float """ trade = self.Database.get_open_trade(coin_pair) sell_data = self.Bittrex.sell_limit(coin_pair, trade["quantity"], price) if not sell_data["success"]: return logger.error( "Failed to sell on {} market. Bittrex error message: {}".format(coin_pair, sell_data["message"]) ) sell_order_data = self.get_order(sell_data["result"]["uuid"], trade_time_limit * 60) # TODO: Handle partial/incomplete sales. self.Database.store_sell(sell_order_data["result"], stats) self.Messenger.print_sell(coin_pair, price, stats["rsi"], stats["profitMargin"]) self.Messenger.send_sell_slack(coin_pair, stats["rsi"], stats["profitMargin"]) self.Messenger.send_sell_gmail(sell_order_data["result"], stats) self.Messenger.play_sw_theme() def get_markets(self, main_market_filter=None): """ Gets all the Bittrex markets and filters them based on the main market filter :param main_market_filter: Main market to filter on (ex: BTC, ETH, USDT) :type main_market_filter: str :return: All Bittrex markets (with filter applied, if any) :rtype : list """ markets = self.Bittrex.get_markets() if not markets["success"]: logger.error("Failed to fetch Bittrex markets") exit() markets = markets["result"] if main_market_filter is not None: market_check = main_market_filter + "-" markets = py_.filter_(markets, lambda market: market_check in market["MarketName"]) markets = py_.map_(markets, lambda market: market["MarketName"]) return markets def get_current_price(self, coin_pair, price_type): """ Gets current market price for a coin pair :param coin_pair: Coin pair market to check (ex: BTC-ETH, BTC-FCT) :type coin_pair: str :param price_type: The type of price to get (one of: 'ask', 'bid') :type price_type: str :return: Coin pair's current market price :rtype : float """ coin_summary = self.Bittrex.get_market_summary(coin_pair) if not coin_summary["success"]: logger.error("Failed to fetch Bittrex market summary for the {} market".format(coin_pair)) return None if price_type == "ask": return coin_summary["result"][0]["Ask"] if price_type == "bid": return coin_summary["result"][0]["Bid"] return coin_summary["result"][0]["Last"] def get_current_24hr_volume(self, coin_pair): """ Gets current 24 hour market volume for a coin pair :param coin_pair: Coin pair market to check (ex: BTC-ETH, BTC-FCT) :type coin_pair: str :return: Coin pair's current 24 hour market volume :rtype : float """ coin_summary = self.Bittrex.get_market_summary(coin_pair) if not coin_summary["success"]: logger.error("Failed to fetch Bittrex market summary for the {} market".format(coin_pair)) return None return coin_summary["result"][0]["BaseVolume"] def get_closing_prices(self, coin_pair, period, unit): """ Returns closing prices within a specified time frame for a coin pair :param coin_pair: String literal for the market (ex: BTC-LTC) :type coin_pair: str :param period: Number of periods to query :type period: int :param unit: Ticker interval (one of: 'oneMin', 'fiveMin', 'thirtyMin', 'hour', 'week', 'day', and 'month') :type unit: str :return: Array of closing prices :rtype : list """ historical_data = self.Bittrex.get_historical_data(coin_pair, period, unit) closing_prices = [] for i in historical_data: closing_prices.append(i["C"]) return closing_prices def get_order(self, order_uuid, trade_time_limit): """ Used to get an order from Bittrex by it's UUID. First wait until the order is completed before retrieving it. If the order is not completed within trade_time_limit seconds, cancel it. :param order_uuid: The order's UUID :type order_uuid: str :param trade_time_limit: The time in seconds to wait fot the order before cancelling it :type trade_time_limit: float :return: Order object :rtype : dict """ start_time = time.time() order_data = self.Bittrex.get_order(order_uuid) while time.time() - start_time <= trade_time_limit and order_data["result"]["IsOpen"]: time.sleep(10) order_data = self.Bittrex.get_order(order_uuid) if order_data["result"]["IsOpen"]: error_str = self.Messenger.print_order_error(order_uuid, trade_time_limit, order_data["result"]["Exchange"]) logger.error(error_str) if order_data["result"]["Type"] == "LIMIT_BUY": self.Bittrex.cancel(order_uuid) return order_data return order_data def calculate_RSI(self, coin_pair, period, unit): """ Calculates the Relative Strength Index for a coin_pair If the returned value is above 75, it's overbought (SELL IT!) If the returned value is below 25, it's oversold (BUY IT!) :param coin_pair: String literal for the market (ex: BTC-LTC) :type coin_pair: str :param period: Number of periods to query :type period: int :param unit: Ticker interval (one of: 'oneMin', 'fiveMin', 'thirtyMin', 'hour', 'week', 'day', and 'month') :type unit: str :return: RSI :rtype : float """ closing_prices = self.get_closing_prices(coin_pair, period * 3, unit) count = 0 change = [] # Calculating price changes for i in closing_prices: if count != 0: change.append(i - closing_prices[count - 1]) count += 1 if count == 15: break # Calculating gains and losses advances = [] declines = [] for i in change: if i > 0: advances.append(i) if i < 0: declines.append(abs(i)) average_gain = (sum(advances) / 14) average_loss = (sum(declines) / 14) new_avg_gain = average_gain new_avg_loss = average_loss for _ in closing_prices: if 14 < count < len(closing_prices): close = closing_prices[count] new_change = close - closing_prices[count - 1] add_loss = 0 add_gain = 0 if new_change > 0: add_gain = new_change if new_change < 0: add_loss = abs(new_change) new_avg_gain = (new_avg_gain * 13 + add_gain) / 14 new_avg_loss = (new_avg_loss * 13 + add_loss) / 14 count += 1 if new_avg_loss == 0: return None rs = new_avg_gain / new_avg_loss new_rs = 100 - 100 / (1 + rs) return new_rs
class CapitVitaCrypto(CapitVita): def __init__(self, home_path='', num_coins=25, mailing_list=[], debug=False): self.num_coins = num_coins self.mailing_list = mailing_list self.coin_list = [] self.df = [] self.debug = debug self.home_path = home_path self.file_path = home_path + 'crypto-data/' self.volume_sum = [] # bittrex self.B = Bittrex(key, secret) self.b_currencies = [ x['Currency'] for x in self.B.get_currencies()['result'] ] # currencies available to trade in bittrex self.market_summaries = self.B.get_market_summaries()['result'] self.markets = [x['MarketName'] for x in self.market_summaries] # market names self.BTC_markets = [ x for x in self.markets if 'BTC' in x and 'USDT' not in x ] self.ETH_markets = [ x for x in self.markets if 'ETH' in x and 'USDT' not in x ] self.USDT_markets = [x for x in self.markets if 'USDT' in x] self.USDT_BTC = [ x for x in self.market_summaries if x['MarketName'] == 'USDT-BTC' ][-1]['Last'] self.USDT_ETH = [ x for x in self.market_summaries if x['MarketName'] == 'USDT-ETH' ][-1]['Last'] def get_coin_list(self): # get coin list (all coins, some are not tradeable on bittrex) url = 'https://www.cryptocompare.com/api/data/coinlist/' response = urllib2.urlopen(url) data = json.loads(response.read()) self.coin_list = [ x.encode('ascii', 'ignore') for x in data['Data'].keys() ] #print(len(self.coin_list)) # 1507 as of 2017-09-14 def grab_data(self, coin): # get historical OHLC for one cryptocurrency url = 'https://min-api.cryptocompare.com/data/histoday?fsym={}&tsym=USD&limit={}&aggregate=1&e=CCCAGG'.format( coin, 80) response = urllib2.urlopen(url) data = json.loads(response.read()) try: self.df = pd.DataFrame(data['Data']) self.df['date'] = self.df['time'].apply( lambda x: datetime.datetime.fromtimestamp(x)) #self.df.drop(['time', 'volumefrom'], axis = 1) #self.df.columns = ['Adj. Close', 'Adj. High', 'Adj. Low', 'Adj. Open', 'time', 'volumefrom', 'volumeto', 'date'] except KeyError: return False self.volume_sum.append(self.df['volumeto'].iloc[-20:].median()) # generate signals self.df['rsi'] = self.RSI(self.df['close'], 14) self.df['26 ema'] = self.df['close'].ewm(ignore_na=False, min_periods=0, adjust=True, com=26).mean() self.df['12 ema'] = self.df['close'].ewm(ignore_na=False, min_periods=0, adjust=True, com=12).mean() self.df['MACD'] = self.df['12 ema'] - self.df['26 ema'] self.df['MACD signal'] = self.df['MACD'] - self.df['MACD'].ewm( ignore_na=False, min_periods=0, adjust=True, com=9).mean() self.df['MACD_norm'] = self.normalize(self.df['MACD signal']) self.df['MACD_der'] = self.derivative(self.df['MACD_norm']) def get_points(self, coin): try: self.grab_data(coin) ## get the data and store it in self.df if len(self.df) < 20 or self.df['volumeto'].iloc[-20:].median( ) < 850000 * 0.8: # if grab is unsuccessful or below average volume * 0.7, end points = {'admin': -500} else: points = {} mb, tb, bb, = self.bbands(self.df['close']) if self.df['close'].iloc[-1] < (mb.iloc[-1] + bb.iloc[-1]) / 2: points['admin'] = -500 # RSI points (max 50) points['rsi'] = 50 - round( 1.2 * abs(30 - self.df['rsi'].iloc[-1])) # MACD points (max 50) points['macd1'] = round( 25 * self.df['MACD_norm'].iloc[-1] / max([abs(x) for x in self.df['MACD_norm']])) points['macd2'] = round( 25 * self.df['MACD_der'].iloc[-1] / max([abs(x) for x in self.df['MACD_der']])) # candlestick points (max 10) candlestickFactor = 1 patterns = self.detectCandlestickPatterns( self.df['open'][-7:], self.df['close'][-7:], self.df['low'][-7:], self.df['high'][-7:], candlestickFactor) points['candlesticks'] = self.rangeLimit( round(sum([x[2] for x in patterns])), -20, 20) except BufferError as e: #except Exception as e: print('problem: {}'.format(e)) return points def find_coins(self, graph=False, bittrex_currencies_only=True): # start counting duration of script start_time = time.time() print('Initiating log...') # create log ff = open(self.file_path + 'readme.txt', 'w') ff.write(str(datetime.datetime.now())) ff.write('\n') print('Deleting old plots...') # delete old files os.chdir(self.file_path) filelist = glob.glob('*.png') for f in filelist: os.remove(f) os.chdir(self.home_path) print('Fetching coin list...') if bittrex_currencies_only: self.update_B() self.coin_list = self.b_currencies else: self.get_coin_list() if self.debug: self.coin_list = self.coin_list[:30] len_coin_list = len(self.coin_list) print(' {} coins.'.format(len_coin_list)) #print(' Expect script to take approximately {} minutes'.format(round(len_coin_list*1.0613 - 14)/60, 2)) # grab data in batches print('Getting points for {} coins...'.format(len_coin_list)) coin_points = {} for i, coin in enumerate(self.coin_list): if i % (len(self.coin_list) / 25) == 0: print('{}% done'.format( round(100 * float(i) / len(self.coin_list), 1))) try: points = self.get_points(coin) coin_points[coin] = [sum([points[x] for x in points]), points] #except BufferError: except Exception as e: print('failed {} because {}'.format(coin, e)) original_len_coin_list = len(coin_points) print('Sorting coins...') # sort stocks by point system sorted_coins = sorted(coin_points.items(), key=itemgetter(1), reverse=True)[:self.num_coins] print(sorted_coins) if graph: print('Graphing coins...') for coin in [x[0] for x in sorted_coins]: try: self.graph_data(coin, saveLocation=self.file_path) except BufferError: #except Exception as e: print('failed {} because {}'.format(coin, e)) # write into log ff.write('Cheap coins to invest in for 2 days ~ 1 week: \n\n') ff.write('#\n') for i in sorted_coins: ff.write(i[0] + ': ' + str(round(i[1][0], 1)) + ' ' + str(i[1][1]) + '\n') ff.write('#\n') ff.write('\n\n ' + str(original_len_coin_list) + ' stocks shortened by point system to ' + str(len(sorted_coins)) + ' stocks') ff.write("\n\n--- %s seconds ---" % (round(time.time() - start_time, 2))) ff.write('\n\n\n Capit-Vita Crypto Version 1.1 (2017-09-22)\n\n') ff.write(' - Buying is confirmed to work\n') ff.close() #print(self.volume_sum[-20:]) #print('average volume', sum(self.volume_sum)/len(self.volume_sum)) # median volumeto: 850k # send email if len(self.mailing_list) > 0: send_email(self.file_path, 'Top ' + str(self.num_coins) + ' Coin Prospects', self.mailing_list) ###### remove coin types I currently own my_coins = [x['Currency'] for x in self.B.get_balances()['result']] print('my coins: {}'.format(my_coins)) print('before: {}'.format([x[0] for x in sorted_coins])) sorted_coins = [x for x in sorted_coins if x[0] not in my_coins] print('after: {}'.format([x[0] for x in sorted_coins])) # save wanted coins with open(self.file_path + 'wanted_coins.txt', 'w') as f: f.write('{}, '.format([str(x[0]) for x in sorted_coins])) return sorted_coins def buy_next_coin(self): # save wanted_coins if os.path.isfile(self.file_path + 'wanted_coins.txt'): with open(self.file_path + 'wanted_coins.txt', 'r') as f: data = eval(f.readlines()[0][:-2]) else: return False print(data) def update_B(self): self.b_currencies = [ x['Currency'] for x in self.B.get_currencies()['result'] ] # currencies available to trade in bittrex self.market_summaries = self.B.get_market_summaries()['result'] self.markets = [x['MarketName'] for x in self.market_summaries] # market names self.BTC_markets = [ x for x in self.markets if 'BTC' in x and 'USDT' not in x ] self.ETH_markets = [ x for x in self.markets if 'ETH' in x and 'USDT' not in x ] self.USDT_markets = [x for x in self.markets if 'USDT' in x] self.USDT_BTC = [ x for x in self.market_summaries if x['MarketName'] == 'USDT-BTC' ][-1]['Last'] self.USDT_ETH = [ x for x in self.market_summaries if x['MarketName'] == 'USDT-ETH' ][-1]['Last'] #print len(self.b_currencies) # 277 as of 2017-09-21 def thing(self): BTC_market_prices = [] ETH_market_prices = [] ### create value exchange rate for currency in self.b_currencies: if any(currency in x for x in BTC_markets): last_price = [ x['Last'] for x in self.market_summaries if x['MarketName'] == 'BTC-{}'.format(currency) ] if len(last_price) > 0: BTC_market_prices.append('Last price for {} is ${}'.format( currency, round(last_price[0] * USDT_BTC, 2))) elif any(currency in x for x in ETH_markets): last_price = [ x['Last'] for x in self.market_summaries if x['MarketName'] == 'ETH-{}'.format(currency) ] if len(last_price) > 0: ETH_market_prices.append('Last price for {} is ${}'.format( currency, round(last_price[0] * USDT_ETH, 2))) cnt_in = 0 cnt_not_in = 0 for currency in self.b_currencies: if all(currency not in x for x in self.BTC_markets + self.ETH_markets): cnt_not_in += 1 #print('{} not in any market'.format(currency)) else: cnt_in += 1 #print(cnt_in, cnt_not_in) #203 in market, 74 out of market as of 2017-09-21 ### can only buy and sell on existing markets def my_coins(self): my_coins = [x for x in self.B.get_balances()['result']] print(my_coins) total = 0 print('\n\n----------- My Wallet -----------\n') for coin in my_coins: if coin['Currency'] == 'BTC': print('{} available for {} (${})'.format( coin['Available'], coin['Currency'], round(coin['Available'] * self.USDT_BTC, 2))) total += coin['Available'] * self.USDT_BTC elif any(coin['Currency'] in x for x in self.BTC_markets): BTC_coin_rate = [ x['Last'] for x in self.market_summaries if x['MarketName'] == 'BTC-{}'.format(coin['Currency']) ][0] print('{} available for {} (${})'.format( coin['Available'], coin['Currency'], round(coin['Available'] * self.USDT_BTC * BTC_coin_rate, 2))) total += coin['Available'] * self.USDT_BTC * BTC_coin_rate else: print('{} available for {} (${})'.format( coin['Available'], coin['Currency'], 'hold')) ## add ethereum #return summary return my_coins def total_available_USD(self, BTC_ETH_only=True): balances = self.B.get_balances()['result'] total_USD = 0 for balance in balances: if balance['Balance'] > 0: if balance['Currency'] == 'BTC': total_USD += balance['Balance'] * self.USDT_BTC print('BTC: {}'.format(balance['Balance'] * self.USDT_BTC)) elif balance['Currency'] == 'ETH': total_USD += balance['Balance'] * self.USDT_ETH print('ETH: {}'.format(balance['Balance'] * self.USDT_ETH)) elif not BTC_ETH_only: if any(balance['Currency'] in x for x in self.BTC_markets): to_add = balance['Balance'] * [ x['Last'] for x in self.market_summaries if x['MarketName'] == 'BTC-{}'.format(balance['Currency']) ][0] * self.USDT_BTC total_USD += to_add print('{}: {}'.format(balance['Currency'], to_add)) elif any(balance['Currency'] in x for x in self.ETH_markets): to_add = balance['Balance'] * [ x['Last'] for x in self.market_summaries if x['MarketName'] == 'ETH-{}'.format(balance['Currency']) ][0] * self.USDT_ETH total_USD += to_add print('{}: {}'.format(balance['Currency'], to_add)) # consider only BTC and ETH liquid? print('Total available: {}'.format(total_USD)) return total_USD def buy_altcoin(self, coin): if any(coin in x['Currency'] for x in self.B.get_balances()['result']): print('not buying, already have') return False if any(coin in x for x in self.BTC_markets): market = [x for x in self.BTC_markets if coin in x][0] print(market) available_USD = self.total_available_USD() print('available USD', available_USD) increment_USD = available_USD / 20 print('5% available USD: {}'.format(increment_USD)) BTC_coin_rate = self.B.get_marketsummary( market)['result'][0]['Last'] print('BTC - {} conversion: {}'.format(coin, BTC_coin_rate)) print('BTC - USD conversion: {}'.format(self.USDT_BTC)) print('want to buy {} {} coins'.format( increment_USD / self.USDT_BTC / BTC_coin_rate, coin)) print('buying {}: {}'.format( coin, self.B.buy_limit(market, increment_USD / self.USDT_BTC / BTC_coin_rate, BTC_coin_rate))) # market, quantity, rate def sell_altcoin(self, order): # takes a buy order and reverses it (sell) coin = order['Exchange'][4:] if any(coin in x for x in self.BTC_markets): market = [x for x in self.BTC_markets if coin in x][0] elif any(coin in x for x in self.ETH_markets): market = [x for x in self.ETH_markets if coin in x][0] coin_rate = self.B.get_marketsummary(market)['result'][0]['Last'] quantity = order['Quantity'] if all(coin not in x['Currency'] for x in self.B.get_balances()['result']): print('cannot sell, do not have') return False #print('selling {}: {}'.format(market, self.B.sell_limit(market, quantity, coin_rate))) # market, quantity, rate def coin_to_USD(self, order): coin = order['Exchange'][4:] market = [x for x in self.BTC_markets if coin in x][0] BTC_coin_rate = self.B.get_marketsummary(market)['result'][0]['Last'] if coin == 'BTC': return order['Quantity'] * self.USDT_BTC elif coin == 'ETH': pass elif any([coin in x for x in self.BTC_markets]): last_price = [ x['Last'] for x in self.market_summaries if coin in x['MarketName'] ] return order['Quantity'] * self.USDT_BTC * BTC_coin_rate elif any(coin in x for x in self.ETH_markets): pass else: pass def my_coin_price_change(self): orders = self.B.get_order_history()['result'] ## remove orders that I don't own orders = [x for x in orders] print(orders) self.update_B() for order in orders: bought_at = round( order['Quantity'] * order['PricePerUnit'] * self.USDT_BTC, 2) currently = round(self.coin_to_USD(order), 2) perc_change = round((currently / bought_at - 1) * 100, 1) timestamp = datetime.datetime.now() - datetime.datetime.strptime( order['TimeStamp'], '%Y-%m-%dT%H:%M:%S.%f') print( ' bought {} ({} ago) for relative BTC value of ${}, currently ${}: {}% change' .format(order['Exchange'][4:], timestamp, bought_at, currently, perc_change)) ### formula for selling: # cost of trade = 0.35% x 2 = 0.7% # have an open sell order at 10% -> 9.3% up # if simulataneous orders are possible, have an open sell order at -10% -> 10.7% down # if the coin is older than 5 days, lower the upper sell limit by 2% to 8% -> 7.3% up # every 3 days after that lower by 2% until @ 2% lower_limit = -10 if timestamp < datetime.timedelta(days=5): upper_limit = 10 elif timestamp < datetime.timedelta(days=8): # approx one week upper_limit = 8 elif timestamp < datetime.timedelta(days=11): upper_limit = 6 elif timestamp < datetime.timedelta(days=14): # two weeks upper_limit = 4 elif timestamp < datetime.timedelta(days=17): upper_limit = 2 elif timestamp > datetime.timedelta( days=21): # sell no matter what after 3 weeks upper_limit = -10 if perc_change < lower_limit or perc_change > upper_limit: self.sell_altcoin(order)
class CryptoCommander: def __init__(self, poloapicreds=['', ''], bittrexapicreds=['', '']): print( "Initializing Crypto Commander, Intelligent and Responsive Crypto-Currency Platform..." ) print( "Disclaimer!! You have launched this via command line, great caution is advised and the developers are NOT responsible for proper usage or lost coins!" ) print( "Notice - :: :: Bitcoin & Crypto-Currencies are largely untested and come with no assurances! Trade with care. :: ::" ) if poloapicreds == ['', '']: print( "No poloniex credentials found, skipping initialization. This may cause instability!" ) else: try: self.poloniexBot = poloniex(poloapicreds[0], poloapicreds[1]) self.btcBalance, self.btsBalance, self.clamBalance, self.dashBalance, self.dogeBalance, self.ethBalance, self.fctBalance, self.ltcBalance, self.maidBalance, self.strBalance, self.xmrBalance, self.xrpBalance, = Decimal( 0.0), Decimal(0.0), Decimal(0.0), Decimal(0.0), Decimal( 0.0), Decimal(0.0), Decimal(0.0), Decimal( 0.0), Decimal(0.0), Decimal(0.0), Decimal( 0.0), Decimal(0.0) except AttributeError: print( "An error occurred trying to initialize Poloniex functionality." ) if bittrexapicreds == ['', '']: print( "No bittrex credentials detected, skipping initialization. This may cause instability!" ) else: try: self.bittrexBot = Bittrex(bittrexapicreds[0], bittrexapicreds[1]) except AttributeError: print( "An error occurred trying to initialized Bittrex functionality." ) def convert_coinpair_poloniex(self, coinpair): return coinpair.replace('-', '_') def get_tickers_raw(self, market): # A clone of the bittrex get_markets() & poloniex returnTicker commands, in a unified stream. if market == 'poloniex': return self.poloniexBot.returnTicker() elif market == 'bittrex': return self.bittrexBot.get_markets() def get_coinpair_ticker_raw(self, market, coinpair): # Returns raw market information on coin pair on market if market == 'poloniex': coinpair = self.convert_coinpair_poloniex(coinpair) rawtickerdata = self.get_tickers_raw(market) for coinpairdata in rawtickerdata: if coinpairdata == coinpair: return rawtickerdata[coinpairdata] if market == 'bittrex': return self.bittrexBot.get_ticker(coinpair.capitalize()) def getTickerData(self, market, bitcoinMarketsOnly=True, activeOnly=True, printFriendly=False, decimalTypes=True): #if market == 'poloniex: if market == 'bittrex': cryptoCommandTickers = {'BTC': [], 'Other': []} btcMarketsList = cryptoCommandTickers['BTC'] otherMarketsList = cryptoCommandTickers['Other'] stagingList = [] if printFriendly == True: decimalTypes = False for ticker in self.bittrexBot.get_markets()['result']: if ticker != None: stagingList.append([ str(ticker['MarketName']), str(ticker['BaseCurrency']), bool(str(ticker['IsActive'])) ]) for ticker in self.bittrexBot.get_market_summaries()['result']: if ticker != None: for list in stagingList: if list[0] == str(ticker['MarketName']): list.extend([ ticker['High'], ticker['Low'], ticker['Ask'], ticker['Bid'], ticker['Last'], ticker['PrevDay'], ticker['Volume'], ticker['BaseVolume'], (ticker['High'] + ticker['Low'] / 2.0) ]) for list in stagingList: if list[1] == 'BTC': btcMarketsList.append(list) else: otherMarketsList.append(list) if printFriendly == True: for dictobject in cryptoCommandTickers: for list in cryptoCommandTickers[dictobject]: for n, listobject in enumerate(list): if type(listobject) == float: list[n] = format(listobject, '.8f') elif decimalTypes == True: for dictobject in cryptoCommandTickers: for list in cryptoCommandTickers[dictobject]: for n, listobject in enumerate(list): if type(listobject) == float: list[n] = Decimal(format(listobject, '.8f')) return cryptoCommandTickers def getActiveMarketCurrencies(self, market, appendString=''): currentMarketList = [] if market == 'poloniex': rawCoinPairData = self.poloniexBot.api_query('returnTicker') for coinPairData in rawCoinPairData: if str(rawCoinPairData[coinPairData]['isFrozen']) == '0': currentMarketList.append( str(coinPairData).split('_', 1)[1]) if market == 'bittrex': for coinData in self.bittrexBot.get_currencies()['result']: if coinData['IsActive'] == True: currentMarketList.append(appendString + str(coinData['Currency'])) return set(currentMarketList) def getCurrentBalance(self, market, coin): if market == 'poloniex': return self.poloniexBot.returnBalances()[coin.upper()] elif market == 'bittrex': return self.bittrexBot.get_balance(coin)['result']['Balance'] def getTopOrder(self, market, coinPair, buyOrders): if buyOrders == True: if market == 'poloniex': for i in self.poloniexBot.returnOrderBook( coinPair.replace('-', '_'))['bids']: return i elif market == 'bittrex': for i in self.bittrexBot.get_orderbook(coinPair, 'buy')['result']: return i else: print('Not a valid market: ' + str(market)) else: if market == 'poloniex': for i in self.poloniexBot.returnOrderBook( coinPair.replace('-', '_'))['asks']: return i elif market == 'bittrex': for i in self.bittrexBot.get_orderbook(coinPair, 'sell')['results']: return i else: print('Not a valid market: ' + str(market)) def getWalletAddress(self, market, coin): if market == "poloniex" or market == "Poloniex": return self.poloniexBot.api_query('returnDepositAddresses')[coin] elif market == "bittrex" or market == "Bittrex": return self.bittrexBot.get_balance(coin)['result']['CryptoAddress'] def compareMarkets(self, market1, market2): currentActiveMarketsLists = [ self.getActiveMarketCurrencies(market1), self.getActiveMarketCurrencies(market2) ] comparisonList = [] for i in currentActiveMarketsLists[0]: for y in currentActiveMarketsLists[1]: if i == y: comparisonList.append(i) else: continue return comparisonList def getCoinPairPriceDifferencePercent(self, buyPrice, sellPrice): return (((float(buyPrice) - float(sellPrice)) / float(buyPrice)) * 100.00) def arbitrageScan(self, market1, market2, minPercent=0.45): try: arbOpportunitiesList = [] for coinpair in self.doMarketComparison(market1, market2): print("Scanning Coin Pair : " + str(coinpair)) differenceBetweenMarket1and2 = format( self.getCoinPairPriceDifferencePercent( float(self.getTopOrder(market1, coinpair, False, 1)), float(self.getTopOrder(market2, coinpair, True, 1)))) differenceBetweenMarket2and1 = format( self.getCoinPairPriceDifferencePercent( float(self.getTopOrder(market2, coinpair, False, 1)), float(self.getTopOrder(market1, coinpair, True, 1)))) if float(differenceBetweenMarket2and1) < (-.525 - minPercent): if (float(self.getTopOrder(market1, coinpair, True)[0]) * float( self.getTopOrder(market1, coinpair, True)[1]) ) >= float(self.getCurrentBalance(market1, "BTC")): print("Arb Op: " + str(differenceBetweenMarket2and1) + " for coin pair ") print("Info: Bittrex: Buy:: ") print(self.getTopOrder('bittrex', coinpair, True)) print("- Sell:: ") print(self.getTopOrder('bittrex', coinpair, False)) arbOpportunity = (coinpair, "Market2to1", differenceBetweenMarket2and1, 1) arbOpportunitiesList.append(arbOpportunity) else: continue elif float(differenceBetweenMarket1and2) < (-.525 - minPercent): if float( self.getTopOrder('bittrex', coinpair, True, 3)[0] ) * float(self.getTopOrder( 'bittrex', coinpair, True)[1]) >= float( self.getCurrentBalance(market2, "BTC")): print("Arb Op: ") print(str(differenceBetweenMarket1and2)) print("Info: Bittrex: Buy:: ") print(self.getTopOrder('poloniex', coinpair, True)) print("- Sell:: ") print(self.getTopOrder('poloniex', coinpair, False)) print("Info: Poloniex: Buy:: ") print(self.getTopOrder('bittrex', coinpair, True)) print("- Sell:: ") print(self.getTopOrder('bittrex', coinpair, False)) arbOpportunity = (coinpair, "Market1to2", differenceBetweenMarket1and2, 1) arbOpportunitiesList.append(arbOpportunity) else: continue else: print(differenceBetweenMarket1and2 + " or " + differenceBetweenMarket2and1 + " is more than -.7") continue return arbOpportunitiesList except AttributeError: print("Attribute Error") def selectBestOpportunity(self, market1, market2, minPercent=0.45): opportunitiesList = [] while opportunitiesList == []: opportunitiesList = self.arbitrageScan(market1, market2, minPercent) if len(opportunitiesList) != 0: bestOpportunity = opportunitiesList[0] for opportunity in opportunitiesList: if bestOpportunity[2] < opportunity[2]: bestOpportunity = opportunity else: print("No Opportunities Found") bestOpportunity = ("", "", 0.0, 0) return bestOpportunity def activateArbitrage(self, market1, market2, minPercent=0.45): bestArbitrageOpportunity = self.selectBestOpportunity( market1, market2, minPercent) coinName = str(bestArbitrageOpportunity[0]).replace("BTC-", "") if bestArbitrageOpportunity[1] == 'Market1to2': fullTopBuyOrder = self.getTopOrder(market1, bestArbitrageOpportunity[0], False) btcBuyOrderAvailable = (float(fullTopBuyOrder[0]) * float(fullTopBuyOrder[1])) btcBalanceOnMarket = float( self.getCurrentBalance('poloniex', "BTC")) if float(btcBuyOrderAvailable) > float(btcBalanceOnMarket): btcBuyOrderAvailable = float(btcBalanceOnMarket) coinAvailable = float(btcBuyOrderAvailable) / float( fullTopBuyOrder[0]) if market1 == "poloniex" or market1 == "Poloniex": try: if float( self.getTopOrder( market1, bestArbitrageOpportunity[0], False, 0)[0]) * float( self.getTopOrder( market1, bestArbitrageOpportunity[0], False, 0)[1]) < float( self.getBalance('poloniex', 'BTC')): self.poloniexBot.buy( bestArbitrageOpportunity[0].replace("-", "_"), fullTopBuyOrder[0], coinAvailable) print( "Successfully Bought on Poloniex, Attempting to Send to Bittrex Now..." ) time.sleep(3) self.poloniexBot.withdraw( coinName, (self.getCurrentBalance('poloniex', coinName)), self.getWalletAddress('bittrex', coinName)) tempCounter = 0 print(self.getCurrentBalance('bittrex', coinName)) while float(self.getCurrentBalance( 'bittrex', coinName)) < 0.0005: time.sleep(5) tempCounter = tempCounter + 1 if tempCounter > 15: print("Still Awaiting Deposit...") tempCounter = 0 print( "Deposit Confirmed & Active! Preparing to Dump in 5 Seconds" ) time.sleep(5) while float(self.getCurrentBalance(market2, coinName) ) > 0.00050055 or self.getCurrentBalance( market2, coinName) == None: time.sleep(3) self.bittrexBot.sell_limit( bestArbitrageOpportunity[0], self.getCurrentBalance('bittrex', coinName), self.getTopOrder(market2, bestArbitrageOpportunity[0], True, 1)) print( "Finished Selling All the Coins that Could be Sold. Cycle Complete." ) else: print( "The order didnt stay high enough, starting over") self.activateArbitrage(market1, market2, minPercent) except MemoryError: print("Error") if bestArbitrageOpportunity[1] == 'Market2to1': fullTopBuyOrder = self.getTopOrder(market2, bestArbitrageOpportunity[0], False, 0) btcBuyOrderAvailable = (float(fullTopBuyOrder[0]) * float(fullTopBuyOrder[1])) btcBalanceOnMarket = float(self.getCurrentBalance(market2, "BTC")) if btcBuyOrderAvailable > btcBalanceOnMarket: btcBuyOrderAvailable = btcBalanceOnMarket coinAvailable = float(btcBuyOrderAvailable) / float( fullTopBuyOrder[0]) if market2 == "bittrex" or market2 == "Bittrex": try: if float( self.getTopOrder( market1, bestArbitrageOpportunity[0], False, 0)[0]) * float( self.getTopOrder( market1, bestArbitrageOpportunity[0], False, 0)[1]) < float( self.getCurrentBalance( 'bittrex', 'BTC')): print("Buying " + str(bestArbitrageOpportunity[0]) + " " + str(coinAvailable)) buy = self.bittrexBot.buy_limit( bestArbitrageOpportunity[0], coinAvailable, fullTopBuyOrder[0]) print(buy) time.sleep(5) if buy['success'] == True: print( "Successfully Bought on Bittrex, Attempting to Send to Poloniex Now..." ) time.sleep(5) self.bittrexBot.withdraw( coinName, self.getCurrentBalance(market2, coinName), self.getWalletAddress(market1, coinName)) tempCounter = 0 print(self.getCurrentBalance(market1, coinName)) while float( self.getCurrentBalance(market1, coinName) ) < 0.00050055 or self.getCurrentBalance( market1, coinName) == None: time.sleep(5) tempCounter = tempCounter + 1 if tempCounter > 15: print("Still Awaiting Deposit...") tempCounter = 0 print( "Deposit Confirmed and Active! Preparing to Dump in 5 Seconds" ) time.sleep(5) while float( self.getCurrentBalance( market1, coinName)) > 0.00010055: time.sleep(5) self.poloniexBot.sell( str(bestArbitrageOpportunity[0]).replace( "-", "_"), float( self.getTopOrder( market1, bestArbitrageOpportunity[0]. replace("-", "_"), True, 1)), self.getCurrentBalance(market1, coinName)) print( "Attempting to Sell Maximum Amount of Coins that Could be Sold." ) print("Finished Selling all coins. Cycle Complete") else: print("Failed to Buy") return "Failed to Buy" else: print( "The order didn't stay high enough, starting over") self.activateArbitrage(market1, market2, minPercent) except AttributeError: print("Attribute Error, sorry") def getLendingBalances(self): #Only works with Poloniex try: return cryptoCommander.poloniexBot.api_query( 'returnAvailableAccountBalances')['lending'] except KeyError: return [] def getCurrentLoanOffers(self, coin): #Only works with Poloniex ret = urllib2.request.urlopen('http://poloniex.com/public?command=' + 'returnLoanOrders' + '¤cy=' + str(coin)) return json.loads(ret.read()) def getPrimeLendingRate(self, coin, minWeight=Decimal('25.0')): #Only works with Poloniex accumulatedWeight, bestRate = Decimal('0.0'), Decimal('0.0') print(accumulatedWeight) for offer in self.getCurrentLoanOffers(coin)['offers']: if accumulatedWeight < minWeight: print('Accumulated weight is less than 25: ' + str(accumulatedWeight)) accumulatedWeight = accumulatedWeight + Decimal( str(offer['amount'])) else: print('Best rate is: ' + str(offer['rate'])) bestRate = Decimal(str(offer['rate'])) - Decimal('0.000001') break if bestRate < Decimal('0.000001'): bestRate = Decimal('0.000001') return bestRate def getActiveLoans(self): #Only works with Poloniex return self.poloniexBot.api_query('returnActiveLoans') def getOpenLoanOffers(self): #Only works with Poloniex try: return self.poloniexBot.api_query('returnOpenLoanOffers') except KeyError: return [] def cancelLoanOffer(self, currency, orderNumber): #Only works with Poloniex return self.poloniexBot.api_query('cancelLoanOffer', { "currency": currency, "orderNumber": orderNumber }) def cancelAllLoanOffers(self): openLoansDict = self.getOpenLoanOffers() for openLoanCoin in openLoansDict: for dataObject in openLoansDict[openLoanCoin]: self.cancelLoanOffer(openLoanCoin, dataObject[id]) def createLoanOffer(self, currency, amount, duration, autoRenew, lendingRate): return self.poloniexBot.api_query( 'createLoanOffer', { "currency": currency, "amount": amount, "duration": duration, "autoRenew": autoRenew, "lendingRate": lendingRate, }) def checkLendingStagnation(self): openLoansDict = self.getOpenLoanOffers() for openLoanCoin in openLoansDict: for data in openLoansDict[openLoanCoin]: if (datetime.datetime.utcnow() - datetime.datetime.strptime( str(data['date']), '%Y-%m-%d %X') > datetime.timedelta(minutes=2)): print('Cancelling Loan Orders that are stagnant.') self.cancelLoanOffer(openLoanCoin, data['id']) def placeAllLoans(self): balances = self.getLendingBalances() for coin in balances: try: print(balances[coin]) if type(balances[coin] ) != Decimal and balances[coin] > Decimal('0.0'): balances[coin] = Decimal(str(balances[coin])) if type(balances[coin] ) == Decimal and balances[coin] >= Decimal('0.01'): #print "Print currency available is: " + str(balances[coin]) + str(coin) + ", Lending Now." while Decimal(str(balances[coin])) >= Decimal('0.01'): if Decimal(str(balances[coin])) <= Decimal( '0.02') and Decimal(str( balances[coin])) >= Decimal('0.01'): print('lending between 0.01 and 0.02') print( self.createLoanOffer( coin, float(balances[coin]), 2, 0, self.getPrimeLendingRate(coin))) else: primeRate = self.getPrimeLendingRate(coin) print("Prime Rate is: " + str(primeRate)) if primeRate <= Decimal('0.000025') or Decimal( balances[coin]) > Decimal('0.1'): if Decimal(balances[coin]) >= Decimal('10.0'): if Decimal( balances[coin] ) < Decimal('20.0') and Decimal( balances[coin]) > Decimal('10.0'): print('lending between 10 and 20') print( self.createLoanOffer( coin, float(balances[coin]), 2, 0, primeRate)) else: print('lending 10') print( self.createLoanOffer( coin, 10.0, 2, 0, primeRate)) else: if Decimal( balances[coin]) > Decimal('0.1'): if Decimal(balances[coin]) < Decimal( '0.2') and Decimal( balances[coin]) > Decimal( '0.1'): print( 'lending between 0.1 and 0.2') print( self.createLoanOffer( coin, float(balances[coin]), 2, 0, primeRate)) else: print('lending 0.1') print( self.createLoanOffer( coin, 0.1, 2, 0, primeRate)) else: print('lending 0.01') print( self.createLoanOffer( coin, 0.01, 2, 0, primeRate)) else: print('lending 0.01') print( self.createLoanOffer( coin, 0.01, 2, 0, primeRate)) time.sleep(.2) balances = self.getLendingBalances() else: print('No coins available to lend, sorry!') except KeyError: print('All loans for ' + str(coin) + ' actively being lent.') def startLendingAutomation(self): while True: try: while self.getLendingBalances( ) != None and self.getOpenLoanOffers() != None: while any(self.getLendingBalances()) > Decimal( '0.001') or any(self.getOpenLoanOffers()): self.placeAllLoans() time.sleep(150) self.checkLendingStagnation() print('All Done.') except TypeError: print("NOT done")
break # покупает заданную монету while True: sellOrderBook = sorted(my_bittrex.get_orderbook( "BTC-" + last_message['text'])['result']['sell'][0:10], key=lambda k: k['Quantity'], reverse=True) for x in range(0, 10): # баланс БТС выраженный в xCoin < количество монет из книги ордеров if BTC / sellOrderBook[x]['Rate'] < sellOrderBook[x][ 'Quantity']: text = my_bittrex.buy_limit( 'BTC-' + last_message['text'], BTC / sellOrderBook[x]['Rate'] * float(1 - cfg.getfloat('Data', 'commission') / 100), sellOrderBook[x]['Rate']) print( text, BTC / sellOrderBook[x]['Rate'] * float(1 - cfg.getfloat('Data', 'commission') / 100), sellOrderBook[x]['Rate']) else: text = my_bittrex.buy_limit( 'BTC-' + last_message['text'], sellOrderBook[x]['Quantity'] * float(1 - cfg.getfloat('Data', 'commission') / 100), sellOrderBook[x]['Rate']) BTC = BTC - BTC / sellOrderBook[x]['Rate'] * float( 1 - cfg.getfloat('Data', 'commission') / 100)
new_slave_order = slave_bittrex.sell_limit( market=new_order['Exchange'], quantity=new_order['Quantity'], rate=new_order['Limit']) if new_slave_order['success']: print('Order Copied Successfully to Slave', slave_number) order_mapping[slave_number - 1][new_order[ 'OrderUuid']] = new_slave_order['result']['uuid'] else: print('Error in slave', slave_number, new_slave_order['message']) order_mapping[slave_number - 1][new_order['OrderUuid']] = 0 elif new_order['OrderType'] == 'LIMIT_BUY': write_debug('Limit buy in slave', fl) new_slave_order = slave_bittrex.buy_limit( market=new_order['Exchange'], quantity=new_order['Quantity'], rate=new_order['Limit']) if new_slave_order['success']: print('Order Copied Successfully to Slave', slave_number) order_mapping[slave_number - 1][new_order[ 'OrderUuid']] = new_slave_order['result']['uuid'] else: print('Error in slave', slave_number, new_slave_order['message']) order_mapping[slave_number - 1][new_order['OrderUuid']] = 0 else: print('Order type not supported') i_open_count += 1 i_count = i_open_count + i_history_count sleep(10) elif len(master_order_history['result']) > i_history_count: