import os
import sys
from pprint import pprint
from altair.vegalite.v4.schema.core import UtcSingleTimeUnit
import ccxt
#import ccxt.async_support as ccxt
from pyti.exponential_moving_average import exponential_moving_average as ema
import pandas as pd
import datetime
import time
import numpy as np
import matplotlib
from matplotlib import pyplot as plt
from IPython.display import clear_output
import numpy as np
import datetime as dt
import pytz
# import mplcursors

import streamlit as st
# from compute2d import compute_2d_histogram
import numpy as np
import pandas as pd
import altair as at
from copy import copy
import plotly.graph_objects as go
# from paracoords import create_paracoords
from mpl_toolkits.mplot3d import axes3d
from matplotlib import cm
import plotly
import plotly.graph_objs as go



import warnings
warnings.filterwarnings('ignore')


# root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
# sys.path.append(root + '/python')

# print('CCXT Version:', ccxt.__version__)

def get_last_n_kline_closes(n=50,interval='1h',symbol='BTCUSDT',exchange=None):

    if exchange is None:
        print('Exchange not initiated')
        return None
    
    # exchange = ccxt.binance({
    #     'apiKey': g_api_key,
    #     'secret': g_secret_key,
    #     'enableRateLimit': True,  
    #     'options': {
    #         'defaultType': 'future',
    #     },
    #     'hedgeMode':True
    # })
    # # symbol = 'BTC/USDT'

    # market = exchange.load_markets()
    
    closes = [[dt.datetime.utcfromtimestamp(float(elem[0]) / 1000.),elem[4]] for elem in exchange.fapiPublic_get_klines({'symbol':symbol,'interval':interval})][-n:-1]
    dates = [elem[0] for elem in closes]
    values = [float(elem[1]) for elem in closes]
    df = pd.DataFrame([(elem[0],elem[1]) for elem in zip(dates,values)],columns=['datetime','closes'])

    return df

def generate_signal(candles=50,interval='1h',symbol='BTCUSDT',strat='ema_cross_over_under',strat_params={'fast_ema':10,'slow_ema':40},exchange=None):

    if exchange is None:
        return 'Exchange not Initiated'

    allowed_strats = ['ema_diff_peak_trough','ema_cross_over_under','ema_oscillator_peak_trough']

    if strat not in allowed_strats:
        print('INVALID STRATEGY')
        return "NONE"

    if strat == 'ema_oscillator_peak_trough':

        '''under development'''
        return "NONE"

   
    if strat == 'ema_diff_peak_trough':
        candles = strat_params['slow_ema'] + 10

        current_input=get_last_n_kline_closes(symbol=symbol,n=candles,interval=interval,exchange=exchange)

        min_input_length =   np.max([float(strat_params['fast_ema']),float(strat_params['slow_ema'])])

        if len(list(current_input['closes'].values))<min_input_length:
            return "INPUT HAS TOO FEW ELEMENTS"
        
        closes = current_input['closes'].astype(float)
        # closes = closes[:-1]
        # closes['close'] = closes['close'].astype(float)
    
        ema_diff = pd.DataFrame(ema(closes.tolist(),strat_params['fast_ema']) - ema(closes.tolist(),strat_params['slow_ema']),columns=['ema_diff'])
        p = strat_params['slow_ema']+1
        closes = closes[p:].reset_index(drop=True)
        ema_diff = ema_diff[p:].reset_index(drop=True)

        last = ema_diff.values[-1]
        second_last = ema_diff.values[-2]
        third_last = ema_diff.values[-3]

        # short if local peak
        if last < second_last and third_last < second_last:
            return 'SHORT'
        # long if local trough 
        if last > second_last and third_last > second_last:
            return 'LONG'
        return "NONE"
     

    if strat == 'ema_cross_over_under':
        candles = strat_params['slow_ema'] + 10


        current_input=get_last_n_kline_closes(symbol=symbol,n=candles,interval=interval,exchange=exchange)

        min_input_length =   np.max([float(strat_params['fast_ema']),float(strat_params['slow_ema'])])

        if len(list(current_input['closes'].values))<min_input_length:
            return "INPUT HAS TOO FEW ELEMENTS"
        
        closes = current_input['closes'].astype(float)
        # closes = closes[:-1]
        # closes['close'] = closes['close'].astype(float)
    
        ema_diff = pd.DataFrame(ema(closes.tolist(),strat_params['fast_ema']) - ema(closes.tolist(),strat_params['slow_ema']),columns=['ema_diff'])
        p = strat_params['slow_ema']+1
        closes = closes[p:].reset_index(drop=True)
        ema_diff = ema_diff[p:].reset_index(drop=True)

        last = ema_diff.values[-1]
        second_last = ema_diff.values[-2]
        third_last = ema_diff.values[-3]

        # long if diff cross over 0    
        if last > 0 and second_last < 0:
            return "LONG"
        # short if diff cross under 0
        if last < 0 and second_last > 0:
            return "SHORT"
        return "NONE"


def get_open_positions(mode='live',exchange=None):

    if exchange is None:
        return 'Exchange Not Initiated'

    allowed_modes = ['live','paper']

    if mode not in allowed_modes:
        return "INVALID MODE"

    if mode == 'live':
            
        # exchange = ccxt.binance({
        #     'apiKey': g_api_key,
        #     'secret': g_secret_key,
        #     'enableRateLimit': True,
        #     'options': {
        #         'defaultType': 'future',
        #     },
        #     'hedgeMode':True
        # })

        # markets = exchange.load_markets()
        #exchange.verbose=True
        # market = exchange.market(symbol)

        positions = [elem for elem in exchange.fapiPrivate_get_positionrisk() if float(elem['positionAmt'])!=0]

        if len(positions)==0:
            return 0
        return positions

    if mode == 'paper':
        paper_trades = pd.read_csv('paper_trades.csv',index_col=0)
        if paper_trades.position_type.iloc[-1] == '-':
            return 0
        return paper_trades.iloc[-1]
        

def get_balance(mode='live',asset='USDT',exchange=None):

    if exchange is None:
        return 'Exchange not initiated'

    allowed_modes = ['paper','live']

    if mode not in allowed_modes:
        print("INVALID MODE")
        return None
            
    # exchange = ccxt.binance({
    #         'apiKey': g_api_key,
    #         'secret': g_secret_key,
    #         'enableRateLimit': True, 
    #         'options': {
    #             'defaultType': 'future',
    #         },
    #         'hedgeMode':True
    #     })
    # markets = exchange.load_markets()


    if mode == 'live':
        live_balance = str(float([float(elem['balance']) for elem in exchange.fapiPrivate_get_balance() if elem['asset']==asset][0]))
        unrealized_pnl = str(sum([float(elem['unRealizedProfit']) for elem in exchange.fapiPrivateV2_get_positionrisk() if float(elem['positionAmt']) >0]))
        unrealized_pnl_percent = str(float(unrealized_pnl)/float(live_balance))

        balance = {'wallet_balance': live_balance,
                    'unrealized_pnl_percent': unrealized_pnl_percent}
                    
        return balance

    if mode == 'paper':
        
        paper_trades = pd.read_csv('paper_trades.csv',index_col=0)

        if paper_trades.paper_equity.iloc[-1] == '-':
            paper_balance = paper_trades.paper_equity.iloc[-2]
        else:
            paper_balance = paper_trades.paper_equity.iloc[-1]

        if paper_trades.entry_price.iloc[-1] == '-':
            entry = None
        else:
            entry = paper_trades.entry_price.iloc[-1]

        if paper_trades.position_type.iloc[-1] == 'LONG':
            position = 1
        if paper_trades.position_type.iloc[-1] == 'SHORT':
            position = -1
        else:
            position = 0

        if entry is not None and position != 0:

            if paper_trades.exit_price.iloc[-1] == '-':
                
                symbol = paper_trades.market_name.iloc[-1]
                
                last_price = float(exchange.fapiPublic_get_ticker_price({'symbol':symbol})['price'])

                pnl = (last_price-float(entry))/float(entry)*100*float(position)

            else:
                pnl = 0

        else:
            pnl = 0

        balance = {'wallet_balance':paper_balance,'unrealized_pnl_percent':pnl}

        return balance    
        

