示例#1
0
def test_github_issue37_plotaspectratio():
    cerebro = bt.Cerebro()

    data = bt.feeds.YahooFinanceCSVData(
        dataname=getdatadir("orcl-1995-2014.txt"),
        fromdate=datetime.datetime(2000, 1, 1),
        todate=datetime.datetime(2001, 2, 28),
        reverse=False,
    )

    cerebro.adddata(data)
    cerebro.broker.setcash(10000)
    cerebro.coc = True
    cerebro.broker.setcommission(commission=0.00075)
    cerebro.addstrategy(BokehTest)
    cerebro.run()

    plotconfig = {
        'id:rsi': dict(plotaspectratio=10, ),
    }

    b = Bokeh(style='bar',
              plot_mode='single',
              scheme=Tradimo(),
              plotconfig=plotconfig,
              output_mode='memory')
    output = cerebro.plot(b)

    assert output[0][0].figures[1].bfigure.aspect_ratio == 10
示例#2
0
    def run_back_testing(cls, stock_id):
        """
        Run the back testing, return the analysis data.
        :param stock_id(string)
        :return(dict): analysis data.
        """
        # get the data
        data = cls.get_data(stock_id)
        cerebro = bt.Cerebro()
        data = bt.feeds.PandasData(dataname=data)
        cerebro.adddata(data, name=stock_id)
        cerebro.addstrategy(Basic5MA)
        cerebro.addanalyzer(bt.analyzers.TimeReturn,
                            _name='al_return',
                            timeframe=bt.analyzers.TimeFrame.NoTimeFrame)

        cerebro.addanalyzer(bad.TimeDrawDown, _name='al_max_drawdown')

        cerebro.broker.set_cash(bsu.Utils.DEFAULT_CASH)

        cerebro.addsizer(bt.sizers.FixedSize, stake=100)

        cerebro.broker.setcommission(commission=0.005)

        cerebro.run()
        if conf.DEBUG:
            list = [stock_id, '.html']
            b = Bokeh(style='bar',
                      plot_mode='single',
                      scheme=Tradimo(),
                      filename=''.join(list),
                      output_mode='show')
            cerebro.plot(b)
def test_github_issue30():
    cerebro = bt.Cerebro()

    cerebro.addstrategy(MyStrategy)

    data = bt.feeds.YahooFinanceCSVData(
        dataname=getdatadir("orcl-1995-2014.txt"),
        fromdate=datetime.datetime(2000, 1, 1),
        todate=datetime.datetime(2001, 2, 28),
        reverse=False,
    )
    cerebro.adddata(data)
    cerebro.addanalyzer(bt.analyzers.SharpeRatio)

    cerebro.run()

    b = backtrader_plotting.Bokeh(filename='chart.html',
                                  style='bar',
                                  scheme=Tradimo(),
                                  output_mode='memory')

    figs = cerebro.plot(b)

    assert isinstance(figs[0][0], backtrader_plotting.bokeh.bokeh.FigurePage)
    assert len(figs[0][0].figures) == 4
    assert len(figs[0][0].analyzers) == 1
示例#4
0
def save_plot(**kwargs):
    # Instantiate Cerebro
    cerebro = bt.Cerebro()

    # Add data original timestamp
    cerebro.adddata(_data)

    # Upsampling in case of need just uncomment the next line
    cerebro.replaydata(_data, timeframe=tframes[_replay_period])

    # Add strateg
    cerebro.addstrategy(_strategy, **kwargs)

    # Set our desired cash start
    cerebro.broker.setcash(_cash)

    # Set the commission
    cerebro.broker.setcommission(commission=_commission)

    cerebro.run()

    # Plot the result
    b = Bokeh(style='bar',
              scheme=Tradimo(),
              output_mode='save',
              filename='./best_iteration.html')
    cerebro.plot(b)
