import pandas as pd
import datetime as dt
import matplotlib.pyplot as plt
import TheoreticallyOptimalStrategy as tos
from util import get_data
from marketsim.marketsim import compute_portvals
from optimize_something.optimization import calculate_stats


def author():
    return "felixm"


def test_optimal_strategy():
    symbol = "JPM"
    start_value = 100000
    sd = dt.datetime(2008, 1, 1)
    ed = dt.datetime(2009, 12, 31)

    orders = tos.testPolicy(symbol=symbol, sd=sd, ed=ed, sv=start_value)
    portvals = compute_portvals(orders, start_value, 0, 0)

    start_date = portvals.index[0]
    end_date = portvals.index[-1]
    cum_ret, avg_daily_ret, \
        std_daily_ret, sharpe_ratio = calculate_stats(portvals, [1])

    d = {"Symbol": [symbol, symbol],
         "Order": ["BUY", "SELL"],
         "Shares": [1000, 1000]}
    orders = pd.DataFrame(data=d, index=[start_date, end_date])
    bench = compute_portvals(orders, start_value, 0, 0)
    cum_ret_bench, avg_daily_ret_bench, \
        std_daily_ret_bench, sharpe_ratio_bench = calculate_stats(bench, [1])

    # Compare portfolio against benchmark
    print(f"Date Range: {start_date} to {end_date}")
    print()
    print(f"Sharpe Ratio of Optimal Strategy: {sharpe_ratio}")
    print(f"Sharpe Ratio of bench: {sharpe_ratio_bench}")
    print()
    print(f"Cumulative Return of Optimal Strategy: {cum_ret}")
    print(f"Cumulative Return of bench: {cum_ret_bench}")
    print()
    print(f"Standard Deviation of Optimal Strategy: {std_daily_ret}")
    print(f"Standard Deviation of bench: {std_daily_ret_bench}")
    print()
    print(f"Average Daily Return of Optimal Strategy: {avg_daily_ret}")
    print(f"Average Daily Return of bench: {avg_daily_ret_bench}")
    print()
    print(f"Final Portfolio Value Optimal: {portvals.iloc[-1][0]}")
    print(f"Final Portfolio Value Bench: {bench.iloc[-1][0]}")

    portvals["Optimal"] = portvals["Portval"]
    portvals["Bench"] = bench["Portval"]
    portvals.drop(columns=["Portval"], inplace=True)

    portvals.plot(title="Optimal strategy versus 1000 shares of JPM")
    plt.savefig('figure_6.png')


def normalize(timeseries):
    return timeseries / timeseries.iloc[0]


def bollinger_band(df, symbol, period=20, m=2):
    boll_sma = df[symbol].rolling(period).mean()
    std = df[symbol].rolling(period).std()
    boll_up = boll_sma + m * std
    boll_lo = boll_sma - m * std
    df[f"{symbol}-Boll({period})-sma"] = boll_sma
    df[f"{symbol}-Boll({period})-up"] = boll_up
    df[f"{symbol}-Boll({period})-lo"] = boll_lo


def sma(df, symbol, period):
    """Adds a new column to the dataframe SMA(period)"""
    df[f"{symbol}-sma({period})"] = df[symbol].rolling(period).mean()


def ema(df, symbol, period):
    """Adds a new column to the dataframe EMA(period)"""
    df[f"{symbol}-ema({period})"] = df[symbol].ewm(span=period).mean()


def price_sma(df, symbol, period):
    """Calculates SMA and adds new column price divided by SMA to the df."""
    sma = df[symbol].rolling(period).mean()
    df[f"{symbol}-price/sma({period})"] = df[symbol] / sma


def rsi(df, symbol, period=14):
    """Calculates relative strength index over given period."""

    def rsi(x):
        pct = x.pct_change()
        avg_gain = pct[pct > 0].mean()
        avg_loss = pct[pct <= 0].abs().mean()
        rsi = 100 - (100 /
                     (1 + ((avg_gain / period) /
                           (avg_loss / period))))
        return rsi

    key = f"{symbol}-rsi({period})"
    # Add one to get 'period' price changes (first change is nan).
    period += 1
    df[key] = df[symbol].rolling(period).apply(rsi)


def macd(df, symbol):
    macd = df[symbol].ewm(span=12).mean() - df[symbol].ewm(span=26).mean()
    df[f"{symbol}-macd"] = macd
    df[f"{symbol}-macd-signal"] = macd.rolling(9).mean()


def price_delta(df, symbol, period=1):
    """Calculate delta between previous day and today."""
    df[f"{symbol}-diff({period})"] = df[symbol].diff(periods=period)


def test_indicators():
    symbol = "JPM"

    sd = dt.datetime(2008, 1, 1)
    ed = dt.datetime(2009, 12, 31)
    df = get_data([symbol], pd.date_range(sd, ed))
    df.drop(columns=["SPY"], inplace=True)
    df_orig = df.copy()
    # df = normalize(df)

    sma(df, symbol, 21)
    ema(df, symbol, 21)
    df.plot(title="21 SMA and EMA")
    plt.savefig('figure_1.png')

    df = df_orig.copy()
    sma(df, symbol, 8)
    price_sma(df, symbol, 8)
    df.plot(title="SMA and price / SMA", subplots=True)
    plt.savefig('figure_2.png')

    df = df_orig.copy()
    bollinger_band(df, symbol)
    df.plot(title="Bollinger Band")
    plt.savefig('figure_3.png')

    df = df_orig.copy()
    rsi(df, symbol)
    fig, axes = plt.subplots(nrows=2, sharex=True)
    df[symbol].plot(ax=axes[0], title="JPM price action")
    df["JPM-rsi(14)"].plot(ax=axes[1], title="RSI")
    plt.savefig('figure_4.png')

    df = df_orig.copy()
    macd(df, symbol)
    fig, axes = plt.subplots(nrows=2, sharex=True)
    df[symbol].plot(ax=axes[0], title="JPM price action")
    df[["JPM-macd", "JPM-macd-signal"]].plot(ax=axes[1])
    plt.savefig('figure_5.png')


def main():
    test_optimal_strategy()
    test_indicators()


if __name__ == "__main__":
    main()