def close_all_open_positions(mode='live',exchange=None):

    if exchange is None:
        return 'Exchange not Initiated'

    allowed_modes = ['paper','live']
    if mode not in allowed_modes:
        return "INVALID MODE"

    if mode == 'live':
            
        # exchange = ccxt.binance({
        #         'apiKey': g_api_key,
        #         'secret': g_secret_key,
        #         'enableRateLimit': True,
        #         'options': {
        #             'defaultType': 'future',
        #         },
        #         'hedgeMode':True
        #     })

        # markets = exchange.load_markets()
        #exchange.verbose=True
        # market = exchange.market(symbol)

        open_positions = get_open_positions(mode=mode,exchange=exchange)
        if open_positions == 0:
            return None
        
        if np.sign(float(open_positions[0]['positionAmt'])) == -1.0:
            opp_side = "BUY"
        if np.sign(float(open_positions[0]['positionAmt'])) == 1.0:
            opp_side = "SELL" 
        baseqty= abs(float(open_positions[0]['positionAmt']))
        symbol = open_positions[0]['symbol']
        positionSide = open_positions[0]['positionSide']
        order = exchange.fapiPrivatePostOrder({'symbol':symbol, 'type':"MARKET", 'side':opp_side,'positionSide':positionSide ,'quantity':baseqty})

        return order

    if mode == 'paper':
        paper_trades = pd.read_csv('paper_trades.csv',index_col=0)
        if paper_trades.position_type.iloc[-1] == '-':
            return None
    
        if paper_trades.exit_price.iloc[-1] != '-':
            return None
        # exchange = ccxt.binance({
        #     'apiKey': g_api_key,
        #     'secret': g_secret_key,
        #     'enableRateLimit': True, 
        #     'options': {
        #         'defaultType': 'future',
        #     },
        #     'hedgeMode':True
        # })
        # markets = exchange.load_markets()
        
        symbol = paper_trades.market_name.iloc[-1]
        entry_price = paper_trades.entry_price.iloc[-1]
        leverage= paper_trades.leverage.iloc[-1]
        leverage = int(leverage)

        if paper_trades.position_type.iloc[-1] == 'LONG':
            position = 1
            exit_price = 0.999*float(exchange.fapiPublic_get_ticker_price({'symbol':symbol})['price'])
            exit_time = datetime.datetime.utcnow()
    

        if paper_trades.position_type.iloc[-1] == 'SHORT':
            position = -1
            exit_price = 1.001*float(exchange.fapiPublic_get_ticker_price({'symbol':symbol})['price'])
            exit_time = datetime.datetime.utcnow()

        
        trade_pnl_pct = float(position)*float(leverage)*(float(exit_price)-float(entry_price))/float(entry_price)*100
        balance = float(paper_trades.paper_equity.iloc[-2])*(1+trade_pnl_pct/100)

        paper_trades.exit_time.iloc[-1] = exit_time
        paper_trades.exit_price.iloc[-1] = exit_price
        paper_trades.trade_pnl_pct.iloc[-1] = trade_pnl_pct
        paper_trades.paper_equity.iloc[-1] = balance

        paper_trades.to_csv('paper_trades.csv')

        trade = paper_trades.iloc[-1]

        return trade
        
def open_market_order(mode='live',balance=1,symbol='BTCUSDT',leverage="5",side="BUY",hedge_mode="BOTH",exchange=None):

    if exchange is None:
        return 'Exchange not initiated'

    allowed_modes = ['paper','live']

    if mode not in allowed_modes:
        return "INVALID MODE"

    if mode == 'live':

        closed_position =  close_all_open_positions(mode=mode,exchange=exchange)

        quoteqty = float([elem for elem in exchange.fapiPrivate_get_balance({'asset':"USDT"}) if elem['asset']=='USDT'][0]['balance']) * balance
        price = float(exchange.fapiPublic_get_ticker_price({'symbol':symbol})['price'])
        baseqty = "{:.3f}".format(quoteqty*float(leverage)/price)
        baseqty = float(baseqty)-float([elem for elem in exchange.fapiPublic_get_exchangeinfo()['symbols'] if elem['symbol']==symbol][0]['filters'][2]['minQty'])
        baseqty = "{:.3f}".format(baseqty)
        baseqty = str(baseqty)
        lev_req = exchange.fapiPrivate_post_leverage({'symbol':symbol,'leverage':leverage})
        order = exchange.fapiPrivatePostOrder({'symbol':symbol, 'type':"MARKET", 'side':side,'positionSide':hedge_mode ,'quantity':baseqty})

        return order,closed_position
    
    if mode == 'paper':
        closed_position = close_all_open_positions(mode=mode,exchange=exchange)

        
        paper_trades = pd.read_csv('paper_trades.csv',index_col=0)

        
        if side == 'BUY':
            position_type = 'LONG'
            entry_price = 1.001*float(exchange.fapiPublic_get_ticker_price({'symbol':symbol})['price'])
            entry_time = datetime.datetime.utcnow()
        if side == 'SELL':
            position_type = 'SHORT'
            entry_price = 0.999*float(exchange.fapiPublic_get_ticker_price({'symbol':symbol})['price'])
            entry_time = datetime.datetime.utcnow()

        trade = pd.DataFrame([[symbol,position_type,entry_time,'-', entry_price,'-',leverage,'-','-']],columns=['market_name','position_type','entry_time','exit_time','entry_price','exit_price','leverage','trade_pnl_pct','paper_equity'])
        paper_trades = paper_trades.append(trade,ignore_index=True)

        paper_trades.to_csv('paper_trades.csv')

        return paper_trades.iloc[-1],closed_position


# def get_strat_performance(strat='ema_cross_over_under',leverage=1,strat_params={'fast_ema':4,'slow_ema':20},interval='4h',symbol='BTCUSDT',candles=50,input=None,exchange=None):

#     if exchange is None:
#         return 'Exchange not initiated'
    
#     allowed_strats = ['ema_cross_over_under','ema_diff_peak_trough']
#     if strat not in allowed_strats:
#         print("INVALID STRATEGY")
#         return None

#     if input == None:
#         current_input=get_last_n_kline_closes(symbol=symbol,n=candles,interval=interval,exchange=exchange)

#     else:
#         current_input = input
    
#     closes = pd.DataFrame(current_input,columns=['close'])
#     closes = closes[:-1]
#     closes['close'] = closes['close'].astype(float)

#     ema_diff = pd.DataFrame(ema(closes['close'].tolist(),strat_params['fast_ema']) - ema(closes['close'].tolist(),strat_params['slow_ema']),columns=['ema_diff'])
#     p = strat_params['slow_ema']+1
#     closes = closes[p:].reset_index(drop=True)
#     ema_diff = ema_diff[p:].reset_index(drop=True)

#     if strat == 'ema_cross_over_under':
#         signal = [0]+[1 if float(ema_diff.loc[index]) > 0 and float(ema_diff.loc[index-1]) < 0 else -1 if float(ema_diff.loc[index]) < 0 and float(ema_diff.loc[index-1]) > 0  else 0 for index in ema_diff.index[1:]]

#     if strat == 'ema_diff_peak_trough':
#         signal = [0,0]+ [-1 if float(ema_diff.loc[index]) < float(ema_diff.loc[index-1]) and float(ema_diff.loc[index-1]) > float(ema_diff.loc[index-2]) else 1 if float(ema_diff.loc[index]) > float(ema_diff.loc[index-1]) and float(ema_diff.loc[index-1]) < float(ema_diff.loc[index-2]) else 0 for index in ema_diff.index[2:]]