示例#5
0
def runstart():
    cerebro = bt.Cerebro()
    
    #画图
    b = Bokeh(style='bar', plot_mode='single', scheme=Tradimo())
    

    #数据加工清洗:
    #for d in fk.get_cyb:
    
    for code in stockpool:
        codename=code
        df = pro.daily(ts_code=code,start_date=20180101)
     #数据-加工
        df['trade_date']=pd.to_datetime(df['trade_date'])
        df=df.rename(columns={'vol':'volume'})
        df.set_index('trade_date', inplace=True)  # 设置索引覆盖原来的数据
        df = df.sort_index(ascending=True)  #从小到大
        df['openinterest']=0
        df=df[['open','high','low','close','volume','openinterest']]
        data = bt.feeds.PandasData(dataname=df)
        cerebro.adddata(data,name=code)


    
    cerebro.addstrategy(MyStrategy)
    
    cerebro.addanalyzer(bt.analyzers.SharpeRatio, _name='SP') #夏普
    cerebro.addanalyzer(bt.analyzers.AnnualReturn, _name='AR')#每年化收益率
    cerebro.addanalyzer(bt.analyzers.DrawDown, _name='DD')#回撤
    cerebro.addanalyzer(bt.analyzers.Returns, _name='RE') #收益率
   
    
    
 
    
    #回测-资金规则(总资产和手续费)
    cerebro.broker.setcash(100000.0) 
    cerebro.broker.setcommission(0.0003)
    
    
    #回测-启动
    print('初始金额: %.2f' % cerebro.broker.getvalue())
    back = cerebro.run()
    #总份额,年化,回撤,夏普
    ratio_list=[[
        x.analyzers.SP.get_analysis()['sharperatio'],#夏普比率
        x.analyzers.RE.get_analysis()['rtot']*100, #总复合收益率        
        x.analyzers.DD.get_analysis()['max']['drawdown'], #最大回撤
        x.analyzers.DD.get_analysis()['max']['len']]#最大回撤周期
        for x in back]  #夏普
    ratio_df = pd.DataFrame(ratio_list,columns=['夏普','年化%','最大回撤','最大回撤周期'])
    print(ratio_df)
    
    print('历年收益率:%s' %back[0].analyzers.AR.get_analysis())#每年年化收益率
    print('标准收益率:%s' %back[0].analyzers.RE.get_analysis()['rnorm100']) # 年化标准化回报以100%展示
    cerebro.plot(b)
    # cerebro.plot(style='candle')
    print('最终收益: %.2f' % cerebro.broker.getvalue())
示例#6
0
    def run_back_testing(cls, stock_id):
        """
        Run the back testing, return the analysis data.
        :param stock_id(string)
        :return(dict): analysis data.
        """
        # get the data
        data = cls.get_data(stock_id)
        length = len(data)
        # get the params
        best_params = cls.get_params(stock_id)

        cerebro = bt.Cerebro()
        data = bt.feeds.PandasData(dataname=data)

        cerebro.adddata(data, name=stock_id)
        ma_periods = best_params.ma_periods
        cerebro.addstrategy(cls, ma_periods=dict(ma_period_s=ma_periods.get('ma_period_s'),
                                                 ma_period_l=ma_periods.get('ma_period_l'),
                                                 stock_id=ma_periods.get('stock_id')))
        cerebro.addanalyzer(bt.analyzers.TimeReturn, _name='al_return',
                            timeframe=bt.analyzers.TimeFrame.NoTimeFrame)

        cerebro.addanalyzer(bad.TimeDrawDown, _name='al_max_drawdown')

        cerebro.broker.set_cash(bsu.Utils.DEFAULT_CASH)

        logger.debug(
            'Starting back testing, stock is %s, params is ma_period_s: %d, ma_period_l: %d...' %
            (
                ma_periods.get('stock_id'),
                ma_periods.get('ma_period_s'),
                ma_periods.get('ma_period_l')
            ))

        strats = cerebro.run()
        strat = strats[0]

        for k, v in strat.analyzers.al_return.get_analysis().items():
            total_return_rate = v

        al_result = dict(
            stock_id=ma_periods.get('stock_id'),
            trading_days=length,
            total_return_rate=total_return_rate,
            max_drawdown=strat.analyzers.al_max_drawdown.get_analysis().get('maxdrawdown'),
            max_drawdown_period=strat.analyzers.al_max_drawdown.get_analysis().get('maxdrawdownperiod'),
            drawdown_points=strat.analyzers.al_max_drawdown.get_analysis().get('drawdownpoints')
        )
        if conf.DEBUG:
            list = [ma_periods.get('stock_id'), '.html']
            b = Bokeh(style='bar', plot_mode='single', scheme=Tradimo(), filename=''.join(list), output_mode='show')
            cerebro.plot(b)
        return al_result
