#pip install backtrader

import pandas as pd
import warnings
warnings.filterwarnings("ignore")
from __future__ import (absolute_import, division, print_function,
                        unicode_literals)

import datetime  # For datetime objects
import os.path  # To manage paths
import sys  # To find out the script name (in argv[0])

# Import the backtrader platform
import backtrader as bt
import time
# Create a Stratey
class TestStrategy(bt.Strategy):
    # paramMACD = (('period_me1', 12), ('period_me2', 26), ('period_signal', 9), ('movav', MovAv.Exponential),)
    # paramRSI = (('period', 14),('movav', MovAv.Smoothed),('upperband', 70.0),('lowerband', 30.0),('safediv', False),('safehigh', 100.0),('safelow', 50.0),('lookback', 1),)
    # params = (
    #     ('maperiod', 15),
    # )
    
    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))
        pass

    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

            
        self.macd = bt.indicators.MACD(self.datas[0])
        self.rsi = bt.indicators.RelativeStrengthIndex(self.datas[0])
    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')

        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
        try:
            if not self.position:
                    if (self.macd[0] > 0 and self.macd[1] < 0 and self.rsi[0] > 30 and self.rsi[1] < 30 ):
                        self.log('BUY CREATE, %.2f' % self.dataclose[0])
                        self.order = self.buy()
            else:
                    if (self.macd[0] < 0 and self.macd[1] > 0 and self.rsi[0] < 70 and self.rsi[1] > 70 ):
                        self.log('SELL CREATE, %.2f' % self.dataclose[0])
                        self.order = self.sell()
        except:
            pass

if __name__ == '__main__':
    # Create a cerebro entity
    ts_start = time.time()
    stocks  = pd.read_csv('C:/Users/yitian.yang/Desktop/backtrader-master/datas/mink_data.csv')
    stocka, stockb, stockc = stocks[stocks['symbol']=='AAAAAA.XSHG'], stocks[stocks['symbol']=='BBBBBB.XSHE'], stocks[stocks['symbol']=='CCCCCC.XSHE']
    for i,j in zip([stocka, stockb, stockc],['AAAAAA.XSHG','BBBBBB.XSHE','CCCCCC.XSHE']):
        i['close'] = i['open'].shift(1)
        i['Volume'] = 0
        i['OpenInterest'] = 0
        i = i[1:]
        i = i[['tradeTime','open','high','low','close','Volume','OpenInterest']]
        i.columns = ['Date', 'Open', 'High', 'Low', 'Close', 'Volume', 'OpenInterest']
        i.set_index('Date', inplace=True)
        i.index = pd.to_datetime(i.index)
        
        cerebro = bt.Cerebro()
        cerebro.addstrategy(TestStrategy)
        # Create a Data Feed
        data = bt.feeds.PandasData(dataname=i)
        # Add the Data Feed to Cerebro
        cerebro.adddata(data)
        # Set our desired cash start
        cerebro.broker.setcash(100000000.0)
        # Add a FixedSize sizer according to the stake
        cerebro.addsizer(bt.sizers.FixedSize, stake=10)
        # Set the commission
        cerebro.broker.setcommission(commission=0.00015)
        # 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())
        var_str_local = [name for name, value in locals().items() if value is i][0]
        print('Finished backtest:'+j)

    ts_end = time.time()
    print('Total time usage(second): %.2f' % (ts_end - ts_start))

#Total time usage(second): 25.20