#     trades = list()
#     for idx in range(len(signal)):
#         if signal[idx] != 0:
#             trades.append([closes.loc[idx],signal[idx]])
#     result = list()
#     for idx in range(len(trades)):
#         if idx > 0:
#             position = trades[idx-1][1] * leverage
#             performance = position * ((trades[idx][0]['close'] - trades[idx-1][0]['close']) / trades[idx-1][0]['close'])*100 
#             trade = [position,performance]
#             result.append(trade)

#     equity_curve = list()
#     principal = 1
#     for elem in result:
#         principal = principal * (1 + elem[1]/100)
#         # print(principal)
#         equity_curve.append(principal)
#     pd.DataFrame(equity_curve).plot()
    

#     trade_pnl = list()
#     principal = 1
#     for elem in result:
#         pnl=elem[1]
#         # print(principal)
#         trade_pnl.append(pnl)
#     pd.DataFrame(trade_pnl).plot(kind='bar')


def get_strat_price_ti_plot(strat='ema_cross_over_under',strat_params={'fast_ema':4,'slow_ema':20},symbol='DEFIUSDT',leverage=1,decay=0.995,interval='1d',candles=50,exchange=None,animate=False,data=None):

    if exchange is None:
        return 'Exchange not initiated'

    allowed_strats = ['ema_cross_over_under','ema_diff_peak_trough','ema_oscillator_peak_trough']

    if strat not in allowed_strats:
        print("INVALID STRATEGY")
        return None

    if strat == 'ema_oscillator_peak_trough':

        '''in devlopment'''
        # current_input=list(get_last_n_kline_closes(symbol=symbol,n=candles,interval=interval,exchange=exchange)['closes'].values)

        # closes = pd.DataFrame(current_input,columns=['close'])
        # # closes = closes[:-1]
        # closes['close'] = closes['close'].astype(float)

        # ema_oscillator = list()

        return None

    if data is None:
        current_input=get_last_n_kline_closes(symbol=symbol,n=candles,interval=interval,exchange=exchange)
    if data == 'complete':
        current_input = pd.read_parquet('C:\\Users\\ZankarSS\\Downloads\\BTC-USDT.parquet')['close'].astype(float).values
        current_input = pd.read_csv('Binance_BTCUSDT_d.csv').iloc[::-1][['date','close']]
        current_input['datetime'] = [pd.Timestamp(elem) for elem in current_input['date'].values]
        current_input['closes'] = [np.float64(elem) for elem in current_input['close'].values]
        del current_input['date']
        del current_input['close']
        current_input.reset_index(drop=True)
        # dates = True


    if strat == 'ema_cross_over_under':        
        
        min_input_length =   np.max([float(strat_params['fast_ema']),float(strat_params['slow_ema'])])

        if len(list(current_input['closes'].values))<min_input_length:
            return "INPUT HAS TOO FEW ELEMENTS"
        
        closes = current_input['closes'].astype(float)
        datetimes = current_input['datetime']
        # closes = closes[:-1]
        # closes['close'] = closes['close'].astype(float)
    
        indicator = pd.DataFrame(ema(closes.tolist(),strat_params['fast_ema']) - ema(closes.tolist(),strat_params['slow_ema']),columns=['ema_diff'])
        p = strat_params['slow_ema']+1
        closes = closes[p:].reset_index(drop=True)
        indicator = indicator[p:].reset_index(drop=True)
        datetimes = datetimes[p:].reset_index(drop=True)
        signal = [0] + [1 if float(indicator.loc[index]) > 0 and float(indicator.loc[index-1]) < 0 else -1 if float(indicator.loc[index]) < 0 and float(indicator.loc[index-1]) > 0  else 0 for index in indicator.index[1:]]

    if strat == 'ema_diff_peak_trough':
        # current_input=get_last_n_kline_closes(symbol=symbol,n=candles,interval=interval,exchange=exchange)

        min_input_length =   np.max([float(strat_params['fast_ema']),float(strat_params['slow_ema'])])

        if len(list(current_input['closes'].values))<min_input_length:
            return "INPUT HAS TOO FEW ELEMENTS"
        
        closes = current_input['closes'].astype(float)
        datetimes = current_input['datetime']
        
        # closes = closes[:-1]
        # closes['close'] = closes['close'].astype(float)
    
        indicator = pd.DataFrame(ema(closes.tolist(),strat_params['fast_ema']) - ema(closes.tolist(),strat_params['slow_ema']),columns=['ema_diff'])
        p = strat_params['slow_ema']+1
        closes = closes[p:].reset_index(drop=True)
        indicator = indicator[p:].reset_index(drop=True)
        datetimes = datetimes[p:].reset_index(drop=True)
        signal = [0,0]+ [-1 if float(indicator.loc[index]) < float(indicator.loc[index-1]) and float(indicator.loc[index-1]) > float(indicator.loc[index-2]) else 1 if float(indicator.loc[index]) > float(indicator.loc[index-1]) and float(indicator.loc[index-1]) < float(indicator.loc[index-2]) else 0 for index in indicator.index[2:]]

    
    navs = list()
    current_position = 0
    current_nav = 1
    current_position_entry = 0
    cumulative_nav = 1

    for idx in indicator.index[2:]:
        
        # if idx == 0 or idx == 1:
        #     navs.append(current_nav)
        #     continue
    
        if current_position == 1:
            current_position_entry =  current_position_entry * float(1/float(decay))
            current_nav = (float(closes[idx]) / float(current_position_entry)) * float(cumulative_nav)
            navs.append(current_nav)
            
        if current_position == -1:
            current_position_entry = current_position_entry * float(decay)
            current_nav = (1 + ((float(current_position_entry) - float(closes[idx])) / float(current_position_entry))) * float(cumulative_nav)  
            navs.append(current_nav)
            
        if current_position == 0:
            navs.append(current_nav)


        if signal[idx] != current_position and signal[idx] != 0:
            current_position = signal[idx]
            current_position_entry = closes[idx]    
            cumulative_nav = current_nav
            
            

    navs = [1,1] + navs

    # for elem in zip(closes.values,signal):
        
    #     if elem[1] == 0:
    #         if last_position == 0:
    #             last_nav =
    #             navs.append(last_nav) 
    #         if last_position != 0:
    #             last_nav = 
    #             navs.append(last_nav)
        
    #     if elem[1] == 1:
    #         last_position =1 
    #         last_nav = 
    #         navs.append(last_nav)
            
    #     if elem[1] == -1:
    #         last_position = -1
    #         last_nav = 
    #         navs.append(last_nav)

    dynamic_closes = list()
    dynamic_signal = list()
    dynamic_indicator = list()
    dynamic_dates = list()
    dynamic_nav = list()


    assert len(closes) == len(signal) == len(indicator) == len(datetimes) == len(navs)


    for elem in zip(closes.values,signal,indicator.values,datetimes.values,navs):

        dynamic_closes.append(elem[0])
        dynamic_signal.append(elem[1])
        dynamic_indicator.append(elem[2])
        dynamic_dates.append(elem[3])
        dynamic_nav.append(elem[4])
        clear_output(wait=True)

        if animate is False and elem != [elem for elem in zip(closes.values,signal,indicator.values,datetimes.values,navs)][-1]:
            continue

        fig, (ax1,ax2,ax3,ax4) = plt.subplots(nrows=4, sharex=True, subplot_kw=dict(frameon=True),figsize=(20,20)) # frameon=False removes frames        
        # x = range(len(dynamic_signal))
        # plt.subplots_adjust(hspace=.0)
        ax1.grid()
        ax1.plot(dynamic_dates, dynamic_closes, color='green',linewidth=2)
        for i in range(len(dynamic_signal)):
            if dynamic_signal[i] == 1:
                ax1.axvline(pd.DataFrame(dynamic_dates).iloc[pd.DataFrame(dynamic_dates).index.values[i]],color='g')
            if dynamic_signal[i] == -1:
                ax1.axvline(pd.DataFrame(dynamic_dates).iloc[pd.DataFrame(dynamic_dates).index.values[i]],color='r')
        # closes.plot()
        ax1.axhline(dynamic_closes[-1],color='k')
        ax1.legend([str(symbol)+': '+  str(float(dynamic_closes[-1]))] )

        # ax1.set_xlabel('Days')
        ax1.set_ylabel('Price')

        ax2.grid()
        ax2.plot(dynamic_dates, dynamic_indicator, color='lightgreen', linestyle='--',linewidth=2)
        # indicator.plot()
        for i in range(len(dynamic_signal)):
            if dynamic_signal[i] == 1:
                ax2.axvline(pd.DataFrame(dynamic_dates).iloc[pd.DataFrame(dynamic_dates).index.values[i]],color='g')
            if dynamic_signal[i] == -1:
                ax2.axvline(pd.DataFrame(dynamic_dates).iloc[pd.DataFrame(dynamic_dates).index.values[i]],color='r')
        ax2.axhline(0,color='k',linestyle='--')
        ax2.legend([float(dynamic_indicator[-1])]) 
        ax2.set_ylabel('Trend Indicator')

        ax3.grid()
        ax3.plot(dynamic_dates, dynamic_nav, color='darkmagenta',linewidth=2)
        # leg_strat = ax3.legend(strat_plot,'Strategy: '+ str(dynamic_nav[-1]))
        
        # bh = [dynamic_closes[idx]/dynamic_closes[0] for idx in range(len(dynamic_closes))]
        # buy_hold_plot = ax3.plot(dynamic_dates, bh, color='y',linewidth=2)
        # leg_bh = ax3.legend(buy_hold_plot,'Strategy: '+ str(bh[-1]))

        for i in range(len(dynamic_signal)):
            if dynamic_signal[i] == 1:
                ax3.axvline(pd.DataFrame(dynamic_dates).iloc[pd.DataFrame(dynamic_dates).index.values[i]],color='g')
            if dynamic_signal[i] == -1:
                ax3.axvline(pd.DataFrame(dynamic_dates).iloc[pd.DataFrame(dynamic_dates).index.values[i]],color='r')
      
        # ax3.axhline(dynamic_nav[-1],color='b')
        # ax3.axhline(1,color='k',linestyle='--')
        ax3.legend([round(float(dynamic_nav[-1]),2)])

        ax3.set_ylabel('Strategy ROI')


        ax4.grid()
        bh = [dynamic_closes[idx]/dynamic_closes[0] for idx in range(len(dynamic_closes))]
        ax4.plot(dynamic_dates, bh, color='hotpink',linewidth=2)
        for i in range(len(dynamic_signal)):
            if dynamic_signal[i] == 1:
                ax4.axvline(pd.DataFrame(dynamic_dates).iloc[pd.DataFrame(dynamic_dates).index.values[i]],color='g')
            if dynamic_signal[i] == -1:
                ax4.axvline(pd.DataFrame(dynamic_dates).iloc[pd.DataFrame(dynamic_dates).index.values[i]],color='r')
              
        ax4.legend([round(float(bh[-1]),2)])

        ax4.set_ylabel('Buy and Hold ROI')


        plt.xlabel('1 Tick = ' + interval)

        plt.xticks(rotation=45)
        # plt.figure(figsize=(10,70))
        plt.show()
        return fig