示例#7
0
def test_github_issue36():
    cerebro = bt.Cerebro()

    cerebro.addstrategy(MyStrategy)

    filedir = os.path.dirname(os.path.abspath(__file__))

    df = pd.read_csv(os.path.join(filedir, "datas/NQ.csv"), index_col=0)
    df.index = pd.DatetimeIndex(df.index)
    data = bt.feeds.PandasData(dataname=df, name='NQ', timeframe=bt.TimeFrame.Minutes)
    cerebro.adddata(data)
    cerebro.resampledata(data, name='NQ_5min', timeframe=bt.TimeFrame.Minutes, compression=5)
    cerebro.addanalyzer(bt.analyzers.SharpeRatio)
    cerebro.run()

    b = Bokeh(filename='chart.html', style='bar', plot_mode="single", scheme=Tradimo(), output_mode='memory')
    cerebro.plot(b)
示例#8
0
def trade_run():
    cerebro = bt.Cerebro()
    data = DBDataFeed(
        # 本地postgresql数据库
        db_uri=ConfigUtils.get_mysql('engine'),
        dataname="sh.600004",
        fromdate=datetime.date(2010, 1, 1),
    )
    cerebro.adddata(data)

    cerebro.addstrategy(SMACross)
    cerebro.addsizer(bt.sizers.AllInSizerInt)
    cerebro.broker.set_cash(100000)

    cerebro.addanalyzer(bt.analyzers.AnnualReturn, _name="annual_returns")
    cerebro.addanalyzer(bt.analyzers.DrawDown, _name="draw_down")
    cerebro.addanalyzer(bt.analyzers.Transactions, _name="transactions")

    results = cerebro.run()

    # 打印Analyzer结果到日志
    for result in results:

        annual_returns = result.analyzers.annual_returns.get_analysis()
        log.info("annual returns:")
        for year, ret in annual_returns.items():
            log.info("\t {} {}%, ".format(year, round(ret * 100, 2)))

        draw_down = result.analyzers.draw_down.get_analysis()
        log.info(
            "drawdown={drawdown}%, moneydown={moneydown}, drawdown len={len}, "
            "max.drawdown={max.drawdown}, max.moneydown={max.moneydown}, "
            "max.len={max.len}".format(**draw_down))

        transactions = result.analyzers.transactions.get_analysis()
        log.info("transactions")

    # 运行结果绘图
    # cerebro.plot()
    b = Bokeh(style="bar", tabs="multi", scheme=Tradimo())
    cerebro.plot(b)
def _run_cerebro(stratcls):
    cerebro = bt.Cerebro()

    cerebro.addstrategy(stratcls)

    datas = [
        'nvda-1999-2014.txt',
        'orcl-1995-2014.txt',
    ]

    for dname in datas:
        data = bt.feeds.YahooFinanceCSVData(
            dataname=getdatadir(dname),
            fromdate=datetime.datetime(2000, 1, 1),
            todate=datetime.datetime(2001, 2, 28),
            reverse=False,
        )
        cerebro.adddata(data)

    cerebro.addanalyzer(bt.analyzers.SharpeRatio)
    cerebro.run()
    b = backtrader_plotting.Bokeh(style='bar', scheme=Tradimo(), output_mode='memory')
    return cerebro.plot(b)

if __name__ == '__main__':
    cerebro = bt.Cerebro(maxcpus=1)

    data = bt.feeds.YahooFinanceCSVData(
        dataname="datas/orcl-1995-2014.txt",
        fromdate=datetime.datetime(2000, 1, 1),
        todate=datetime.datetime(2001, 2, 28),
    )
    cerebro.adddata(data)
    cerebro.addanalyzer(bt.analyzers.TradeAnalyzer)

    cerebro.optstrategy(MyStrategy, buydate=range(40, 180, 30))

    optres = cerebro.run(optreturn=False)

    def benchmark(optresults):
        a = [x.analyzers.tradeanalyzer.get_analysis() for x in optresults]
        return sum([x.pnl.gross.total if 'pnl' in x else 0 for x in a])

    result = [
        OrderedOptResult.BenchmarkedResult(benchmark(x), x) for x in optres
    ]
    ordered_result = sorted(result, key=lambda x: x.benchmark, reverse=True)

    ordered_result = OrderedOptResult("Profit & Losss", ordered_result)

    b = Bokeh(style='bar', plot_mode="single", scheme=Tradimo())
    b.plot_result(ordered_result)
