__author__ = 'saeedamen'

#
# Copyright 2016 Cuemacro
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the
# License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
# See the License for the specific language governing permissions and limitations under the License.
#

"""
TradingModelFXCTA

Shows how to create a simple FX CTA style strategy, using the StrategyTemplate abstract class (backtest_examples.py
is a lower level way of doing this). Uses BBG total returns data.

"""

import datetime

from findatapy.market import Market, MarketDataGenerator, MarketDataRequest
from finmarketpy.backtest import TradingModel, BacktestRequest
from finmarketpy.economics import TechIndicator

class TradingModelFXTrend_BBG_Example(TradingModel):

    def __init__(self):
        super(TradingModel, self).__init__()

        ##### FILL IN WITH YOUR OWN PARAMETERS FOR display, dumping, TSF etc.
        self.market = Market(market_data_generator=MarketDataGenerator())
        self.DUMP_PATH = ''
        self.FINAL_STRATEGY = 'FX trend'
        self.SCALE_FACTOR = 1
        self.DEFAULT_PLOT_ENGINE = 'matplotlib'

        self.br = self.load_parameters()
        return

    ###### Parameters and signal generations (need to be customised for every model)
    def load_parameters(self, br = None):
        if br is not None: return br

        ##### FILL IN WITH YOUR OWN BACKTESTING PARAMETERS
        br = BacktestRequest()

        # get all asset data
        br.start_date = "04 Jan 1989"
        br.finish_date = datetime.datetime.utcnow().date()
        br.spot_tc_bp = 0.5
        br.ann_factor = 252

        br.plot_start = "01 Apr 2015"
        br.calc_stats = True
        br.write_csv = False
        br.plot_interim = True
        br.include_benchmark = True

        # have vol target for each signal
        br.signal_vol_adjust = True
        br.signal_vol_target = 0.1
        br.signal_vol_max_leverage = 5
        br.signal_vol_periods = 20
        br.signal_vol_obs_in_year = 252
        br.signal_vol_rebalance_freq = 'BM'
        br.signal_vol_resample_freq = None

        # have vol target for portfolio
        br.portfolio_vol_adjust = True
        br.portfolio_vol_target = 0.1
        br.portfolio_vol_max_leverage = 5
        br.portfolio_vol_periods = 20
        br.portfolio_vol_obs_in_year = 252
        br.portfolio_vol_rebalance_freq = 'BM'
        br.portfolio_vol_resample_freq = None

        # tech params
        br.tech_params.sma_period = 200

        return br

    def load_assets(self, br = None):
        ##### FILL IN WITH YOUR ASSET DATA
        from findatapy.util.loggermanager import  LoggerManager
        logger = LoggerManager().getLogger(__name__)

        # for FX basket
        full_bkt    = ['EURUSD', 'USDJPY', 'GBPUSD', 'AUDUSD', 'USDCAD',
                       'NZDUSD', 'USDCHF', 'USDNOK', 'USDSEK']

        basket_dict = {}

        for i in range(0, len(full_bkt)):
            basket_dict[full_bkt[i]] = [full_bkt[i]]

        basket_dict['FX trend'] = full_bkt

        br = self.load_parameters(br = br)

        logger.info("Loading asset data...")

        vendor_tickers = [x + 'CR CMPN Curncy' for x in full_bkt]

        market_data_request = MarketDataRequest(
                    start_date = br.start_date,                     # start date
                    finish_date = br.finish_date,                   # finish date
                    freq = 'daily',                                 # daily data
                    data_source = 'bloomberg',                      # use Quandl as data source
                    tickers = full_bkt,                             # ticker (Cuemacro)
                    fields = ['close'],                             # which fields to download
                    vendor_tickers = vendor_tickers,                # ticker (Quandl)
                    vendor_fields = ['PX_LAST'],                    # which Bloomberg fields to download
                    cache_algo = 'internet_load_return')            # how to return data

        asset_df = self.market.fetch_market(market_data_request)

        # if web connection fails read from CSV
        if asset_df is None:
            import pandas

            asset_df = pandas.read_csv("d:/fxcta.csv", index_col=0, parse_dates=['Date'],
                                       date_parser = lambda x: pandas.datetime.strptime(x, '%Y-%m-%d'))

        # signalling variables
        spot_df = asset_df
        spot_df2 = None

        # asset_df

        return asset_df, spot_df, spot_df2, basket_dict

    def construct_signal(self, spot_df, spot_df2, tech_params, br, run_in_parallel=False):

        ##### FILL IN WITH YOUR OWN SIGNALS

        # use technical indicator to create signals
        # (we could obviously create whatever function we wanted for generating the signal dataframe)
        tech_ind = TechIndicator()
        tech_ind.create_tech_ind(spot_df, 'SMA', tech_params); signal_df = tech_ind.get_signal()

        return signal_df

    def construct_strategy_benchmark(self):

        ###### FILL IN WITH YOUR OWN BENCHMARK

        tsr_indices = MarketDataRequest(
            start_date = self.br.start_date,                # start date
            finish_date = self.br.finish_date,              # finish date
            freq = 'daily',                                 # intraday data
            data_source = 'bloomberg',                      # use Bloomberg as data source
            tickers = ["EURUSD"],                           # tickers to download
            vendor_tickers=['EURUSDCR CMPN Curncy'],
            fields = ['close'],                             # which fields to download
            vendor_fields = ['PX_LAST'],
            cache_algo = 'internet_load_return')            # how to return data

        df = self.market.fetch_market(tsr_indices)

        df.columns = [x.split(".")[0] for x in df.columns]

        return df

