def before_request(): # if no users found, send to setup try: users = User.query.all() except Exception: users = [] if users == []: return redirect(url_for("user_routes.initial_setup")) # Ignore check for some pages - these are mostly methods that need # to run even in setup mode exclude_list = [ "warden.setup", "warden.specter_auth", "warden.login", "warden.register", "warden.logout", "warden.show_broadcast", "warden.show_log", "warden.config_ini", "warden.newtrade" ] if request.endpoint in exclude_list: return if not current_user.is_authenticated: return redirect(url_for("warden.login")) txs = transactions_fx() if txs.empty: flash("No Transactions Found. You can start by including a transaction below. You may also Connect to Specter or import a CSV file.", "info") return redirect(url_for("warden.newtrade")) # Create empty status dictionary meta = { 'tor': current_app.tor, 'specter_reached': current_app.specter.specter_reached, 'specter_auth': current_app.specter.specter_auth } # Save this in Flask session session['status'] = json.dumps(meta) # Check if still downloading data, if so load files if current_app.downloading: # No need to test if still downloading txs flash("Downloading from Specter. In the mean time, some transactions may be outdated or missing. Leave the app running to finish download.", "info") # Check that Specter is > 1.1.0 version # (this is the version where tx API was implemented) try: specter_version = str(current_app.specter.home_parser()['version']) if version.parse(specter_version) < version.parse("1.1.0"): flash(f"Sorry, you need Specter version 1.1.0 or higher to connect to WARden. You are running version {specter_version}. Please upgrade.", "danger") return redirect(url_for('warden.specter_auth')) # An error below means no file was ever created - probably needs setup except Exception: pass # Remove duplicate messages from Flask Flash messages = get_flashed_messages(with_categories=True) messages = list(set(messages)) for category, message in messages: flash(message, category)
def exportcsv(): transactions = Trades.query.filter_by( user_id=current_user.username).order_by(Trades.trade_date) if transactions.count() == 0: return render_template("empty_txs.html") filename = (current_user.username + "_" + datetime.now().strftime("%Y%m%d") + ".") filepath = os.path.join(home_path(), filename) df = transactions_fx() compression_opts = dict(method='zip', archive_name=filename + 'csv') df.to_csv(filepath + 'zip', index=True, compression=compression_opts) return send_file(filepath + 'zip', as_attachment=True)
def heatmapbenchmark_json(): # Get portfolio data first heatmap_gen, heatmap_stats, years, cols = heatmap_generator() # Now get the ticker information and run comparison if request.method == "GET": ticker = request.args.get("ticker") # Defaults to king BTC if not ticker: ticker = "BTC" # Gather the first trade date in portfolio and store # used to match the matrixes later # Panda dataframe with transactions df = transactions_fx() # Filter the df acccoring to filter passed as arguments df["trade_date"] = pd.to_datetime(df["trade_date"]) start_date = df["trade_date"].min() start_date -= timedelta(days=1) # start on t-1 of first trade # Generate price Table now for the ticker and trim to match portfolio fx = current_app.settings['PORTFOLIO']['base_fx'] data = historical_prices(ticker, fx) mask = data.index >= start_date data = data.loc[mask] # If notification is an error, skip this ticker if data is None: messages = data.errors return jsonify(messages) data = data.rename(columns={'close_converted': ticker + '_price'}) data = data[[ticker + '_price']] data.sort_index(ascending=True, inplace=True) data["pchange"] = (data / data.shift(1)) - 1 # Run the mrh function to generate heapmap table heatmap = mrh.get(data["pchange"], eoy=True) heatmap_stats = heatmap cols = [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "eoy", ] cols_months = [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", ] years = heatmap.index.tolist() # Create summary stats for the Ticker heatmap_stats["MAX"] = heatmap_stats[heatmap_stats[cols_months] != 0].max( axis=1) heatmap_stats["MIN"] = heatmap_stats[heatmap_stats[cols_months] != 0].min( axis=1) heatmap_stats["POSITIVES"] = heatmap_stats[ heatmap_stats[cols_months] > 0].count(axis=1) heatmap_stats["NEGATIVES"] = heatmap_stats[ heatmap_stats[cols_months] < 0].count(axis=1) heatmap_stats["POS_MEAN"] = heatmap_stats[ heatmap_stats[cols_months] > 0].mean(axis=1) heatmap_stats["NEG_MEAN"] = heatmap_stats[ heatmap_stats[cols_months] < 0].mean(axis=1) heatmap_stats["MEAN"] = heatmap_stats[ heatmap_stats[cols_months] != 0].mean(axis=1) # Create the difference between the 2 df - Pandas is cool! heatmap_difference = heatmap_gen - heatmap # return (heatmap, heatmap_stats, years, cols, ticker, heatmap_diff) return simplejson.dumps( { "heatmap": heatmap.to_dict(), "heatmap_stats": heatmap_stats.to_dict(), "cols": cols, "years": years, "ticker": ticker, "heatmap_diff": heatmap_difference.to_dict(), }, ignore_nan=True, default=datetime.isoformat, )
def price_and_position(): # Gets price and position data for a specific ticker ticker = request.args.get("ticker") fx = request.args.get("fx") if fx is None: fx = fx_rate()['base'] # Gets Price and market data first realtime_data = realtime_price(ticker=ticker, fx=fx) historical_data = historical_prices(ticker=ticker, fx=fx) historical_data.index = historical_data.index.astype('datetime64[ns]') filemeta = (ticker + "_" + fx + ".meta") historical_meta = pickle_it(action='load', filename=filemeta) price_chart = historical_data[["close_converted", "close"]].copy() # dates need to be in Epoch time for Highcharts price_chart.index = price_chart.index.astype('datetime64[ns]') price_chart.index = (price_chart.index - datetime(1970, 1, 1)).total_seconds() price_chart.index = price_chart.index * 1000 price_chart.index = price_chart.index.astype(np.int64) price_chart = price_chart.to_dict() price_chart_usd = price_chart["close"] price_chart = price_chart["close_converted"] # Now gets position data df = positions() if isinstance(df, pd.DataFrame): if not df.empty: df = df[df['trade_asset_ticker'] == ticker] df_trades = transactions_fx() position_chart = None if isinstance(df_trades, pd.DataFrame): df_trades = df_trades[df_trades['trade_asset_ticker'] == ticker] if not df_trades.empty: df_trades = df_trades.sort_index(ascending=True) df_trades['trade_quantity_cum'] = df_trades[ 'trade_quantity'].cumsum() position_chart = df_trades[["trade_quantity_cum"]].copy() # dates need to be in Epoch time for Highcharts position_chart.index = position_chart.index.astype( 'datetime64[ns]') position_chart.index = (position_chart.index - datetime(1970, 1, 1)).total_seconds() position_chart.index = position_chart.index * 1000 position_chart.index = position_chart.index.astype(np.int64) position_chart = position_chart.to_dict() position_chart = position_chart["trade_quantity_cum"] if ticker == 'GBTC': from pricing_engine.engine import GBTC_premium from parseNumbers import parseNumber GBTC_price = parseNumber(realtime_data['price']) GBTC_fairvalue, GBTC_premium = GBTC_premium(GBTC_price) else: GBTC_premium = GBTC_fairvalue = None return render_template("warden/price_and_position.html", title="Ticker Price and Positions", current_app=current_app, current_user=fx_rate(), realtime_data=realtime_data, historical_data=historical_data, historical_meta=historical_meta, positions=df, ticker=ticker, fx=fx, price_chart=price_chart, price_chart_usd=price_chart_usd, position_chart=position_chart, GBTC_premium=GBTC_premium, GBTC_fairvalue=GBTC_fairvalue)
def warden_page(): # For now pass only static positions, will update prices and other # data through javascript after loaded. This improves load time # and refresh speed. # Get positions and prepare df for delivery df = positions() try: df = positions() except Exception as e: flash(f"Error getting transactions: {e}", "danger") return redirect(url_for("warden.newtrade")) if df.index.name != 'trade_asset_ticker': df.set_index('trade_asset_ticker', inplace=True) df = df[df['is_currency'] == 0].sort_index(ascending=True) df = df.to_dict(orient='index') # Create a custody DF transactions = transactions_fx() custody_df = transactions.groupby(["trade_account", "trade_asset_ticker" ])[["trade_quantity"]].sum() # Open Counter, increment, send data try: counter = pickle_it('load', 'counter.pkl') if counter == 'file not found': raise counter += 1 pickle_it('save', 'counter.pkl', counter) if counter == 25: flash( "Looks like you've been using the app frequently. " + "Consider donating to support it.", "info") if counter == 50: flash( "Open Source software is transparent and free. " + "Support it. Make a donation.", "info") if counter % 100: flash( "Looks like you are a frequent user of the WARden. " + "Consider a donation.", "info") except Exception: # File wasn't found. Create start at zero flash( "Welcome. Consider making a donation " + "to support this software.", "info") counter = 0 pickle_it('save', 'counter.pkl', counter) meta = warden_metadata() # Sort the wallets by balance sorted_wallet_list = [] try: for wallet in current_app.specter.wallet_alias_list(): wallet_df = meta['full_df'].loc[meta['full_df']['wallet_alias'] == wallet] if wallet_df.empty: balance = 0 else: balance = wallet_df['amount'].sum() sorted_wallet_list.append((wallet, balance)) sorted_wallet_list = sorted(sorted_wallet_list, reverse=True, key=itemgetter(1)) sorted_wallet_list = [i[0] for i in sorted_wallet_list] wallets_exist = True except Exception as e: logging.error(e) wallets_exist = False from api.routes import alert_activity if not current_app.downloading: activity = alert_activity() else: activity = False templateData = { "title": "Portfolio Dashboard", "warden_metadata": meta, "portfolio_data": df, "FX": current_app.settings['PORTFOLIO']['base_fx'], "alerts": activity, "current_app": current_app, "sorted_wallet_list": sorted_wallet_list, "wallets_exist": wallets_exist, "custody_df": custody_df } return (render_template('warden/warden.html', **templateData))
def heatmap_generator(): # If no Transactions for this user, return empty.html from warden_modules import transactions_fx, generatenav transactions = transactions_fx() if transactions.empty: return None, None, None, None # Generate NAV Table first data = generatenav() data["navpchange"] = (data["NAV_fx"] / data["NAV_fx"].shift(1)) - 1 returns = data["navpchange"] # Run the mrh function to generate heapmap table heatmap = mrh.get(returns, eoy=True) heatmap_stats = heatmap cols = [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "eoy", ] cols_months = [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", ] years = (heatmap.index.tolist()) heatmap_stats["MAX"] = heatmap_stats[heatmap_stats[cols_months] != 0].max( axis=1) heatmap_stats["MIN"] = heatmap_stats[heatmap_stats[cols_months] != 0].min( axis=1) heatmap_stats["POSITIVES"] = heatmap_stats[ heatmap_stats[cols_months] > 0].count(axis=1) heatmap_stats["NEGATIVES"] = heatmap_stats[ heatmap_stats[cols_months] < 0].count(axis=1) heatmap_stats["POS_MEAN"] = heatmap_stats[ heatmap_stats[cols_months] > 0].mean(axis=1) heatmap_stats["NEG_MEAN"] = heatmap_stats[ heatmap_stats[cols_months] < 0].mean(axis=1) heatmap_stats["MEAN"] = heatmap_stats[ heatmap_stats[cols_months] != 0].mean(axis=1) return (heatmap, heatmap_stats, years, cols)
def warden_page(): # For now pass only static positions, will update prices and other # data through javascript after loaded. This improves load time # and refresh speed. # Get positions and prepare df for delivery try: df = positions() except Exception: flash("Seems like transactions may be downloading... Check Specter Transactions for status.", "warning") return redirect(url_for("warden.newtrade")) if df.empty: flash("No Transactions Found. You can start by including a transaction below. You may also Connect to Specter or import a CSV file.", "info") return redirect(url_for("warden.newtrade")) if df.index.name != 'trade_asset_ticker': df.set_index('trade_asset_ticker', inplace=True) df = df[df['is_currency'] == 0].sort_index(ascending=True) df = df.to_dict(orient='index') # Create a custody DF transactions = transactions_fx() custody_df = transactions.groupby(["trade_account", "trade_asset_ticker" ])[["trade_quantity"]].sum() # Open Counter, increment, send data counter_file = os.path.join(home_path(), 'warden/counter.json') donated = False try: with open(counter_file) as data_file: json_all = json.loads(data_file.read()) if json_all == "donated": donated = True else: counter = int(json_all) counter += 1 if counter == 25: flash( "Looks like you've been using the app frequently. " + "Awesome! Consider donating.", "info") if counter == 50: flash( "Open Source software is transparent and free. " + "Support it. Make a donation.", "info") if counter == 200: flash( "Looks like you are a frequent user of the WARden. " + "Have you donated?", "info") if counter >= 1000: flash( "You've opened this page 1,000 times or more. " + "Really! Time to make a donation?", "danger") with open(counter_file, 'w') as fp: json.dump(counter, fp) except Exception: # File wasn't found. Create start at zero if not donated: flash( "Welcome. Consider making a donation " + "to support this software.", "info") counter = 0 with open(counter_file, 'w') as fp: json.dump(counter, fp) meta = warden_metadata() # Sort the wallets by balance sorted_wallet_list = [] try: for wallet in current_app.specter.wallet_alias_list(): wallet_df = meta['full_df'].loc[meta['full_df']['wallet_alias'] == wallet] if wallet_df.empty: balance = 0 else: balance = wallet_df['amount'].sum() sorted_wallet_list.append((wallet, balance)) sorted_wallet_list = sorted(sorted_wallet_list, reverse=True, key=itemgetter(1)) sorted_wallet_list = [i[0] for i in sorted_wallet_list] wallets_exist = True except Exception: wallets_exist = False from api.routes import alert_activity if not current_app.downloading: activity = alert_activity() else: activity = False templateData = { "title": "Portfolio Dashboard", "warden_metadata": meta, "portfolio_data": df, "FX": current_app.settings['PORTFOLIO']['base_fx'], "donated": donated, "alerts": activity, "current_app": current_app, "sorted_wallet_list": sorted_wallet_list, "wallets_exist": wallets_exist, "custody_df": custody_df } return (render_template('warden/warden.html', **templateData))