Robot-Wealth / rsims

R package for financial simulation
Other
38 stars 15 forks source link

Differing Ave.Ann.Turnover using fixed or minimum commission backtest #11

Closed Thie1e closed 2 years ago

Thie1e commented 2 years ago

Hi Kris,

I have noticed that the backtest functions fixed_commission_backtest and min_commission_backtest lead to different estimates of the average annual turnover.

For the below example, I have set costs to zero and use the same data. So I would expect the average annual turnover to be identical. However, also with other periods of my data, the turnover estimation from the min_commission_backtest is always about 1.5 times as high as the one from fixed_commission_backtest.

As reported in another issue, I had to tamper a bit with the column names that are returned by fixed_commission_backtest to make the downstream functions work, but I am not sure if this is the problem here. I have attached the necessary data.

library(rsims)
library(tidyverse)

# contains closeprices_test, closeprices_unadj_test, and sizes_test
load("reprexdat.RData")

initial_equity <- 2e5
bt_rsims_fixed <- fixed_commission_backtest(
  prices = as.matrix(closeprices_test),
  theo_weights = as.matrix(sizes_test),
  capitalise_profits = T,
  trade_buffer = 0.004,
  initial_cash = initial_equity,
  commission_pct = 0
)

bt_rsims_min <- min_commission_backtest(
  prices = as.matrix(closeprices_test),
  unadjusted_prices = as.matrix(closeprices_unadj_test),
  target_weights = as.matrix(sizes_test),
  trade_buffer = 0.004,
  capitalise_profits = T,
  commission_fun = us_tiered_commission,
  max_pct_per_order = 0,
  min_dollars_per_order = 0,
  dollars_per_share = 0,
  initial_cash = initial_equity
)

# Have to fix column names for fixed_commission_backtest:
colnames(bt_rsims_fixed) <- tolower(colnames(bt_rsims_fixed))
bt_rsims_fixed$exposure <- bt_rsims_fixed$value

summary_performance(bt_rsims_fixed %>%
                      rename(trade_value = tradevalue),
                    initial_equity = initial_equity) %>%
  glimpse()

# Rows: 1
# Columns: 6
# $ `Ann.Return(%)`       <dbl> 26.3488
# $ `Ann.Volatility(%)`   <dbl> 12.46426
# $ Ann.Sharpe            <dbl> 2.113948
# $ `Ave.Ann.Turnover(%)` <dbl> 70.88472
# $ `Tot.Profit($)`       <dbl> 179691.8
# $ `Costs(%Profit)`      <dbl> 0

summary_performance(bt_rsims_min,
                    initial_equity = initial_equity) %>%
  glimpse()

# Rows: 1
# Columns: 6
# $ `Ann.Return(%)`       <dbl> 27.98645
# $ `Ann.Volatility(%)`   <dbl> 12.94524
# $ Ann.Sharpe            <dbl> 2.16191
# $ `Ave.Ann.Turnover(%)` <dbl> 106.4369
# $ `Tot.Profit($)`       <dbl> 194991.5
# $ `Costs(%Profit)`      <dbl> 0

Thanks again!

reprexdat.zip

Thie1e commented 2 years ago

I just realized that with trade_buffer = 0 the average annual turnovers from the two functions are very similar. They only differ if a trade buffer is set.

Thie1e commented 2 years ago

Sorry, now I understood that the behavior of trade_buffer changes depending on the commission model. This does not seem to be explained in the help files, only in the readme on Github. But I got it now.