Example #1
0
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)
Example #2
0
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)
Example #3
0
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,
    )
Example #4
0
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)
Example #5
0
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))
Example #6
0
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)
Example #7
0
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))