示例#11
0
    cerebro.addstrategy(TestStrategy)

    # Create a data feed
    data = bt.feeds.YahooFinanceData(dataname='MSFT',
                                     fromdate=datetime.datetime(2019, 1, 1),
                                     todate=datetime.datetime(2019, 12, 31))

    # Add the Data Feed to Cerebro
    cerebro.adddata(data)

    # Set our desired cash start
    cerebro.broker.setcash(1000.0)

    # Add a FixedSize sizer according to the stake
    cerebro.addsizer(bt.sizers.FixedSize, stake=10)

    # Set the commission
    cerebro.broker.setcommission(commission=0.0)

    # Print out the starting conditions
    #print('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue())

    # Run over everything
    cerebro.run()

    # Print out the final result
    #print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())

    # Plot the result
    b = Bokeh(style='bar', tabs='multi', scheme=Tradimo())
    cerebro.plot(b)
示例#12
0
        bt.indicators.Ichimoku()

    def next(self):
        pos = len(self.data)
        if pos == 45 or pos == 145:
            self.buy(self.datas[0], size=None)

        if pos == 116 or pos == 215:
            self.sell(self.datas[0], size=None)


if __name__ == '__main__':
    cerebro = bt.Cerebro()

    cerebro.addstrategy(MyStrategy)

    data = bt.feeds.YahooFinanceCSVData(
        dataname="datas/orcl-1995-2014.txt",
        fromdate=datetime.datetime(2000, 1, 1),
        todate=datetime.datetime(2001, 2, 28),
        reverse=False,
        swapcloses=True,
    )
    cerebro.adddata(data)
    cerebro.addanalyzer(bt.analyzers.SharpeRatio)

    cerebro.run()

    b = Bokeh(style='bar', scheme=Tradimo())
    cerebro.plot(b)
示例#13
0
def perform_backtest(params, df, strategy, PandasData_Custom, bokeh=False):

    curr_result = {}
    curr_result = params

    data = PandasData_Custom(dataname=df)
    cerebro = bt.Cerebro()

    cerebro.adddata(data)
    cerebro.addstrategy(strategy, parameters=params)

    cerebro.addanalyzer(bt.analyzers.SharpeRatio,
                        riskfreerate=0.0,
                        annualize=True,
                        timeframe=bt.TimeFrame.Days)
    cerebro.addanalyzer(bt.analyzers.Calmar)
    cerebro.addanalyzer(bt.analyzers.DrawDown)
    cerebro.addanalyzer(bt.analyzers.Returns)
    cerebro.addanalyzer(bt.analyzers.TradeAnalyzer)

    initial_cash = 1000
    cerebro.broker = bt.brokers.BackBroker(
        cash=initial_cash,
        slip_perc=0.01 / 100,
        commission=CommInfoFractional(commission=(0.075 * params['mult']) /
                                      100,
                                      mult=params['mult']),
        slip_open=True,
        slip_out=True)  # 0.5%

    run = cerebro.run()

    all_logs = run[0].get_logs()
    portfolio = all_logs[0]
    trades = all_logs[1]
    operations = all_logs[2]

    trades_analysis = trades.merge(operations, on='Date', how='left')
    trades_analysis = trades_analysis.fillna(method='bfill')
    trades_analysis['Date'] = pd.to_datetime(trades_analysis['Date'])
    trades_analysis['Date'] = trades_analysis['Date'] - timedelta(minutes=10)

    analysis = run[0].analyzers.getbyname('tradeanalyzer').get_analysis()

    try:
        curr_result['Total Trades'] = analysis['total']['total']
    except:
        curr_result['Total Trades'] = 0

    try:
        curr_result['Total Profit'] = analysis['won']['total']
        curr_result['Avg Profit'] = analysis['won']['pnl']['average']
    except:
        curr_result['Total Profit'] = 0
        curr_result['Avg Profit'] = 0

    try:
        curr_result['Total Loss'] = analysis['lost']['total']
        curr_result['Average Loss'] = analysis['lost']['pnl']['average']
    except:
        curr_result['Total Loss'] = 0
        curr_result['Average Loss'] = 0

    try:
        curr_result['Total Long'] = analysis['long']['total']
        curr_result['Average Long'] = analysis['long']['pnl']['average']
    except:
        curr_result['Total Long'] = 0
        curr_result['Average Long'] = 0

    try:
        curr_result['Total Short'] = analysis['short']['total']
        curr_result['Average Short'] = analysis['short']['pnl']['average']
    except:
        curr_result['Total Short'] = 0
        curr_result['Average Short'] = 0

    curr_result['Return (%)'] = round(
        ((portfolio['Value'].iloc[-1] - portfolio['Value'].iloc[0]) /
         portfolio['Value'].iloc[0]) * 100, 2)
    curr_result['sharpe'] = run[0].analyzers.getbyname(
        'sharperatio').get_analysis()['sharperatio']

    portfolio['Date'] = pd.to_datetime(portfolio['Date'])
    portfolio = portfolio.set_index('Date')

    daily_portfolio = portfolio.resample('1D').agg(
        {'Value': lambda x: x.iloc[-1]})

    if bokeh == True:
        b = Bokeh(style='bar', plot_mode='single', scheme=Tradimo())
        fig = cerebro.plot(b)

        s_fig = fig[0][0]

        bokeh_html = file_html(s_fig.model, CDN, "Backtest Plot")

        if not os.path.isdir("bokeh/"):
            os.makedirs("bokeh/")

        fname = secrets.token_hex(3) + ".html"

        with open('bokeh/{}'.format(fname), 'w') as file:
            file.write(bokeh_html)

        return fname

    return curr_result
