def __init__(self,
              data_mgr: DataManager = DataManager(),
              calendars: Union[str, Tuple[str, ...]] = 'Weekend',
              tz: timezone = timezone('America/New_York'),
              valuation_method: ValuationMethod = ValuationMethod(ValuationFixingType.PRICE),
              action_impl_map=None):
     if action_impl_map is None:
         action_impl_map = {Action: SubmitOrderActionImpl}
     self.action_impl_map = action_impl_map
     self.calendars = calendars
     self.tz = tz
     self.data_handler = DataHandler(data_mgr, tz=tz)
     self.valuation_method = valuation_method
     self.execution_engine = None
def test_backtest_predefined_timezone_aware():
    tz = 'Europe/London'
    start_dt = '2021-01-01T08:00'
    end_dt = '2021-12-31T17:00'

    states = pd.bdate_range(start_dt, end_dt,
                            freq='1H', tz=tz).to_series().between_time(
                                '08:00', '17:00').index.tolist()
    trigger_dates = pd.bdate_range(
        start_dt, end_dt, freq='1H',
        tz=tz).to_series().at_time('17:00').index.tolist()
    data = np.random.randn(len(states))
    s_rt = pd.Series(index=states, data=data)
    s_eod = s_rt.at_time('17:00')
    s_eod.index = s_eod.index.date

    generic_bond_future = IRBondFuture(currency='EUR')
    add_trade_action = AddTradeAction(generic_bond_future)
    simple_date_trigger_requirement = DateTriggerRequirements(
        dates=trigger_dates)
    simple_date_trigger = DateTrigger(
        trigger_requirements=simple_date_trigger_requirement,
        actions=[add_trade_action])

    data_manager = DataManager()
    data_manager.add_data_source(pd.Series(index=states, data=data),
                                 DataFrequency.REAL_TIME, generic_bond_future,
                                 ValuationFixingType.PRICE)
    data_manager.add_data_source(s_eod, DataFrequency.DAILY,
                                 generic_bond_future,
                                 ValuationFixingType.PRICE)

    # instantiate a new strategy
    strategy = Strategy(None, triggers=simple_date_trigger)

    engine = PredefinedAssetEngine(data_mgr=data_manager,
                                   tz=timezone(tz),
                                   calendars='Weekend')
    backtest = engine.run_backtest(strategy=strategy,
                                   start=states[0],
                                   end=states[-1],
                                   states=states)
    assert len(backtest.trade_ledger()) == 364
def test_backtest_predefined():
    # Test simple MOC order
    trigger = ExampleTestTrigger()
    strategy = Strategy(initial_portfolio=None, triggers=[trigger])
    start = dt.date(2021, 1, 4)
    mid = dt.date(2021, 1, 5)
    end = dt.date(2021, 1, 6)

    # these mocks are needed as the date functions need a GSSession
    gs_quant.backtests.predefined_asset_engine.is_business_day = mock.Mock(
        return_value=True)
    gs_quant.backtests.predefined_asset_engine.business_day_offset = mock.Mock(
        return_value=mid)

    data_mgr = DataManager()
    underlying = Security(ric='TestRic')
    close_prices = pd.Series(dtype=float)
    close_prices[start] = 1
    close_prices[mid] = 1.5
    close_prices[end] = 2
    data_mgr.add_data_source(close_prices, DataFrequency.DAILY, underlying,
                             ValuationFixingType.PRICE)

    engine = PredefinedAssetEngine(data_mgr=data_mgr)

    backtest = engine.run_backtest(strategy, start=start, end=end)
    perf = backtest.performance
    holdings = backtest.historical_holdings
    cash_asset = backtest.cash_asset

    # 100 on the initial date
    assert perf[start] == 100
    # 100 on the next day as we traded MOC
    assert perf[mid] == 100
    assert holdings[mid][cash_asset] == 100 - 1.5
    assert holdings[mid][underlying] == 1
    # 100.5 = 98.5 (cash) + 2 ( test asset)
    assert holdings[end][cash_asset] == 100 - 1.5
    assert holdings[end][underlying] == 1
    assert perf[end] == 100.5

    # Test TWAP orders with no ON positions
    twap_entry_mid = 16
    twap_exit_mid = 25

    twap_entry_end = 30
    twap_exit_end = 40

    data_twap = {
        dt.datetime.combine(mid, dt.time(10, 30)): twap_entry_mid,
        dt.datetime.combine(mid, dt.time(14, 30)): twap_exit_mid,
        dt.datetime.combine(end, dt.time(10, 30)): twap_entry_end,
        dt.datetime.combine(end, dt.time(14, 30)): twap_exit_end
    }

    data_mgr.add_data_source(pd.Series(data_twap), DataFrequency.REAL_TIME,
                             underlying, ValuationFixingType.PRICE)
    trigger = FuturesExample()
    strategy = Strategy(initial_portfolio=None, triggers=[trigger])
    engine = PredefinedAssetEngine(data_mgr=data_mgr,
                                   tz=timezone('Europe/London'))
    backtest = engine.run_backtest(strategy, start=start, end=end)
    perf = backtest.performance
    holdings = backtest.historical_holdings
    weights = backtest.historical_weights
    cash_asset = backtest.cash_asset

    # start: 100
    assert perf[start] == 100
    # mid: 100 + (twap_exit - twap_entry)
    assert perf[mid] == 100 - twap_entry_mid + twap_exit_mid
    assert holdings[mid][cash_asset] == perf[mid]
    assert underlying not in holdings[mid]
    assert weights[mid][cash_asset] == 1
    assert underlying not in weights[mid]
    # 100.5 = 98.5 (cash) + 2 ( test asset)
    assert perf[
        end] == 100 - twap_entry_mid + twap_exit_mid - twap_entry_end + twap_exit_end
    assert holdings[end][cash_asset] == perf[end]
    assert underlying not in holdings[end]
    assert weights[end][cash_asset] == 1
    assert underlying not in weights[end]