Skip to content

Commit

Permalink
version 0.11.2
Browse files Browse the repository at this point in the history
  • Loading branch information
Robert Carver committed Jun 6, 2016
1 parent 7fd2822 commit bdad2f5
Show file tree
Hide file tree
Showing 8 changed files with 56 additions and 114 deletions.
5 changes: 5 additions & 0 deletions DONE_TO_DO.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Release notes

## Version 0.11.2

* Smooth fixed weights as well as variable: removed ewma_span and moved to new config item forecast_weight_ewma_span and same for instruments. Removed override of get_instrument_weights, get_forecast_weights method from estimated classes.


## Version 0.11.1

* Added extra methods to support capital scaling, but not implemented yet.
Expand Down
18 changes: 14 additions & 4 deletions docs/userguide.md
Original file line number Diff line number Diff line change
Expand Up @@ -3445,11 +3445,9 @@ If we haven't accounted for costs earlier (eg by setting `cost_multiplier=0`) th

If weights are *cleaned*, then in a fitting period when we need a weight, but none has been calculated (due to insufficient data for example), an instrument is given a share of the weight.

We also smooth weights with an EWMA to avoid trading when they change.

```
apply_cost_weight: True
ewma_span: 125
cleaning: True
```

Expand Down Expand Up @@ -3925,6 +3923,13 @@ Python (example)
config.use_forecast_weight_estimates=True
```
Change smoothing used for both fixed and variable weights:
YAML: (example)
```
forecast_weight_ewma_span: 125
```
#### Forecast weights (fixed using `ForecastCombinedFixed`)
Represented as: (a) dict of floats. Keywords: trading rule variation names.
Expand Down Expand Up @@ -4033,7 +4038,6 @@ forecast_weight_estimate:
shrinkage_corr: 0.50
monte_runs: 100
bootstrap_length: 50
ewma_span: 125
correlation_estimate:
func: syscore.correlations.correlation_single_period
using_exponent: False
Expand Down Expand Up @@ -4200,6 +4204,13 @@ Python (example)
config.use_instrument_weight_estimates=True
```
Change smoothing used for both fixed and variable weights:
YAML: (example)
```
instrument_weight_ewma_span: 125
```
#### Instrument weights (fixed, using `PortfoliosFixed`)
Represented as: dict of floats. Keywords: instrument_codes
Expand Down Expand Up @@ -4250,7 +4261,6 @@ instrument_weight_estimate:
shrinkage_corr: 0.50
monte_runs: 100
bootstrap_length: 50
ewma_span: 125
correlation_estimate:
func: syscore.correlations.correlation_single_period
using_exponent: False
Expand Down
8 changes: 8 additions & 0 deletions examples/breakout/temp.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
from matplotlib.pyplot import show, title
from systems.provided.futures_chapter15.estimatedsystem import futures_system
system = futures_system(log_level="on")
system.config.capital_multiplier['func']='syscore.capital.full_compounding'

system.accounts.capital_multiplier().plot()
show()

system.accounts.get_actual_capital().plot()
show()


system.accounts.portfolio_with_multiplier().percent().curve().plot()
show()
Expand Down
6 changes: 5 additions & 1 deletion syscore/capital.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
"""
Functions to calculate capital multiplier
Change to pass what is needed
"""

def fixed_capital(system, **ignored_args):
Expand All @@ -9,7 +11,9 @@ def fixed_capital(system, **ignored_args):
return pandl

def full_compounding(system, **ignored_args):
pass
pandl = system.accounts.portfolio().percent().curve()
pandl = pandl / 100.0
return pandl

def half_compounding(system, **ignored_args):
pass
10 changes: 7 additions & 3 deletions systems/account.py
Original file line number Diff line number Diff line change
Expand Up @@ -1803,10 +1803,14 @@ def _get_actual_capital(system, not_used, this_stage,
delayfill, roundpositions):

capmult = this_stage.capital_multiplier()
notional = this_stage.get_notional_capital()
notional = notional.reindex(capmult.index).ffill()
notional = this_stage.get_notional_capital()

capital = capmult*notional
if type(notional) is not pd.core.series.Series:
notional_ts = pd.Series([notional]*len(capmult), capmult.index)
else:
notional_ts = notional.reindex(capmult.index).ffill()