st.set_page_config(page_title="Manne",
    page_icon=":money:",
    layout='wide')

st.title('Backtester')
# st.write("This interactive webapp allows you to explore and visualize how 3 differently trained machine learning models try to predict the mileage of a car, given various numerical attributes about it, including: cylinders, displacement, horsepower, weight, and acceleration. The models used in creating the second visualization can be interactively customized by changing their parameters in the first visualization.")


# '''ínstantiate exchange object'''
exchange_nmn = ccxt.binance({
'apiKey': '<KEY>',
'secret': '<KEY>',
'enableRateLimit': True, 
'options': {
    'defaultType': 'delivery',
},
'hedgeMode':True
})

# '''load markets in exchange object'''
markets = exchange_nmn.load_markets()

symbol_selection_slider = st.sidebar.select_slider('Symbol',['BTCUSDT','ADAUSDT','BNBUSDT','ETHUSDT','DOGEUSDT','1000SHIBUSDT'],'BTCUSDT')
interval_selection_slider = st.sidebar.select_slider('Interval',['1d','4h','1h','15m'],'1d')
candles_selection_slider = st.sidebar.select_slider('# Candles',list(np.arange(500)+1),200)


fig = get_strat_price_ti_plot(strat='ema_cross_over_under',strat_params={'fast_ema':10,'slow_ema':40},symbol=symbol_selection_slider,interval=interval_selection_slider,candles=candles_selection_slider,exchange=exchange_nmn,decay=0.9995,animate=False)
st.write(fig)

import os
import sys
from pprint import pprint
from altair.vegalite.v4.schema.core import UtcSingleTimeUnit
import ccxt
#import ccxt.async_support as ccxt
from pyti.exponential_moving_average import exponential_moving_average as ema
import pandas as pd
import datetime
import time
import numpy as np
import matplotlib
from matplotlib import pyplot as plt
from IPython.display import clear_output
import numpy as np
import datetime as dt
import pytz
# import mplcursors

import streamlit as st
# from compute2d import compute_2d_histogram
import numpy as np
import pandas as pd
import altair as at
from copy import copy
import plotly.graph_objects as go
# from paracoords import create_paracoords
from mpl_toolkits.mplot3d import axes3d
from matplotlib import cm
import plotly
import plotly.graph_objs as go



import warnings
warnings.filterwarnings('ignore')


# root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
# sys.path.append(root + '/python')

# print('CCXT Version:', ccxt.__version__)

def get_last_n_kline_closes(n=50,interval='1h',symbol='BTCUSDT',exchange=None):

    if exchange is None:
        print('Exchange not initiated')
        return None
    
    # exchange = ccxt.binance({
    #     'apiKey': g_api_key,
    #     'secret': g_secret_key,
    #     'enableRateLimit': True,  
    #     'options': {
    #         'defaultType': 'future',
    #     },
    #     'hedgeMode':True
    # })
    # # symbol = 'BTC/USDT'

    # market = exchange.load_markets()
    
    closes = [[dt.datetime.utcfromtimestamp(float(elem[0]) / 1000.),elem[4]] for elem in exchange.fapiPublic_get_klines({'symbol':symbol,'interval':interval})][-n:-1]
    dates = [elem[0] for elem in closes]
    values = [float(elem[1]) for elem in closes]
    df = pd.DataFrame([(elem[0],elem[1]) for elem in zip(dates,values)],columns=['datetime','closes'])

    return df

def generate_signal(candles=50,interval='1h',symbol='BTCUSDT',strat='ema_cross_over_under',strat_params={'fast_ema':10,'slow_ema':40},exchange=None):

    if exchange is None:
        return 'Exchange not Initiated'

    allowed_strats = ['ema_diff_peak_trough','ema_cross_over_under','ema_oscillator_peak_trough']

    if strat not in allowed_strats:
        print('INVALID STRATEGY')
        return "NONE"

    if strat == 'ema_oscillator_peak_trough':

        '''under development'''
        return "NONE"

   
    if strat == 'ema_diff_peak_trough':
        candles = strat_params['slow_ema'] + 10

        current_input=get_last_n_kline_closes(symbol=symbol,n=candles,interval=interval,exchange=exchange)

        min_input_length =   np.max([float(strat_params['fast_ema']),float(strat_params['slow_ema'])])

        if len(list(current_input['closes'].values))<min_input_length:
            return "INPUT HAS TOO FEW ELEMENTS"
        
        closes = current_input['closes'].astype(float)
        # closes = closes[:-1]
        # closes['close'] = closes['close'].astype(float)
    
        ema_diff = pd.DataFrame(ema(closes.tolist(),strat_params['fast_ema']) - ema(closes.tolist(),strat_params['slow_ema']),columns=['ema_diff'])
        p = strat_params['slow_ema']+1
        closes = closes[p:].reset_index(drop=True)
        ema_diff = ema_diff[p:].reset_index(drop=True)

        last = ema_diff.values[-1]
        second_last = ema_diff.values[-2]
        third_last = ema_diff.values[-3]

        # short if local peak
        if last < second_last and third_last < second_last:
            return 'SHORT'
        # long if local trough 
        if last > second_last and third_last > second_last:
            return 'LONG'
        return "NONE"
     

    if strat == 'ema_cross_over_under':
        candles = strat_params['slow_ema'] + 10


        current_input=get_last_n_kline_closes(symbol=symbol,n=candles,interval=interval,exchange=exchange)

        min_input_length =   np.max([float(strat_params['fast_ema']),float(strat_params['slow_ema'])])

        if len(list(current_input['closes'].values))<min_input_length:
            return "INPUT HAS TOO FEW ELEMENTS"
        
        closes = current_input['closes'].astype(float)
        # closes = closes[:-1]
        # closes['close'] = closes['close'].astype(float)
    
        ema_diff = pd.DataFrame(ema(closes.tolist(),strat_params['fast_ema']) - ema(closes.tolist(),strat_params['slow_ema']),columns=['ema_diff'])
        p = strat_params['slow_ema']+1
        closes = closes[p:].reset_index(drop=True)
        ema_diff = ema_diff[p:].reset_index(drop=True)

        last = ema_diff.values[-1]
        second_last = ema_diff.values[-2]
        third_last = ema_diff.values[-3]

        # long if diff cross over 0    
        if last > 0 and second_last < 0:
            return "LONG"
        # short if diff cross under 0
        if last < 0 and second_last > 0:
            return "SHORT"
        return "NONE"


