예제 #1
0
def transactions_fx():
    # Gets the transaction table and fills with fx information
    # Note that it uses the currency exchange for the date of transaction
    # Get all transactions from Specter and format

    # SPECTER ============================================
    df = specter_df()
    if not df.empty:
        df['trade_date'] = pd.to_datetime(df['trade_date'])
        df = df.set_index('trade_date')
        # Ignore times in df to merge - keep only dates
        df.index = df.index.floor('d')
        df.index.rename('date', inplace=True)

    # SQL DATABASE ========================================
    # Get all transactions from db and format
    df_sql = pd.read_sql_table('trades', current_app.db.engine)
    if not df_sql.empty:
        df_sql = df_sql[(df_sql.user_id == current_user.username)]
        # df = df[(df.trade_operation == "B") | (df.trade_operation == "S")]
        df_sql['trade_date'] = pd.to_datetime(df_sql['trade_date'])
        df_sql = df_sql.set_index('trade_date')
        # Ignore times in df to merge - keep only dates
        df_sql.index = df_sql.index.floor('d')
        df_sql.index.rename('date', inplace=True)

    # Merge both
    df = df.append(df_sql, sort=False)

    if df.empty:
        logging.warning("Transactions_FX - No txs found")
        return df

    # The current fx needs no conversion, set to 1
    df[fx_rate()['fx_rate']] = 1

    # Need to get currencies into the df in order to normalize
    # let's load a list of currencies needed and merge
    list_of_fx = df.trade_currency.unique().tolist()
    # loop through currency list
    for currency in list_of_fx:
        if currency == fx_rate()['fx_rate']:
            continue
        # Make a price request
        df[currency] = df.apply(find_fx, axis=1)
    # Now create a cash value in the preferred currency terms
    df['fx'] = df.apply(lambda x: x[x['trade_currency']], axis=1)
    df['cash_value_fx'] = df['cash_value'].astype(float) / df['fx'].astype(
        float)
    df['trade_fees_fx'] = df['trade_fees'].astype(float) / df['fx'].astype(
        float)
    df['trade_price_fx'] = df['trade_price'].astype(float) / df['fx'].astype(
        float)

    if 'trade_date' not in df.columns:
        df['trade_date'] = pd.to_datetime(df.index)

    return (df)
예제 #2
0
def navchart():
    data = generatenav()
    navchart = data[["NAV_fx"]].copy()
    # dates need to be in Epoch time for Highcharts
    navchart.index = (navchart.index - datetime(1970, 1, 1)).total_seconds()
    navchart.index = navchart.index * 1000
    navchart.index = navchart.index.astype(np.int64)
    navchart = navchart.to_dict()
    navchart = navchart["NAV_fx"]

    port_value_chart = data[[
        "PORT_cash_value_fx", "PORT_fx_pos", "PORT_ac_CFs_fx"
    ]].copy()
    port_value_chart["ac_pnl_fx"] = (port_value_chart["PORT_fx_pos"] -
                                     port_value_chart["PORT_ac_CFs_fx"])
    # dates need to be in Epoch time for Highcharts
    port_value_chart.index = (port_value_chart.index -
                              datetime(1970, 1, 1)).total_seconds()
    port_value_chart.index = port_value_chart.index * 1000
    port_value_chart.index = port_value_chart.index.astype(np.int64)
    port_value_chart = port_value_chart.to_dict()

    return render_template("warden/warden_navchart.html",
                           title="NAV Historical Chart",
                           navchart=navchart,
                           port_value_chart=port_value_chart,
                           fx=current_app.settings['PORTFOLIO']['base_fx'],
                           current_user=fx_rate(),
                           data=data,
                           current_app=current_app)
예제 #3
0
def config_ini():
    from config import Config
    config_file = Config.config_file
    if not os.path.isfile(config_file):
        flash('Config File not Found. Restart the app.', 'danger')
        config_contents = None
    else:
        f = open(config_file, 'r')
        config_contents = f.read()

    if request.method == 'POST':
        config_txt = request.form.get('config_txt')
        f = open(config_file, "w")
        f.write(config_txt)
        f.close()
        flash("Config File Saved", "success")
        config_contents = config_txt

    return render_template('warden/config_ini.html',
                           title="Custom Configurations",
                           current_app=current_app,
                           current_user=fx_rate(),
                           config_file=config_file,
                           config_contents=config_contents
                           )