def bt_run(strat_p_list,df):
    
    # Create a cerebro entity
    try:
        
        cerebro = bt.Cerebro(tradehistory=True)
        cerebro.addanalyzer(bt.analyzers.cmtrans.cmTrans)
        # cerebro.addwriter(bt.WriterFile, out = 'test.csv', csv=True, rounding=5)
        
        data_table_id = strat_p_list[0]
        scrip_code = strat_p_list[1]
        strategy = strat_p_list[2]
        trade_size = strat_p_list[3]
        start_cash = strat_p_list[4]
        
        ex,m_t,t_f = su.parameters_from_data_table_id(data_table_id)
        
        # Get Class from strategy Name
        module = importlib.import_module('spe.strategies.'+strategy)
        class_name = strategy
        strategy = getattr(module, class_name)
        
        # Add a strategy
        cerebro.addstrategy(strategy,trade_size=trade_size)
        
        # Minimum datalength
        min_data = strategy.candle_lb()
        
        # Add the Data Feed to Cerebro
        # Returns Cerebro riteith datafeed attached
        cerebro_w_data = dh.data_feed(scrip_code,ex,m_t,t_f,cerebro,min_data)
        
        if cerebro_w_data is None:
            print('No Data Available')
            return []
        
        # Set our desired cash start
        cerebro_w_data.broker.setcash(start_cash)     
    
        # Set the commission - 0.1% ... divide by 100 to remove the %
        cerebro_w_data.broker.setcommission(commission=0.000)
        
        # cerebro_w_data.addanalyzer(bt.analyzers.TradeAnalyzer, _name="stats")
        # cerebro_w_data.addanalyzer(bt.analyzers.PositionsValue, _name="an_return")
        cerebro_w_data.addanalyzer(bt.analyzers.Returns)
        # cerebro_w_data.addanalyzer(bt.analyzers.PyFolio)
        
        # Print out the starting conditions
#        print('Starting Portfolio Value: %.2f' % cerebro_w_data.broker.getvalue())
    
        # Run over everything
        strategy = cerebro_w_data.run()
        b = Bokeh(style='bar', plot_mode='single', scheme=Tradimo())
        # cerebro_w_data.plot(b)
        Strat = strategy[0]
        # Print out the final result
#        print('Final Portfolio Value: %.2f' % cerebro_w_data.broker.getvalue())
    
        # Strat.analyzers.stats.print()
        # Strat.analyzers.an_return.print()
#        print(f"Norm. Annual Return: {Strat.analyzers.returns.get_analysis()['rnorm100']:.2f}%")
        # pyfolizer = Strat.analyzers.getbyname('pyfolio')
        # returns, positions, transactions, gross_lev = pyfolizer.get_pf_items()
        # pf.create_returns_tear_sheet(returns)
        
        df = backtest_out(Strat,df)
        
        return Strat,df

    except Exception as e:
        # err.error_log(str(e),bt_run.__name__,'bt_run')
        logging.exception(str(e))
