Whitelist portfolio simulation

In [25]:
from simple_back_test import *
import warnings
warnings.filterwarnings('ignore')
In [26]:
import pandas as pd
pd.core.common.is_list_like = pd.api.types.is_list_like
import numpy as np
from plotnine import *
import logging

logging.basicConfig(format='%(message)s', level=logging.DEBUG)
In [27]:
model_data = get_model_data()

Generate prices from predcted and actual streams

In [28]:
stream_prices = (generate_prices_for(model_data,
        artist_advance_fraction=0.8,
        payment_per_stream=5e-3,
        pop_5_slippage=0.15,          # Penalises both predicted and actual streams
        execution_slippage=0.1,       # Penalises only actual streams (How does it take to sign up the artist)
        clip_individual_returns=3))   # Clip extreme positive returns so they don't skew the results too much

Limit to our range

In [29]:
min_price = 5e3
max_price = 10e3
stream_prices = stream_prices >> mask(X.open_price >= min_price, X.open_price <= max_price)

Randomly generated events

We create a series of tracks drawn from the existing ones but distributed over the desired period with a specific number per day (on average). Note that this is with replacement so each track will be used several times

In [30]:
duration_days = 365       # How long is the simulated backtest period?
new_streams_per_date = 3  # How many artists can we sign per day
randomly_generated_events = generate_random_draws(stream_prices,
        new_streams_per_date=new_streams_per_date,
        duration_days=duration_days)

ggplot(randomly_generated_events, aes('open_date')) + geom_bar()
Out[30]:
<ggplot: (-9223363261488740152)>
In [ ]:
capital = 500e3
ps= execute_backtest(randomly_generated_events, capital) >> arrange('Date')
In [32]:
ps['Portfolio_return'] = ps['Portfolio_worth'].pct_change()
ps['Cumulative_portfolio_return'] = ps['Portfolio_worth']/ps['Portfolio_worth'][0] - 1
display(ps.tail())
portfolio_summary_stats = calculate_portfolio_summary_stats(ps)
display(portfolio_summary_stats)
Date day Positions Position_Size Cash Portfolio_worth Skipped tracks Portfolio_return Cumulative_portfolio_return
2018-04-06 2018-04-06 461 12 84725.776581 1.621207e+06 1.705932e+06 0 -0.001370 2.411865
2018-04-07 2018-04-07 462 11 79038.564543 1.640439e+06 1.719477e+06 0 0.007940 2.438955
2018-04-08 2018-04-08 463 5 36490.713060 1.714646e+06 1.751137e+06 0 0.018412 2.502273
2018-04-09 2018-04-09 464 3 23393.330882 1.729732e+06 1.753125e+06 0 0.001136 2.506250
2018-04-10 2018-04-10 465 0 0.000000 1.764668e+06 1.764668e+06 0 0.006584 2.529336
average_positions average_position_size average_portfolio_return portfolio_std cumulative_return max_drawdown sharpe annualised_ret annual_volatility sortino downside_risk tail_risk
0 101.075269 718059.079655 0.002752 0.007902 2.529336 -0.03364 5.528638 0.98068 0.125448 24.755389 0.028016 6.920876
In [33]:
chart_portfolio_stats(ps)
<ggplot: (8775444733483)>
<ggplot: (8775365863046)>
<ggplot: (8775370025578)>
<ggplot: (8775365895032)>