capital = capmult*notional_ts

return capital

Expand Down
49 changes: 5 additions & 44 deletions systems/forecast_combine.py
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,11 @@ def _get_forecast_weights(system, instrument_code, this_stage):
# also aligns them together
forecast_weights = fix_weights_vs_pdm(forecast_weights, forecasts)

weighting=system.config.forecast_weight_ewma_span

# smooth
forecast_weights = pd.ewma(forecast_weights, weighting)

return forecast_weights

forecast_weights = self.parent.calc_or_cache(
Expand Down Expand Up @@ -1089,50 +1094,6 @@ def _get_raw_forecast_weights(system, instrument_code, this_stage):

return raw_forecast_weights

def get_forecast_weights(self, instrument_code):
"""
Get the forecast weights
We forward fill all forecasts. We then adjust forecast weights so that they sum to 1.0 in every
period; after setting to zero when no forecast is available. we then take a smooth
:param instrument_code:
:type str:
:returns: TxK pd.DataFrame containing weights, columns are trading rule variation names, T covers all
KEY OUTPUT
>>> from systems.tests.testdata import get_test_object_futures_with_rules_and_capping_estimate
>>> from systems.basesystem import System
>>> (accounts, fcs, rules, rawdata, data, config)=get_test_object_futures_with_rules_and_capping_estimate()
>>> system=System([accounts, rawdata, rules, fcs, ForecastCombineEstimated()], data, config)
>>> system.config.forecast_weight_estimate['method']="shrinkage"
>>> system.combForecast.get_forecast_weights("EDOLLAR").tail(3)
carry ewmac16 ewmac8
2015-12-09 0.441002 0.256888 0.302111
2015-12-10 0.441013 0.256883 0.302104
2015-12-11 0.441024 0.256879 0.302097
"""
def _get_forecast_weights(system, instrument_code, this_stage):
this_stage.log.msg("Calculating forecast weights for %s" % instrument_code,
instrument_code=instrument_code)

## Get some useful stuff from the config
weighting_params=copy(system.config.forecast_weight_estimate)

forecast_weights = this_stage.get_raw_forecast_weights(
instrument_code)
rule_variation_list = list(forecast_weights.columns)
forecasts = this_stage.get_all_forecasts(instrument_code, rule_variation_list)

# adjust weights for missing data
forecast_weights = fix_weights_vs_pdm(forecast_weights, forecasts)

# smooth
forecast_weights = pd.ewma(forecast_weights, weighting_params['ewma_span'])

return forecast_weights


forecast_weights = self.parent.calc_or_cache(
Expand Down
70 changes: 10 additions & 60 deletions systems/portfolio.py
Original file line number Diff line number Diff line change
Expand Up @@ -220,10 +220,10 @@ def get_instrument_weights(self):
"""
def _get_clean_instrument_weights(
def _get_instrument_weights(
system, an_ignored_variable, this_stage):

this_stage.log.terse("Calculating clean instrument weights")
this_stage.log.terse("Calculating instrument weights")

raw_instr_weights = this_stage.get_raw_instrument_weights()
instrument_list = list(raw_instr_weights.columns)
Expand All @@ -237,10 +237,15 @@ def _get_clean_instrument_weights(
instrument_weights = fix_weights_vs_pdm(
raw_instr_weights, subsys_positions)

weighting=system.config.instrument_weight_ewma_span

# smooth
instrument_weights = pd.ewma(instrument_weights, weighting)

return instrument_weights

instrument_weights = self.parent.calc_or_cache(
"get_instrument_weights", ALL_KEYNAME, _get_clean_instrument_weights, self)
"get_instrument_weights", ALL_KEYNAME, _get_instrument_weights, self)
return instrument_weights


Expand Down Expand Up @@ -491,7 +496,7 @@ def _get_buffers_for_position(system, instrument_code, this_stage):
return pos_buffers

def capital_multiplier(self):
return self.accounts.capital_multiplier()
return self.parent.accounts.capital_multiplier()

def get_actual_position(self, instrument_code):
"""
Expand All @@ -511,7 +516,7 @@ def _get_actual_position(system, instrument_code, this_stage):

notional_position = this_stage.get_notional_position(instrument_code)
cap_multiplier = this_stage.capital_multiplier()
cap_multiplier = cap_multiplier.reindex(notional_position.index).fill()
cap_multiplier = cap_multiplier.reindex(notional_position.index).ffill()

actual_position = notional_position * cap_multiplier

Expand Down Expand Up @@ -749,61 +754,6 @@ def _get_raw_instrument_weights(system, notUsed, this_stage):

return raw_instrument_weights

def get_instrument_weights(self):
"""
Get the instrument weights
We forward fill all forecasts. We then adjust forecast weights so that they sum to 1.0 in every
period; after setting to zero when no forecast is available. we then take a smooth
:param instrument_code:
:type str:
:returns: TxK pd.DataFrame containing weights, columns are trading rule variation names, T covers all
KEY OUTPUT
>>> from systems.tests.testdata import get_test_object_futures_with_pos_sizing_estimates
>>> from systems.basesystem import System
>>> (account, posobject, combobject, capobject, rules, rawdata, data, config)=get_test_object_futures_with_pos_sizing_estimates()
>>> system=System([rawdata, rules, posobject, combobject, capobject,PortfoliosEstimated(), account], data, config)
>>> system.config.forecast_weight_estimate["method"]="shrinkage" ## speed things up
>>> system.config.forecast_weight_estimate["date_method"]="in_sample" ## speed things up
>>> system.config.instrument_weight_estimate["method"]="shrinkage" ## speed things up
>>> system.portfolio.get_instrument_weights().tail(3)
BUND EDOLLAR US10
2015-12-08 0.387229 0.306034 0.306737
2015-12-09 0.388637 0.305331 0.306032
2015-12-10 0.390033 0.304634 0.305334
>>> system.config.instrument_weight_estimate["method"]="bootstrap"
>>> system.portfolio.get_instrument_weights().tail(3)
BUND EDOLLAR US10
2015-12-08 0.387229 0.306034 0.306737
2015-12-09 0.388637 0.305331 0.306032
2015-12-10 0.390033 0.304634 0.305334
"""
def _get_instrument_weights(system, notUsed, this_stage):

this_stage.log.msg("Getting instrument weights")

raw_instr_weights = this_stage.get_raw_instrument_weights()
instrument_list = list(raw_instr_weights.columns)

subsys_positions = [this_stage.get_subsystem_position(code)
for code in instrument_list]

subsys_positions = pd.concat(subsys_positions, axis=1).ffill()
subsys_positions.columns = instrument_list

instrument_weights = fix_weights_vs_pdm(
raw_instr_weights, subsys_positions)

weighting_params=copy(system.config.instrument_weight_estimate)

# smooth
instrument_weights = pd.ewma(instrument_weights, weighting_params['ewma_span'])

return instrument_weights


instrument_weights = self.parent.calc_or_cache(
Expand Down
4 changes: 2 additions & 2 deletions systems/provided/defaults.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ forecast_cost_estimates:
use_pooled_costs: False
use_pooled_turnover: True
#
forecast_weight_ewma_span: 125
forecast_weight_estimate:
func: syscore.optimisation.GenericOptimiser
method: shrinkage
Expand All @@ -81,7 +82,6 @@ forecast_weight_estimate:
shrinkage_corr: 0.50
monte_runs: 100
bootstrap_length: 50
ewma_span: 125
correlation_estimate:
func: syscore.correlations.correlation_single_period
using_exponent: False
Expand Down Expand Up @@ -127,6 +127,7 @@ instrument_div_mult_estimate:
#
use_instrument_weight_estimates: False
#
instrument_weight_ewma_span: 125
instrument_weight_estimate:
func: syscore.optimisation.GenericOptimiser
method: shrinkage
Expand All @@ -144,7 +145,6 @@ instrument_weight_estimate:
shrinkage_corr: 0.50
monte_runs: 100
bootstrap_length: 50
ewma_span: 125
correlation_estimate:
func: syscore.correlations.correlation_single_period
using_exponent: False
Expand Down

0 comments on commit bdad2f5

Please sign in to comment.