import backtrader
from strategies.strategies import TestStrategy
import pandas as pd
from backtrader_plotting import Bokeh
from backtrader_plotting.schemes import Tradimo
#pip3 install backtrader_plotting
#import matplotlib.pyplot as plt

plotconfig = {
    'id:ind#0': dict(subplot=True, ),
}
b = Bokeh(style='bar',
          plot_mode='single',
          scheme=Tradimo(),
          plotconfig=plotconfig)


def create_stock_sp500_ratio_csv(stockName):
    datapath = (rf'Data\{stockName}.csv')
    dataframeStock = pd.read_csv(datapath)
    datapath = (rf'Data\SPY.csv')
    dataframeSPY = pd.read_csv(datapath)
    #crate copy
    df = dataframeSPY.copy()
    for i in range(df.shape[0]):  # gives number of row count
        # df['Date'].iloc[i]-=dataframeStock['Date'].iloc[i]
        df['Open'].iloc[i] -= dataframeStock['Open'].iloc[i]
        df['High'].iloc[i] -= -dataframeStock['High'].iloc[i]
        df['Low'].iloc[i] -= dataframeStock['Low'].iloc[i]
        df['Close'].iloc[i] -= dataframeStock['Close'].iloc[i]
        df['Volume'].iloc[i] -= dataframeStock['Volume'].iloc[i]
示例#16
0
print('最大回撤DW:', results[0].analyzers.DrawDown.get_analysis())

# 选取一只股票进行回测
cerebro2 = bt.Cerebro()
baseline = '000300.SH'
feed = bt.feeds.PandasData(dataname=get_data(baseline))
cerebro2.adddata(feed, name=baseline)
cerebro2.broker.get_notification()
# 回测设置
cerebro2.broker.setcash(startcash)
#  设置佣金为千分之一
cerebro2.broker.setcommission(commission=0.001)
#  添加策略
cerebro2.addstrategy(BaseStrategy, printlog=True)
results2 = cerebro2.run()
# 获取回测结束后的总资金
portvalue2 = cerebro2.broker.getvalue()
pnl2 = portvalue2 - startcash

# 打印结果
print(f'沪深300 总资金: {round(portvalue2, 2)}')
print(f'沪深300 净收益: {round(pnl2, 2)}')
print('沪深300Final Portfolio Value: %.2f' % cerebro2.broker.getvalue())

# 绘制图像
b = Bokeh(style='bar', plot_mode='multi', scheme=Tradimo())