if __name__ == '__main__':

# just change "False" to "True" to run any of the below examples

    # create a FX trend strategy then chart the returns, leverage over time
    if True:
        model = TradingModelFXTrend_BBG_Example()

        model.construct_strategy()

        model.plot_strategy_pnl()                        # plot the final strategy
        model.plot_strategy_leverage()                   # plot the leverage of the portfolio
        model.plot_strategy_group_pnl_trades()           # plot the individual trade P&Ls
        model.plot_strategy_group_benchmark_pnl()        # plot all the cumulative P&Ls of each component
        model.plot_strategy_group_benchmark_pnl_ir()     # plot all the IR of individual components
        model.plot_strategy_group_leverage()             # plot all the individual leverages

        from finmarketpy.backtest import TradeAnalysis

        ta = TradeAnalysis()

        # create statistics for the model returns using both finmarketpy and pyfolio
        ta.run_strategy_returns_stats(model, engine='finmarketpy')
        # ta.run_strategy_returns_stats(model, engine='pyfolio')

        # model.plot_strategy_group_benchmark_annualised_pnl()

    # create a FX CTA strategy, then examine how P&L changes with different vol targeting
    # and later transaction costs
    if True:
        strategy = TradingModelFXTrend_BBG_Example()

        from finmarketpy.backtest import TradeAnalysis

        ta = TradeAnalysis()
        ta.run_strategy_returns_stats(model, engine='finmarketpy')

        # which backtesting parameters to change
        # names of the portfolio
        # broad type of parameter name
        parameter_list = [
            {'portfolio_vol_adjust': True, 'signal_vol_adjust' : True},
            {'portfolio_vol_adjust': False, 'signal_vol_adjust' : False}]

        pretty_portfolio_names = \
            ['Vol target',
             'No vol target']

        parameter_type = 'vol target'

        ta.run_arbitrary_sensitivity(strategy,
                                     parameter_list=parameter_list,
                                     pretty_portfolio_names=pretty_portfolio_names,
                                     parameter_type=parameter_type)

        # now examine sensitivity to different transaction costs
        tc = [0, 0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2.0]
        ta.run_tc_shock(strategy, tc = tc)

        # how does P&L change on day of month
        ta.run_day_of_month_analysis(strategy)

    # create a FX CTA strategy then use TradeAnalysis (via pyfolio) to analyse returns
    if False:
        from finmarketpy.backtest import TradeAnalysis
        model = TradingModelFXTrend_BBG_Example()
        model.construct_strategy()

        tradeanalysis = TradeAnalysis()
        tradeanalysis.run_strategy_returns_stats(strategy)
