def print_capital_and_get_user_input(data: dataBlob): data_capital = dataCapital(data) all_calcs = data_capital.get_series_of_all_global_capital() print("\n") if all_calcs is missing_data: # No capital no_capital_setup = True print("No capital setup yet") else: no_capital_setup = False print(all_calcs.tail(10)) print("\n") if no_capital_setup: possible_options = {1: "Setup initial capital parameters"} else: possible_options = { 2: "Update capital from IB account value", 3: "Adjust account value for withdrawal or deposit", 4: "Modify any/all values", 5: "Delete values of capital since time T", 6: "Delete everything and start again" } user_option_int = print_menu_and_get_response(possible_options, default_option=0, default_str="EXIT") return user_option_int
def run_system_classic( strategy_name, data, backtest_config_filename="systems.provided.futures_chapter15.futures_config.yaml" ): capital_data = dataCapital(data) capital_value = capital_data.get_capital_for_strategy(strategy_name) if capital_data is missing_data: ## critical log will send email error_msg = "Capital data is missing for %s: can't run backtest" % strategy_name data.log.critical(error_msg) raise Exception(error_msg) currency_data = currencyData(data) base_currency = currency_data.get_base_currency() system = production_classic_futures_system( data, backtest_config_filename, log=data.log, notional_trading_capital=capital_value, base_currency=base_currency) updated_buffered_positions(data, strategy_name, system) store_backtest_state(data, system, strategy_name=strategy_name, backtest_config_filename=backtest_config_filename) return success
def update_total_capital(self): data = self.data capital_data = dataCapital(data) broker_data = dataBroker(data) log = data.log # This assumes that each account only reports either in one currency or # for each currency, i.e. no double counting total_account_value_in_base_currency = broker_data.get_total_capital_value_in_base_currency( ) log.msg("Broker account value is %f" % total_account_value_in_base_currency) # Update total capital try: new_capital = capital_data.get_total_capital_with_new_broker_account_value( total_account_value_in_base_currency) except Exception as e: # Problem, most likely spike log.critical( "Error %s whilst updating total capital; you may have to use update_capital_manual script or function" % e) return failure log.msg("New capital is %f" % new_capital)
def interactive_update_capital_manual(): """ Interactive session that allows you to manipulate capital manually :return: Nothing """ with dataBlob(log_name="Interactive-Update-Capital-Manual") as data: data_capital = dataCapital(data) still_running = True while still_running: # display capital and get input user_option_int = print_capital_and_get_user_input(data_capital) if user_option_int==0: setup_initial_capital(data_capital) elif user_option_int==1: update_capital_from_ib(data_capital) elif user_option_int==2: adjust_capital_for_delta(data_capital) elif user_option_int==3: modify_any_value(data_capital) elif user_option_int==4: delete_capital_since_time(data_capital) elif user_option_int==919: delete_all_capital(data_capital) elif user_option_int==5: still_running=False break else: print("%d is not a valid option but was in list of possible options: check code" % str(user_option_int)) ## Back to top of while loop return success
def capital_strategy(data): data_capital = dataCapital(data) strat_list = data_capital.get_list_of_strategies_with_capital() strategy_name = print_menu_of_values_and_get_response(strat_list, default_str=strat_list[0]) capital_series = data_capital.get_capital_pd_series_for_strategy(strategy_name) print(capital_series) return None
def get_values_from_user_to_modify(data: dataBlob): data_capital = dataCapital(data) capital_calculator = data_capital.total_capital_calculator current_broker_value = capital_calculator.get_broker_account()[-1] broker_account_value = get_and_convert("Broker account value", type_expected=float, default_value=current_broker_value) current_total_capital = capital_calculator.get_current_total_capital() total_capital = get_and_convert("Total capital at risk", type_expected=float, default_value=current_total_capital) current_maximum_capital = capital_calculator.get_maximum_account()[-1] maximum_capital = get_and_convert( "Max capital, only used for half compounding", type_expected=float, default_value=current_maximum_capital) current_acc_profit = capital_calculator.get_profit_and_loss_account()[-1] acc_pandl = get_and_convert("Accumulated profit", type_expected=float, default_value=current_acc_profit) return broker_account_value, total_capital, maximum_capital, acc_pandl
def run_system_classic(self): strategy_name = self.strategy_name data = self.data capital_data = dataCapital(data) capital_value = capital_data.get_capital_for_strategy(strategy_name) if capital_data is missing_data: # critical log will send email error_msg = ( "Capital data is missing for %s: can't run backtest" % strategy_name) data.log.critical(error_msg) raise Exception(error_msg) currency_data = currencyData(data) base_currency = currency_data.get_base_currency() system = self.system_method( notional_trading_capital=capital_value, base_currency=base_currency ) updated_buffered_positions(data, strategy_name, system) store_backtest_state(data, system, strategy_name=strategy_name) return success
def capital_for_strategy(data, strategy_name): data_capital = dataCapital(data) capital = data_capital.get_capital_for_strategy(strategy_name) if capital is missing_data: return 0.00001 return capital
def write_allocated_weights(data, strategy_capital_dict): capital_data = dataCapital(data) date = datetime.datetime.now() for strategy_name, strategy_capital in strategy_capital_dict.items(): capital_data.update_capital_value_for_strategy(strategy_name, strategy_capital, date=date) data.log.msg("Updated capital for %s to %f" % (strategy_name, strategy_capital)) return success
def delete_capital_since_time(data: dataBlob): data_capital = dataCapital(data) start_date = get_datetime_input("Delete capital from when?") ans = input("Are you sure about this? Can't be undone Yes/<other for no>") if ans == "Yes": data_capital.total_capital_calculator.delete_recent_capital( start_date, are_you_sure=True)
def get_total_current_capital(data: dataBlob) -> float: data_capital = dataCapital(data) total_capital = data_capital.get_current_total_capital() if total_capital is missing_data: data.log.critical("Can't allocate strategy capital without total capital") raise Exception() return total_capital
def write_allocated_strategy_capital(data: dataBlob, strategy_capital_dict: dict): capital_data = dataCapital(data) date = datetime.datetime.now() for strategy_name, strategy_capital in strategy_capital_dict.items(): capital_data.update_capital_value_for_strategy( strategy_name, strategy_capital, date=date ) data.log.msg( "Updated capital for %s to %f" % (strategy_name, strategy_capital), strategy_name=strategy_name, )
def get_daily_perc_pandl(data): data_capital_object = dataCapital(data) ## This is for 'non compounding' p&l total_pandl_series = data_capital_object.get_series_of_accumulated_capital( ) daily_pandl_series = total_pandl_series.ffill().diff() all_capital = get_total_capital_series(data) perc_pandl_series = daily_pandl_series / all_capital return perc_pandl_series
def get_daily_perc_pandl(data): data_capital_object = dataCapital(data) all_capital_data = data_capital_object.total_capital_calculator.get_all_capital_calcs() ## This is for 'non compounding' p&l total_pandl_series = all_capital_data.Accumulated daily_pandl_series = total_pandl_series.ffill().diff() all_capital = get_total_capital_series(data) perc_pandl_series = daily_pandl_series / all_capital return perc_pandl_series
def adjust_capital_for_delta(data: dataBlob): data_capital = dataCapital(data) capital_delta = get_and_convert( "What change have you made to brokerage account that will not change capital +ve deposit, -ve withdrawal", type_expected=float, ) old_capital = data_capital.get_series_of_broker_capital()[-1] new_capital = old_capital + capital_delta user_wants_adjustment = true_if_answer_is_yes( "New brokerage capital will be %f, are you sure? " % new_capital) if user_wants_adjustment: data_capital.total_capital_calculator.adjust_broker_account_for_delta( capital_delta)
def adjust_capital_for_delta(data: dataBlob): data_capital = dataCapital(data) capital_delta = get_and_convert( "What change have you made to brokerage account that will not change capital +ve deposit, -ve withdrawal", type_expected=float, ) old_capital = data_capital.get_current_total_capital() new_capital = old_capital + capital_delta ans = input( "New brokerage capital will be %f, are you sure? Yes/<anything else for no>" % new_capital) if ans == "Yes": data_capital.total_capital_calculator.adjust_broker_account_for_delta( capital_delta)
def delete_all_capital(data: dataBlob): data_capital = dataCapital(data) ans = input( "Will delete all capital history (though not for individual strategies). Really sure this is a good idea? Can't be recovered from: 'YESyesYES'/<anything else for no>" ) if ans == "YESyesYES": try: data_capital.total_capital_calculator.delete_all_capital( are_you_really_sure=True) except BaseException: print( "Something went wrong: You may have to manually drop collection in mongo DB" )
def _get_currency_and_capital(self): data = self.data strategy_name = self.strategy_name capital_data = dataCapital(data) notional_trading_capital = capital_data.get_capital_for_strategy( strategy_name) if notional_trading_capital is missing_data: # critical log will send email error_msg = ("Capital data is missing for %s: can't run backtest" % strategy_name) data.log.critical(error_msg) raise Exception(error_msg) currency_data = dataCurrency(data) base_currency = currency_data.get_base_currency() return base_currency, notional_trading_capital
def update_capital_from_ib(data: dataBlob): data_capital = dataCapital(data) broker_account_value = get_broker_account_value(data) try: total_capital = data_capital.total_capital_calculator.get_total_capital_with_new_broker_account_value( broker_account_value, check_limit=0.1) except BaseException: ans = input( "Do you want to try again, without checking for large capital changes? Yes/<anything else>" ) if ans == "Yes": total_capital = data_capital.total_capital_calculator.get_total_capital_with_new_broker_account_value( broker_account_value, check_limit=9999) else: return failure print("New total capital is %s" % total_capital)
def update_account_values(): """ Do a daily update of accounting information Get the total account value from IB, and calculate the p&l since we last ran This calculation is done using a user specified handler, which can deal with eg multiple accounts if required Needs to know about any withdrawals. Does spike checking: large changes in account value are checked before writing If your strategy has very high risk you may wish to do this more frequently than daily :return: Nothing """ with mongoDb() as mongo_db,\ logger("Update-Account-Values", mongo_db=mongo_db) as log,\ connectionIB(mongo_db = mongo_db, log=log.setup(component="IB-connection")) as ib_conn: data = dataBlob(mongo_db=mongo_db, log=log, ib_conn=ib_conn) capital_data = dataCapital(data) ## This assumes that each account only reports eithier in one currency or for each currency, i.e. no double counting total_account_value_in_base_currency = capital_data.get_ib_total_capital_value( ) log.msg("Broker account value is %f" % total_account_value_in_base_currency) # Update total capital try: new_capital = capital_data.total_capital_calculator.\ get_total_capital_with_new_broker_account_value(total_account_value_in_base_currency) except Exception as e: ## Problem, most likely spike log.critical( "Error %s whilst updating total capital; you may have to use update_capital_manual script or function" % e) return failure log.msg("New capital is %f" % new_capital) return success
def setup_initial_capital(data: dataBlob): ( broker_account_value, total_capital, maximum_capital, acc_pandl, ) = get_initial_capital_values_from_user(data) ans = input( "Are you sure about this? Will delete all existing capital (not for individual strategies) Yes/<anything else>" ) if ans == "Yes": data_capital = dataCapital(data) data_capital.total_capital_calculator.create_initial_capital( broker_account_value, total_capital=total_capital, maximum_capital=maximum_capital, acc_pandl=acc_pandl, are_you_really_sure=True, )
def modify_any_value(data: dataBlob): data_capital = dataCapital(data) ( broker_account_value, total_capital, maximum_capital, acc_pandl, ) = get_values_from_user_to_modify(data=data) ans_is_yes = true_if_answer_is_yes( "Sure about this? May cause subtle weirdness in capital calculations?") if ans_is_yes: data_capital.total_capital_calculator.modify_account_values( broker_account_value=broker_account_value, total_capital=total_capital, maximum_capital=maximum_capital, acc_pandl=acc_pandl, propagate=True)
def setup_initial_capital(data: dataBlob): ( broker_account_value, total_capital, maximum_capital, acc_pandl, ) = get_initial_capital_values_from_user(data) user_agrees_to_do_this = true_if_answer_is_yes( "Are you *REALLY* sure about this? Will delete all existing capital (not for individual strategies)?" ) if user_agrees_to_do_this: data_capital = dataCapital(data) data_capital.total_capital_calculator.create_initial_capital( broker_account_value, total_capital=total_capital, maximum_capital=maximum_capital, acc_pandl=acc_pandl, are_you_really_sure=True, )
def modify_any_value(data: dataBlob): data_capital = dataCapital(data) ( broker_account_value, total_capital, maximum_capital, acc_pandl, ) = get_values_from_user_to_modify() ans = input( "Sure about this? May cause subtle weirdness in capital calculations? Yes/<anything else>" ) if ans == "Yes": data_capital.total_capital_calculator.modify_account_values( broker_account_value=broker_account_value, total_capital=total_capital, maximum_capital=maximum_capital, acc_pandl=acc_pandl, )
def update_capital_from_ib(data: dataBlob): data_capital = dataCapital(data) broker_account_value = get_broker_account_value(data) try: total_capital = data_capital.\ update_and_return_total_capital_with_new_broker_account_value(broker_account_value) print("New total capital is %s" % total_capital) except BaseException: ans = input( "Do you want to try again, without checking for large capital changes? Yes/<anything else>" ) if ans == "Yes": total_capital = data_capital.update_and_return_total_capital_with_new_broker_account_value( broker_account_value, check_limit=9999) else: total_capital = "Capital not updated" print("New total capital is %s" % str(total_capital))
def update_capital_manual(): """ Interactive session that allows you to manipulate capital manually :return: Nothing """ with mongoDb() as mongo_db,\ logger("Update-Capital-Manual", mongo_db=mongo_db) as log,\ connectionIB(mongo_db = mongo_db, log=log.setup(component="IB-connection")) as ib_conn: data = dataBlob(mongo_db = mongo_db, log = log, ib_conn = ib_conn) data_capital = dataCapital(data) still_running = True while still_running: # display capital and get input user_option_int = print_capital_and_get_user_input(data_capital) if user_option_int==0: setup_initial_capital(data_capital) elif user_option_int==1: update_capital_from_ib(data_capital) elif user_option_int==2: adjust_capital_for_delta(data_capital) elif user_option_int==3: modify_any_value(data_capital) elif user_option_int==4: delete_capital_since_time(data_capital) elif user_option_int==919: delete_all_capital(data_capital) elif user_option_int==5: still_running=False break else: print("%d is not a valid option but was in list of possible options: check code" % str(user_option_int)) ## Back to top of while loop return success
def update_capital_from_ib(data: dataBlob): data_capital = dataCapital(data) broker_account_value = get_broker_account_value(data) try: total_capital = ( data_capital. update_and_return_total_capital_with_new_broker_account_value( broker_account_value)) print("New total capital is %s" % total_capital) except LargeCapitalChange: ans_is_yes = true_if_answer_is_yes( "Do you want to try again, without checking for large capital changes??" ) if ans_is_yes: total_capital = data_capital.update_and_return_total_capital_with_new_broker_account_value( broker_account_value, check_limit=A_VERY_LARGE_NUMBER) else: print("Capital not updated") return failure print("New total capital is %s" % str(total_capital))
def get_total_capital_series(data): data_capital_object = dataCapital(data) return data_capital_object.get_series_of_maximum_capital()
def total_capital(data): data_capital = dataCapital(data) total_capital = data_capital.get_current_total_capital() return total_capital
def capital(): capital_data = dataCapital(data) capital_series = capital_data.get_series_of_all_global_capital() now = capital_series.iloc[-1]["Actual"] yesterday = capital_series.last("1D").iloc[0]["Actual"] return {"now": now, "yesterday": yesterday}