예제 #4
0
def show_broadcast():
    category = request.args.get("category")
    return render_template('warden/show_broadcast.html',
                           title="Message Broadcaster",
                           current_app=current_app,
                           current_user=fx_rate(),
                           category=category,
                           )
예제 #5
0
def trade_transactions():
    transactions = Trades.query.filter_by(user_id=current_user.username)

    if transactions.count() == 0:
        form = TradeForm()
        form.trade_currency.data = current_app.fx['code']
        form.trade_date.data = datetime.utcnow()
        return render_template("warden/empty_txs.html",
                               title="Empty Transaction List",
                               current_app=current_app,
                               current_user=fx_rate(),
                               form=form)

    return render_template("warden/trade_transactions.html",
                           title="Transaction History",
                           transactions=transactions,
                           current_app=current_app,
                           current_user=fx_rate())
예제 #6
0
def heatmap():
    heatmap_gen, heatmap_stats, years, cols = heatmap_generator()

    return render_template("warden/heatmap.html",
                           title="Monthly Returns HeatMap",
                           heatmap=heatmap_gen,
                           heatmap_stats=heatmap_stats,
                           years=years,
                           cols=cols,
                           current_app=current_app,
                           current_user=fx_rate())
예제 #7
0
def realtime_btc():
    try:
        fx_details = fx_rate()
        fx_r = {
            'cross': fx_details['symbol'],
            'fx_rate': fx_details['fx_rate']
        }
        fx_r['btc_usd'] = realtime_price("BTC", fx='USD')['price']
        fx_r['btc_fx'] = fx_r['btc_usd'] * fx_r['fx_rate']
    except Exception as e:
        logging.warn(
            f"There was an error while getting realtime prices. Error: {e}")
        fx_r = 0
    return json.dumps(fx_r)
예제 #8
0
def positions_json():
    # Get all transactions and cost details
    # This serves the main page
    try:
        dfdyn, piedata = positions_dynamic()
        btc_price = realtime_price("BTC")['price'] * fx_rate()['fx_rate']
        dfdyn = dfdyn.to_dict(orient='index')
    except Exception:
        dfdyn = piedata = None
        btc_price = 0
    try:
        btc = realtime_price("BTC")['price']
    except TypeError:
        btc = 0
    if not btc:
        btc = 0

    json_dict = {
        'positions': dfdyn,
        'piechart': piedata,
        'user': current_app.fx,
        'btc': btc_price
    }
    return simplejson.dumps(json_dict, ignore_nan=True)
예제 #9
0
def delalltrades():

    transactions = Trades.query.filter_by(
        user_id=current_user.username).order_by(Trades.trade_date)

    if transactions.count() == 0:
        form = TradeForm()
        form.trade_currency.data = current_app.fx['code']
        form.trade_date.data = datetime.utcnow()
        return render_template("warden/empty_txs.html",
                               title="Empty Transaction List",
                               current_app=current_app,
                               current_user=fx_rate(),
                               form=form)

    if request.method == "GET":
        Trades.query.filter_by(user_id=current_user.username).delete()
        current_app.db.session.commit()
        regenerate_nav()
        flash("ALL TRANSACTIONS WERE DELETED", "danger")
        return redirect(url_for("warden.warden_page"))

    else:
        return redirect(url_for("warden.warden_page"))
예제 #10
0
def allocation_history():
    return render_template("warden/allocation_history.html",
                           title="Portfolio Historical Allocation",
                           current_app=current_app,
                           current_user=fx_rate())
예제 #11
0
def drawdown():
    return render_template("warden/drawdown.html",
                           title="Drawdown Analysis",
                           current_app=current_app,
                           current_user=fx_rate())
예제 #12
0
def running_services():
    return render_template("warden/running_services.html",
                           title="Running Services and Status",
                           current_app=current_app,
                           current_user=fx_rate())
