class Bittrex: def __init__(self, key, secret): self.logger = Logger(__name__) try: self.client = Client(key, secret, api_version="v2.0") except Exception as e: self.logger.log(e) raise ExchangeException(self.__class__.__name__, e) def getBalances(self): try: result = self.client.get_balances() balances = {} if not result['success']: raise Exception(result['message']) for currency in result["result"]: name = currency["Currency"]["Currency"] value = currency["Balance"]["Balance"] if value >= Config.BALANCE_ZERO: balances[name] = value return balances except Exception as e: self.logger.log(e) raise ExchangeException(self.__class__.__name__, e)
class Bittrex: def __init__(self, key, secret): self.client = Client(key, secret) self.logger = Logger(__name__) def getBalances(self): try: result = self.client.get_balances() balances = {} if not result['success']: raise ExchangeException(self.__class__.__name__, result['message']) for currency in result["result"]: name = currency["Currency"].encode('utf-8').upper() value = currency["Balance"] if value > 0.0: balances[name] = value return balances except Exception as e: self.logger.log(e) raise ExchangeException(self.__class__.__name__, e.message)
def show_balances(bot, update): if update.message.chat_id in auth.masters_chat_idx: my_b = Bittrex(auth.api_key, auth.api_secret) balances = my_b.get_balances() for currency in balances['result']: if currency['Available'] > 0: curr = str(currency['Currency']) bal = str(currency['Available']) update.message.reply_text(curr + ' ' + bal) else: update.message.reply_text("Не хватает прав. Попробуй другую команду")
class TestBittrexAccountAPI(unittest.TestCase): def setUp(self): self.bittrex = Bittrex() def test_get_balances(self): actual = self.bittrex.get_balances() test_basic_response(self, actual, 'get_balances') def test_get_balance(self): self.assertRaises(TypeError, self.bittrex.get_balance) actual = self.bittrex.get_balance('BTC') test_basic_response(self, actual, 'get_balance') invalid_actual = self.bittrex.get_balance('Invalid currency') test_failed_response(self, invalid_actual, 'get_balance') def test_get_deposit_address(self): self.assertRaises(TypeError, self.bittrex.get_deposit_address) actual = self.bittrex.get_deposit_address('BTC') test_basic_response(self, actual, 'get_deposit_address') invalid_actual = self.bittrex.get_deposit_address('Invalid currency') test_failed_response(self, invalid_actual, 'get_deposit_address') def test_withdraw(self): self.assertRaises(TypeError, self.bittrex.withdraw) def test_get_order(self): self.assertRaises(TypeError, self.bittrex.get_order) actual = self.bittrex.get_order('test') test_response_structure(self, actual, 'get_order') def test_get_order_history(self): actual = self.bittrex.get_order_history() test_basic_response(self, actual, 'get_order_history') actual = self.bittrex.get_order_history('BTC-LTC') test_basic_response(self, actual, 'get_order_history') def test_get_withdrawal_historyself(self): actual = self.bittrex.get_withdrawal_history() test_basic_response(self, actual, 'get_withdrawal_history') actual = self.bittrex.get_withdrawal_history('BTC') test_basic_response(self, actual, 'get_withdrawal_history') def test_get_deposit_history(self): actual = self.bittrex.get_deposit_history() test_basic_response(self, actual, 'get_deposit_history') actual = self.bittrex.get_deposit_history('BTC') test_basic_response(self, actual, 'get_deposit_history')
def getBalances(self): bittrex = Bittrex(api_key=self.key, api_secret=self.secret) resp = bittrex.get_balances() balance = dict() for entry in resp['result']: cur = entry['Currency'] value = entry['Balance'] if value == 0: continue if cur not in balance: balance[cur] = 0.0 balance[cur] += value logging.debug(resp) return balance
def my_bittrex(): total = [] my_b = Bittrex(auth.api_key, auth.api_secret) balances = my_b.get_balances() for currency in balances['result']: if currency['Available'] > 0: curr = str(currency['Currency']) if curr == 'BTC': bal = currency['Available'] - my_btc - foxy_btc btc = requests.get('https://api.coinmarketcap.com/v1/ticker/bitcoin/') output = btc.json()[0]['price_usd'] usd = float(output)*bal*0.5 rub_btc = usd_to_rub(usd) total.append(rub_btc) elif curr == 'ETH': bal = currency['Available'] - my_eth - foxy_eth ethereum = requests.get('https://api.coinmarketcap.com/v1/ticker/ethereum/') output = ethereum.json()[0]['price_usd'] usd = float(output)*bal*0.5 rub_eth = usd_to_rub(usd) total.append(rub_eth) elif curr == 'DCR': bal = currency['Available'] decred = requests.get('https://api.coinmarketcap.com/v1/ticker/decred/') output = decred.json()[0]['price_usd'] usd = float(output)*bal*0.5 rub_decred = usd_to_rub(usd) total.append(rub_decred) elif curr == 'ZEC': bal = currency['Available'] zcash = requests.get('https://api.coinmarketcap.com/v1/ticker/zcash/') output = zcash.json()[0]['price_usd'] usd = float(output)*bal*0.5 rub_zcash = usd_to_rub(usd) total.append(rub_zcash) else: pass return int(sum(total))
class TestBittrexV20AccountAPI(unittest.TestCase): """ 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'], api_version=API_V2_0) def test_handles_invalid_key_or_secret(self): self.bittrex = Bittrex('invalidkey', self.secrets['secret'], api_version=API_V2_0) actual = self.bittrex.get_balance('BTC') test_auth_basic_failures(self, actual, 'Invalid key, valid secret') self.bittrex = Bittrex(None, self.secrets['secret'], api_version=API_V2_0) actual = self.bittrex.get_balance('BTC') test_auth_basic_failures(self, actual, 'None key, valid secret') self.bittrex = Bittrex(self.secrets['key'], 'invalidsecret', api_version=API_V2_0) actual = self.bittrex.get_balance('BTC') test_auth_basic_failures(self, actual, 'valid key, invalid secret') self.bittrex = Bittrex(self.secrets['key'], None, api_version=API_V2_0) actual = self.bittrex.get_balance('BTC') test_auth_basic_failures(self, actual, 'valid key, None secret') self.bittrex = Bittrex('invalidkey', 'invalidsecret', api_version=API_V2_0) actual = self.bittrex.get_balance('BTC') test_auth_basic_failures(self, actual, 'invalid key, invalid secret') def test_get_openorders(self): actual = self.bittrex.get_open_orders('BTC-LTC') test_basic_response(self, actual, "get_openorders") self.assertTrue(isinstance(actual['result'], list), "result is not a list") def test_get_balances(self): actual = self.bittrex.get_balances() test_basic_response(self, actual, "get_balances") self.assertTrue(isinstance(actual['result'], list), "result is not a list") @unittest.skip( "the return result is an empty dict. API bug? the 2.0 get_balances works as expected" ) def test_get_balance(self): actual = self.bittrex.get_balance('BTC') test_basic_response(self, actual, "get_balance") self.assertTrue(isinstance(actual['result'], dict), "result is not a dict") self.assertEqual( actual['result']['Currency'], "BTC", "requested currency {0:s} does not match returned currency {1:s}". format("BTC", actual['result']['Currency'])) @unittest.skip("my testing account is acting funny this should work") def test_get_depositaddress(self): actual = self.bittrex.get_deposit_address('BTC') test_basic_response(self, actual, "get_deposit_address") def test_get_order_history_all_markets(self): actual = self.bittrex.get_order_history() test_basic_response(self, actual, "get_order_history") self.assertIsInstance(actual['result'], list, "result is not a list") def test_get_order_history_one_market(self): actual = self.bittrex.get_order_history(market='BTC-LTC') test_basic_response(self, actual, "get_order_history") self.assertIsInstance(actual['result'], list, "result is not a list") def test_get_withdrawlhistory_all_currencies(self): actual = self.bittrex.get_withdrawal_history() test_basic_response(self, actual, "get_withdrawal_history") self.assertIsInstance(actual['result'], list, "result is not a list") def test_get_withdrawlhistory_one_currency(self): actual = self.bittrex.get_withdrawal_history('BTC') test_basic_response(self, actual, "get_withdrawal_history") self.assertIsInstance(actual['result'], list, "result is not a list") def test_get_deposithistory_all_currencies(self): actual = self.bittrex.get_deposit_history() test_basic_response(self, actual, "get_deposit_history") self.assertIsInstance(actual['result'], list, "result is not a list") def test_get_deposithistory_one_currency(self): actual = self.bittrex.get_deposit_history('BTC') test_basic_response(self, actual, "get_deposit_history") self.assertIsInstance(actual['result'], list, "result is not a list") def test_get_pending_withdrawals_all_currencies(self): actual = self.bittrex.get_pending_withdrawals() test_basic_response(self, actual, "get_pending_withdrawals") self.assertIsInstance(actual['result'], list, "result is not a list") def test_get_pending_withdrawals_one_currency(self): actual = self.bittrex.get_pending_withdrawals('BTC') test_basic_response(self, actual, "get_pending_withdrawals") self.assertIsInstance(actual['result'], list, "result is not a list") def test_get_pending_deposits_all_currencies(self): actual = self.bittrex.get_pending_deposits() test_basic_response(self, actual, "get_pending_deposits") self.assertIsInstance(actual['result'], list, "result is not a list") def test_get_pending_deposits_one_currency(self): actual = self.bittrex.get_pending_deposits('BTC') test_basic_response(self, actual, "get_pending_deposits") self.assertIsInstance(actual['result'], list, "result is not a list") def test_generate_deposit_address(self): actual = self.bittrex.generate_deposit_address(currency='BTC') test_basic_response(self, actual, "generate_deposit_address") self.assertIsInstance(actual['result'], list, "result is not a list")
class TestBittrexV11AccountAPI(unittest.TestCase): """ 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_handles_invalid_key_or_secret(self): self.bittrex = Bittrex('invalidkey', self.secrets['secret']) actual = self.bittrex.get_balance('BTC') test_auth_basic_failures(self, actual, 'Invalid key, valid secret') self.bittrex = Bittrex(None, self.secrets['secret']) actual = self.bittrex.get_balance('BTC') test_auth_basic_failures(self, actual, 'None key, valid secret') self.bittrex = Bittrex(self.secrets['key'], 'invalidsecret') actual = self.bittrex.get_balance('BTC') test_auth_basic_failures(self, actual, 'valid key, invalid secret') self.bittrex = Bittrex(self.secrets['key'], None) actual = self.bittrex.get_balance('BTC') test_auth_basic_failures(self, actual, 'valid key, None secret') self.bittrex = Bittrex('invalidkey', 'invalidsecret') actual = self.bittrex.get_balance('BTC') test_auth_basic_failures(self, actual, 'invalid key, invalid secret') def test_get_openorders(self): actual = self.bittrex.get_open_orders('BTC-LTC') test_basic_response(self, actual, "get_openorders") self.assertTrue(isinstance(actual['result'], list), "result is not a list") def test_get_balances(self): actual = self.bittrex.get_balances() test_basic_response(self, actual, "get_balances") self.assertTrue(isinstance(actual['result'], list), "result is not a list") def test_get_balance(self): actual = self.bittrex.get_balance('BTC') test_basic_response(self, actual, "get_balance") self.assertTrue(isinstance(actual['result'], dict), "result is not a dict") self.assertEqual( actual['result']['Currency'], "BTC", "requested currency {0:s} does not match returned currency {1:s}". format("BTC", actual['result']['Currency'])) def test_get_depositaddress(self): actual = self.bittrex.get_deposit_address('BTC') if not actual['success']: self.assertTrue(actual['message'], 'ADDRESS_GENERATING') else: test_basic_response(self, actual, "get_deposit_address") def test_get_order_history_all_markets(self): actual = self.bittrex.get_order_history() test_basic_response(self, actual, "get_order_history") self.assertIsInstance(actual['result'], list, "result is not a list") def test_get_order_history_one_market(self): actual = self.bittrex.get_order_history(market='BTC-LTC') test_basic_response(self, actual, "get_order_history") self.assertIsInstance(actual['result'], list, "result is not a list") def test_get_withdrawlhistory_all_currencies(self): actual = self.bittrex.get_withdrawal_history() test_basic_response(self, actual, "get_withdrawal_history") self.assertIsInstance(actual['result'], list, "result is not a list") def test_get_withdrawlhistory_one_currency(self): actual = self.bittrex.get_withdrawal_history('BTC') test_basic_response(self, actual, "get_withdrawal_history") self.assertIsInstance(actual['result'], list, "result is not a list") def test_get_deposithistory_all_currencies(self): actual = self.bittrex.get_deposit_history() test_basic_response(self, actual, "get_deposit_history") self.assertIsInstance(actual['result'], list, "result is not a list") def test_get_deposithistory_one_currency(self): actual = self.bittrex.get_deposit_history('BTC') test_basic_response(self, actual, "get_deposit_history") self.assertIsInstance(actual['result'], list, "result is not a list") def test_get_pending_withdrawals(self): self.assertRaisesRegexp(Exception, 'method call not available', self.bittrex.get_pending_withdrawals) def test_get_pending_deposits(self): self.assertRaisesRegexp(Exception, 'method call not available', self.bittrex.get_pending_deposits) def test_generate_deposit_address(self): self.assertRaisesRegexp(Exception, 'method call not available', self.bittrex.generate_deposit_address, currency='BTC')
def mainrun(): if Path(PATH+'currencyretain.pickle').is_file(): remaining = pickle.load(open(PATH+'currencyretain.pickle','rb')) else: remaining = OrderedDict() BTX = Bittrex(key=apikey,secret=apisecret) blockPrint() balances = BTX.get_balances()['result'] orders = BTX.get_open_orders()['result'] enablePrint() waitingon = [] for ORDS in orders: EX = ORDS["Exchange"] TYPE = ORDS["OrderType"] if (SelltoCurrency in EX) and ('BUY' in TYPE): continue elif (orderwait==1) and (SelltoCurrency not in EX): EX = EX.replace(SelltoCurrency+'-','') EX = EX.replace('-'+SelltoCurrency,'') if EX not in EX: waitingon.append(EX) else: continue for BAL in balances: Currency = BAL["Currency"] Available = BAL["Available"] if Currency in retainspec.keys(): retained = retainspec[Currency] else: retained = retainednorm if retentionROI == 1: ROI = 1.00 + retained + retained**2 + retained**3 + retained**4 else: ROI = ROI if Currency in remaining.keys(): CurrencyHold = remaining[Currency] Available = Available - CurrencyHold else: CurrencyHold = 0.00 if (Currency not in waitingon) and (Currency != SelltoCurrency) and ( (Available + CurrencyHold) > (CurrencyHold + Minimumtradeorder) ): Quantitytosell = (Available-(retained*Available)) blockPrint() price = BTX.get_market_history(SelltoCurrency+'-'+Currency)['result'][0]["Price"] enablePrint() #Take into account the initial fee zerofeeamount = ( price ) / (1-bidFee) Netprice = (zerofeeamount*ROI) / (1-askFee) if (Quantitytosell*price) > Minimumtradeorder: BTX.sell_limit(SelltoCurrency+'-'+Currency,Quantitytosell,Netprice) #Make sure to 'Hold' the amount remaining until it goes above this amount. remaining[Currency] = retained*Available + CurrencyHold pickle_out = open(PATH+'currencyretain.pickle','wb') pickle.dump(remaining,pickle_out) pickle_out.close() else: print("Minimum Trade order is: "+ str(Minimumtradeorder) + " " + SelltoCurrency + ", You tried to sell: " + str(Quantitytosell*price) + " " + SelltoCurrency + " Worth.")
list_currency=[] list_balance=[] list_available=[] list_pending=[] list_last=[] list_btcvalue=[] list_market=[] list_percent=[] totalworth=0 i=0 n=0 k=0 btceuro=0 btcusd=0 wallet1=Bittrex(api_key,api_secret) data=wallet1.get_balances() #Date print "\n","=====",time.strftime("%A %d %B %Y %H:%M:%S"),"=====","\n" #Requesting BTC price contenteuro=requests.get("https://www.bitstamp.net/api/v2/ticker/btceur/") contenteuro=contenteuro.json() btceuro=contenteuro["last"] contentusd=requests.get("https://www.bitstamp.net/api/v2/ticker/btcusd/") contentusd=contentusd.json() btcusd=contentusd["last"] #BTC percentage btcfloat=float(btcusd) btcopen=contentusd["open"]
class Trader(object): """ Used for handling all trade functionality """ def __init__(self, secrets, settings): self.trade_params = settings["tradeParameters"] self.pause_params = settings["pauseParameters"] self.Bittrex = Bittrex(secrets) self.Messenger = Messenger(secrets, settings) 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_error("connection", [], True) logger.exception(exception) exit() def analyse_pauses(self): """ Checks all the paused buy and sell pairs and the balance notification timer 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 "sell" in self.pause_params and 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() if "balance" in self.pause_params and self.Database.check_resume( self.pause_params["balance"]["pauseTime"], "balance"): current_balance = self.Messenger.send_balance_slack( self.get_non_zero_balances(), self.Database.get_previous_total_balance()) self.Database.reset_balance_notifier(current_balance) 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 rsi is None: return 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 "buy" in self.pause_params and rsi >= self.pause_params["buy"][ "rsiThreshold"] > 0: self.Messenger.print_pause(coin_pair, [rsi, day_volume], self.pause_params["buy"]["pauseTime"], "buy") self.Database.pause_buy(coin_pair) else: self.Messenger.print_no_buy(coin_pair, rsi, day_volume, current_buy_price) 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 rsi is None: return 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 "sell" in self.pause_params and profit_margin <= self.pause_params[ "sell"]["profitMarginThreshold"] < 0: self.Messenger.print_pause(coin_pair, [profit_margin, rsi], self.pause_params["sell"]["pauseTime"], "sell") self.Database.pause_sell(coin_pair) else: self.Messenger.print_no_sell(coin_pair, rsi, profit_margin, current_sell_price) 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 """ rsi_check = rsi <= self.trade_params["buy"]["rsiThreshold"] day_volume_check = day_volume >= self.trade_params["buy"][ "24HourVolumeThreshold"] current_buy_price_check = current_buy_price >= self.trade_params[ "buy"]["minimumUnitPrice"] return rsi_check and day_volume_check and current_buy_price_check 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 """ rsi_check = rsi >= self.trade_params["sell"]["rsiThreshold"] lower_profit_check = profit_margin >= self.trade_params["sell"][ "minProfitMarginThreshold"] upper_profit_check = profit_margin >= self.trade_params["sell"][ "profitMarginThreshold"] loss_check = ("lossMarginThreshold" in self.trade_params["sell"] and 0 > self.trade_params["sell"]["lossMarginThreshold"] >= profit_margin) return (rsi_check and lower_profit_check) or upper_profit_check or ( rsi_check and loss_check) 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_quantity = round(btc_quantity / price, 8) buy_data = self.Bittrex.buy_limit(coin_pair, buy_quantity, price) if not buy_data["success"]: error_str = self.Messenger.print_error( "buy", [coin_pair, buy_data["message"]]) logger.error(error_str) return 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"]: error_str = self.Messenger.print_error( "sell", [coin_pair, sell_data["message"]]) logger.error(error_str) return 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"]: error_str = self.Messenger.print_error("market", [], True) logger.error(error_str) 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"]: error_str = self.Messenger.print_error("coinMarket", [coin_pair]) logger.error(error_str) 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"]: error_str = self.Messenger.print_error("coinMarket", [coin_pair]) logger.error(error_str) 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_error("order", [ 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 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 def get_non_zero_balances(self): """ Gets all non-zero user coin balances in the correct format """ balances_data = self.Bittrex.get_balances() if not balances_data["success"]: error_str = self.Messenger.print_error("balance") logger.error(error_str) return non_zero_balances = py_.filter_( balances_data["result"], lambda balance_item: balance_item["Balance"] > 0) return py_.map_(non_zero_balances, lambda balance: self.create_balance_object(balance)) def create_balance_object(self, balance_item): """ Creates a new balance object containing only the relevant values and the BTC value of the coin's balance :param balance_item: The Bittrex user balance object for a coin :type balance_item: dict """ btc_price = 1 is_tracked = False if balance_item["Currency"] != "BTC": coin_pair = "BTC-" + balance_item["Currency"] is_tracked = coin_pair in self.Database.trades["trackedCoinPairs"] btc_price = self.get_current_price(coin_pair, "bid") return py_.assign( py_.pick(balance_item, "Currency", "Balance"), { "BtcValue": round(btc_price * balance_item["Balance"], 8), "IsTracked": is_tracked })
from bittrex import Bittrex from pymarketcap import * from twilio.rest import Client import simplejson as json apiKeys = json.loads(open("secrets.json").read()) myBittrex = Bittrex(apiKeys['key'], apiKeys['secret']) cmc = Pymarketcap() twilio = Client(apiKeys['SID'], apiKeys['AUTH']) data = json.loads(json.dumps(myBittrex.get_balances())) deposited = 1297.20 if data["success"]: total = 0 balances = {} changes = {} for curr in data['result']: balance = curr['Balance'] currency = curr['Currency'] if balance > 0: balances[currency] = balance for curr, balance in balances.items(): # get balances print(curr, balance) cmcData = json.loads(json.dumps(cmc.ticker(curr))) usd = cmcData['price_usd'] total += usd * balance
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 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)