class TestDependencyGraphSubscriber(unittest.TestCase): def setUp(self): contract_specification_repo = MagicMock( spec=ContractSpecificationRepository) call_dependencies_repo = MagicMock(spec=CallDependenciesRepository) call_dependents_repo = MagicMock(spec=CallDependentsRepository) call_leafs_repo = MagicMock(spec=CallLeafsRepository) call_requirement_repo = MagicMock(spec=CallRequirementRepository) self.dependency_graph_subscriber = DependencyGraphSubscriber( contract_specification_repo, call_dependencies_repo, call_dependents_repo, call_leafs_repo, call_requirement_repo, # Todo: Test call limiting in this test case. max_dependency_graph_size=None, dsl_classes={}) def tearDown(self): self.dependency_graph_subscriber.close() @patch( 'quantdsl.infrastructure.dependency_graph_subscriber.generate_dependency_graph' ) def test_dependency_graph_subscriber(self, generate_dependency_graph): market_simulation_created = ContractSpecification.Created( entity_id='1', specification='1') publish(market_simulation_created) self.assertEqual(generate_dependency_graph.call_count, 1)
def setUp(self): contract_specification_repo = MagicMock( spec=ContractSpecificationRepository) call_dependencies_repo = MagicMock(spec=CallDependenciesRepository) call_dependents_repo = MagicMock(spec=CallDependentsRepository) self.dependency_graph_subscriber = DependencyGraphSubscriber( contract_specification_repo, call_dependencies_repo, call_dependents_repo)
def setUp(self): contract_specification_repo = MagicMock( spec=ContractSpecificationRepository) call_dependencies_repo = MagicMock(spec=CallDependenciesRepository) call_dependents_repo = MagicMock(spec=CallDependentsRepository) call_leafs_repo = MagicMock(spec=CallLeafsRepository) call_requirement_repo = MagicMock(spec=CallRequirementRepository) self.dependency_graph_subscriber = DependencyGraphSubscriber( contract_specification_repo, call_dependencies_repo, call_dependents_repo, call_leafs_repo, call_requirement_repo, # Todo: Test call limiting in this test case. max_dependency_graph_size=None, dsl_classes={})
def setUp(self): contract_specification_repo = MagicMock(spec=ContractSpecificationRepository) call_dependencies_repo = MagicMock(spec=CallDependenciesRepository) call_dependents_repo = MagicMock(spec=CallDependentsRepository) self.dependency_graph_subscriber = DependencyGraphSubscriber( contract_specification_repo, call_dependencies_repo, call_dependents_repo)
class TestDependencyGraphSubscriber(unittest.TestCase): def setUp(self): contract_specification_repo = MagicMock(spec=ContractSpecificationRepository) call_dependencies_repo = MagicMock(spec=CallDependenciesRepository) call_dependents_repo = MagicMock(spec=CallDependentsRepository) self.dependency_graph_subscriber = DependencyGraphSubscriber( contract_specification_repo, call_dependencies_repo, call_dependents_repo) def tearDown(self): self.dependency_graph_subscriber.close() @patch('quantdsl.infrastructure.dependency_graph_subscriber.generate_dependency_graph') def test_dependency_graph_subscriber(self, generate_dependency_graph): market_simulation_created = ContractSpecification.Created(entity_id='1') publish(market_simulation_created) self.assertEqual(generate_dependency_graph.call_count, 1)
def __init__(self): super(BaseQuantDslApplication, self).__init__() self.contract_specification_repo = ContractSpecificationRepo(event_store=self.event_store) self.contract_valuation_repo = ContractValuationRepo(event_store=self.event_store) self.market_calibration_repo = MarketCalibrationRepo(event_store=self.event_store) self.market_simulation_repo = MarketSimulationRepo(event_store=self.event_store) self.simulated_price_repo = SimulatedPriceRepo(event_store=self.event_store) self.call_requirement_repo = CallRequirementRepo(event_store=self.event_store) self.call_dependencies_repo = CallDependenciesRepo(event_store=self.event_store) self.call_dependents_repo = CallDependentsRepo(event_store=self.event_store) self.call_link_repo = CallLinkRepo(event_store=self.event_store) self.call_result_repo = CallResultRepo(event_store=self.event_store) self.simulation_subscriber = SimulationSubscriber( market_calibration_repo=self.market_calibration_repo, market_simulation_repo=self.market_simulation_repo ) self.dependency_graph_subscriber = DependencyGraphSubscriber( contract_specification_repo=self.contract_specification_repo, call_dependencies_repo=self.call_dependencies_repo, call_dependents_repo=self.call_dependents_repo )
def __init__(self, call_evaluation_queue=None, max_dependency_graph_size=DEFAULT_MAX_DEPENDENCY_GRAPH_SIZE, dsl_classes=None, *args, **kwargs): super(QuantDslApplication, self).__init__(*args, **kwargs) self.contract_specification_repo = ContractSpecificationRepo(event_store=self.event_store, use_cache=True) self.contract_valuation_repo = ContractValuationRepo(event_store=self.event_store, use_cache=True) self.market_calibration_repo = MarketCalibrationRepo(event_store=self.event_store, use_cache=True) self.market_simulation_repo = MarketSimulationRepo(event_store=self.event_store, use_cache=True) self.perturbation_dependencies_repo = PerturbationDependenciesRepo(event_store=self.event_store, use_cache=True) self.simulated_price_requirements_repo = SimulatedPriceRequirementsRepo(event_store=self.event_store, use_cache=True) # self.simulated_price_repo = SimulatedPriceRepo(event_store=self.event_store, use_cache=True) self.simulated_price_repo = {} self.call_requirement_repo = CallRequirementRepo(event_store=self.event_store, use_cache=True) self.call_dependencies_repo = CallDependenciesRepo(event_store=self.event_store, use_cache=True) self.call_dependents_repo = CallDependentsRepo(event_store=self.event_store, use_cache=True) self.call_leafs_repo = CallLeafsRepo(event_store=self.event_store, use_cache=True) self.call_link_repo = CallLinkRepo(event_store=self.event_store, use_cache=True) # self.call_result_repo = CallResultRepo(event_store=self.event_store, use_cache=True) self.call_result_repo = {} self.call_evaluation_queue = call_evaluation_queue self.max_dependency_graph_size = max_dependency_graph_size self.dsl_classes = dsl_classes self.simulation_subscriber = SimulationSubscriber( market_calibration_repo=self.market_calibration_repo, market_simulation_repo=self.market_simulation_repo, simulated_price_repo=self.simulated_price_repo ) self.dependency_graph_subscriber = DependencyGraphSubscriber( contract_specification_repo=self.contract_specification_repo, call_dependencies_repo=self.call_dependencies_repo, call_dependents_repo=self.call_dependents_repo, call_leafs_repo=self.call_leafs_repo, call_requirement_repo=self.call_requirement_repo, max_dependency_graph_size=self.max_dependency_graph_size, dsl_classes=self.dsl_classes, ) self.evaluation_subscriber = EvaluationSubscriber( contract_valuation_repo=self.contract_valuation_repo, call_link_repo=self.call_link_repo, call_dependencies_repo=self.call_dependencies_repo, call_requirement_repo=self.call_requirement_repo, call_result_repo=self.call_result_repo, simulated_price_repo=self.simulated_price_repo, market_simulation_repo=self.market_simulation_repo, call_evaluation_queue=self.call_evaluation_queue, call_leafs_repo=self.call_leafs_repo, call_dependents_repo=self.call_dependents_repo, perturbation_dependencies_repo=self.perturbation_dependencies_repo, simulated_price_requirements_repo=self.simulated_price_requirements_repo, ) self.call_result_policy = CallResultPolicy(self.call_result_repo, self.call_evaluation_queue)
class TestDependencyGraphSubscriber(unittest.TestCase): def setUp(self): contract_specification_repo = MagicMock( spec=ContractSpecificationRepository) call_dependencies_repo = MagicMock(spec=CallDependenciesRepository) call_dependents_repo = MagicMock(spec=CallDependentsRepository) self.dependency_graph_subscriber = DependencyGraphSubscriber( contract_specification_repo, call_dependencies_repo, call_dependents_repo) def tearDown(self): self.dependency_graph_subscriber.close() @patch( 'quantdsl.infrastructure.dependency_graph_subscriber.generate_dependency_graph' ) def test_dependency_graph_subscriber(self, generate_dependency_graph): market_simulation_created = ContractSpecification.Created( entity_id='1') publish(market_simulation_created) self.assertEqual(generate_dependency_graph.call_count, 1)
def __init__(self, call_evaluation_queue=None, result_counters=None, usage_counters=None, *args, **kwargs): super(QuantDslApplication, self).__init__(*args, **kwargs) self.contract_specification_repo = ContractSpecificationRepo( event_store=self.event_store, use_cache=True) self.contract_valuation_repo = ContractValuationRepo( event_store=self.event_store, use_cache=True) self.market_calibration_repo = MarketCalibrationRepo( event_store=self.event_store, use_cache=True) self.market_simulation_repo = MarketSimulationRepo( event_store=self.event_store, use_cache=True) self.perturbation_dependencies_repo = PerturbationDependenciesRepo( event_store=self.event_store, use_cache=True) self.simulated_price_requirements_repo = SimulatedPriceRequirementsRepo( event_store=self.event_store, use_cache=True) self.simulated_price_repo = SimulatedPriceRepo( event_store=self.event_store, use_cache=True) self.call_requirement_repo = CallRequirementRepo( event_store=self.event_store, use_cache=True) self.call_dependencies_repo = CallDependenciesRepo( event_store=self.event_store, use_cache=True) self.call_dependents_repo = CallDependentsRepo( event_store=self.event_store, use_cache=True) self.call_leafs_repo = CallLeafsRepo(event_store=self.event_store, use_cache=True) self.call_link_repo = CallLinkRepo(event_store=self.event_store, use_cache=True) self.call_result_repo = CallResultRepo(event_store=self.event_store, use_cache=True) self.call_evaluation_queue = call_evaluation_queue self.result_counters = result_counters self.usage_counters = usage_counters self.simulation_subscriber = SimulationSubscriber( market_calibration_repo=self.market_calibration_repo, market_simulation_repo=self.market_simulation_repo, ) self.dependency_graph_subscriber = DependencyGraphSubscriber( contract_specification_repo=self.contract_specification_repo, call_dependencies_repo=self.call_dependencies_repo, call_dependents_repo=self.call_dependents_repo, call_leafs_repo=self.call_leafs_repo, call_requirement_repo=self.call_requirement_repo, ) self.evaluation_subscriber = EvaluationSubscriber( contract_valuation_repo=self.contract_valuation_repo, call_link_repo=self.call_link_repo, call_dependencies_repo=self.call_dependencies_repo, call_requirement_repo=self.call_requirement_repo, call_result_repo=self.call_result_repo, simulated_price_repo=self.simulated_price_repo, market_simulation_repo=self.market_simulation_repo, call_evaluation_queue=self.call_evaluation_queue, call_leafs_repo=self.call_leafs_repo, result_counters=self.result_counters, usage_counters=self.usage_counters, call_dependents_repo=self.call_dependents_repo, perturbation_dependencies_repo=self.perturbation_dependencies_repo, simulated_price_requirements_repo=self. simulated_price_requirements_repo, )
class QuantDslApplication(EventSourcingApplication): """ Flow of user stories: Register contract specification (DSL text). --> gives required market names Generate compile call dependency graph using contract specification (and observation time?). --> gives required fixing times Register price histories. Generate market calibration for required market names using available price histories and observation time. Generate market simulation for required market names from market calibration, observation time, and fixing times. Evaluate contract given call dependency graph and market simulation. """ def __init__(self, call_evaluation_queue=None, result_counters=None, usage_counters=None, *args, **kwargs): super(QuantDslApplication, self).__init__(*args, **kwargs) self.contract_specification_repo = ContractSpecificationRepo( event_store=self.event_store, use_cache=True) self.contract_valuation_repo = ContractValuationRepo( event_store=self.event_store, use_cache=True) self.market_calibration_repo = MarketCalibrationRepo( event_store=self.event_store, use_cache=True) self.market_simulation_repo = MarketSimulationRepo( event_store=self.event_store, use_cache=True) self.perturbation_dependencies_repo = PerturbationDependenciesRepo( event_store=self.event_store, use_cache=True) self.simulated_price_requirements_repo = SimulatedPriceRequirementsRepo( event_store=self.event_store, use_cache=True) self.simulated_price_repo = SimulatedPriceRepo( event_store=self.event_store, use_cache=True) self.call_requirement_repo = CallRequirementRepo( event_store=self.event_store, use_cache=True) self.call_dependencies_repo = CallDependenciesRepo( event_store=self.event_store, use_cache=True) self.call_dependents_repo = CallDependentsRepo( event_store=self.event_store, use_cache=True) self.call_leafs_repo = CallLeafsRepo(event_store=self.event_store, use_cache=True) self.call_link_repo = CallLinkRepo(event_store=self.event_store, use_cache=True) self.call_result_repo = CallResultRepo(event_store=self.event_store, use_cache=True) self.call_evaluation_queue = call_evaluation_queue self.result_counters = result_counters self.usage_counters = usage_counters self.simulation_subscriber = SimulationSubscriber( market_calibration_repo=self.market_calibration_repo, market_simulation_repo=self.market_simulation_repo, ) self.dependency_graph_subscriber = DependencyGraphSubscriber( contract_specification_repo=self.contract_specification_repo, call_dependencies_repo=self.call_dependencies_repo, call_dependents_repo=self.call_dependents_repo, call_leafs_repo=self.call_leafs_repo, call_requirement_repo=self.call_requirement_repo, ) self.evaluation_subscriber = EvaluationSubscriber( contract_valuation_repo=self.contract_valuation_repo, call_link_repo=self.call_link_repo, call_dependencies_repo=self.call_dependencies_repo, call_requirement_repo=self.call_requirement_repo, call_result_repo=self.call_result_repo, simulated_price_repo=self.simulated_price_repo, market_simulation_repo=self.market_simulation_repo, call_evaluation_queue=self.call_evaluation_queue, call_leafs_repo=self.call_leafs_repo, result_counters=self.result_counters, usage_counters=self.usage_counters, call_dependents_repo=self.call_dependents_repo, perturbation_dependencies_repo=self.perturbation_dependencies_repo, simulated_price_requirements_repo=self. simulated_price_requirements_repo, ) @abstractmethod def create_stored_event_repo(self, **kwargs): raise NotImplementedError() def close(self): self.evaluation_subscriber.close() self.dependency_graph_subscriber.close() self.simulation_subscriber.close() super(QuantDslApplication, self).close() # Todo: Register historical data. def compute_market_calibration_params(self, price_process_name, historical_data): """ Returns market calibration params for given price process name and historical data. """ return compute_market_calibration_params(price_process_name, historical_data) def register_contract_specification(self, specification): """ The contract specification is a Quant DSL module. """ return register_contract_specification(specification=specification) def register_market_calibration(self, price_process_name, calibration_params): """ Calibration params result from fitting a model of market dynamics to historical data. """ assert isinstance(price_process_name, six.string_types) assert isinstance(calibration_params, (dict, list)) return register_market_calibration(price_process_name, calibration_params) def register_market_simulation(self, market_calibration_id, observation_date, requirements, path_count, interest_rate): """ A market simulation has simulated prices at specified times across a set of markets. """ return register_market_simulation(market_calibration_id, observation_date, requirements, path_count, interest_rate) def register_dependency_graph(self, contract_specification_id): return register_dependency_graph(contract_specification_id) def register_call_requirement(self, call_id, dsl_source, effective_present_time): """ A call requirement is a node of the dependency graph. """ return register_call_requirement( call_id=call_id, dsl_source=dsl_source, effective_present_time=effective_present_time) def register_call_dependencies(self, call_id, dependencies): return register_call_dependencies(call_id=call_id, dependencies=dependencies) def register_call_dependents(self, call_id, dependents): return register_call_dependents(call_id=call_id, dependents=dependents) def register_call_link(self, link_id, call_id): return register_call_link(link_id, call_id) def identify_simulation_requirements(self, contract_specification, observation_date, requirements): assert isinstance(contract_specification, ContractSpecification), contract_specification assert isinstance(requirements, set) return identify_simulation_requirements( contract_specification.id, self.call_requirement_repo, self.call_link_repo, self.call_dependencies_repo, self.perturbation_dependencies_repo, observation_date, requirements) def start_contract_valuation(self, entity_id, dependency_graph_id, market_simulation): assert isinstance(dependency_graph_id, six.string_types), dependency_graph_id assert isinstance(market_simulation, MarketSimulation) return start_contract_valuation(entity_id, dependency_graph_id, market_simulation.id) def loop_on_evaluation_queue(self, call_result_lock, compute_pool=None, result_counters=None, usage_counters=None): loop_on_evaluation_queue( call_evaluation_queue=self.call_evaluation_queue, contract_valuation_repo=self.contract_valuation_repo, call_requirement_repo=self.call_requirement_repo, market_simulation_repo=self.market_simulation_repo, call_dependencies_repo=self.call_dependencies_repo, call_result_repo=self.call_result_repo, simulated_price_repo=self.simulated_price_repo, call_dependents_repo=self.call_dependents_repo, perturbation_dependencies_repo=self.perturbation_dependencies_repo, simulated_price_requirements_repo=self. simulated_price_requirements_repo, call_result_lock=call_result_lock, compute_pool=compute_pool, result_counters=result_counters, usage_counters=usage_counters, ) def evaluate_call_and_queue_next_calls(self, contract_valuation_id, dependency_graph_id, call_id, lock): evaluate_call_and_queue_next_calls( contract_valuation_id=contract_valuation_id, dependency_graph_id=dependency_graph_id, call_id=call_id, call_evaluation_queue=self.call_evaluation_queue, contract_valuation_repo=self.contract_valuation_repo, call_requirement_repo=self.call_requirement_repo, market_simulation_repo=self.market_simulation_repo, call_dependencies_repo=self.call_dependencies_repo, call_result_repo=self.call_result_repo, simulated_price_repo=self.simulated_price_repo, call_dependents_repo=self.call_dependents_repo, perturbation_dependencies_repo=self.perturbation_dependencies_repo, simulated_price_requirements_repo=self. simulated_price_requirements_repo, call_result_lock=lock, ) def compile(self, specification): return self.register_contract_specification( specification=specification) def simulate(self, contract_specification, market_calibration, observation_date, path_count=20000, interest_rate='2.5'): simulation_requirements = set() self.identify_simulation_requirements(contract_specification, observation_date, simulation_requirements) market_simulation = self.register_market_simulation( market_calibration_id=market_calibration.id, requirements=list(simulation_requirements), observation_date=observation_date, path_count=path_count, interest_rate=interest_rate, ) return market_simulation def evaluate(self, contract_specification, market_simulation): contract_valuation_id = create_contract_valuation_id() call_result_id = make_call_result_id(contract_valuation_id, contract_specification.id) self.start_contract_valuation(contract_valuation_id, contract_specification.id, market_simulation) return self.call_result_repo[call_result_id]
def __init__(self, call_evaluation_queue=None, max_dependency_graph_size=DEFAULT_MAX_DEPENDENCY_GRAPH_SIZE, dsl_classes=None, *args, **kwargs): super(QuantDslApplication, self).__init__(*args, **kwargs) self.contract_specification_repo = ContractSpecificationRepo( event_store=self.event_store, use_cache=True) self.contract_valuation_repo = ContractValuationRepo( event_store=self.event_store, use_cache=True) self.market_calibration_repo = MarketCalibrationRepo( event_store=self.event_store, use_cache=True) self.market_simulation_repo = MarketSimulationRepo( event_store=self.event_store, use_cache=True) self.perturbation_dependencies_repo = PerturbationDependenciesRepo( event_store=self.event_store, use_cache=True) self.simulated_price_requirements_repo = SimulatedPriceRequirementsRepo( event_store=self.event_store, use_cache=True) # self.simulated_price_repo = SimulatedPriceRepo(event_store=self.event_store, use_cache=True) self.simulated_price_repo = {} self.call_requirement_repo = CallRequirementRepo( event_store=self.event_store, use_cache=True) self.call_dependencies_repo = CallDependenciesRepo( event_store=self.event_store, use_cache=True) self.call_dependents_repo = CallDependentsRepo( event_store=self.event_store, use_cache=True) self.call_leafs_repo = CallLeafsRepo(event_store=self.event_store, use_cache=True) self.call_link_repo = CallLinkRepo(event_store=self.event_store, use_cache=True) # self.call_result_repo = CallResultRepo(event_store=self.event_store, use_cache=True) self.call_result_repo = {} self.call_evaluation_queue = call_evaluation_queue self.max_dependency_graph_size = max_dependency_graph_size self.dsl_classes = dsl_classes self.simulation_subscriber = SimulationSubscriber( market_calibration_repo=self.market_calibration_repo, market_simulation_repo=self.market_simulation_repo, simulated_price_repo=self.simulated_price_repo) self.dependency_graph_subscriber = DependencyGraphSubscriber( contract_specification_repo=self.contract_specification_repo, call_dependencies_repo=self.call_dependencies_repo, call_dependents_repo=self.call_dependents_repo, call_leafs_repo=self.call_leafs_repo, call_requirement_repo=self.call_requirement_repo, max_dependency_graph_size=self.max_dependency_graph_size, dsl_classes=self.dsl_classes, ) self.evaluation_subscriber = EvaluationSubscriber( contract_valuation_repo=self.contract_valuation_repo, call_link_repo=self.call_link_repo, call_dependencies_repo=self.call_dependencies_repo, call_requirement_repo=self.call_requirement_repo, call_result_repo=self.call_result_repo, simulated_price_repo=self.simulated_price_repo, market_simulation_repo=self.market_simulation_repo, call_evaluation_queue=self.call_evaluation_queue, call_leafs_repo=self.call_leafs_repo, call_dependents_repo=self.call_dependents_repo, perturbation_dependencies_repo=self.perturbation_dependencies_repo, simulated_price_requirements_repo=self. simulated_price_requirements_repo, ) self.call_result_policy = CallResultPolicy(self.call_result_repo, self.call_evaluation_queue)
class QuantDslApplication(EventSourcingApplication): """ Flow of user stories: Register contract specification (DSL text). --> gives required market names Generate compile call dependency graph using contract specification (and observation time?). --> gives required fixing times Register price histories. Generate market calibration for required market names using available price histories and observation time. Generate market simulation for required market names from market calibration, observation time, and fixing times. Evaluate contract given call dependency graph and market simulation. """ def __init__(self, call_evaluation_queue=None, max_dependency_graph_size=DEFAULT_MAX_DEPENDENCY_GRAPH_SIZE, dsl_classes=None, *args, **kwargs): super(QuantDslApplication, self).__init__(*args, **kwargs) self.contract_specification_repo = ContractSpecificationRepo( event_store=self.event_store, use_cache=True) self.contract_valuation_repo = ContractValuationRepo( event_store=self.event_store, use_cache=True) self.market_calibration_repo = MarketCalibrationRepo( event_store=self.event_store, use_cache=True) self.market_simulation_repo = MarketSimulationRepo( event_store=self.event_store, use_cache=True) self.perturbation_dependencies_repo = PerturbationDependenciesRepo( event_store=self.event_store, use_cache=True) self.simulated_price_requirements_repo = SimulatedPriceRequirementsRepo( event_store=self.event_store, use_cache=True) # self.simulated_price_repo = SimulatedPriceRepo(event_store=self.event_store, use_cache=True) self.simulated_price_repo = {} self.call_requirement_repo = CallRequirementRepo( event_store=self.event_store, use_cache=True) self.call_dependencies_repo = CallDependenciesRepo( event_store=self.event_store, use_cache=True) self.call_dependents_repo = CallDependentsRepo( event_store=self.event_store, use_cache=True) self.call_leafs_repo = CallLeafsRepo(event_store=self.event_store, use_cache=True) self.call_link_repo = CallLinkRepo(event_store=self.event_store, use_cache=True) # self.call_result_repo = CallResultRepo(event_store=self.event_store, use_cache=True) self.call_result_repo = {} self.call_evaluation_queue = call_evaluation_queue self.max_dependency_graph_size = max_dependency_graph_size self.dsl_classes = dsl_classes self.simulation_subscriber = SimulationSubscriber( market_calibration_repo=self.market_calibration_repo, market_simulation_repo=self.market_simulation_repo, simulated_price_repo=self.simulated_price_repo) self.dependency_graph_subscriber = DependencyGraphSubscriber( contract_specification_repo=self.contract_specification_repo, call_dependencies_repo=self.call_dependencies_repo, call_dependents_repo=self.call_dependents_repo, call_leafs_repo=self.call_leafs_repo, call_requirement_repo=self.call_requirement_repo, max_dependency_graph_size=self.max_dependency_graph_size, dsl_classes=self.dsl_classes, ) self.evaluation_subscriber = EvaluationSubscriber( contract_valuation_repo=self.contract_valuation_repo, call_link_repo=self.call_link_repo, call_dependencies_repo=self.call_dependencies_repo, call_requirement_repo=self.call_requirement_repo, call_result_repo=self.call_result_repo, simulated_price_repo=self.simulated_price_repo, market_simulation_repo=self.market_simulation_repo, call_evaluation_queue=self.call_evaluation_queue, call_leafs_repo=self.call_leafs_repo, call_dependents_repo=self.call_dependents_repo, perturbation_dependencies_repo=self.perturbation_dependencies_repo, simulated_price_requirements_repo=self. simulated_price_requirements_repo, ) self.call_result_policy = CallResultPolicy(self.call_result_repo, self.call_evaluation_queue) def create_persistence_subscriber(self): return PersistencePolicy(event_store=self.event_store) def close(self): self.evaluation_subscriber.close() self.dependency_graph_subscriber.close() self.simulation_subscriber.close() self.call_result_policy.close() super(QuantDslApplication, self).close() def register_contract_specification(self, source_code, observation_date=None): """ Registers a new contract specification, from given Quant DSL source code. """ return register_contract_specification( source_code=source_code, observation_date=observation_date) def register_market_calibration(self, price_process_name, calibration_params): """ Calibration params result from fitting a model of market dynamics to historical data. """ assert isinstance(price_process_name, six.string_types) assert isinstance(calibration_params, (dict, list)) return register_market_calibration(price_process_name, calibration_params) def register_market_simulation(self, market_calibration_id, observation_date, requirements, path_count, interest_rate, perturbation_factor=0.001): """ A market simulation has simulated prices at specified times across a set of markets. """ return register_market_simulation(market_calibration_id, observation_date, requirements, path_count, interest_rate, perturbation_factor) def register_call_dependencies(self, call_id, dependencies): return register_call_dependencies(call_id=call_id, dependencies=dependencies) def register_call_dependents(self, call_id, dependents): return register_call_dependents(call_id=call_id, dependents=dependents) def identify_simulation_requirements(self, contract_specification, observation_date, requirements, periodisation): assert isinstance(contract_specification, ContractSpecification), type(contract_specification) assert isinstance(requirements, set) return identify_simulation_requirements(contract_specification.id, self.call_requirement_repo, self.call_link_repo, self.call_dependencies_repo, observation_date, requirements, periodisation) def start_contract_valuation(self, contract_specification_id, market_simulation_id, periodisation, is_double_sided_deltas): return start_contract_valuation(contract_specification_id, market_simulation_id, periodisation, is_double_sided_deltas) def loop_on_evaluation_queue(self): loop_on_evaluation_queue( call_evaluation_queue=self.call_evaluation_queue, contract_valuation_repo=self.contract_valuation_repo, call_requirement_repo=self.call_requirement_repo, market_simulation_repo=self.market_simulation_repo, call_dependencies_repo=self.call_dependencies_repo, call_result_repo=self.call_result_repo, simulated_price_repo=self.simulated_price_repo, perturbation_dependencies_repo=self.perturbation_dependencies_repo, simulated_price_requirements_repo=self. simulated_price_requirements_repo, ) def compile(self, source_code, observation_date=None): return self.register_contract_specification( source_code=source_code, observation_date=observation_date) def simulate(self, contract_specification, price_process_name, calibration_params, observation_date, path_count=20000, interest_rate='2.5', perturbation_factor=0.01, periodisation=None): market_calibration = self.register_market_calibration( price_process_name, calibration_params) simulation_requirements = set() self.identify_simulation_requirements(contract_specification, observation_date, simulation_requirements, periodisation) market_simulation = self.register_market_simulation( market_calibration_id=market_calibration.id, requirements=list(simulation_requirements), observation_date=observation_date, path_count=path_count, interest_rate=interest_rate, perturbation_factor=perturbation_factor, ) return market_simulation def evaluate(self, contract_specification_id, market_simulation_id, periodisation=None, is_double_sided_deltas=False): return self.start_contract_valuation(contract_specification_id, market_simulation_id, periodisation, is_double_sided_deltas) def read_results(self, evaluation): assert isinstance(evaluation, ContractValuation) market_simulation = self.market_simulation_repo[ evaluation.market_simulation_id] call_result_id = make_call_result_id( evaluation.id, evaluation.contract_specification_id) call_result = self.call_result_repo[call_result_id] fair_value = call_result.result_value perturbation_names = call_result.perturbed_values.keys() perturbation_names = [ i for i in perturbation_names if not i.startswith('-') ] perturbation_names = sorted( perturbation_names, key=lambda x: [int(i) for i in x.split('-')[1:]]) periods = [] for perturbation_name in perturbation_names: perturbed_value = call_result.perturbed_values[perturbation_name] if evaluation.is_double_sided_deltas: perturbed_value_negative = call_result.perturbed_values[ '-' + perturbation_name] else: perturbed_value_negative = None # Assumes format: NAME-YEAR-MONTH perturbed_name_split = perturbation_name.split('-') market_name = perturbed_name_split[0] if market_name == perturbation_name: simulated_price_id = make_simulated_price_id( market_simulation.id, market_name, market_simulation.observation_date, market_simulation.observation_date) simulated_price = self.simulated_price_repo[simulated_price_id] price = simulated_price.value if evaluation.is_double_sided_deltas: dy = perturbed_value - perturbed_value_negative else: dy = perturbed_value - fair_value dx = market_simulation.perturbation_factor * price if evaluation.is_double_sided_deltas: dx *= 2 delta = dy / dx hedge_units = -delta hedge_cost = hedge_units * price periods.append({ 'market_name': market_name, 'delivery_date': None, 'delta': delta, 'perturbation_name': perturbation_name, 'hedge_units': hedge_units, 'price_simulated': price, 'price_discounted': price, 'hedge_cost': hedge_cost, }) elif len(perturbed_name_split) > 2: year = int(perturbed_name_split[1]) month = int(perturbed_name_split[2]) if len(perturbed_name_split) > 3: day = int(perturbed_name_split[3]) delivery_date = datetime.date(year, month, day) simulated_price_id = make_simulated_price_id( market_simulation.id, market_name, delivery_date, delivery_date) simulated_price = self.simulated_price_repo[ simulated_price_id] simulated_price_value = simulated_price.value else: delivery_date = datetime.date(year, month, 1) sum_simulated_prices = 0 count_simulated_prices = 0 for i in range(1, 32): try: _delivery_date = datetime.date(year, month, i) except ValueError: continue else: simulated_price_id = make_simulated_price_id( market_simulation.id, market_name, _delivery_date, _delivery_date) try: simulated_price = self.simulated_price_repo[ simulated_price_id] except KeyError: pass else: sum_simulated_prices += simulated_price.value count_simulated_prices += 1 assert count_simulated_prices, "Can't find any simulated prices for {}-{}".format( year, month) simulated_price_value = sum_simulated_prices / count_simulated_prices # Assume present time of perturbed values is observation date. if evaluation.is_double_sided_deltas: dy = perturbed_value - perturbed_value_negative else: dy = perturbed_value - fair_value discount_rate = discount( value=1, present_date=market_simulation.observation_date, value_date=delivery_date, interest_rate=market_simulation.interest_rate) discounted_simulated_price_value = simulated_price_value * discount_rate dx = market_simulation.perturbation_factor * simulated_price_value if evaluation.is_double_sided_deltas: dx *= 2 delta = dy / dx # The delta of a forward contract at the observation date # is the discount factor at the delivery date. forward_contract_delta = discount_rate # Flatten the book with delta hedging in forward markets. # delta + hedge-units * hedge-delta = 0 # hence: hedge-units = -delta / hedge-delta hedge_units = -delta / forward_contract_delta # Present value of cost of hedge. hedge_cost = hedge_units * discounted_simulated_price_value periods.append({ 'market_name': market_name, 'delivery_date': delivery_date, 'delta': delta, 'perturbation_name': perturbation_name, 'hedge_units': hedge_units, 'price_simulated': simulated_price_value, 'price_discounted': discounted_simulated_price_value, 'hedge_cost': hedge_cost, }) return Results(fair_value, periods) def wait_results(self, contract_valuation): self.get_result(contract_valuation) def get_result(self, contract_valuation): call_result_id = make_call_result_id( contract_valuation.id, contract_valuation.contract_specification_id) return self.call_result_repo[call_result_id] def calc_call_count(self, contract_specification_id): # Todo: Return the call count from the compilation method? return len( list( regenerate_execution_order(contract_specification_id, self.call_link_repo))) def calc_counts_and_costs(self, contract_specification_id, is_double_sided_deltas): """Returns a dict of call IDs -> perturbation requirements.""" costs = {} counts = {} for call_id in regenerate_execution_order(contract_specification_id, self.call_link_repo): # Get estimated cost of evaluating the expression once. call_requirement = self.call_requirement_repo[call_id] estimated_cost_of_expr = call_requirement.cost # Get the perturbation requirements for this call. perturbation_dependencies = self.perturbation_dependencies_repo[ call_id] assert isinstance(perturbation_dependencies, PerturbationDependencies) # "1 + 2 * number of dependencies" because of the double sided delta. num_perturbation_dependencies = len( perturbation_dependencies.dependencies) num_perturbations = (2 if is_double_sided_deltas else 1) * num_perturbation_dependencies num_evaluations = 1 + num_perturbations # Cost is cost of doing it once, times the number of times it needs doing. costs[call_id] = num_evaluations * estimated_cost_of_expr counts[call_id] = num_evaluations return counts, costs
class BaseQuantDslApplication(EventSourcingApplication): """ Flow of user stories: Register contract specification (DSL text). --> gives required market names Generate compile call dependency graph using contract specification (and observation time?). --> gives required fixing times Register price histories. Generate market calibration for required market names using available price histories and observation time. Generate market simulation for required market names from market calibration, observation time, and fixing times. Evaluate contract given call dependency graph and market simulation. """ def __init__(self): super(BaseQuantDslApplication, self).__init__() self.contract_specification_repo = ContractSpecificationRepo(event_store=self.event_store) self.contract_valuation_repo = ContractValuationRepo(event_store=self.event_store) self.market_calibration_repo = MarketCalibrationRepo(event_store=self.event_store) self.market_simulation_repo = MarketSimulationRepo(event_store=self.event_store) self.simulated_price_repo = SimulatedPriceRepo(event_store=self.event_store) self.call_requirement_repo = CallRequirementRepo(event_store=self.event_store) self.call_dependencies_repo = CallDependenciesRepo(event_store=self.event_store) self.call_dependents_repo = CallDependentsRepo(event_store=self.event_store) self.call_link_repo = CallLinkRepo(event_store=self.event_store) self.call_result_repo = CallResultRepo(event_store=self.event_store) self.simulation_subscriber = SimulationSubscriber( market_calibration_repo=self.market_calibration_repo, market_simulation_repo=self.market_simulation_repo ) self.dependency_graph_subscriber = DependencyGraphSubscriber( contract_specification_repo=self.contract_specification_repo, call_dependencies_repo=self.call_dependencies_repo, call_dependents_repo=self.call_dependents_repo ) def close(self): self.dependency_graph_subscriber.close() self.simulation_subscriber.close() super(BaseQuantDslApplication, self).close() # Todo: Register historical data. def compute_market_calibration_params(self, price_process_name, historical_data): """ Returns market calibration params for given price process name and historical data. """ return compute_market_calibration_params(price_process_name, historical_data) def register_contract_specification(self, specification): """ The contract specification is a Quant DSL module. """ return register_contract_specification(specification=specification) def register_market_calibration(self, price_process_name, calibration_params): """ Calibration params result from fitting a model of market dynamics to historical data. """ assert isinstance(price_process_name, six.string_types) assert isinstance(calibration_params, dict) return register_market_calibration(price_process_name, calibration_params) def register_market_simulation(self, market_calibration_id, market_names, fixing_dates, observation_date, path_count, interest_rate): """ A market simulation has simulated prices at specified times across a set of markets. """ return register_market_simulation(market_calibration_id, market_names, fixing_dates, observation_date, path_count, interest_rate) def register_dependency_graph(self, contract_specification_id): return register_dependency_graph(contract_specification_id) def register_call_requirement(self, call_id, dsl_source, effective_present_time): """ A call requirement is a node of the dependency graph. """ return register_call_requirement( call_id=call_id, dsl_source=dsl_source, effective_present_time=effective_present_time ) def register_call_dependencies(self, call_id, dependencies): return register_call_dependencies(call_id=call_id, dependencies=dependencies) def register_call_dependents(self, call_id, dependents): return register_call_dependents(call_id=call_id, dependents=dependents) def register_call_link(self, link_id, call_id): return register_call_link(link_id, call_id) def generate_dependency_graph(self, contract_specification): return generate_dependency_graph(contract_specification, self.call_dependencies_repo, self.call_dependents_repo) def register_call_result(self, call_id, result_value): return register_call_result(call_id=call_id, result_value=result_value) def register_contract_valuation(self, dependency_graph_id): return register_contract_valuation(dependency_graph_id) def generate_contract_valuation(self, dependency_graph_id, market_simulation): assert isinstance(dependency_graph_id, six.string_types), dependency_graph_id assert isinstance(market_simulation, MarketSimulation) v = self.register_contract_valuation(dependency_graph_id) for call_id in regenerate_execution_order(dependency_graph_id, self.call_link_repo): call = self.call_requirement_repo[call_id] assert isinstance(call, CallRequirement) # Evaluate the call requirement. dependency_values = get_dependency_values(call_id, self.call_dependencies_repo, self.call_result_repo) # - parse the expr stubbed_module = dsl_parse(call.dsl_source) assert isinstance(stubbed_module, Module), "Parsed stubbed expr string is not a module: %s" % stubbed_module # - build a namespace from the dependency values dsl_locals = DslNamespace(dependency_values) # - compile the parsed expr dsl_expr = stubbed_module.body[0].reduce(dsl_locals=dsl_locals, dsl_globals=DslNamespace()) assert isinstance(dsl_expr, DslExpression), dsl_expr # - evaluate the compiled expr first_market_name = market_simulation.market_names[0] if market_simulation.market_names else None evaluation_kwds = { 'simulated_price_repo': self.simulated_price_repo, 'simulation_id': market_simulation.id, 'interest_rate': market_simulation.interest_rate, 'present_time': call.effective_present_time or market_simulation.observation_date, 'first_market_name': first_market_name, } result_value = dsl_expr.evaluate(**evaluation_kwds) # - store the result register_call_result(call_id=call_id, result_value=result_value)
class QuantDslApplication(EventSourcingApplication): """ Flow of user stories: Register contract specification (DSL text). --> gives required market names Generate compile call dependency graph using contract specification (and observation time?). --> gives required fixing times Register price histories. Generate market calibration for required market names using available price histories and observation time. Generate market simulation for required market names from market calibration, observation time, and fixing times. Evaluate contract given call dependency graph and market simulation. """ def __init__(self, call_evaluation_queue=None, max_dependency_graph_size=DEFAULT_MAX_DEPENDENCY_GRAPH_SIZE, dsl_classes=None, *args, **kwargs): super(QuantDslApplication, self).__init__(*args, **kwargs) self.contract_specification_repo = ContractSpecificationRepo(event_store=self.event_store, use_cache=True) self.contract_valuation_repo = ContractValuationRepo(event_store=self.event_store, use_cache=True) self.market_calibration_repo = MarketCalibrationRepo(event_store=self.event_store, use_cache=True) self.market_simulation_repo = MarketSimulationRepo(event_store=self.event_store, use_cache=True) self.perturbation_dependencies_repo = PerturbationDependenciesRepo(event_store=self.event_store, use_cache=True) self.simulated_price_requirements_repo = SimulatedPriceRequirementsRepo(event_store=self.event_store, use_cache=True) # self.simulated_price_repo = SimulatedPriceRepo(event_store=self.event_store, use_cache=True) self.simulated_price_repo = {} self.call_requirement_repo = CallRequirementRepo(event_store=self.event_store, use_cache=True) self.call_dependencies_repo = CallDependenciesRepo(event_store=self.event_store, use_cache=True) self.call_dependents_repo = CallDependentsRepo(event_store=self.event_store, use_cache=True) self.call_leafs_repo = CallLeafsRepo(event_store=self.event_store, use_cache=True) self.call_link_repo = CallLinkRepo(event_store=self.event_store, use_cache=True) # self.call_result_repo = CallResultRepo(event_store=self.event_store, use_cache=True) self.call_result_repo = {} self.call_evaluation_queue = call_evaluation_queue self.max_dependency_graph_size = max_dependency_graph_size self.dsl_classes = dsl_classes self.simulation_subscriber = SimulationSubscriber( market_calibration_repo=self.market_calibration_repo, market_simulation_repo=self.market_simulation_repo, simulated_price_repo=self.simulated_price_repo ) self.dependency_graph_subscriber = DependencyGraphSubscriber( contract_specification_repo=self.contract_specification_repo, call_dependencies_repo=self.call_dependencies_repo, call_dependents_repo=self.call_dependents_repo, call_leafs_repo=self.call_leafs_repo, call_requirement_repo=self.call_requirement_repo, max_dependency_graph_size=self.max_dependency_graph_size, dsl_classes=self.dsl_classes, ) self.evaluation_subscriber = EvaluationSubscriber( contract_valuation_repo=self.contract_valuation_repo, call_link_repo=self.call_link_repo, call_dependencies_repo=self.call_dependencies_repo, call_requirement_repo=self.call_requirement_repo, call_result_repo=self.call_result_repo, simulated_price_repo=self.simulated_price_repo, market_simulation_repo=self.market_simulation_repo, call_evaluation_queue=self.call_evaluation_queue, call_leafs_repo=self.call_leafs_repo, call_dependents_repo=self.call_dependents_repo, perturbation_dependencies_repo=self.perturbation_dependencies_repo, simulated_price_requirements_repo=self.simulated_price_requirements_repo, ) self.call_result_policy = CallResultPolicy(self.call_result_repo, self.call_evaluation_queue) def create_persistence_subscriber(self): return PersistencePolicy(event_store=self.event_store) def close(self): self.evaluation_subscriber.close() self.dependency_graph_subscriber.close() self.simulation_subscriber.close() self.call_result_policy.close() super(QuantDslApplication, self).close() def register_contract_specification(self, source_code, observation_date=None): """ Registers a new contract specification, from given Quant DSL source code. """ return register_contract_specification(source_code=source_code, observation_date=observation_date) def register_market_calibration(self, price_process_name, calibration_params): """ Calibration params result from fitting a model of market dynamics to historical data. """ assert isinstance(price_process_name, six.string_types) assert isinstance(calibration_params, (dict, list)) return register_market_calibration(price_process_name, calibration_params) def register_market_simulation(self, market_calibration_id, observation_date, requirements, path_count, interest_rate, perturbation_factor=0.001): """ A market simulation has simulated prices at specified times across a set of markets. """ return register_market_simulation(market_calibration_id, observation_date, requirements, path_count, interest_rate, perturbation_factor) def register_call_dependencies(self, call_id, dependencies): return register_call_dependencies(call_id=call_id, dependencies=dependencies) def register_call_dependents(self, call_id, dependents): return register_call_dependents(call_id=call_id, dependents=dependents) def identify_simulation_requirements(self, contract_specification, observation_date, requirements, periodisation): assert isinstance(contract_specification, ContractSpecification), type(contract_specification) assert isinstance(requirements, set) return identify_simulation_requirements(contract_specification.id, self.call_requirement_repo, self.call_link_repo, self.call_dependencies_repo, observation_date, requirements, periodisation) def start_contract_valuation(self, contract_specification_id, market_simulation_id, periodisation, is_double_sided_deltas): return start_contract_valuation(contract_specification_id, market_simulation_id, periodisation, is_double_sided_deltas) def loop_on_evaluation_queue(self): loop_on_evaluation_queue( call_evaluation_queue=self.call_evaluation_queue, contract_valuation_repo=self.contract_valuation_repo, call_requirement_repo=self.call_requirement_repo, market_simulation_repo=self.market_simulation_repo, call_dependencies_repo=self.call_dependencies_repo, call_result_repo=self.call_result_repo, simulated_price_repo=self.simulated_price_repo, perturbation_dependencies_repo=self.perturbation_dependencies_repo, simulated_price_requirements_repo=self.simulated_price_requirements_repo, ) def compile(self, source_code, observation_date=None): return self.register_contract_specification(source_code=source_code, observation_date=observation_date) def simulate(self, contract_specification, price_process_name, calibration_params, observation_date, path_count=20000, interest_rate='2.5', perturbation_factor=0.01, periodisation=None): market_calibration = self.register_market_calibration(price_process_name, calibration_params) simulation_requirements = set() self.identify_simulation_requirements(contract_specification, observation_date, simulation_requirements, periodisation) market_simulation = self.register_market_simulation( market_calibration_id=market_calibration.id, requirements=list(simulation_requirements), observation_date=observation_date, path_count=path_count, interest_rate=interest_rate, perturbation_factor=perturbation_factor, ) return market_simulation def evaluate(self, contract_specification_id, market_simulation_id, periodisation=None, is_double_sided_deltas=False): return self.start_contract_valuation(contract_specification_id, market_simulation_id, periodisation, is_double_sided_deltas) def get_result(self, contract_valuation): call_result_id = make_call_result_id(contract_valuation.id, contract_valuation.contract_specification_id) return self.call_result_repo[call_result_id] def get_periods(self, contract_valuation): assert isinstance(contract_valuation, ContractValuation) market_simulation = self.market_simulation_repo[contract_valuation.market_simulation_id] call_result_id = make_call_result_id(contract_valuation.id, contract_valuation.contract_specification_id) call_result = self.call_result_repo[call_result_id] fair_value = call_result.result_value perturbation_names = call_result.perturbed_values.keys() perturbation_names = [i for i in perturbation_names if not i.startswith('-')] perturbation_names = sorted(perturbation_names, key=lambda x: [int(i) for i in x.split('-')[1:]]) periods = [] for perturbation_name in perturbation_names: perturbed_value = call_result.perturbed_values[perturbation_name] if contract_valuation.is_double_sided_deltas: perturbed_value_negative = call_result.perturbed_values['-' + perturbation_name] else: perturbed_value_negative = None # Assumes format: NAME-YEAR-MONTH perturbed_name_split = perturbation_name.split('-') market_name = perturbed_name_split[0] if market_name == perturbation_name: simulated_price_id = make_simulated_price_id(market_simulation.id, market_name, market_simulation.observation_date, market_simulation.observation_date) simulated_price = self.simulated_price_repo[simulated_price_id] price = simulated_price.value if contract_valuation.is_double_sided_deltas: dy = perturbed_value - perturbed_value_negative else: dy = perturbed_value - fair_value dx = market_simulation.perturbation_factor * price if contract_valuation.is_double_sided_deltas: dx *= 2 delta = dy / dx hedge_units = - delta hedge_cost = hedge_units * price periods.append({ 'market_name': market_name, 'delivery_date': None, 'delta': delta, 'perturbation_name': perturbation_name, 'hedge_units': hedge_units, 'price_simulated': price, 'price_discounted': price, 'hedge_cost': hedge_cost, 'cash': -hedge_cost, }) elif len(perturbed_name_split) > 2: year = int(perturbed_name_split[1]) month = int(perturbed_name_split[2]) if len(perturbed_name_split) > 3: day = int(perturbed_name_split[3]) delivery_date = datetime.date(year, month, day) simulated_price_id = make_simulated_price_id( market_simulation.id, market_name, delivery_date, delivery_date ) simulated_price = self.simulated_price_repo[simulated_price_id] simulated_price_value = simulated_price.value else: delivery_date = datetime.date(year, month, 1) sum_simulated_prices = 0 count_simulated_prices = 0 for i in range(1, 32): try: _delivery_date = datetime.date(year, month, i) except ValueError: continue else: simulated_price_id = make_simulated_price_id( market_simulation.id, market_name, _delivery_date, _delivery_date ) try: simulated_price = self.simulated_price_repo[simulated_price_id] except KeyError: pass else: sum_simulated_prices += simulated_price.value count_simulated_prices += 1 assert count_simulated_prices, "Can't find any simulated prices for {}-{}".format(year, month) simulated_price_value = sum_simulated_prices / count_simulated_prices # Assume present time of perturbed values is observation date. if contract_valuation.is_double_sided_deltas: dy = perturbed_value - perturbed_value_negative else: dy = perturbed_value - fair_value discount_rate = discount( value=1, present_date=market_simulation.observation_date, value_date=delivery_date, interest_rate=market_simulation.interest_rate ) discounted_simulated_price_value = simulated_price_value * discount_rate dx = market_simulation.perturbation_factor * simulated_price_value if contract_valuation.is_double_sided_deltas: dx *= 2 delta = dy / dx # The delta of a forward contract at the observation date # is the discount factor at the delivery date. forward_contract_delta = discount_rate # Flatten the book with delta hedging in forward markets. # delta + hedge-units * hedge-delta = 0 # hence: hedge-units = -delta / hedge-delta hedge_units = -delta / forward_contract_delta # Present value of cost of hedge. hedge_cost = hedge_units * discounted_simulated_price_value periods.append({ 'market_name': market_name, 'delivery_date': delivery_date, 'delta': delta, 'perturbation_name': perturbation_name, 'hedge_units': hedge_units, 'price_simulated': simulated_price_value, 'price_discounted': discounted_simulated_price_value, 'hedge_cost': hedge_cost, 'cash': -hedge_cost, }) return periods def calc_call_count(self, contract_specification_id): # Todo: Return the call count from the compilation method? return len(list(regenerate_execution_order(contract_specification_id, self.call_link_repo))) def calc_counts_and_costs(self, contract_specification_id, is_double_sided_deltas): """Returns a dict of call IDs -> perturbation requirements.""" costs = {} counts = {} for call_id in regenerate_execution_order(contract_specification_id, self.call_link_repo): # Get estimated cost of evaluating the expression once. call_requirement = self.call_requirement_repo[call_id] estimated_cost_of_expr = call_requirement.cost # Get the perturbation requirements for this call. perturbation_dependencies = self.perturbation_dependencies_repo[call_id] assert isinstance(perturbation_dependencies, PerturbationDependencies) # "1 + 2 * number of dependencies" because of the double sided delta. num_perturbation_dependencies = len(perturbation_dependencies.dependencies) num_perturbations = (2 if is_double_sided_deltas else 1) * num_perturbation_dependencies num_evaluations = 1 + num_perturbations # Cost is cost of doing it once, times the number of times it needs doing. costs[call_id] = num_evaluations * estimated_cost_of_expr counts[call_id] = num_evaluations return counts, costs