Skip to content

Instantly share code, notes, and snippets.

@robcarver17
Created January 9, 2026 16:51
Show Gist options
  • Select an option

  • Save robcarver17/c58b9e0f2d6b3ab077b01864849dc22f to your computer and use it in GitHub Desktop.

Select an option

Save robcarver17/c58b9e0f2d6b3ab077b01864849dc22f to your computer and use it in GitHub Desktop.
import datetime
import matplotlib.patches as mpatches
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from syscore.dateutils import SECONDS_IN_YEAR
from systems.provided.rob_system.run_system import futures_system
from private.projects.futures_book.generate_instrument_list import MASTER_INSTRUMENT_LIST
def calculate_synthetic_spot(system, instrument_code):
price = system.data.daily_prices(instrument_code)
cum_carry = calculate_cum_carry(system, instrument_code)
syn_spot = price - cum_carry
return syn_spot
def calculate_cum_carry(system, instrument_code):
price = system.data.daily_prices(instrument_code)
ann_carry = system.rawdata.daily_annualised_roll(instrument_code)
ann_carry_fitted = ann_carry.reindex(price.index, method="ffill")
diff_index_in_years_as_pd = pd_series_of_diff_index_in_years(ann_carry_fitted)
carry_per_period = diff_index_in_years_as_pd * ann_carry_fitted
cum_carry = carry_per_period.cumsum()
return cum_carry
def pd_series_of_diff_index_in_years(x: pd.Series):
diff_index_in_years = get_annual_intervals_from_series(x)
return pd.Series([0] + diff_index_in_years, x.index)
def get_annual_intervals_from_series(x: pd.Series):
diff_index = x[1:].index - x[:-1].index
diff_index_as_list = list(diff_index)
diff_index_in_seconds = [
index_item.total_seconds() for index_item in diff_index_as_list
]
diff_index_in_years = [
index_item_in_seconds / SECONDS_IN_YEAR
for index_item_in_seconds in diff_index_in_seconds
]
return diff_index_in_years
system = futures_system()
adjusted_price_dict = dict([(key,
system.rawdata.get_daily_prices(key))
for key in MASTER_INSTRUMENT_LIST
]
)
adjusted_price_df = pd.DataFrame(adjusted_price_dict)
adjusted_price_df = adjusted_price_df.resample("1B").last()
carry_price_dict = dict([(key,
calculate_cum_carry(system, key))
for key in MASTER_INSTRUMENT_LIST
]
)
carry_price_df = pd.DataFrame(carry_price_dict)
carry_price_df = carry_price_df.resample("1B").last()
synthetic_price_dict = dict([(key,
calculate_synthetic_spot(system, key))
for key in MASTER_INSTRUMENT_LIST
]
)
synthetic_price_df = pd.DataFrame(synthetic_price_dict)
synthetic_price_df = synthetic_price_df.resample("1B").last()
strategy_return_dict = dict(
[(rule_name,
dict(
[
(instrument, system.accounts.pandl_for_instrument_forecast(instrument, rule_name ).percent)
for instrument in MASTER_INSTRUMENT_LIST
]
)
) for rule_name in ['momentum8', 'momentum16', 'momentum64']]
)
from sklearn.linear_model import LinearRegression
def do_a_plot(rule_name: str, underlying_price: pd.DataFrame, price_label: str, scatter=True, regr_line=False):
list_of_dict = get_a_list_of_tuples_underlying_and_strat_SR_for_five_year_blocks(rule_name, underlying_price)
dict_as_df = pd.DataFrame(list_of_dict)
asset_classes = list(set(dict_as_df.asset.values))
colour_list = ['red', 'black', 'yellow', 'green', 'blue', 'gray', 'orange']
patchList = []
for asset, color in zip(asset_classes, colour_list):
data_key = mpatches.Patch(color=color, label=asset)
patchList.append(data_key)
this_asset = dict_as_df[dict_as_df.asset == asset]
x = this_asset['price_SR'].values
y = this_asset['trend_SR'].values
X = x.reshape(-1, 1)
Y = y.reshape(-1, 1)
linear_regressor = LinearRegression()
linear_regressor.fit(X, Y)
Y_pred = linear_regressor.predict(X)
if scatter:
plt.scatter(x, y, color=color)
if regr_line:
plt.plot(X, Y_pred, color=color)
plt.title("%s %s" % (price_label, rule_name))
plt.xlabel('Abs(SR) of %s' % price_label)
plt.ylabel("SR of %s" % rule_name)
plt.legend(handles=patchList)
plt.show(block=True)
def get_distribution_of_SR( underlying_price: pd.DataFrame, price_label: str):
arbitrary_rule_name = "momentum8"
list_of_dict = get_a_list_of_tuples_underlying_and_strat_SR_for_five_year_blocks(arbitrary_rule_name, underlying_price)
dict_as_df = pd.DataFrame(list_of_dict)
asset_classes = list(set(dict_as_df.asset.values))
new_dict={}
for asset in asset_classes:
this_asset = dict_as_df[dict_as_df.asset == asset]
new_dict[asset] = pd.Series(this_asset.price_SR.values, name=asset)
new_df = pd.concat(new_dict, axis=1)
new_df.boxplot()
plt.title("%s returns" % (price_label))
plt.show(block=True)
return new_df.median(axis=0)
def get_distribution_of_SR_rule(rule_name: str):
arbitrary_underlying_price = adjusted_price_df
list_of_dict = get_a_list_of_tuples_underlying_and_strat_SR_for_five_year_blocks(rule_name, arbitrary_underlying_price)
dict_as_df = pd.DataFrame(list_of_dict)
asset_classes = list(set(dict_as_df.asset.values))
new_dict={}
for asset in asset_classes:
this_asset = dict_as_df[dict_as_df.asset == asset]
new_dict[asset] = pd.Series(this_asset.trend_SR.values, name=asset)
new_df = pd.concat(new_dict, axis=1)
new_df.boxplot()
plt.title("%s returns" % (rule_name))
plt.show(block=True)
return new_df.median(axis=0)
def get_a_list_of_tuples_underlying_and_strat_SR_for_five_year_blocks(rule_name: str, underlying_price: pd.DataFrame):
list_of_starts =pd.date_range(underlying_price.index[0], end=underlying_price.index[-1], freq="60M")
list_of_ends = list(list_of_starts[1:])
list_of_starts =list(list_of_starts[:-1])
list_of_tuples = []
for start, end in zip(list_of_starts, list_of_ends):
print(start)
list_of_tuples+= get_tuples_underlying_and_strat_SR_for_five_year_block(
rule_name=rule_name,
underlying_price=underlying_price,
start=start,end=end
)
return list_of_tuples
def get_tuples_underlying_and_strat_SR_for_five_year_block(rule_name: str, underlying_price: pd.DataFrame, start:datetime.datetime, end:datetime.datetime):
list_of_tuples = []
for instrument in MASTER_INSTRUMENT_LIST:
tups =get_tuples_underlying_and_strat_SR_for_five_year_block_one_instrument(
rule_name=rule_name,
underlying_price=underlying_price,
start=start, end=end,
instrument=instrument
)
if np.isnan(tups['price_SR']) or np.isnan(tups['trend_SR']):
continue
list_of_tuples.append(tups)
return list_of_tuples
def get_tuples_underlying_and_strat_SR_for_five_year_block_one_instrument(instrument: str,
rule_name: str, underlying_price: pd.DataFrame, start:datetime.datetime, end:datetime.datetime):
asset_class = system.data.asset_class_for_instrument(instrument)
if asset_class=="Sector":
asset_class="Equity"
x=get_SR_for_price_series_in_time_period(
underlying_price=underlying_price,
start=start, end=end,
instrument=instrument)
y=get_SR_for_trend_rule_in_time_period( rule_name=rule_name,
start=start, end=end,
instrument=instrument)
return dict(asset=asset_class, price_SR=x, trend_SR=y)
def get_SR_for_price_series_in_time_period(instrument: str,
underlying_price: pd.DataFrame, start:datetime.datetime, end:datetime.datetime):
px = underlying_price[instrument][start:end]
returns = px.diff()
return abs(16*returns.mean()/returns.std())
def get_SR_for_trend_rule_in_time_period(instrument: str,
rule_name: str, start:datetime.datetime, end:datetime.datetime):
returns = strategy_return_dict[rule_name][instrument][start:end]
SR= 16*returns.mean()/returns.std()
return SR
import matplotlib
matplotlib.rcParams.update({"font.size": 16})
rule_name="momentum64"
do_a_plot(rule_name, adjusted_price_df, "adjusted prices")
do_a_plot(rule_name, synthetic_price_df, "spot prices")
do_a_plot(rule_name, carry_price_df, "cumulative carry")
do_a_plot(rule_name, adjusted_price_df, "adjusted prices", scatter=False,regr_line=True)
do_a_plot(rule_name, synthetic_price_df, "spot prices", scatter=False,regr_line=True)
do_a_plot(rule_name, carry_price_df, "cumulative carry", scatter=False,regr_line=True)
x=get_distribution_of_SR(adjusted_price_df, "adjusted prices")
y=get_distribution_of_SR_rule(rule_name)
new_df=pd.DataFrame([x,y], index=['prices','trend'])
new_df = new_df.transpose()
fig, axs = plt.subplots()
axs.scatter(data=new_df, x='prices', y='trend')
for i, row in new_df.iterrows():
axs.annotate( row.name, (row["prices"], row["trend"]))
plt.xlabel("Adjusted price SR")
plt.ylabel("%s SR" % rule_name)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment