def pandl_across_subsystems(self, percentage=True, delayfill=True, roundpositions=False): """ Get the p&l across subsystems :param percentage: Return results as % of total notional capital :type percentage: bool :param delayfill: Lag fills by one day :type delayfill: bool :param roundpositions: Round positions to whole contracts :type roundpositions: bool :returns: accountCurve >>> from systems.basesystem import System >>> from systems.tests.testdata import get_test_object_futures_with_portfolios >>> (portfolio, posobject, combobject, capobject, rules, rawdata, data, config)=get_test_object_futures_with_portfolios() >>> system=System([portfolio, posobject, combobject, capobject, rules, rawdata, Account()], data, config) >>> >>> system.accounts.pandl_across_subsystems(percentage=True).to_frame().tail(5) EDOLLAR US10 2015-12-07 0.001191 -0.005012 2015-12-08 0.000448 -0.002395 2015-12-09 0.000311 -0.002797 2015-12-10 -0.002384 0.003957 2015-12-11 0.004835 -0.007594 """ def _pandl_across_subsystems(system, instrumentCodeNotUsed, this_stage, percentage, delayfill, roundpositions): instruments = this_stage.get_instrument_list() pandl_across_subsys = [ this_stage.pandl_for_subsystem(instrument_code, percentage=percentage, delayfill=delayfill, roundpositions=roundpositions) for instrument_code in instruments ] pandl = accountCurveGroup(pandl_across_subsys, instruments) return pandl itemname = "pandl_across_subsystems__percentage%sdelayfill%sroundpositions%s" % ( TorF(percentage), TorF(delayfill), TorF(roundpositions)) instr_pandl = self.parent.calc_or_cache(itemname, ALL_KEYNAME, _pandl_across_subsystems, self, percentage, delayfill, roundpositions) return instr_pandl
def portfolio(self, percentage=True, delayfill=True, roundpositions=False): """ Get the p&l for entire portfolio :param percentage: Return results as % of total notional capital :type percentage: bool :param delayfill: Lag fills by one day :type delayfill: bool :param roundpositions: Round positions to whole contracts :type roundpositions: bool :returns: accountCurve >>> from systems.basesystem import System >>> from systems.tests.testdata import get_test_object_futures_with_portfolios >>> (portfolio, posobject, combobject, capobject, rules, rawdata, data, config)=get_test_object_futures_with_portfolios() >>> system=System([portfolio, posobject, combobject, capobject, rules, rawdata, Account()], data, config) >>> >>> round(system.accounts.portfolio(percentage=True).std()*16,3) 0.28199999999999997 >>> round(system.accounts.portfolio(percentage=False).std()*16/100000.0,3) 0.28199999999999997 """ def _portfolio(system, not_used, this_stage, percentage, delayfill, roundpositions): this_stage.log.terse("Calculating pandl for portfolio") instruments = this_stage.get_instrument_list() port_pandl = [ this_stage.pandl_for_instrument(instrument_code, percentage=percentage, delayfill=delayfill, roundpositions=roundpositions) for instrument_code in instruments ] port_pandl = pd.concat(port_pandl, axis=1).sum(axis=1) port_pandl = accountCurve(port_pandl) return port_pandl itemname = "portfolio__percentage%sdelayfill%sroundpositions%s" % ( TorF(percentage), TorF(delayfill), TorF(roundpositions)) port_pandl = self.parent.calc_or_cache(itemname, ALL_KEYNAME, _portfolio, self, percentage, delayfill, roundpositions) return port_pandl
def instrument_turnover(self, instrument_code, roundpositions=True): """ Get the annualised turnover for an instrument :param instrument_code: instrument to get values for :type instrument_code: str :param rule_variation_name: rule to get values for :type rule_variation_name: str :returns: float """ def _instrument_turnover(system, instrument_code, this_stage, roundpositions): average_position_for_turnover = multiply_df_single_column( this_stage.get_volatility_scalar(instrument_code), this_stage.get_instrument_scaling_factor(instrument_code), ffill=(True, True)) positions = this_stage.get_buffered_position( instrument_code, roundpositions=roundpositions) return turnover(positions, average_position_for_turnover) instr_turnover = self.parent.calc_or_cache( "instrument_turnover_%s" % TorF(roundpositions), instrument_code, _instrument_turnover, self, roundpositions) return instr_turnover
def subsystem_turnover(self, instrument_code, roundpositions): """ Get the annualised turnover for an instrument subsystem :param instrument_code: instrument to get values for :type instrument_code: str :returns: float """ def _subsystem_turnover(system, instrument_code, this_stage, roundpositions): positions = this_stage.get_subsystem_position(instrument_code) average_position_for_turnover = this_stage.get_volatility_scalar( instrument_code) return turnover(positions, average_position_for_turnover) subsys_turnover = self.parent.calc_or_cache( "subsystem_turnover_%s" % TorF(roundpositions), instrument_code, _subsystem_turnover, self, roundpositions) return subsys_turnover
def pandl_for_instrument_rules_unweighted(self, instrument_code, delayfill=True): """ Get the p&l for one instrument over multiple forecasts; as % of arbitrary capital All forecasting rules will have same expected std dev of returns; these aren't weighted KEY OUTPUT :param instrument_code: instrument to get values for :type instrument_code: str :param delayfill: Lag fills by one day :type delayfill: bool :returns: accountCurve >>> from systems.basesystem import System >>> from systems.tests.testdata import get_test_object_futures_with_portfolios >>> (portfolio, posobject, combobject, capobject, rules, rawdata, data, config)=get_test_object_futures_with_portfolios() >>> system=System([portfolio, posobject, combobject, capobject, rules, rawdata, Account()], data, config) >>> >>> system.accounts.pandl_for_instrument_rules_unweighted("EDOLLAR").get_stats("sharpe") {'ewmac16': 0.6799720823590352, 'ewmac8': 0.69594671177102} """ def _pandl_for_instrument_rules_unweighted(system, instrument_code, this_stage, delayfill): this_stage.log.terse( "Calculating pandl for instrument rules for %s" % instrument_code, instrument_code=instrument_code) forecast_rules = this_stage.get_trading_rule_list(instrument_code) pandl_rules = [ this_stage.pandl_for_instrument_forecast(instrument_code, rule_variation_name, delayfill=delayfill, weighting=None) for rule_variation_name in forecast_rules ] pandl_rules = accountCurveGroup(pandl_rules, forecast_rules) return pandl_rules itemname = "pandl_for_instrument_rules_unweighted_delayfill%s" % TorF( delayfill) pandl_rules = self.parent.calc_or_cache( itemname, instrument_code, _pandl_for_instrument_rules_unweighted, self, delayfill) return pandl_rules
def pandl_for_instrument_rules(self, instrument_code, delayfill=True): """ Get the p&l for one instrument over multiple forecasts; as % of arbitrary capital KEY OUTPUT :param instrument_code: instrument to get values for :type instrument_code: str :param rule_variation_name: rule to get values for :type rule_variation_name: str :param delayfill: Lag fills by one day :type delayfill: bool :returns: accountCurve >>> from systems.basesystem import System >>> from systems.tests.testdata import get_test_object_futures_with_portfolios >>> (portfolio, posobject, combobject, capobject, rules, rawdata, data, config)=get_test_object_futures_with_portfolios() >>> system=System([portfolio, posobject, combobject, capobject, rules, rawdata, Account()], data, config) >>> >>> system.accounts.pandl_for_instrument_rules("EDOLLAR") wibble """ def _pandl_for_instrument_rules(system, instrument_code, this_stage, delayfill): this_stage.log.terse( "Calculating pandl for instrument rules for %s" % instrument_code, instrument_code=instrument_code) forecast_rules = system.combForecast.get_trading_rule_list( instrument_code) pandl_rules = pd.concat([ this_stage.pandl_for_instrument_forecast( instrument_code, rule_variation_name, delayfill) for rule_variation_name in forecast_rules ], axis=1) pandl_rules.columns = forecast_rules return pandl_rules itemname = "pandl_for_instrument__rules_delayfill%s" % TorF(delayfill) pandl_rules = self.parent.calc_or_cache(itemname, instrument_code, _pandl_for_instrument_rules, self, delayfill) return pandl_rules
def pandl_for_trading_rule_unweighted(self, rule_variation_name, delayfill=True): """ Get the p&l for one trading rule over multiple instruments; as % of arbitrary capital Within the trading rule the instrument returns are NOT weighted by instrument weight :param rule_variation_name: rule to get values for :type rule_variation_name: str :param delayfill: Lag fills by one day :type delayfill: bool :returns: accountCurve """ def _pandl_for_trading_rule_unweighted(system, instrument_code_unused, this_stage, rule_variation_name, delayfill): this_stage.log.terse( "Calculating pandl for trading rule (unweighted) %s" % rule_variation_name) instrument_list = system.get_instrument_list() instrument_list = [ instr_code for instr_code in instrument_list if rule_variation_name in this_stage.get_trading_rule_list( instr_code) ] pandl_by_instrument = [ this_stage.pandl_for_instrument_forecast( instr_code, rule_variation_name, delayfill) for instr_code in instrument_list ] pandl_rule = accountCurveGroup(pandl_by_instrument, instrument_list) return pandl_rule itemname = "pandl_for_trading_rule_unweighted_%s_delayfill%s" % ( rule_variation_name, TorF(delayfill)) pandl_trading_rule_unweighted = self.parent.calc_or_cache( itemname, ALL_KEYNAME, _pandl_for_trading_rule_unweighted, self, rule_variation_name, delayfill) return pandl_trading_rule_unweighted
def get_buffered_position(self, instrument_code, roundpositions=True): """ Get the buffered position :param instrument_code: instrument to get :type percentage: bool :param roundpositions: Round positions to whole contracts :type roundpositions: bool :returns: Tx1 pd.DataFrame >>> from systems.basesystem import System >>> from systems.tests.testdata import get_test_object_futures_with_portfolios >>> (portfolio, posobject, combobject, capobject, rules, rawdata, data, config)=get_test_object_futures_with_portfolios() >>> system=System([portfolio, posobject, combobject, capobject, rules, rawdata, Account()], data, config) >>> >>> system.accounts.get_buffered_position("EDOLLAR").tail(3) position 2015-12-09 1 2015-12-10 1 2015-12-11 1 """ def _get_buffered_position(system, instrument_code, this_stage, roundpositions): this_stage.log.msg("Calculating buffered positions") optimal_position = this_stage.get_notional_position( instrument_code) pos_buffers = this_stage.get_buffers_for_position(instrument_code) trade_to_edge = system.config.buffer_trade_to_edge buffered_position = apply_buffer(optimal_position, pos_buffers, trade_to_edge=trade_to_edge, roundpositions=roundpositions) buffered_position.columns = ["position"] return buffered_position itemname = "get_buffered_position__roundpositions%s" % TorF( roundpositions) buffered_position = self.parent.calc_or_cache(itemname, instrument_code, _get_buffered_position, self, roundpositions) return buffered_position
def pandl_for_instrument_forecast(self, instrument_code, rule_variation_name, delayfill=True): """ Get the p&l for one instrument and forecast; as % of arbitrary capital KEY OUTPUT: :param instrument_code: instrument to get values for :type instrument_code: str :param rule_variation_name: rule to get values for :type rule_variation_name: str :param delayfill: Lag fills by one day :type delayfill: bool :returns: accountCurve >>> from systems.basesystem import System >>> from systems.tests.testdata import get_test_object_futures_with_portfolios >>> (portfolio, posobject, combobject, capobject, rules, rawdata, data, config)=get_test_object_futures_with_portfolios() >>> system=System([portfolio, posobject, combobject, capobject, rules, rawdata, Account()], data, config) >>> >>> round(system.accounts.pandl_for_instrument_forecast("EDOLLAR", "ewmac8").std()*16,3) 0.20999999999999999 """ def _pandl_for_instrument_forecast(system, instrument_code, rule_variation_name, this_stage, delayfill): this_stage.log.msg( "Calculating pandl for instrument forecast for %s %s" % (instrument_code, rule_variation_name), instrument_code=instrument_code, rule_variation_name=rule_variation_name) price = this_stage.get_daily_price(instrument_code) forecast = this_stage.get_capped_forecast(instrument_code, rule_variation_name) get_daily_returns_volatility = this_stage.get_daily_returns_volatility( instrument_code) pandl_fcast = pandl( price=price, delayfill=delayfill, get_daily_returns_volatility=get_daily_returns_volatility, forecast=forecast, capital=0.0) return pandl_fcast itemname = "pandl_for_instrument__forecast_delayfill%s" % TorF( delayfill) pandl_fcast = self.parent.calc_or_cache_nested( itemname, instrument_code, rule_variation_name, _pandl_for_instrument_forecast, self, delayfill) return pandl_fcast
def pandl_for_instrument(self, instrument_code, percentage=True, delayfill=True, roundpositions=False): """ Get the p&l for one instrument :param instrument_code: instrument to get values for :type instrument_code: str :param percentage: Return results as % of total notional capital :type percentage: bool :param delayfill: Lag fills by one day :type delayfill: bool :param roundpositions: Round positions to whole contracts :type roundpositions: bool :returns: accountCurve >>> from systems.basesystem import System >>> from systems.tests.testdata import get_test_object_futures_with_portfolios >>> (portfolio, posobject, combobject, capobject, rules, rawdata, data, config)=get_test_object_futures_with_portfolios() >>> system=System([portfolio, posobject, combobject, capobject, rules, rawdata, Account()], data, config) >>> >>> round(system.accounts.pandl_for_instrument("US10", percentage=False).std()*16/100000.0,3) 0.14299999999999999 >>> round(system.accounts.pandl_for_instrument("EDOLLAR", percentage=False).std()*16/100000.0,3) 0.152 >>> round(system.accounts.pandl_for_instrument("US10", percentage=True).std()*16,3) 0.14299999999999999 """ def _pandl_for_instrument(system, instrument_code, this_stage, percentage, delayfill, roundpositions): this_stage.log.msg("Calculating pandl for instrument for %s" % instrument_code, instrument_code=instrument_code) price = this_stage.get_daily_price(instrument_code) positions = this_stage.get_notional_position(instrument_code) fx = this_stage.get_fx_rate(instrument_code) value_of_price_point = this_stage.get_value_of_price_move( instrument_code) if percentage: capital = this_stage.get_notional_capital() else: capital = None instr_pandl = pandl(price=price, positions=positions, delayfill=delayfill, roundpositions=roundpositions, fx=fx, value_of_price_point=value_of_price_point, capital=capital) return instr_pandl itemname = "pandl_for_instrument__percentage%sdelayfill%sroundpositions%s" % ( TorF(percentage), TorF(delayfill), TorF(roundpositions)) instr_pandl = self.parent.calc_or_cache(itemname, instrument_code, _pandl_for_instrument, self, percentage, delayfill, roundpositions) return instr_pandl
def pandl_for_instrument(self, instrument_code, percentage=True, delayfill=True, roundpositions=True): """ Get the p&l for one instrument :param instrument_code: instrument to get values for :type instrument_code: str :param percentage: Return results as % of total notional capital :type percentage: bool :param delayfill: Lag fills by one day :type delayfill: bool :param roundpositions: Round positions to whole contracts :type roundpositions: bool :returns: accountCurve >>> from systems.basesystem import System >>> from systems.tests.testdata import get_test_object_futures_with_portfolios >>> (portfolio, posobject, combobject, capobject, rules, rawdata, data, config)=get_test_object_futures_with_portfolios() >>> system=System([portfolio, posobject, combobject, capobject, rules, rawdata, Account()], data, config) >>> system.accounts.pandl_for_instrument("US10", percentage=True).ann_std() 0.13908407620762306 """ def _pandl_for_instrument(system, instrument_code, this_stage, percentage, delayfill, roundpositions): this_stage.log.msg("Calculating pandl for instrument for %s" % instrument_code, instrument_code=instrument_code) price = this_stage.get_daily_price(instrument_code) positions = this_stage.get_buffered_position( instrument_code, roundpositions=roundpositions) fx = this_stage.get_fx_rate(instrument_code) value_of_price_point = this_stage.get_value_of_price_move( instrument_code) get_daily_returns_volatility = this_stage.get_daily_returns_volatility( instrument_code) capital = this_stage.get_notional_capital() ann_risk_target = this_stage.get_ann_risk_target() (SR_cost, cash_costs) = this_stage.get_costs(instrument_code) if SR_cost is not None: ## Note that SR cost is done as a proportion of capital ## Since we're only using part of the capital we need to correct for this turnover_for_SR = this_stage.instrument_turnover( instrument_code, roundpositions=roundpositions) SR_cost = SR_cost * turnover_for_SR weighting = this_stage.get_instrument_scaling_factor( instrument_code) apply_weight_to_costs_only = True else: ## Costs wil be correct ## We don't need to do anything weighting = None apply_weight_to_costs_only = False instr_pandl = accountCurve( price, positions=positions, delayfill=delayfill, roundpositions=roundpositions, fx=fx, value_of_price_point=value_of_price_point, capital=capital, ann_risk_target=ann_risk_target, percentage=percentage, SR_cost=SR_cost, cash_costs=cash_costs, get_daily_returns_volatility=get_daily_returns_volatility, weighting=weighting, apply_weight_to_costs_only=apply_weight_to_costs_only) return instr_pandl itemname = "pandl_for_instrument__percentage%sdelayfill%sroundpositions%s" % ( TorF(percentage), TorF(delayfill), TorF(roundpositions)) instr_pandl = self.parent.calc_or_cache(itemname, instrument_code, _pandl_for_instrument, self, percentage, delayfill, roundpositions) return instr_pandl
def pandl_for_subsystem(self, instrument_code, percentage=True, delayfill=True, roundpositions=False): """ Get the p&l for one instrument :param instrument_code: instrument to get values for :type instrument_code: str :param percentage: Return results as % of total notional capital :type percentage: bool :param delayfill: Lag fills by one day :type delayfill: bool :param roundpositions: Round positions to whole contracts :type roundpositions: bool :returns: accountCurve >>> from systems.basesystem import System >>> from systems.tests.testdata import get_test_object_futures_with_portfolios >>> (portfolio, posobject, combobject, capobject, rules, rawdata, data, config)=get_test_object_futures_with_portfolios() >>> system=System([portfolio, posobject, combobject, capobject, rules, rawdata, Account()], data, config) >>> >>> system.accounts.pandl_for_subsystem("US10", percentage=True).ann_std() 0.23422378634127036 """ def _pandl_for_subsystem(system, instrument_code, this_stage, percentage, delayfill, roundpositions): this_stage.log.msg( "Calculating pandl for subsystem for instrument %s" % instrument_code, instrument_code=instrument_code) price = this_stage.get_daily_price(instrument_code) positions = this_stage.get_subsystem_position(instrument_code) fx = this_stage.get_fx_rate(instrument_code) value_of_price_point = this_stage.get_value_of_price_move( instrument_code) get_daily_returns_volatility = this_stage.get_daily_returns_volatility( instrument_code) (SR_cost, cash_costs) = this_stage.get_costs(instrument_code) if SR_cost is not None: turnover_for_SR = this_stage.subsystem_turnover( instrument_code, roundpositions=roundpositions) SR_cost = SR_cost * turnover_for_SR capital = this_stage.get_notional_capital() ann_risk_target = this_stage.get_ann_risk_target() instr_pandl = accountCurve( price, positions=positions, delayfill=delayfill, roundpositions=roundpositions, fx=fx, value_of_price_point=value_of_price_point, capital=capital, percentage=percentage, SR_cost=SR_cost, cash_costs=cash_costs, get_daily_returns_volatility=get_daily_returns_volatility, ann_risk_target=ann_risk_target) return instr_pandl itemname = "pandl_for_subsystem__percentage%sdelayfill%sroundpositions%s" % ( TorF(percentage), TorF(delayfill), TorF(roundpositions)) instr_pandl = self.parent.calc_or_cache(itemname, instrument_code, _pandl_for_subsystem, self, percentage, delayfill, roundpositions) return instr_pandl