In [1]:
__author__ = 'saeedamen'  # Saeed Amen

#
# 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.
#

"""
backtest

Gives several examples of backtesting simple trading strategies, using Backtest (a lower level class)

"""


Out[1]:
'\nbacktest\n\nGives several examples of backtesting simple trading strategies, using Backtest (a lower level class)\n\n'

In [2]:
# for backtest and loading data
from finmarketpy.backtest import BacktestRequest, Backtest
from findatapy.market import Market, MarketDataRequest, MarketDataGenerator
from findatapy.util.fxconv import FXConv

In [3]:
# for logging
from findatapy.util.loggermanager import LoggerManager

In [4]:
# for signal generation
from finmarketpy.economics import TechIndicator, TechParams

In [5]:
# for plotting
from chartpy import Chart, Style

In [ ]:
# housekeeping
logger = LoggerManager().getLogger(__name__)

import datetime

In [ ]:
# pick USD crosses in G10 FX
# note: we are calculating returns from spot (it is much better to use to total return
# indices for FX, which include carry)
logger.info("Loading asset data...")

tickers = ['EURUSD', 'USDJPY', 'GBPUSD', 'AUDUSD', 'USDCAD',
           'NZDUSD', 'USDCHF', 'USDNOK', 'USDSEK']

vendor_tickers = ['FRED/DEXUSEU', 'FRED/DEXJPUS', 'FRED/DEXUSUK', 'FRED/DEXUSAL', 'FRED/DEXCAUS',
                  'FRED/DEXUSNZ', 'FRED/DEXSZUS', 'FRED/DEXNOUS', 'FRED/DEXSDUS']

md_request = MarketDataRequest(
    start_date="01 Jan 1989",  # start date
    finish_date=datetime.date.today(),  # finish date
    freq='daily',  # daily data
    data_source='quandl',  # use Quandl as data source
    tickers=tickers,  # ticker (findatapy)
    fields=['close'],  # which fields to download
    vendor_tickers=vendor_tickers,  # ticker (Quandl)
    vendor_fields=['close'],  # which Bloomberg fields to download
    cache_algo='internet_load_return')  # how to return data

market = Market(market_data_generator=MarketDataGenerator())

asset_df = market.fetch_market(md_request)
spot_df = asset_df


2019-11-02 15:17:31,641 - __main__ - INFO - Loading asset data...
2019-11-02 15:17:32,265 - findatapy.market.datavendorweb - INFO - Request Quandl data
2019-11-02 15:17:32,266 - findatapy.market.datavendorweb - INFO - Request Quandl data2019-11-02 15:17:32,270 - findatapy.market.datavendorweb - INFO - Request Quandl data

2019-11-02 15:17:32,270 - findatapy.market.datavendorweb - INFO - Request Quandl data
2019-11-02 15:17:35,867 - findatapy.market.datavendorweb - INFO - Completed request from Quandl for ['EURUSD.close']
2019-11-02 15:17:36,000 - findatapy.market.datavendorweb - INFO - Request Quandl data
2019-11-02 15:17:37,908 - findatapy.market.datavendorweb - INFO - Completed request from Quandl for ['GBPUSD.close']
2019-11-02 15:17:38,078 - findatapy.market.datavendorweb - INFO - Request Quandl data
2019-11-02 15:17:38,120 - findatapy.market.datavendorweb - INFO - Completed request from Quandl for ['USDJPY.close']
2019-11-02 15:17:38,481 - findatapy.market.datavendorweb - INFO - Request Quandl data
2019-11-02 15:17:40,606 - findatapy.market.datavendorweb - INFO - Completed request from Quandl for ['AUDUSD.close']
2019-11-02 15:17:40,743 - findatapy.market.datavendorweb - INFO - Request Quandl data
2019-11-02 15:17:41,608 - findatapy.market.datavendorweb - INFO - Completed request from Quandl for ['USDCAD.close']
2019-11-02 15:17:41,696 - findatapy.market.datavendorweb - INFO - Request Quandl data
2019-11-02 15:17:42,674 - findatapy.market.datavendorweb - INFO - Completed request from Quandl for ['NZDUSD.close']

In [ ]:
backtest = Backtest()
br = BacktestRequest()
fxconv = FXConv()

# get all asset data
br.start_date = "02 Jan 1990"
br.finish_date = datetime.datetime.utcnow()
br.spot_tc_bp = 0  # 2.5 bps bid/ask spread
br.ann_factor = 252

# have vol target for each signal
br.signal_vol_adjust = True
br.signal_vol_target = 0.05
br.signal_vol_max_leverage = 3
br.signal_vol_periods = 60
br.signal_vol_obs_in_year = 252
br.signal_vol_rebalance_freq = 'BM'
br.signal_vol_resample_freq = None

tech_params = TechParams();
tech_params.bb_period = 200;
tech_params.bb_mult = 0.5 ;
indicator = 'BB'

logger.info("Running backtest...")

# 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, indicator, tech_params);
signal_df = tech_ind.get_signal()

contract_value_df = None

# use the same data for generating signals
backtest.calculate_trading_PnL(br, asset_df, signal_df, contract_value_df, run_in_parallel=False)
port = backtest.portfolio_cum()
port.columns = [indicator + ' = ' + str(tech_params.sma_period) + ' ' + str(backtest.portfolio_pnl_desc()[0])]
signals = backtest.portfolio_signal()

# print the last positions (we could also save as CSV etc.)
print(signals.tail(1))

In [ ]:
style = Style()
style.title = "FX trend strategy"
style.source = 'Quandl'
style.scale_factor = 1
style.file_output = 'fx-trend-example.png'

Chart().plot(port, style=style)