def get_open_positions(mode='live',exchange=None):

    if exchange is None:
        return 'Exchange Not Initiated'

    allowed_modes = ['live','paper']

    if mode not in allowed_modes:
        return "INVALID MODE"

    if mode == 'live':
            
        # exchange = ccxt.binance({
        #     'apiKey': g_api_key,
        #     'secret': g_secret_key,
        #     'enableRateLimit': True,
        #     'options': {
        #         'defaultType': 'future',
        #     },
        #     'hedgeMode':True
        # })

        # markets = exchange.load_markets()
        #exchange.verbose=True
        # market = exchange.market(symbol)

        positions = [elem for elem in exchange.fapiPrivate_get_positionrisk() if float(elem['positionAmt'])!=0]

        if len(positions)==0:
            return 0
        return positions

    if mode == 'paper':
        paper_trades = pd.read_csv('paper_trades.csv',index_col=0)
        if paper_trades.position_type.iloc[-1] == '-':
            return 0
        return paper_trades.iloc[-1]
        

def get_balance(mode='live',asset='USDT',exchange=None):

    if exchange is None:
        return 'Exchange not initiated'

    allowed_modes = ['paper','live']

    if mode not in allowed_modes:
        print("INVALID MODE")
        return None
            
    # exchange = ccxt.binance({
    #         'apiKey': g_api_key,
    #         'secret': g_secret_key,
    #         'enableRateLimit': True, 
    #         'options': {
    #             'defaultType': 'future',
    #         },
    #         'hedgeMode':True
    #     })
    # markets = exchange.load_markets()


    if mode == 'live':
        live_balance = str(float([float(elem['balance']) for elem in exchange.fapiPrivate_get_balance() if elem['asset']==asset][0]))
        unrealized_pnl = str(sum([float(elem['unRealizedProfit']) for elem in exchange.fapiPrivateV2_get_positionrisk() if float(elem['positionAmt']) >0]))
        unrealized_pnl_percent = str(float(unrealized_pnl)/float(live_balance))

        balance = {'wallet_balance': live_balance,
                    'unrealized_pnl_percent': unrealized_pnl_percent}
                    
        return balance

    if mode == 'paper':
        
        paper_trades = pd.read_csv('paper_trades.csv',index_col=0)

        if paper_trades.paper_equity.iloc[-1] == '-':
            paper_balance = paper_trades.paper_equity.iloc[-2]
        else:
            paper_balance = paper_trades.paper_equity.iloc[-1]

        if paper_trades.entry_price.iloc[-1] == '-':
            entry = None
        else:
            entry = paper_trades.entry_price.iloc[-1]

        if paper_trades.position_type.iloc[-1] == 'LONG':
            position = 1
        if paper_trades.position_type.iloc[-1] == 'SHORT':
            position = -1
        else:
            position = 0

        if entry is not None and position != 0:

            if paper_trades.exit_price.iloc[-1] == '-':
                
                symbol = paper_trades.market_name.iloc[-1]
                
                last_price = float(exchange.fapiPublic_get_ticker_price({'symbol':symbol})['price'])

                pnl = (last_price-float(entry))/float(entry)*100*float(position)

            else:
                pnl = 0

        else:
            pnl = 0

        balance = {'wallet_balance':paper_balance,'unrealized_pnl_percent':pnl}

        return balance    
        

def close_all_open_positions(mode='live',exchange=None):

    if exchange is None:
        return 'Exchange not Initiated'

    allowed_modes = ['paper','live']
    if mode not in allowed_modes:
        return "INVALID MODE"

    if mode == 'live':
            
        # exchange = ccxt.binance({
        #         'apiKey': g_api_key,
        #         'secret': g_secret_key,
        #         'enableRateLimit': True,
        #         'options': {
        #             'defaultType': 'future',
        #         },
        #         'hedgeMode':True
        #     })

        # markets = exchange.load_markets()
        #exchange.verbose=True
        # market = exchange.market(symbol)

        open_positions = get_open_positions(mode=mode,exchange=exchange)
        if open_positions == 0:
            return None
        
        if np.sign(float(open_positions[0]['positionAmt'])) == -1.0:
            opp_side = "BUY"
        if np.sign(float(open_positions[0]['positionAmt'])) == 1.0:
            opp_side = "SELL" 
        baseqty= abs(float(open_positions[0]['positionAmt']))
        symbol = open_positions[0]['symbol']
        positionSide = open_positions[0]['positionSide']
        order = exchange.fapiPrivatePostOrder({'symbol':symbol, 'type':"MARKET", 'side':opp_side,'positionSide':positionSide ,'quantity':baseqty})

        return order

    if mode == 'paper':
        paper_trades = pd.read_csv('paper_trades.csv',index_col=0)
        if paper_trades.position_type.iloc[-1] == '-':
            return None
    
        if paper_trades.exit_price.iloc[-1] != '-':
            return None
        # exchange = ccxt.binance({
        #     'apiKey': g_api_key,
        #     'secret': g_secret_key,
        #     'enableRateLimit': True, 
        #     'options': {
        #         'defaultType': 'future',
        #     },
        #     'hedgeMode':True
        # })
        # markets = exchange.load_markets()
        
        symbol = paper_trades.market_name.iloc[-1]
        entry_price = paper_trades.entry_price.iloc[-1]
        leverage= paper_trades.leverage.iloc[-1]
        leverage = int(leverage)

        if paper_trades.position_type.iloc[-1] == 'LONG':
            position = 1
            exit_price = 0.999*float(exchange.fapiPublic_get_ticker_price({'symbol':symbol})['price'])
            exit_time = datetime.datetime.utcnow()
    

        if paper_trades.position_type.iloc[-1] == 'SHORT':
            position = -1
            exit_price = 1.001*float(exchange.fapiPublic_get_ticker_price({'symbol':symbol})['price'])
            exit_time = datetime.datetime.utcnow()

        
        trade_pnl_pct = float(position)*float(leverage)*(float(exit_price)-float(entry_price))/float(entry_price)*100
        balance = float(paper_trades.paper_equity.iloc[-2])*(1+trade_pnl_pct/100)

        paper_trades.exit_time.iloc[-1] = exit_time
        paper_trades.exit_price.iloc[-1] = exit_price
        paper_trades.trade_pnl_pct.iloc[-1] = trade_pnl_pct
        paper_trades.paper_equity.iloc[-1] = balance

        paper_trades.to_csv('paper_trades.csv')

        trade = paper_trades.iloc[-1]

        return trade
        