예제 #13
0
def edittransaction():
    form = TradeForm()
    reference_id = request.args.get("reference_id")
    id = request.args.get("id")
    if reference_id:
        trade = Trades.query.filter_by(
            user_id=current_user.username).filter_by(
                trade_reference_id=reference_id).first()
        if trade.count() == 0:
            abort(404, "Transaction not found")
        id = trade.id

    trade = Trades.query.filter_by(user_id=current_user.username).filter_by(
        id=id).first()

    if trade is None:
        abort(404)

    if trade.user_id != current_user.username:
        abort(403)

    acclist = AccountInfo.query.filter_by(user_id=current_user.username)
    accounts = []
    for item in acclist:
        accounts.append((item.account_longname, item.account_longname))
    form.trade_account.choices = accounts
    form.submit.label.text = 'Edit Trade'

    if request.method == "POST":

        if form.validate_on_submit():
            # Write changes to database
            if form.trade_operation.data in ("B", "D"):
                qop = 1
            elif form.trade_operation.data in ("S", "W"):
                qop = -1
            else:
                qop = 0

            # Calculate Trade's cash value
            cvfail = False

            try:
                p = float(clean_float(form.trade_price.data))
                q = float(clean_float(form.trade_quantity.data))
                f = float(clean_float(form.trade_fees.data))
                cv = qop * (q * p) + f

            except ValueError:
                flash(
                    "Error on calculating cash amount \
                for transaction - TRADE NOT edited. Try Again.",
                    "danger",
                )
                cvfail = True
                cv = 0

            trade.trade_date = form.trade_date.data
            trade.trade_asset_ticker = form.trade_asset_ticker.data
            trade.trade_currency = form.trade_currency.data
            trade.trade_operation = form.trade_operation.data
            trade.trade_quantity = float(form.trade_quantity.data) * qop
            trade.trade_price = float(clean_float(form.trade_price.data))
            trade.trade_fees = float(clean_float(form.trade_fees.data))
            trade.trade_account = form.trade_account.data
            trade.trade_notes = form.trade_notes.data
            trade.cash_value = cv

            if not cvfail:
                current_app.db.session.commit()
                regenerate_nav()
                flash("Trade edit successful", "success")

            return redirect(url_for("warden.warden_page"))

        flash("Trade edit failed. Something went wrong. Try Again.", "danger")

    # Pre-populate the form
    form.trade_date.data = trade.trade_date
    form.trade_currency.data = trade.trade_currency
    form.trade_asset_ticker.data = trade.trade_asset_ticker
    form.trade_operation.data = trade.trade_operation
    form.trade_quantity.data = abs(float(trade.trade_quantity))
    form.trade_price.data = trade.trade_price
    form.trade_fees.data = trade.trade_fees
    form.trade_account.data = trade.trade_account
    form.trade_notes.data = trade.trade_notes

    return render_template("warden/edittransaction.html",
                           title="Edit Transaction",
                           form=form,
                           trade=trade,
                           id=id,
                           current_app=current_app,
                           current_user=fx_rate())
예제 #14
0
def volchart():
    return render_template("warden/volchart.html",
                           title="Historical Volatility Chart",
                           current_app=current_app,
                           current_user=fx_rate())
예제 #15
0
def newtrade():
    form = TradeForm()
    acclist = AccountInfo.query.filter_by(user_id=current_user.username)
    accounts = []
    for item in acclist:
        accounts.append((item.account_longname, item.account_longname))
    form.trade_account.choices = accounts

    if request.method == "POST":

        if form.validate_on_submit():
            # Need to include two sides of trade:
            if form.trade_operation.data in ("B"):
                qop = 1
            elif form.trade_operation.data in ("S"):
                qop = -1
            else:
                qop = 0
                flash(
                    "Trade Operation Error. Should be B for buy or S for sell.",
                    "warning")

            # Calculate Trade's cash value
            cvfail = False

            try:
                p = float(clean_float(form.trade_price.data))
                q = float(clean_float(form.trade_quantity.data))
                f = float(clean_float(form.trade_fees.data))
                cv = qop * (q * p) + f

            except ValueError:
                flash(
                    "Error on calculating fiat amount \
                for transaction - TRADE NOT included",
                    "danger",
                )
                cvfail = True
                cv = 0

            # Check what type of trade this is
            # Cash and/or Asset

            try:
                tquantity = float(form.trade_quantity.data) * qop
            except ValueError:
                tquantity = 0

            try:
                tprice = float(form.trade_price.data)
            except ValueError:
                tprice = 0

            trade = Trades(
                user_id=current_user.username,
                trade_date=form.trade_date.data,
                trade_account=form.trade_account.data,
                trade_currency=form.trade_currency.data,
                trade_asset_ticker=form.trade_asset_ticker.data,
                trade_quantity=tquantity,
                trade_operation=form.trade_operation.data,
                trade_price=tprice,
                trade_fees=form.trade_fees.data,
                trade_notes=form.trade_notes.data,
                cash_value=cv,
            )
            if not cvfail:
                current_app.db.session.add(trade)
                current_app.db.session.commit()
                regenerate_nav()
                flash("Trade included", "success")

            return redirect(url_for("warden.warden_page"))
        else:
            flash("Trade Input failed. Something went wrong. Try Again.",
                  "danger")

    form.trade_currency.data = current_app.fx['code']
    form.trade_date.data = datetime.utcnow()
    return render_template("warden/newtrade.html",
                           form=form,
                           title="New Trade",
                           current_app=current_app,
                           current_user=fx_rate())
