def exchange_fees_coin(): """'Exchange fees by cryptocurrency' page. """ # If 'calc_currency' exists in cookie, use it currency = request.cookies.get('calc_currency') if currency: curr = currency else: curr = Params.DEFAULT_CURRENCY curr = get_coin(curr) feedback_form = FeedbackForm() # Get exchanges coins = get_coins(pos_limit=Params.BROWSE_FEE_COINS, status="Active") # Get Meta tags title = get_meta_tags('Exchanges|Fees|Coin', 'Title') description = get_meta_tags('Exchanges|Fees|Coin', 'Description') # Actions if Feedback Form was filled if feedback_form.feedback_submit.data: if feedback_form.validate(): manage_feedback_form(feedback_form, request.path) # Load page return render_template('exchange_fees_coin.html', curr=curr, title=title, description=description, feedback_form=feedback_form, coins=coins)
def get_best_coinZ(self, coin, baseCoin): """Finds a coin that trades in the exchange against both given coins. Returns a 'CoinZ' object. """ # Get CoinZ's that trade against 'coin' & 'baseCoin' coinZ_coin = self.get_all_coinZs(coin) coinZ_baseCoin = self.get_all_coinZs(baseCoin) # Find CoinZ that trades agains both coins with highest liquidity winning_coinZ = CoinZ(None, -1, -1) for coinZ in coinZ_coin: for coinZ_2 in coinZ_baseCoin: if coinZ[0] == coinZ_2[0]: if min(coinZ[1], coinZ_2[1]) < winning_coinZ.min_liq(): continue # If same liquidity (or no available), BTC prevails elif min(coinZ[1], coinZ_2[1]) == winning_coinZ.min_liq(): if (winning_coinZ.coin and winning_coinZ.coin.id == 'BTC'): continue winning_coinZ = CoinZ(get_coin(coinZ[0]), coinZ[1], coinZ_2[1]) if not winning_coinZ.coin: return None self.logger.debug("[{}] Chosen CoinZ: {}".format( self.exchange.id, winning_coinZ)) return winning_coinZ
def exchange_fees_exch(): """'Exchange fees by exchange' page. """ # If 'calc_currency' exists in cookie, use it currency = request.cookies.get('calc_currency') if currency: curr = currency else: curr = Params.DEFAULT_CURRENCY curr = get_coin(curr) feedback_form = FeedbackForm() # Get exchanges exchanges = get_exchanges(['Exchange'], status='Active') # Get promos promos = get_promos() # Get Meta tags title = get_meta_tags('Exchanges|Fees|Exch', 'Title') description = get_meta_tags('Exchanges|Fees|Exch', 'Description') # Actions if Feedback Form was filled if feedback_form.feedback_submit.data: if feedback_form.validate(): manage_feedback_form(feedback_form, request.path) return render_template('exchange_fees_exch.html', curr=curr, title=title, description=description, feedback_form=feedback_form, exchanges=exchanges, promos=promos)
def exchange_fees_by_exch(exch_id): """Displays the fees of the exchange given as argument. """ exchange = get_exchange(exch_id) # If exchange not recognnized, redirect if not exchange: return redirect(url_for('exchange_fees_exch')) # Get Exchange fees trading_fees = get_trading_fees_by_exch(exch_id) dep_with_fees = get_dep_with_fees_by_exch(exch_id) # Get Exchange data exch_data = get_exchange_data(exchange.id, exchange.site_url, exchange_info_file, logger) # Get promos promos = get_promos() # If 'calc_currency' exists in cookie, use it currency = request.cookies.get('calc_currency') if currency: curr = currency else: curr = Params.DEFAULT_CURRENCY curr = get_coin(curr) # Get forms feedback_form = FeedbackForm() promo_form = PromoForm() # Get Meta tags title = get_meta_tags('Exchanges|Fees|Exch|Exch', 'Title', [exchange.name]) description = get_meta_tags('Exchanges|Fees|Exch|Exch', 'Description', [exchange.name]) # Get Texts trading_text = Markup(get_exch_text(exch_id, 'Trade')) withdrawal_text = Markup(get_exch_text(exch_id, 'Withdrawal')) # Actions if Feedback Form was filled if feedback_form.feedback_submit.data: if feedback_form.validate(): manage_feedback_form(feedback_form, request.path) # Load page return render_template('exchange_fees_by_exch.html', exchange=exchange, curr=curr, title=title, description=description, feedback_form=feedback_form, promo_form=promo_form, trading_text=trading_text, withdrawal_text=withdrawal_text, trading_fees=trading_fees, dep_with_fees=dep_with_fees, exch_data=exch_data, promos=promos)
def home(): url_orig_coin = 'empty' url_dest_coin = 'empty' input_form = SearchForm() # If 'calc_currency' exists in cookie, use it currency = request.cookies.get('calc_currency') if currency: curr = currency input_form.currency.data = currency else: curr = Params.DEFAULT_CURRENCY curr = get_coin(curr) exchanges = get_exchanges(['Exchange'], status='Active') user_exchanges = [exch.id for exch in exchanges] # Get Blog information posts = get_latest_posts(None, 6) # Get Meta tags title = get_meta_tags('Home', 'Title') description = get_meta_tags('Home', 'Description') # Get forms feedback_form = FeedbackForm() promo_form = PromoForm() # Get promos promos = get_promos() # Actions if Feedback Form was filled if promo_form.promo_submit.data: if promo_form.validate(): manage_promo_form(promo_form, 'Promos') # Actions if Feedback Form was filled if feedback_form.feedback_submit.data: if feedback_form.validate(): manage_feedback_form(feedback_form, request.path) resp = make_response(render_template('home.html', form=input_form, curr=curr, exchanges=exchanges, user_exchanges=user_exchanges, title=title, description=description, feedback_form=feedback_form, promo_form=promo_form, promos=promos, url_orig_coin=url_orig_coin, url_dest_coin=url_dest_coin, add_flaticon_link=True, posts=posts)) # Store session ID in cookie if it is not already stored session_id = request.cookies.get('session') if not session_id: resp.set_cookie('session', token_hex(8)) session_id = request.cookies.get('session') return resp
def perform_trade(self, sell_amt, sell_coin, buy_coin): """Performs the trade from 'sell_coin' to 'buy_coin'. Returns a 'Trade' object """ # Find the trading fee for the given pairget_trade_fee( fee_amt_perc, fee_coin, fee_literal = self.get_trade_fee( sell_amt, sell_coin, buy_coin) if fee_amt_perc is None: self.logger.warning("perform_trade: No trade fee for '{}[{}/{}]'." "Skipping trade calculation.".format( self.exchange.id, sell_coin.id, buy_coin.id)) return None # Perform trade: buy_amt = fx_exchange(sell_coin.id, buy_coin.id, sell_amt * (1 - fee_amt_perc / 100), self.logger) if buy_amt is None: self.logger.warning("perform_trade [2]: Trade could not be " "performed '{}[{}/{}]'. " "Skipping trade calculation.".format( self.exchange.id, sell_coin.id, buy_coin.id)) return None elif buy_amt <= 0: self.logger.warning( "perform_trade [3]: Trade performed with negative outcome '{}[{} {} --> {} {}]'. " "Skipping trade calculation.".format(self.exchange.id, sell_amt, sell_coin.id, buy_amt, buy_coin.id)) return None # Fees calculated by default in 'sell_coin' fee_amt = fee_amt_perc / 100 * sell_amt # If 'FeeCoin' has a value, calculate fees in 'FeeCoin' if fee_coin and fee_coin is not '-': fee_amt = fx_exchange(sell_coin.id, fee_coin, fee_amt, self.logger) fee_coin = get_coin(fee_coin) else: fee_coin = sell_coin # Return calculated trade self.logger.debug("perform_trade [3]: Trade for '{}[{}/{}]:" " Sell={} {} / Buy={} {} / Fee={} {}'" "".format(self.exchange.id, sell_coin.id, buy_coin.id, sell_amt, sell_coin.id, buy_amt, buy_coin.id, fee_amt, fee_coin.id)) return Trade(sell_amt, sell_coin, buy_amt, buy_coin, fee_amt, fee_coin, fee_literal)
def promotions(): try: # If 'calc_currency' exists in cookie, use it currency = request.cookies.get('calc_currency') if currency: curr = currency else: curr = Params.DEFAULT_CURRENCY curr = get_coin(curr) # Get forms feedback_form = FeedbackForm() promo_form = PromoForm() # Get Meta tags title = get_meta_tags('Promotions', 'Title') description = get_meta_tags('Promotions', 'Description') # Get promos promos = get_promos() # Actions if Feedback Form was filled if promo_form.promo_submit.data: if promo_form.validate(): manage_promo_form(promo_form, 'Promos') # Actions if Feedback Form was filled if feedback_form.feedback_submit.data: if feedback_form.validate(): manage_feedback_form(feedback_form, request.path) # Catch generic exception just in case anything went wront except Exception as e: logger.error("routes: Error procesing 'crypto-promotions'") error_notifier(type(e).__name__, traceback.format_exc(), mail, logger) return redirect(url_for('home')) # Load page return render_template('promotions.html', curr=curr, title=title, description=description, feedback_form=feedback_form, promo_form=promo_form, promos=promos)
def exchange_fees_by_coin(coin_url_name): """Displays the fees for the coin given as as argument. """ try: coin = get_coin_by_urlname(coin_url_name) # If coin not recognized, redirect if not coin: return redirect(url_for('exchange_fees_coin')) # Get coin fees coin_fees = get_coin_fees(coin.id) # Get coin data coin_data = get_coin_data(coin.paprika_id, coin_info_file, people_info_file, tag_info_file, logger) # If 'calc_currency' exists in cookie, use it currency = request.cookies.get('calc_currency') if currency: curr = currency else: curr = Params.DEFAULT_CURRENCY feedback_form = FeedbackForm() # Get Meta tags title = get_meta_tags('Exchanges|Fees|Coin|Coin', 'Title', [coin.long_name, coin.symbol]) description = get_meta_tags('Exchanges|Fees|Coin|Coin', 'Description', [coin.long_name, coin.symbol]) # Get search coins if (coin.type == 'Crypto'): quick_search_coins = Params.QUICK_SEARCH_COINS['Crypto'] else: quick_search_coins = Params.QUICK_SEARCH_COINS['Fiat'] search_coins = [] search_count = 0 for item in quick_search_coins: if item != coin.id: coinA = get_coin(item) search_coins.append({"coinA": coinA, "coinB": coin}) search_count += 1 # If for items have been gathered, exit loop if search_count == 4: break # Catch generic exception just in case anything went wront except Exception as e: logger.error("routes: Error procesing '{}'".format(coin_url_name)) error_notifier(type(e).__name__, traceback.format_exc(), mail, logger) return redirect(url_for('exchange_fees_coin')) # Load page return render_template('exchange_fees_by_coin.html', coin=coin, coin_data=coin_data, curr=curr, title=title, description=description, feedback_form=feedback_form, coin_fees=coin_fees, search_coins=search_coins)
def exch_results(url_orig_coin=None, url_dest_coin=None): """There are two ways of landing in this page: - Search form was filled: performs search and returns results - Direct external link (no form was filled!): in this case, a page with no results is shown, and then from the page a proper calculation is triggered. It is done like this to let the user load the page as soon as possible. """ session_id = request.cookies.get('session') if not session_id: new_session_id = token_hex(8) sorted_paths = [] input_form = SearchForm() # Choose currency: 1) Form 2) Cookie 3) Default currency = request.cookies.get('calc_currency') if input_form.currency.data != 'Empty': curr = input_form.currency.data elif currency: curr = currency input_form.currency.data = curr else: curr = Params.DEFAULT_CURRENCY input_form.currency.data = curr auto_search = False feedback_form = FeedbackForm() exchanges = get_exchanges(['Exchange']) user_exchanges = [exch.id for exch in exchanges] path_results = None open_fbck_modal = False # Get Meta tags (in case form was not filled) title = get_meta_tags('Exchanges|Results', 'Title', [url_orig_coin.upper(), url_dest_coin.upper()]) description = get_meta_tags('Exchanges|Results', 'Description', [url_orig_coin.upper(), url_dest_coin.upper()]) # 1) ACTIONS IF *SEARCH* FORM WAS FILLED if input_form.search_submit.data: if input_form.validate(): curr = input_form.currency.data orig_loc = get_exch_by_name(input_form.orig_loc.data) orig_coin = get_coin_by_longname(input_form.orig_coin.data) # Save 'orig_amt' as Float or integer depending on value num = float(input_form.orig_amt.data) if num % 1 == 0: num = int(num) orig_amt = num dest_loc = get_exch_by_name(input_form.dest_loc.data) dest_coin = get_coin_by_longname(input_form.dest_coin.data) user_exchanges = input_form.exchanges.data # Get Meta tags (again, if form was filled) title = get_meta_tags('Exchanges|Results', 'Title', [orig_coin.symbol, dest_coin.symbol]) description = get_meta_tags('Exchanges|Results', 'Description', [orig_coin.long_name, dest_coin.long_name]) # If user selected all Exchanges or none of them, don't filter if len(user_exchanges) == len(exchanges): user_exchanges = [] fee_settings = {"CEP": input_form.cep_promos.data, "Default": input_form.default_fee.data, "Binance": input_form.binance_fee.data} # start_time = datetime.datetime.now() try: paths = calc_paths(orig_loc, orig_coin, orig_amt, dest_loc, dest_coin, curr, fee_settings, logger) path_results = len(paths) # Catch generic exception just in case anything went wront in logic except Exception as e: db.session.rollback() error_notifier(type(e).__name__, traceback.format_exc(), mail, logger) paths = [] path_results = -1 # If no results were found, send worning email if path_results == 0: args_dic = {"orig_amt": orig_amt, "orig_coin": orig_coin.id, "orig_loc": orig_loc.id, "dest_coin": dest_coin.id, "dest_loc": dest_loc.id, "currency": curr} warning_notifier("Search with no results", args_dic, mail, logger) # Register query # finish_time = datetime.datetime.now() # results = len(paths) # exchs = "" # for exch in user_exchanges: # exchs += exch + '|' # exchs = exchs[:-1] # try: # query = QueryRegister(session_id=session_id, # orig_amt=orig_amt, # orig_coin=orig_coin.id, # orig_loc=orig_loc.id, # dest_coin=dest_coin.id, # dest_loc=dest_loc.id, # currency=curr, # connection_type=connection_type, # exchanges=exchs, # results=results, # start_time=start_time, # finish_time=finish_time) # db.session.add(query) # db.session.commit() # except Exception as e: # db.session.rollback() # error_notifier(type(e).__name__, # traceback.format_exc(), # mail, # logger) # Select all Exchanges if no partial selection was made if not user_exchanges: user_exchanges = [exch.id for exch in exchanges] # Return capped list of results sorted_paths = sorted(paths, key=lambda x: x.total_fees) sorted_paths = sorted_paths[0:Params.MAX_PATHS] # 2) ACTIONS IF *NO* FORM WAS FILLED (DIRECT LINK!) else: orig_coin = get_coin(url_orig_coin.upper()) dest_coin = get_coin(url_dest_coin.upper()) if orig_coin: input_form.orig_coin.data = orig_coin.long_name amt = fx_exchange("USD", orig_coin.id, 3000, logger) input_form.orig_amt.data = str(math.ceil(amt)) + " " if dest_coin: input_form.dest_coin.data = dest_coin.long_name auto_search = True resp = make_response(render_template('exch_results.html', form=input_form, curr=curr, exchanges=exchanges, user_exchanges=user_exchanges, paths=sorted_paths, path_results=path_results, auto_search=auto_search, feedback_form=feedback_form, title=title, description=description, open_feedback_modal=open_fbck_modal, url_orig_coin=url_orig_coin, url_dest_coin=url_dest_coin)) # Store session ID & Currency in cookie if there are not already stored if not session_id: resp.set_cookie('session', new_session_id) if currency != curr: resp.set_cookie('calc_currency', curr) return resp
def exch_results(url_orig_coin=None, url_dest_coin=None): """There are two ways of landing in this page: - Search form was filled: performs search and returns results - Direct external link (no form was filled!): in this case, a page with no results is shown, and then from the page a proper calculation is triggered. It is done like this to let the user load the page as soon as possible. """ try: session_id = request.cookies.get('session') if not session_id: new_session_id = token_hex(8) sorted_paths = [] input_form = SearchForm() # Choose currency: 1) Form 2) Cookie 3) Default currency = request.cookies.get('calc_currency') if input_form.currency.data != 'Empty': curr = input_form.currency.data elif currency: curr = currency input_form.currency.data = curr else: curr = Params.DEFAULT_CURRENCY input_form.currency.data = curr curr = get_coin(curr) if not curr: curr = get_coin('usd-us-dollars') auto_search = False feedback_form = FeedbackForm() exchanges = get_exchanges(['Exchange'], status='Active') user_exchanges = [exch.id for exch in exchanges] path_results = None amt_warning = None # Get Meta tags (in case form was not filled) title = get_meta_tags('Exchanges|Results', 'Title', [url_orig_coin.upper(), url_dest_coin.upper()]) description = get_meta_tags('Exchanges|Results', 'Description', [url_orig_coin.upper(), url_dest_coin.upper()]) # 1) ACTIONS IF *SEARCH* FORM WAS FILLED if input_form.search_submit.data: if input_form.validate(): curr = input_form.currency.data curr = get_coin(curr) orig_loc = get_exch_by_name(input_form.orig_loc.data) orig_coin = get_coin_by_longname(input_form.orig_coin.data) # Save 'orig_amt' as Float or integer depending on value num = float(input_form.orig_amt.data) if num % 1 == 0: num = int(num) orig_amt = num dest_loc = get_exch_by_name(input_form.dest_loc.data) dest_coin = get_coin_by_longname(input_form.dest_coin.data) user_exchanges = input_form.exchanges.data # Get Meta tags (again, if form was filled) title = get_meta_tags('Exchanges|Results', 'Title', [orig_coin.symbol, dest_coin.symbol]) description = get_meta_tags('Exchanges|Results', 'Description', [orig_coin.long_name, dest_coin.long_name]) # If user selected all Exchanges or none of them, don't filter if len(user_exchanges) == len(exchanges): user_exchanges = [] fee_settings = {"CEP": input_form.cep_promos.data, "Default": input_form.default_fee.data, "Binance": input_form.binance_fee.data} # start_time = datetime.datetime.now() try: paths = calc_paths(orig_loc, orig_coin, orig_amt, dest_loc, dest_coin, curr, fee_settings, logger) path_results = len(paths) # Catch generic exception if anything went wrong in logic except Exception as e: db.session.rollback() error_notifier(type(e).__name__, traceback.format_exc(), mail, logger) paths = [] path_results = -1 # If no results were found, check "orign_amt" to try again if path_results == 0: amount_usd = fx_exchange(orig_coin.id, 'usd-us-dollars', orig_amt, logger) if amount_usd and amount_usd < Params.RECALC_AMOUNT: orig_amt = round_number(orig_amt * Params.RECALC_AMOUNT / amount_usd) orig_amt = round_big_number(orig_amt) input_form.orig_amt.data = orig_amt try: paths = calc_paths(orig_loc, orig_coin, orig_amt, dest_loc, dest_coin, curr, fee_settings, logger) path_results = len(paths) amt_warning = True # Catch generic exception if anything went wrong except Exception as e: db.session.rollback() error_notifier(type(e).__name__, traceback.format_exc(), mail, logger) paths = [] path_results = -1 # If no results were found, send worning email if path_results == 0: args_dic = {"orig_amt": orig_amt, "orig_coin": orig_coin.id, "orig_loc": orig_loc.id, "dest_coin": dest_coin.id, "dest_loc": dest_loc.id, "currency": curr.id} warning_notifier("Search with no results", args_dic, mail, logger) # Select all Exchanges if no partial selection was made if not user_exchanges: user_exchanges = [exch.id for exch in exchanges] # Return capped list of results sorted_paths = sorted(paths, key=lambda x: x.total_fees) sorted_paths = sorted_paths[0:Params.MAX_PATHS] # 2) ACTIONS IF *NO* FORM WAS FILLED (DIRECT LINK!) else: orig_coin = get_coin_by_symbol(url_orig_coin.upper()) dest_coin = get_coin_by_symbol(url_dest_coin.upper()) # If 'orig_coin' or 'dest_coin' not found, try in mappings table if not orig_coin: new_symbol = get_mapping('Coin', 'symbol', url_orig_coin.upper()) if new_symbol: orig_coin = get_coin_by_symbol(new_symbol) if not dest_coin: new_symbol = get_mapping('Coin', 'symbol', url_dest_coin.upper()) if new_symbol: dest_coin = get_coin_by_symbol(new_symbol) # Procced with function if orig_coin: input_form.orig_coin.data = orig_coin.long_name amt = fx_exchange('usd-us-dollars', orig_coin.id, 3000, logger) if amt: amt = round_big_number(amt) input_form.orig_amt.data = str(math.ceil(amt)) + " " if dest_coin: input_form.dest_coin.data = dest_coin.long_name auto_search = True # Actions if Feedback Form was filled if feedback_form.feedback_submit.data: if feedback_form.validate(): manage_feedback_form(feedback_form, request.path) # Catch generic exception just in case anything went wront in logic except Exception as e: db.session.rollback() logger.error("Routes: Non-handled exception at '{}'" .format(request.url)) error_notifier(type(e).__name__, traceback.format_exc(), mail, logger) return redirect(url_for('exchanges')) resp = make_response(render_template('exch_results.html', form=input_form, curr=curr, exchanges=exchanges, user_exchanges=user_exchanges, paths=sorted_paths, amt_warning=amt_warning, path_results=path_results, auto_search=auto_search, feedback_form=feedback_form, title=title, description=description, url_orig_coin=url_orig_coin, url_dest_coin=url_dest_coin)) # Store session ID & Currency in cookie if there are not already stored if not session_id: resp.set_cookie('session', new_session_id) if currency != curr.id: resp.set_cookie('calc_currency', curr.id) return resp
def calc_paths(orig_loc, orig_coin, orig_amt, dest_loc, dest_coin, currency, fee_settings, logger): # Paths container path_list = [] """ *********************************************************************** *************************************************************************** 1. DIRECT EXCHANGE(NO HOPS) *************************************************************************** *********************************************************************** """ logger.info("\n\nSTARTING CALCULATION FOR: \norig_amt = {}\n" "orig_coin = {}\norig_loc = {}\ndest_coin = {}\ndest_loc = {}" "\ncurrency = {}\nfee_settings = {}".format( orig_amt, orig_coin, orig_loc, dest_coin, dest_loc, currency, fee_settings)) logger.info("Main: CALCULATING '1. DIRECT EXCHANGE(NO HOPS)'") # Get exchanges with direct pair exchange direct_pair_exch = get_exch_by_pair(orig_coin.id, dest_coin.id, logger) # Get exchanges that allow deposits of 'orig_coin' exchs_allow_deposits = get_exch_by_coin(orig_coin.id) # Common parts of 'Path' path_type = 0 origin = Location("Origin", orig_loc, orig_amt, orig_coin, logger) # Loop for each exchange to calculate Path fees for exch in direct_pair_exch: # First, check if the exchange allows deposits if exch not in exchs_allow_deposits: continue # If allows deposits, perform trade trade_1_sell_amt = orig_amt if origin.withdraw_fee: trade_1_sell_amt -= origin.withdraw_fee # Calc deposit fee 1 and substract it from sell amount deposit_fee_1 = [None, None] if exch != origin.exchange.id: deposit_fee_1 = calc_fee('Deposit', exch, orig_coin.id, trade_1_sell_amt, logger) if deposit_fee_1 and deposit_fee_1[0] is not None: trade_1_sell_amt -= deposit_fee_1[0] # Perform Trade 1 exchange_1 = ExchangeManager(get_exchange(exch), fee_settings, logger) trade_1 = exchange_1.perform_trade(trade_1_sell_amt, orig_coin, dest_coin) # If 'perform_trade()' did not get results, skip path. Else continue if not trade_1: logger.warning("Main: Trade could not be performed for {}/{}[{}]. " "Path skipped.".format(orig_coin.id, dest_coin.id, exch)) continue # Calc destination amount dest_amt = trade_1.buy_amt # Calc Withdraw fee and modify destination amount withdraw_fee_1 = [] if exch != dest_loc.id: withdraw_fee_1 = calc_fee('Withdrawal', exch, trade_1.buy_coin.id, trade_1.buy_amt, logger) if withdraw_fee_1 and withdraw_fee_1[0] is not None: dest_amt -= withdraw_fee_1[0] if dest_amt < 0: logger.warning("Main: Destination amount " "lower than 0 for {} [{}]. " " Path skipped.".format( exch, trade_1.buy_coin.id)) continue else: logger.warning("Main: Withdraw Fee not found for {} [{}]. " "Path skipped.".format(exch, trade_1.buy_coin.id)) continue # Generate Hop & destination location to finish 'Path' hop_1 = Hop(get_exchange(exch), trade_1, deposit_fee_1, withdraw_fee_1) destination = Location("Destination", dest_loc, dest_amt, dest_coin, logger) if destination.exchange.id == exch: destination.remove_deposit_fees() # Generate 'Path' and add to 'path_list' path = Path(path_type, origin, hop_1, None, destination, currency, logger) path_list.append(path) logger.debug( ('Path Found: {}->{}({})').format(trade_1.sell_coin.id, trade_1.buy_coin.id, exch)) logger.info("End of '1. DIRECT EXCHANGE(NO HOPS)'") """ *********************************************************************** *************************************************************************** 2. INDIRECT EXCHANGE(ONE HOP) *************************************************************************** *********************************************************************** """ logger.info("Main: CALCULATING '2. INDIRECT EXCHANGE(ONE HOP)'") # Get exchanges with indirect pair exchange orig_coin_exchanges = get_exch_by_coin(orig_coin.id) dest_coin_exchanges = get_exch_by_coin(dest_coin.id) # Filter exchanges already used - Filter 'orig_coin_exchanges' filtered_exch = set() for exch in orig_coin_exchanges: if exch not in direct_pair_exch: filtered_exch.add(exch) orig_coin_exchanges = filtered_exch logger.debug( "Main: 'orig_coin_exchanges' filtered: {}".format(orig_coin_exchanges)) # Filter exchanges already used - Filter 'dest_coin_exchanges' filtered_exch = set() for exch in dest_coin_exchanges: if exch not in direct_pair_exch: filtered_exch.add(exch) dest_coin_exchanges = filtered_exch logger.debug( "Main: 'dest_coin_exchanges' filtered: {}".format(dest_coin_exchanges)) # Select exchanges that trade both coins, but not with a direct trade indirect_pair_exch = [ exch for exch in orig_coin_exchanges if exch in dest_coin_exchanges ] logger.debug("Exchanges with both pairs (but not direct trade) [{}]: {}" "".format(len(indirect_pair_exch), indirect_pair_exch)) # Common parts of 'Path' path_type = 1 origin = Location("Origin", orig_loc, orig_amt, orig_coin, logger) # Loop for each exchange with both pairs for exch in indirect_pair_exch: # Get CoinZ that trades against both pairs exchange = ExchangeManager(get_exchange(exch), fee_settings, logger) coinZ = exchange.get_best_coinZ(orig_coin.id, dest_coin.id) if not coinZ: logger.warning("Main: No coinZ found in exchange '{}' to convert" "'{}' to '{}' Path skipped.".format( exch, orig_coin.id, dest_coin.id)) continue # CALCULATE OUTPUTS FOR 'Hop 1' trade_1_sell_amt = orig_amt if origin.withdraw_fee: trade_1_sell_amt -= origin.withdraw_fee # Calc deposit fee 1 and substract it from sell amount deposit_fee_1 = [None, None] if exch != origin.exchange.id: deposit_fee_1 = calc_fee('Deposit', exch, orig_coin.id, trade_1_sell_amt, logger) if deposit_fee_1 and deposit_fee_1[0] is not None: trade_1_sell_amt -= deposit_fee_1[0] # Perform Trade 1 trade_1 = exchange.perform_trade(trade_1_sell_amt, orig_coin, coinZ.coin) # If 'perform_trade()' did not get results, skip path. Else continue if not trade_1: logger.warning("Main: Trade could not be performed for {}/{}[{}]. " "Path skipped.".format(orig_coin.id, coinZ.coin.id, exch)) continue # Generate output object for 'Hop 1' hop_1 = Hop(exchange.exchange, trade_1, deposit_fee_1, None) # CALCULATE OUTPUTS FOR 'Hop 2' trade_2 = exchange.perform_trade(trade_1.buy_amt, trade_1.buy_coin, dest_coin) # If 'perform_trade()' did not get results, skip path. Else continue if not trade_2: logger.warning("Main: Trade could not be performed for {}/{}[{}]. " "Path skipped.".format(trade_1.buy_coin.id, dest_coin.id, exch)) continue # Calc destination amount dest_amt = trade_2.buy_amt # Calc Withdraw fee and modify destination amount withdraw_fee_2 = [] if exch != dest_loc.id: withdraw_fee_2 = calc_fee('Withdrawal', exch, trade_2.buy_coin.id, trade_2.buy_amt, logger) if withdraw_fee_2 and withdraw_fee_2[0] is not None: dest_amt -= withdraw_fee_2[0] else: logger.warning("Main: Withdraw Fee not found for {} [{}]. " "Path skipped.".format(exch, trade_2.buy_coin.id)) continue # Generate Hop & destination location to finish 'Path' deposit_fee_2 = [None, None] hop_2 = Hop(exchange.exchange, trade_2, deposit_fee_2, withdraw_fee_2) destination = Location("Destination", dest_loc, dest_amt, dest_coin, logger) if destination.exchange.id == exch: destination.remove_deposit_fees() # Generate 'Path' and add to 'path_list' path = Path(path_type, origin, hop_1, hop_2, destination, currency, logger) path_list.append(path) logger.debug('Path Found: {}->{}({})' ' --> {}->{}({})'.format(trade_1.sell_coin.id, trade_1.buy_coin.id, exch, trade_2.sell_coin.id, trade_2.buy_coin.id, exch)) logger.info("End of '2. INDIRECT EXCHANGE(ONE HOP)'") """ *********************************************************************** *************************************************************************** 3. INDIRECT EXCHANGE(TWO HOPS) *************************************************************************** *********************************************************************** """ logger.info("Main: CALCULATING '3. INDIRECT EXCHANGE(TWO HOPS)'") # Get all the coins that trade against 'orig_coin' for each exchange orig_coin_exchanges_coinZs = [] for exch in orig_coin_exchanges: exchange = ExchangeManager(get_exchange(exch), fee_settings, logger) coinZs_A = exchange.get_all_cryptoZs(orig_coin.id) exchange.coinZs = coinZs_A orig_coin_exchanges_coinZs.append(exchange) logger.debug("Pairs against [] {}: {}".format(exchange.exchange.id, orig_coin.id, exchange.coinZs)) # Get all the coins that trade against 'dest_coin' for each exchange dest_coin_exchanges_coinZs = [] for exch in dest_coin_exchanges: exchange = ExchangeManager(get_exchange(exch), fee_settings, logger) coinZs_B = exchange.get_all_cryptoZs(dest_coin.id) exchange.coinZs = coinZs_B dest_coin_exchanges_coinZs.append(exchange) logger.debug("Pairs against [] {}: {}".format(exchange.exchange.id, orig_coin.id, exchange.coinZs)) # Common parts of 'Path' path_type = 2 origin = Location("Origin", orig_loc, orig_amt, orig_coin, logger) # Loop through all the exchanges and coins for exch_A in orig_coin_exchanges_coinZs: for coinZ_A in exch_A.coinZs: for exch_B in dest_coin_exchanges_coinZs: if exch_A.exchange.id == exch_B.exchange.id: continue for coinZ_B in exch_B.coinZs: # If coinZ_A==coinZ_B, calculate Exchange Path if coinZ_A[0] == coinZ_B[0]: # CALCULATE OUTPUTS FOR 'Hop 1' trade_1_sell_amt = orig_amt if origin.withdraw_fee: trade_1_sell_amt -= origin.withdraw_fee # Calc deposit fee 1 and substract it from sell amount deposit_fee_1 = [None, None] if exch_A.exchange.id != origin.exchange.id: deposit_fee_1 = calc_fee('Deposit', exch_A.exchange.id, orig_coin.id, trade_1_sell_amt, logger) if deposit_fee_1 and deposit_fee_1[0] is not None: trade_1_sell_amt -= deposit_fee_1[0] # Perform Trade 1 trade_1 = exch_A.perform_trade(trade_1_sell_amt, orig_coin, get_coin(coinZ_A[0])) # If 'perform_trade()' did not get results, skip path if not trade_1: logger.warning( "Main: Trade could not be performed" " for {}/{}[{}]. Path skipped.".format( orig_coin.id, coinZ_A[0], exch_A.exchange.id)) continue # Calc destination amount in_amt_2 = trade_1.buy_amt # Calc Withdraw fee and modify destination amount withdraw_fee_1 = calc_fee('Withdrawal', exch_A.exchange.id, trade_1.buy_coin.id, trade_1.buy_amt, logger) if withdraw_fee_1 and withdraw_fee_1[0] is not None: in_amt_2 -= withdraw_fee_1[0] else: logger.warning("Main: Withdraw Fee not found for" " {} [{}]. Path skipped.".format( exch_A.exchange.id, trade_1.buy_coin.id)) continue # Generate output object for 'Hop 1' hop_1 = Hop(exch_A.exchange, trade_1, deposit_fee_1, withdraw_fee_1) # CALCULATE OUTPUTS FOR 'Hop 2' # Calc deposit fee 2 and substract it from sell amount deposit_fee_2 = calc_fee('Deposit', exch_B.exchange.id, trade_1.buy_coin.id, in_amt_2, logger) if deposit_fee_2 and deposit_fee_2[0] is not None: in_amt_2 -= deposit_fee_2[0] # Perform Trade 2 trade_2 = exch_B.perform_trade(in_amt_2, trade_1.buy_coin, dest_coin) # If 'perform_trade()' did not get results, skip path if not trade_2: logger.warning( "Main: Trade could not be performed" " for {}/{}[{}]. Path skipped.".format( trade_1.buy_coin.id, dest_coin.id, exch_B.exchange.id)) continue # Calc destination amount dest_amt = trade_2.buy_amt # Calc Withdraw fee and modify destination amount withdraw_fee_2 = [] if exch_B.exchange.id != dest_loc.id: withdraw_fee_2 = calc_fee('Withdrawal', exch_B.exchange.id, trade_2.buy_coin.id, trade_2.buy_amt, logger) if (withdraw_fee_2 and withdraw_fee_2[0] is not None): dest_amt -= withdraw_fee_2[0] if dest_amt < 0: logger.warning("Main: Destination amount " "lower than 0 for {} [{}]." " Path skipped.".format( exch_B.exchange.id, trade_2.buy_coin.id)) continue else: logger.warning( "Main: Withdraw Fee not found " "for {} [{}]. Path skipped.".format( exch_B.exchange.id, trade_2.buy_coin.id)) continue # Generate Hop & destination location to finish 'Path' hop_2 = Hop(exch_B.exchange, trade_2, deposit_fee_2, withdraw_fee_2) destination = Location("Destination", dest_loc, dest_amt, dest_coin, logger) if destination.exchange.id == exch_B.exchange.id: destination.remove_deposit_fees() # Generate 'Path' and add to 'path_list' path = Path(path_type, origin, hop_1, hop_2, destination, currency, logger) path_list.append(path) logger.debug( 'Path Found: {}->{}({}) --> {}->{}({})'.format( trade_1.sell_coin.id, trade_1.buy_coin.id, exch_A.exchange.id, trade_2.sell_coin.id, trade_2.buy_coin.id, exch_B.exchange.id)) logger.info("End of '3. INDIRECT EXCHANGE(TWO HOPS)'") # generate_paths_file(path_list, currency, logger) logger.info("Path calculation finished. '{}' results".format( len(path_list))) return path_list