def open_market_order(mode='live',balance=1,symbol='BTCUSDT',leverage="5",side="BUY",hedge_mode="BOTH",exchange=None):

    if exchange is None:
        return 'Exchange not initiated'

    allowed_modes = ['paper','live']

    if mode not in allowed_modes:
        return "INVALID MODE"

    if mode == 'live':

        closed_position =  close_all_open_positions(mode=mode,exchange=exchange)

        quoteqty = float([elem for elem in exchange.fapiPrivate_get_balance({'asset':"USDT"}) if elem['asset']=='USDT'][0]['balance']) * balance
        price = float(exchange.fapiPublic_get_ticker_price({'symbol':symbol})['price'])
        baseqty = "{:.3f}".format(quoteqty*float(leverage)/price)
        baseqty = float(baseqty)-float([elem for elem in exchange.fapiPublic_get_exchangeinfo()['symbols'] if elem['symbol']==symbol][0]['filters'][2]['minQty'])
        baseqty = "{:.3f}".format(baseqty)
        baseqty = str(baseqty)
        lev_req = exchange.fapiPrivate_post_leverage({'symbol':symbol,'leverage':leverage})
        order = exchange.fapiPrivatePostOrder({'symbol':symbol, 'type':"MARKET", 'side':side,'positionSide':hedge_mode ,'quantity':baseqty})

        return order,closed_position
    
    if mode == 'paper':
        closed_position = close_all_open_positions(mode=mode,exchange=exchange)

        
        paper_trades = pd.read_csv('paper_trades.csv',index_col=0)

        
        if side == 'BUY':
            position_type = 'LONG'
            entry_price = 1.001*float(exchange.fapiPublic_get_ticker_price({'symbol':symbol})['price'])
            entry_time = datetime.datetime.utcnow()
        if side == 'SELL':
            position_type = 'SHORT'
            entry_price = 0.999*float(exchange.fapiPublic_get_ticker_price({'symbol':symbol})['price'])
            entry_time = datetime.datetime.utcnow()

        trade = pd.DataFrame([[symbol,position_type,entry_time,'-', entry_price,'-',leverage,'-','-']],columns=['market_name','position_type','entry_time','exit_time','entry_price','exit_price','leverage','trade_pnl_pct','paper_equity'])
        paper_trades = paper_trades.append(trade,ignore_index=True)

        paper_trades.to_csv('paper_trades.csv')

        return paper_trades.iloc[-1],closed_position


# def get_strat_performance(strat='ema_cross_over_under',leverage=1,strat_params={'fast_ema':4,'slow_ema':20},interval='4h',symbol='BTCUSDT',candles=50,input=None,exchange=None):

#     if exchange is None:
#         return 'Exchange not initiated'
    
#     allowed_strats = ['ema_cross_over_under','ema_diff_peak_trough']
#     if strat not in allowed_strats:
#         print("INVALID STRATEGY")
#         return None

#     if input == None:
#         current_input=get_last_n_kline_closes(symbol=symbol,n=candles,interval=interval,exchange=exchange)

#     else:
#         current_input = input
    
#     closes = pd.DataFrame(current_input,columns=['close'])
#     closes = closes[:-1]
#     closes['close'] = closes['close'].astype(float)

#     ema_diff = pd.DataFrame(ema(closes['close'].tolist(),strat_params['fast_ema']) - ema(closes['close'].tolist(),strat_params['slow_ema']),columns=['ema_diff'])
#     p = strat_params['slow_ema']+1
#     closes = closes[p:].reset_index(drop=True)
#     ema_diff = ema_diff[p:].reset_index(drop=True)

#     if strat == 'ema_cross_over_under':
#         signal = [0]+[1 if float(ema_diff.loc[index]) > 0 and float(ema_diff.loc[index-1]) < 0 else -1 if float(ema_diff.loc[index]) < 0 and float(ema_diff.loc[index-1]) > 0  else 0 for index in ema_diff.index[1:]]

#     if strat == 'ema_diff_peak_trough':
#         signal = [0,0]+ [-1 if float(ema_diff.loc[index]) < float(ema_diff.loc[index-1]) and float(ema_diff.loc[index-1]) > float(ema_diff.loc[index-2]) else 1 if float(ema_diff.loc[index]) > float(ema_diff.loc[index-1]) and float(ema_diff.loc[index-1]) < float(ema_diff.loc[index-2]) else 0 for index in ema_diff.index[2:]]

#     trades = list()
#     for idx in range(len(signal)):
#         if signal[idx] != 0:
#             trades.append([closes.loc[idx],signal[idx]])
#     result = list()
#     for idx in range(len(trades)):
#         if idx > 0:
#             position = trades[idx-1][1] * leverage
#             performance = position * ((trades[idx][0]['close'] - trades[idx-1][0]['close']) / trades[idx-1][0]['close'])*100 
#             trade = [position,performance]
#             result.append(trade)

#     equity_curve = list()
#     principal = 1
#     for elem in result:
#         principal = principal * (1 + elem[1]/100)
#         # print(principal)
#         equity_curve.append(principal)
#     pd.DataFrame(equity_curve).plot()
    

#     trade_pnl = list()
#     principal = 1
#     for elem in result:
#         pnl=elem[1]
#         # print(principal)
#         trade_pnl.append(pnl)
#     pd.DataFrame(trade_pnl).plot(kind='bar')


