from __future__ import (absolute_import, division, print_function,
                        unicode_literals)
                        
import os
import datetime

import backtrader as bt
import pandas as pd
from matplotlib import pyplot as plt

from S1_task1 import *
obj = CryptoCompare('BTC', 'USDT', 'binance')
obj.download_histohour('2020-01-01', '2020-04-01')

# declear all environment params / global variables
datadir = 'E:\Yiru Xiong-Professional\实习\CryptoAlgoWheel\Month1\S2\data'  # data path
logdir = 'E:\Yiru Xiong-Professional\实习\CryptoAlgoWheel\Month1\S2\log'  # log path
reportdir = 'E:\Yiru Xiong-Professional\实习\CryptoAlgoWheel\Month1\S2\\report'  # report path
datafile = 'BTC_USDT_1h.csv'  # data file
from_datetime = '2020-01-01 00:00:00'  # start time
to_datetime = '2020-04-01 00:00:00'  # end time
logfile = 'BTC_USDT_1h_SMACross_10_20_2020-01-01_2020-04-01.csv'
figfile = 'BTC_USDT_1h_SMACross_10_20_2020-01-01_2020-04-01.png'

# define strategy class
class SMACross(bt.Strategy):

    params = (
        ('pfast', 10),
        ('pslow', 20),
    )

    def log(self, txt, dt=None):
        ''' Logging function fot this strategy'''
        dt = dt or self.datas[0].datetime.date(0)
        print('%s, %s' % (dt.isoformat(), txt))

    def __init__(self):
        # Keep a reference to the "close" line in the data[0] dataseries
        self.dataclose = self.datas[0].close

        # To keep track of pending orders and buy price/commission
        self.order = None
        self.buyprice = None
        self.buycomm = None

        # Add a MovingAverageSimple indicator
        self.smafast = bt.indicators.SMA(
            self.datas[0], period=self.p.pfast)
        self.smaslow = bt.indicators.SMA(
            self.datas[0], period=self.p.pslow)

    def notify_order(self, order):
        if order.status in [order.Submitted, order.Accepted]:
            # Buy/Sell order submitted/accepted to/by broker - Nothing to do
            return

        # Check if an order has been completed
        # Attention: broker could reject order if not enough cash
        if order.status in [order.Completed]:
            if order.isbuy():
                self.log(
                    'BUY EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' %
                    (order.executed.price,
                     order.executed.value,
                     order.executed.comm))

                self.buyprice = order.executed.price
                self.buycomm = order.executed.comm
            else:  # Sell
                self.log('SELL EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' %
                         (order.executed.price,
                          order.executed.value,
                          order.executed.comm))

            self.bar_executed = len(self)

        elif order.status in [order.Canceled, order.Margin, order.Rejected]:
            self.log('Order Canceled/Margin/Rejected')

        # Write down: no pending order
        self.order = None

    def notify_trade(self, trade):
        if not trade.isclosed:
            return

        self.log('OPERATION PROFIT, GROSS %.2f, NET %.2f' %
                 (trade.pnl, trade.pnlcomm))

    def next(self):
        self.log('Close, %.2f' % self.dataclose[0])
        if self.order:
            return

        # Check if we are in the market
        if not self.position:

            # Not yet ... we MIGHT BUY if ...
            if self.smafast[0] > self.smaslow[0]:
                self.log('BUY CREATE, %.2f' % self.dataclose[0])
                self.order = self.buy()

        else:

            if self.smafast[0] < self.smaslow[0]:
                self.log('SELL CREATE, %.2f' % self.dataclose[0])
                self.order = self.sell()


if __name__ == '__main__':

    # initiate cerebro instance:
    cerebro = bt.Cerebro()

    # feed data:
    data = pd.read_csv(os.path.join(datadir, datafile),
                       index_col='datetime', parse_dates=True)
    data = data.loc[
        (data.index >= pd.to_datetime(from_datetime)) &
        (data.index <= pd.to_datetime(to_datetime))]
    datafeed = bt.feeds.PandasData(dataname=data)
    cerebro.adddata(datafeed)

    # feed strategy:
    cerebro.addstrategy(SMACross)

    # additional backtest setting:
    cerebro.addsizer(bt.sizers.FixedSize, stake=10)
    cerebro.broker.setcash(1000)
    cerebro.broker.setcommission(commission=0.0)

    # add logger:
    cerebro.addwriter(
        bt.WriterFile,
        out=os.path.join(logdir, logfile),
        csv=True)

    # run:
    cerebro.run()

    print(cerebro.strats[0][0][0])
    print(cerebro.strats[0][0][0].params.__dict__)

    # save report:
    plt.rcParams['figure.figsize'] = [13.8, 10]
    fig = cerebro.plot(style='candlestick', barup='green', bardown='red')
    fig[0][0].savefig(
        os.path.join(reportdir, figfile),
        dpi=480)