# cerebro.plot(b)
# cerebro.plot()
plot_result(results, results2, s)
示例#17
0
def perform_backtest(symbol_par,
                     n_fast_par,
                     n_slow_par,
                     long_macd_threshold_par,
                     long_per_threshold_par,
                     long_close_threshold_par,
                     short_macd_threshold_par,
                     short_per_threshold_par,
                     short_close_threshold_par,
                     initial_cash=10000,
                     comission=0.1,
                     df=None):
    '''
    Parameter:
    __________

    symbol_par (string):
    The symbol to use

    n_fast_par (int):
    Fast EMA line used during MACD calculation

    n_slow_par (int):
    Slower EMA line used during MACD calculation

    long_macd_threshold_par (int):
    The threshold of normalized macd, above which we might open a long position

    long_per_threshold_par (int):
    The value of percentage change over the last 2 hours above which we might open a long position
    #Might make this a parameter too

    long_close_threshold_par (int):
    Threshold of normalized macd, below which we will close the opened long position

    short_macd_threshold_par (int):
    The threshold of normalized macd, below which we might open a short position

    short_per_threshold_par (int):
    The value of percentage change over the last 2 hours below which we might open a short position

    short_close_threshold_par (int):
    Threshold of normalized macd, above which we will close the opened short position

    initial_cash (int) (optional):
    The cash to start from. Initiall 10k

    comission (int) (option):
    int fraction value. Defaults to 0.1%. This is much higher than normal. Staying on the safe side.

    df (Dataframe) (option):
    Uses df as features dataframe if specified. Otherwise reads the coin folder
    
    '''
    global n_fast
    global n_slow

    global long_macd_threshold
    global long_per_threshold
    global long_close_threshold
    global short_macd_threshold
    global short_per_threshold
    global short_close_threshold
    global symbol

    n_fast = n_fast_par
    n_slow = n_slow_par

    long_macd_threshold = long_macd_threshold_par
    long_per_threshold = long_per_threshold_par
    long_close_threshold = long_close_threshold_par
    short_macd_threshold = short_macd_threshold_par
    short_per_threshold = short_per_threshold_par
    short_close_threshold = short_close_threshold_par
    symbol = symbol_par

    json_info = {}
    json_info['n_fast'] = n_fast
    json_info['n_slow'] = n_slow
    json_info['long_macd_threshold'] = long_macd_threshold_par
    json_info['long_per_threshold'] = long_per_threshold_par
    json_info['long_close_threshold'] = long_close_threshold_par
    json_info['short_macd_threshold'] = short_macd_threshold_par
    json_info['short_per_threshold'] = short_per_threshold_par
    json_info['short_close_threshold'] = short_close_threshold_par
    json_info['initial_cash'] = initial_cash
    json_info['comission'] = comission

    with open(get_root_dir() + "/data/parameters.json", 'w') as f:
        json.dump(json_info, f)

    features_file = get_root_dir() + "/data/features/{}.csv".format(symbol)

    if df is None:
        df = pd.read_csv(features_file)

    df['macd'] = ta.trend.macd(df['sentistrength_total'],
                               n_fast=n_fast,
                               n_slow=n_slow,
                               fillna=True)
    df['macd'] = df['macd'].fillna(0)

    df['Time'] = pd.to_datetime(df['Time'])

    json_data = {}

    json_data['mean'] = df['macd'].mean()
    json_data['std'] = df['macd'].std()

    df['macd'] = (df['macd'] - json_data['mean']) / json_data['std']

    df = df.dropna(subset=['Time'])

    curr_dir = get_root_dir() + "/data/backtest/{}".format(symbol)

    if not os.path.exists(curr_dir):
        os.makedirs(curr_dir)

    fig = create_plot(df, 'macd', 'SentiStength')

    plotly_json = fig.to_json()

    html = fig.to_html()

    with open(curr_dir + '/plotly.html', 'w') as file:
        file.write(html)

    with open(curr_dir + '/plotly.json', 'w') as file:
        file.write(plotly_json)

    df = df[['Time', 'Open', 'High', 'Low', 'Close', 'Volume', 'macd']]
    df.to_csv(os.path.join(curr_dir, "data.csv"), index=None)

    data = PandasData_Custom(dataname=df)
    cerebro = bt.Cerebro(cheat_on_open=True, maxcpus=None)
    cerebro.adddata(data)

    cerebro.addstrategy(tradeStrategy)

    cerebro.addanalyzer(bt.analyzers.SharpeRatio_A)
    cerebro.addanalyzer(bt.analyzers.Calmar)
    cerebro.addanalyzer(bt.analyzers.DrawDown)
    cerebro.addanalyzer(bt.analyzers.Returns)
    cerebro.addanalyzer(bt.analyzers.TradeAnalyzer)

    cerebro.broker.setcash(initial_cash)
    cerebro.broker.setcommission(comission / 100)

    run = cerebro.run()

    analysis = run[0].analyzers.getbyname('tradeanalyzer').get_analysis()

    trade_analyzer = {}
    trade_analyzer['total'] = analysis['total']['total']
    trade_analyzer['open'] = analysis['total']['open']
    trade_analyzer['closed'] = analysis['total']['closed']

    with open(curr_dir + "/stats.json", 'w') as f:
        json.dump(trade_analyzer, f)

    portfolioValue, trades, operations = run[0].get_logs()

    # fig = cerebro.plot()
    # figure = fig[0][0]
    # figure.savefig(curr_dir + "/backtest.png")

    output_file(curr_dir + "/backtest.html")
    b = Bokeh(style='bar', plot_mode="tabs", scheme=Tradimo())
    b.plot_result(run)

    df = df.set_index('Time')
    df = df.resample('1D').apply(resampler)
    df = df.reset_index()
    df = df[['Time', 'Open']].merge(portfolioValue,
                                    left_on='Time',
                                    right_on='Date').drop('Time', axis=1)
    df['hodl'] = (initial_cash / df['Open'].iloc[0]) * df['Open']
    df = df.drop('Open', axis=1)

    df.to_csv(curr_dir + '/portfolio.csv', index=None)
    trades.to_csv(curr_dir + '/trades.csv', index=None)
    operations.to_csv(curr_dir + '/operations.csv', index=None)

    with open(os.path.join(curr_dir, "data.json"), 'w') as fp:
        json.dump(json_data, fp)