예제 #16
0
def transactions_fx():
    # Gets the transaction table and fills with fx information
    # Note that it uses the currency exchange for the date of transaction
    # Get all transactions from Specter and format

    # SPECTER ============================================
    df = specter_df()
    if not df.empty:
        df['trade_date'] = pd.to_datetime(df['trade_date'])
        df = df.set_index('trade_date')
        # Ignore times in df to merge - keep only dates
        df.index = df.index.floor('d')
        df.index.rename('date', inplace=True)

    # SQL DATABASE ========================================
    # Get all transactions from db and format
    df_sql = pd.read_sql_table('trades', current_app.db.engine)
    if not df_sql.empty:
        df_sql = df_sql[(df_sql.user_id == current_user.username)]
        # df = df[(df.trade_operation == "B") | (df.trade_operation == "S")]
        df_sql['trade_date'] = pd.to_datetime(df_sql['trade_date'])
        df_sql = df_sql.set_index('trade_date')
        # Ignore times in df to merge - keep only dates
        df_sql.index = df_sql.index.floor('d')
        df_sql.index.rename('date', inplace=True)

    # Merge both
    df = df.append(df_sql, sort=False)

    if df.empty:
        flash(f"No Transactions Found. Running Demo Portfolio.", "info")
        logging.warning(
            "Transactions_FX - No txs found - using Demo Portfolio")
        sample_trade = {
            'user_id': current_user.username,
            'trade_date': datetime(2018, 1, 1),
            'trade_currency': 'USD',
            'trade_fees': 0,
            'trade_fees_fx': 0,
            'trade_quantity': 0.1,
            'trade_multiplier': 1,
            'trade_price': 14920,
            'trade_asset_ticker': 'BTC',
            'trade_operation': 'B',
            'status': 'Demo Line',
            'trade_account': 'Demo Account',
            'cash_value': 1492,
            'cash_value_fx': 1492,
        }
        df = df.append(sample_trade, ignore_index=True)
        df = df.set_index('trade_date')

        return df

    # The current fx needs no conversion, set to 1
    df[fx_rate()['fx_rate']] = 1

    # Need to get currencies into the df in order to normalize
    # let's load a list of currencies needed and merge
    list_of_fx = df.trade_currency.unique().tolist()
    # loop through currency list
    for currency in list_of_fx:
        if currency == fx_rate()['fx_rate']:
            continue
        # Make a price request
        df[currency] = df.apply(find_fx, axis=1)
    # Now create a cash value in the preferred currency terms
    df['fx'] = df.apply(lambda x: x[x['trade_currency']], axis=1)
    df['cash_value_fx'] = df['cash_value'].astype(float) / df['fx'].astype(
        float)
    df['trade_fees_fx'] = df['trade_fees'].astype(float) / df['fx'].astype(
        float)
    df['trade_price_fx'] = df['trade_price'].astype(float) / df['fx'].astype(
        float)

    if 'trade_date' not in df.columns:
        df['trade_date'] = pd.to_datetime(df.index)

    return (df)
예제 #17
0
def portfolio_compare():
    return render_template("warden/portfolio_compare.html",
                           title="Portfolio Comparison",
                           current_app=current_app,
                           current_user=fx_rate())