def get_strat_price_ti_plot(strat='ema_cross_over_under',strat_params={'fast_ema':4,'slow_ema':20},symbol='DEFIUSDT',leverage=1,decay=0.995,interval='1d',candles=50,exchange=None,animate=False,data=None):

    if exchange is None:
        return 'Exchange not initiated'

    allowed_strats = ['ema_cross_over_under','ema_diff_peak_trough','ema_oscillator_peak_trough']

    if strat not in allowed_strats:
        print("INVALID STRATEGY")
        return None

    if strat == 'ema_oscillator_peak_trough':

        '''in devlopment'''
        # current_input=list(get_last_n_kline_closes(symbol=symbol,n=candles,interval=interval,exchange=exchange)['closes'].values)

        # closes = pd.DataFrame(current_input,columns=['close'])
        # # closes = closes[:-1]
        # closes['close'] = closes['close'].astype(float)

        # ema_oscillator = list()

        return None

    if data is None:
        current_input=get_last_n_kline_closes(symbol=symbol,n=candles,interval=interval,exchange=exchange)
    if data == 'complete':
        current_input = pd.read_parquet('C:\\Users\\ZankarSS\\Downloads\\BTC-USDT.parquet')['close'].astype(float).values
        current_input = pd.read_csv('Binance_BTCUSDT_d.csv').iloc[::-1][['date','close']]
        current_input['datetime'] = [pd.Timestamp(elem) for elem in current_input['date'].values]
        current_input['closes'] = [np.float64(elem) for elem in current_input['close'].values]
        del current_input['date']
        del current_input['close']
        current_input.reset_index(drop=True)
        # dates = True


    if strat == 'ema_cross_over_under':        
        
        min_input_length =   np.max([float(strat_params['fast_ema']),float(strat_params['slow_ema'])])

        if len(list(current_input['closes'].values))<min_input_length:
            return "INPUT HAS TOO FEW ELEMENTS"
        
        closes = current_input['closes'].astype(float)
        datetimes = current_input['datetime']
        # closes = closes[:-1]
        # closes['close'] = closes['close'].astype(float)
    
        indicator = pd.DataFrame(ema(closes.tolist(),strat_params['fast_ema']) - ema(closes.tolist(),strat_params['slow_ema']),columns=['ema_diff'])
        p = strat_params['slow_ema']+1
        closes = closes[p:].reset_index(drop=True)
        indicator = indicator[p:].reset_index(drop=True)
        datetimes = datetimes[p:].reset_index(drop=True)
        signal = [0] + [1 if float(indicator.loc[index]) > 0 and float(indicator.loc[index-1]) < 0 else -1 if float(indicator.loc[index]) < 0 and float(indicator.loc[index-1]) > 0  else 0 for index in indicator.index[1:]]

    if strat == 'ema_diff_peak_trough':
        # current_input=get_last_n_kline_closes(symbol=symbol,n=candles,interval=interval,exchange=exchange)

        min_input_length =   np.max([float(strat_params['fast_ema']),float(strat_params['slow_ema'])])

        if len(list(current_input['closes'].values))<min_input_length:
            return "INPUT HAS TOO FEW ELEMENTS"
        
        closes = current_input['closes'].astype(float)
        datetimes = current_input['datetime']
        
        # closes = closes[:-1]
        # closes['close'] = closes['close'].astype(float)
    
        indicator = pd.DataFrame(ema(closes.tolist(),strat_params['fast_ema']) - ema(closes.tolist(),strat_params['slow_ema']),columns=['ema_diff'])
        p = strat_params['slow_ema']+1
        closes = closes[p:].reset_index(drop=True)
        indicator = indicator[p:].reset_index(drop=True)
        datetimes = datetimes[p:].reset_index(drop=True)
        signal = [0,0]+ [-1 if float(indicator.loc[index]) < float(indicator.loc[index-1]) and float(indicator.loc[index-1]) > float(indicator.loc[index-2]) else 1 if float(indicator.loc[index]) > float(indicator.loc[index-1]) and float(indicator.loc[index-1]) < float(indicator.loc[index-2]) else 0 for index in indicator.index[2:]]

    
    navs = list()
    current_position = 0
    current_nav = 1
    current_position_entry = 0
    cumulative_nav = 1

    for idx in indicator.index[2:]:
        
        # if idx == 0 or idx == 1:
        #     navs.append(current_nav)
        #     continue
    
        if current_position == 1:
            current_position_entry =  current_position_entry * float(1/float(decay))
            current_nav = (float(closes[idx]) / float(current_position_entry)) * float(cumulative_nav)
            navs.append(current_nav)
            
        if current_position == -1:
            current_position_entry = current_position_entry * float(decay)
            current_nav = (1 + ((float(current_position_entry) - float(closes[idx])) / float(current_position_entry))) * float(cumulative_nav)  
            navs.append(current_nav)
            
        if current_position == 0:
            navs.append(current_nav)


        if signal[idx] != current_position and signal[idx] != 0:
            current_position = signal[idx]
            current_position_entry = closes[idx]    
            cumulative_nav = current_nav
            
            

    navs = [1,1] + navs

    # for elem in zip(closes.values,signal):
        
    #     if elem[1] == 0:
    #         if last_position == 0:
    #             last_nav =
    #             navs.append(last_nav) 
    #         if last_position != 0:
    #             last_nav = 
    #             navs.append(last_nav)
        
    #     if elem[1] == 1:
    #         last_position =1 
    #         last_nav = 
    #         navs.append(last_nav)
            
    #     if elem[1] == -1:
    #         last_position = -1
    #         last_nav = 
    #         navs.append(last_nav)

    dynamic_closes = list()
    dynamic_signal = list()
    dynamic_indicator = list()
    dynamic_dates = list()
    dynamic_nav = list()


    assert len(closes) == len(signal) == len(indicator) == len(datetimes) == len(navs)


    for elem in zip(closes.values,signal,indicator.values,datetimes.values,navs):

        dynamic_closes.append(elem[0])
        dynamic_signal.append(elem[1])
        dynamic_indicator.append(elem[2])
        dynamic_dates.append(elem[3])
        dynamic_nav.append(elem[4])
        clear_output(wait=True)

        if animate is False and elem != [elem for elem in zip(closes.values,signal,indicator.values,datetimes.values,navs)][-1]:
            continue

        fig, (ax1,ax2,ax3,ax4) = plt.subplots(nrows=4, sharex=True, subplot_kw=dict(frameon=True),figsize=(20,20)) # frameon=False removes frames        
        # x = range(len(dynamic_signal))
        # plt.subplots_adjust(hspace=.0)
        ax1.grid()
        ax1.plot(dynamic_dates, dynamic_closes, color='green',linewidth=2)
        for i in range(len(dynamic_signal)):
            if dynamic_signal[i] == 1:
                ax1.axvline(pd.DataFrame(dynamic_dates).iloc[pd.DataFrame(dynamic_dates).index.values[i]],color='g')
            if dynamic_signal[i] == -1:
                ax1.axvline(pd.DataFrame(dynamic_dates).iloc[pd.DataFrame(dynamic_dates).index.values[i]],color='r')
        # closes.plot()
        ax1.axhline(dynamic_closes[-1],color='k')
        ax1.legend([str(symbol)+': '+  str(float(dynamic_closes[-1]))] )

        # ax1.set_xlabel('Days')
        ax1.set_ylabel('Price')

        ax2.grid()
        ax2.plot(dynamic_dates, dynamic_indicator, color='lightgreen', linestyle='--',linewidth=2)
        # indicator.plot()
        for i in range(len(dynamic_signal)):
            if dynamic_signal[i] == 1:
                ax2.axvline(pd.DataFrame(dynamic_dates).iloc[pd.DataFrame(dynamic_dates).index.values[i]],color='g')
            if dynamic_signal[i] == -1:
                ax2.axvline(pd.DataFrame(dynamic_dates).iloc[pd.DataFrame(dynamic_dates).index.values[i]],color='r')
        ax2.axhline(0,color='k',linestyle='--')
        ax2.legend([float(dynamic_indicator[-1])]) 
        ax2.set_ylabel('Trend Indicator')

        ax3.grid()
        ax3.plot(dynamic_dates, dynamic_nav, color='darkmagenta',linewidth=2)
        # leg_strat = ax3.legend(strat_plot,'Strategy: '+ str(dynamic_nav[-1]))
        
        # bh = [dynamic_closes[idx]/dynamic_closes[0] for idx in range(len(dynamic_closes))]
        # buy_hold_plot = ax3.plot(dynamic_dates, bh, color='y',linewidth=2)
        # leg_bh = ax3.legend(buy_hold_plot,'Strategy: '+ str(bh[-1]))

        for i in range(len(dynamic_signal)):
            if dynamic_signal[i] == 1:
                ax3.axvline(pd.DataFrame(dynamic_dates).iloc[pd.DataFrame(dynamic_dates).index.values[i]],color='g')
            if dynamic_signal[i] == -1:
                ax3.axvline(pd.DataFrame(dynamic_dates).iloc[pd.DataFrame(dynamic_dates).index.values[i]],color='r')
      
        # ax3.axhline(dynamic_nav[-1],color='b')
        # ax3.axhline(1,color='k',linestyle='--')
        ax3.legend([round(float(dynamic_nav[-1]),2)])

        ax3.set_ylabel('Strategy ROI')


        ax4.grid()
        bh = [dynamic_closes[idx]/dynamic_closes[0] for idx in range(len(dynamic_closes))]
        ax4.plot(dynamic_dates, bh, color='hotpink',linewidth=2)
        for i in range(len(dynamic_signal)):
            if dynamic_signal[i] == 1:
                ax4.axvline(pd.DataFrame(dynamic_dates).iloc[pd.DataFrame(dynamic_dates).index.values[i]],color='g')
            if dynamic_signal[i] == -1:
                ax4.axvline(pd.DataFrame(dynamic_dates).iloc[pd.DataFrame(dynamic_dates).index.values[i]],color='r')
              
        ax4.legend([round(float(bh[-1]),2)])

        ax4.set_ylabel('Buy and Hold ROI')


        plt.xlabel('1 Tick = ' + interval)

        plt.xticks(rotation=45)
        # plt.figure(figsize=(10,70))
        plt.show()
        return fig


st.set_page_config(page_title="Manne",
    page_icon=":money:",
    layout='wide')

st.title('Backtester')
# st.write("This interactive webapp allows you to explore and visualize how 3 differently trained machine learning models try to predict the mileage of a car, given various numerical attributes about it, including: cylinders, displacement, horsepower, weight, and acceleration. The models used in creating the second visualization can be interactively customized by changing their parameters in the first visualization.")


# '''ínstantiate exchange object'''
exchange_nmn = ccxt.binance({
'apiKey': '<KEY>',
'secret': '<KEY>',
'enableRateLimit': True, 
'options': {
    'defaultType': 'delivery',
},
'hedgeMode':True
})

# '''load markets in exchange object'''
markets = exchange_nmn.load_markets()

symbol_selection_slider = st.sidebar.select_slider('Symbol',['BTCUSDT','ADAUSDT','BNBUSDT','ETHUSDT','DOGEUSDT','1000SHIBUSDT'],'BTCUSDT')
interval_selection_slider = st.sidebar.select_slider('Interval',['1d','4h','1h','15m'],'1d')
candles_selection_slider = st.sidebar.select_slider('# Candles',list(np.arange(500)+1),200)


fig = get_strat_price_ti_plot(strat='ema_cross_over_under',strat_params={'fast_ema':10,'slow_ema':40},symbol=symbol_selection_slider,interval=interval_selection_slider,candles=candles_selection_slider,exchange=exchange_nmn,decay=0.9995,animate=False)
st.write(fig)

#import ccxt.async_support as ccxt # import mplcursors # from compute2d import compute_2d_histogram # from paracoords import create_paracoords # root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) # sys.path.append(root + '/python') # print('CCXT Version:', ccxt.__version__) # exchange = ccxt.binance({ #     'apiKey': g_api_key, #     'secret': g_secret_key, #     'enableRateLimit': True, #     'options': { #         'defaultType': 'future', #     }, #     'hedgeMode':True # }) # # symbol = 'BTC/USDT' # market = exchange.load_markets() under development # closes = closes[:-1] # closes['close'] = closes['close'].astype(float) # short if local peak # long if local trough # closes = closes[:-1] # closes['close'] = closes['close'].astype(float) # long if diff cross over 0 # short if diff cross under 0 # exchange = ccxt.binance({ #     'apiKey': g_api_key, #     'secret': g_secret_key, #     'enableRateLimit': True, #     'options': { #         'defaultType': 'future', #     }, #     'hedgeMode':True # }) # markets = exchange.load_markets() #exchange.verbose=True # market = exchange.market(symbol) # exchange = ccxt.binance({ #         'apiKey': g_api_key, #         'secret': g_secret_key, #         'enableRateLimit': True, #         'options': { #             'defaultType': 'future', #         }, #         'hedgeMode':True #     }) # markets = exchange.load_markets() # exchange = ccxt.binance({ #         'apiKey': g_api_key, #         'secret': g_secret_key, #         'enableRateLimit': True, #         'options': { #             'defaultType': 'future', #         }, #         'hedgeMode':True #     }) # markets = exchange.load_markets() #exchange.verbose=True # market = exchange.market(symbol) # exchange = ccxt.binance({ #     'apiKey': g_api_key, #     'secret': g_secret_key, #     'enableRateLimit': True, #     'options': { #         'defaultType': 'future', #     }, #     'hedgeMode':True # }) # markets = exchange.load_markets() # def get_strat_performance(strat='ema_cross_over_under',leverage=1,strat_params={'fast_ema':4,'slow_ema':20},interval='4h',symbol='BTCUSDT',candles=50,input=None,exchange=None): #     if exchange is None: #         return 'Exchange not initiated' #     allowed_strats = ['ema_cross_over_under','ema_diff_peak_trough'] #     if strat not in allowed_strats: #         print("INVALID STRATEGY") #         return None #     if input == None: #         current_input=get_last_n_kline_closes(symbol=symbol,n=candles,interval=interval,exchange=exchange) #     else: #         current_input = input #     closes = pd.DataFrame(current_input,columns=['close']) #     closes = closes[:-1] #     closes['close'] = closes['close'].astype(float) #     ema_diff = pd.DataFrame(ema(closes['close'].tolist(),strat_params['fast_ema']) - ema(closes['close'].tolist(),strat_params['slow_ema']),columns=['ema_diff']) #     p = strat_params['slow_ema']+1 #     closes = closes[p:].reset_index(drop=True) #     ema_diff = ema_diff[p:].reset_index(drop=True) #     if strat == 'ema_cross_over_under': #         signal = [0]+[1 if float(ema_diff.loc[index]) > 0 and float(ema_diff.loc[index-1]) < 0 else -1 if float(ema_diff.loc[index]) < 0 and float(ema_diff.loc[index-1]) > 0  else 0 for index in ema_diff.index[1:]] #     if strat == 'ema_diff_peak_trough': #         signal = [0,0]+ [-1 if float(ema_diff.loc[index]) < float(ema_diff.loc[index-1]) and float(ema_diff.loc[index-1]) > float(ema_diff.loc[index-2]) else 1 if float(ema_diff.loc[index]) > float(ema_diff.loc[index-1]) and float(ema_diff.loc[index-1]) < float(ema_diff.loc[index-2]) else 0 for index in ema_diff.index[2:]] #     trades = list() #     for idx in range(len(signal)): #         if signal[idx] != 0: #             trades.append([closes.loc[idx],signal[idx]]) #     result = list() #     for idx in range(len(trades)): #         if idx > 0: #             position = trades[idx-1][1] * leverage #             performance = position * ((trades[idx][0]['close'] - trades[idx-1][0]['close']) / trades[idx-1][0]['close'])*100 #             trade = [position,performance] #             result.append(trade) #     equity_curve = list() #     principal = 1 #     for elem in result: #         principal = principal * (1 + elem[1]/100) #         # print(principal) #         equity_curve.append(principal) #     pd.DataFrame(equity_curve).plot() #     trade_pnl = list() #     principal = 1 #     for elem in result: #         pnl=elem[1] #         # print(principal) #         trade_pnl.append(pnl) #     pd.DataFrame(trade_pnl).plot(kind='bar') in devlopment # current_input=list(get_last_n_kline_closes(symbol=symbol,n=candles,interval=interval,exchange=exchange)['closes'].values) # closes = pd.DataFrame(current_input,columns=['close']) # # closes = closes[:-1] # closes['close'] = closes['close'].astype(float) # ema_oscillator = list() # dates = True # closes = closes[:-1] # closes['close'] = closes['close'].astype(float) # current_input=get_last_n_kline_closes(symbol=symbol,n=candles,interval=interval,exchange=exchange) # closes = closes[:-1] # closes['close'] = closes['close'].astype(float) # if idx == 0 or idx == 1: #     navs.append(current_nav) #     continue # for elem in zip(closes.values,signal): #     if elem[1] == 0: #         if last_position == 0: #             last_nav = #             navs.append(last_nav) #         if last_position != 0: #             last_nav = #             navs.append(last_nav) #     if elem[1] == 1: #         last_position =1 #         last_nav = #         navs.append(last_nav) #     if elem[1] == -1: #         last_position = -1 #         last_nav = #         navs.append(last_nav) # frameon=False removes frames # x = range(len(dynamic_signal)) # plt.subplots_adjust(hspace=.0) # closes.plot() # ax1.set_xlabel('Days') # indicator.plot() # leg_strat = ax3.legend(strat_plot,'Strategy: '+ str(dynamic_nav[-1])) # bh = [dynamic_closes[idx]/dynamic_closes[0] for idx in range(len(dynamic_closes))] # buy_hold_plot = ax3.plot(dynamic_dates, bh, color='y',linewidth=2) # leg_bh = ax3.legend(buy_hold_plot,'Strategy: '+ str(bh[-1])) # ax3.axhline(dynamic_nav[-1],color='b') # ax3.axhline(1,color='k',linestyle='--') # plt.figure(figsize=(10,70)) # st.write("This interactive webapp allows you to explore and visualize how 3 differently trained machine learning models try to predict the mileage of a car, given various numerical attributes about it, including: cylinders, displacement, horsepower, weight, and acceleration. The models used in creating the second visualization can be interactively customized by changing their parameters in the first visualization.") # '''ínstantiate exchange object''' # '''load markets in exchange object'''