예제 #18
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)
예제 #19
0
def portstats():
    meta = {}
    # Looking to generate the following data here and return as JSON
    # for AJAX query on front page:
    # Start date, End Date, Start NAV, End NAV, Returns (1d, 1wk, 1mo, 1yr,
    # YTD), average daily return. Best day, worse day. Std dev of daily ret,
    # Higher NAV, Lower NAV + dates. Higher Port Value (date).
    data = generatenav()
    meta["start_date"] = (data.index.min()).date().strftime("%B %d, %Y")
    meta["end_date"] = data.index.max().date().strftime("%B %d, %Y")
    meta["start_nav"] = data["NAV_fx"][0]
    meta["end_nav"] = float(data["NAV_fx"][-1])
    meta["max_nav"] = float(data["NAV_fx"].max())
    meta["max_nav_date"] = data[
        data["NAV_fx"] == data["NAV_fx"].max()].index.strftime("%B %d, %Y")[0]
    meta["min_nav"] = float(data["NAV_fx"].min())
    meta["min_nav_date"] = data[
        data["NAV_fx"] == data["NAV_fx"].min()].index.strftime("%B %d, %Y")[0]
    meta["end_portvalue"] = data["PORT_fx_pos"][-1].astype(float)
    meta["end_portvalue_usd"] = meta["end_portvalue"] / fx_rate()['fx_rate']
    meta["max_portvalue"] = data["PORT_fx_pos"].astype(float).max()
    meta["max_port_date"] = data[data["PORT_fx_pos"] == data["PORT_fx_pos"].
                                 max()].index.strftime("%B %d, %Y")[0]
    meta["min_portvalue"] = round(data["PORT_fx_pos"].min(), 0)
    meta["min_port_date"] = data[data["PORT_fx_pos"] == data["PORT_fx_pos"].
                                 min()].index.strftime("%B %d, %Y")[0]
    meta["return_SI"] = (meta["end_nav"] / meta["start_nav"]) - 1
    # Temporary fix for an issue with portfolios that are just too new
    # Create a function to handle this
    try:
        meta["return_1d"] = (meta["end_nav"] / data["NAV_fx"][-2]) - 1
    except IndexError:
        meta["return_1d"] = "-"

    try:
        meta["return_1wk"] = (meta["end_nav"] / data["NAV_fx"][-7]) - 1
    except IndexError:
        meta["return_1wk"] = "-"

    try:
        meta["return_30d"] = (meta["end_nav"] / data["NAV_fx"][-30]) - 1
    except IndexError:
        meta["return_30d"] = "-"

    try:
        meta["return_90d"] = (meta["end_nav"] / data["NAV_fx"][-90]) - 1
    except IndexError:
        meta["return_90d"] = "-"

    try:
        meta["return_ATH"] = (meta["end_nav"] / meta["max_nav"]) - 1
    except IndexError:
        meta["return_ATH"] = "-"

    try:
        yr_ago = pd.to_datetime(datetime.today() - relativedelta(years=1))
        yr_ago_NAV = data.NAV_fx[data.index.get_loc(yr_ago, method="nearest")]
        meta["return_1yr"] = meta["end_nav"] / yr_ago_NAV - 1
    except IndexError:
        meta["return_1yr"] = "-"

    # Create data for summa"age
    meta["fx"] = current_app.settings['PORTFOLIO']['base_fx']
    meta["daily"] = {}
    for days in range(1, 8):
        meta["daily"][days] = {}
        meta["daily"][days]["date"] = data.index[days * -1].date().strftime(
            "%A <br> %m/%d")
        meta["daily"][days]["nav"] = data["NAV_fx"][days * -1]
        meta["daily"][days]["nav_prev"] = data["NAV_fx"][(days + 1) * -1]
        meta["daily"][days]["perc_chg"] = (meta["daily"][days]["nav"] /
                                           meta["daily"][days]["nav_prev"]) - 1
        meta["daily"][days]["port"] = data["PORT_fx_pos"][days * -1]
        meta["daily"][days]["port_prev"] = data["PORT_fx_pos"][(days + 1) * -1]
        meta["daily"][days]["port_chg"] = (meta["daily"][days]["port"] -
                                           meta["daily"][days]["port_prev"])

    # Removes Numpy type from json - returns int instead
    def convert(o):
        if isinstance(o, np.int64):
            return int(o)
        else:
            return (o)

    # create chart data for a small NAV chart
    return simplejson.dumps(meta, ignore_nan=True, default=convert)
예제 #20
0
def show_log():
    return render_template('warden/show_log.html',
                           title="Debug Viewer",
                           current_app=current_app,
                           current_user=fx_rate())