qs_instruments/
economics.rs1use std::collections::BTreeMap;
2
3use serde::{Deserialize, Serialize};
4
5use crate::{
6 EconomicsImplementationId, EconomicsModelId, InstrumentEconomics, ResolvedInstrumentRef,
7};
8
9#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
11#[serde(rename_all = "snake_case")]
12pub enum EconomicOperation {
13 PositionValue,
14 RealizedPnl,
15 UnrealizedPnl,
16 Inventory,
17 Fees,
18 Funding,
19 Margin,
20 Liquidation,
21}
22
23pub trait EconomicsCapabilityProvider: Send + Sync {
25 fn implementation_id(&self) -> &EconomicsImplementationId;
26
27 fn supports(&self, model: &EconomicsModelId, operation: EconomicOperation) -> bool;
28}
29
30#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
32#[serde(deny_unknown_fields)]
33pub struct BoundEconomicCapability {
34 pub operation: EconomicOperation,
35 pub model: EconomicsModelId,
36 pub implementation: EconomicsImplementationId,
37}
38
39#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
41#[serde(deny_unknown_fields)]
42pub struct EconomicsBinding {
43 pub instrument: ResolvedInstrumentRef,
44 pub capabilities: BTreeMap<EconomicOperation, BoundEconomicCapability>,
45}
46
47pub fn bind_economics(
49 instrument: &ResolvedInstrumentRef,
50 economics: &InstrumentEconomics,
51 required: impl IntoIterator<Item = EconomicOperation>,
52 providers: &[&dyn EconomicsCapabilityProvider],
53) -> Result<EconomicsBinding, EconomicsCapabilityError> {
54 let mut capabilities = BTreeMap::new();
55 for operation in required {
56 let model = model_for_operation(economics, operation)?.clone();
57 let mut implementations = providers
58 .iter()
59 .filter(|provider| provider.supports(&model, operation))
60 .map(|provider| provider.implementation_id().clone())
61 .collect::<Vec<_>>();
62 implementations.sort();
63 implementations.dedup();
64 let implementation = match implementations.as_slice() {
65 [] => {
66 return Err(EconomicsCapabilityError::Unsupported {
67 operation,
68 model: model.clone(),
69 });
70 }
71 [implementation] => implementation.clone(),
72 _ => {
73 return Err(EconomicsCapabilityError::Ambiguous {
74 operation,
75 model: model.clone(),
76 implementations,
77 });
78 }
79 };
80 capabilities.insert(
81 operation,
82 BoundEconomicCapability {
83 operation,
84 model,
85 implementation,
86 },
87 );
88 }
89 Ok(EconomicsBinding {
90 instrument: instrument.clone(),
91 capabilities,
92 })
93}
94
95fn model_for_operation(
96 economics: &InstrumentEconomics,
97 operation: EconomicOperation,
98) -> Result<&EconomicsModelId, EconomicsCapabilityError> {
99 match operation {
100 EconomicOperation::PositionValue
101 | EconomicOperation::RealizedPnl
102 | EconomicOperation::UnrealizedPnl
103 | EconomicOperation::Inventory => Ok(&economics.pnl_model),
104 EconomicOperation::Fees => economics
105 .fee_model
106 .as_ref()
107 .ok_or(EconomicsCapabilityError::MissingModel { operation }),
108 EconomicOperation::Funding => economics
109 .funding_model
110 .as_ref()
111 .ok_or(EconomicsCapabilityError::MissingModel { operation }),
112 EconomicOperation::Margin | EconomicOperation::Liquidation => economics
113 .margin_model
114 .as_ref()
115 .ok_or(EconomicsCapabilityError::MissingModel { operation }),
116 }
117}
118
119#[derive(Clone, Debug, Eq, PartialEq, thiserror::Error)]
121pub enum EconomicsCapabilityError {
122 #[error("instrument economics do not declare a model for {operation:?}")]
123 MissingModel { operation: EconomicOperation },
124 #[error("no implementation supports {operation:?} for model {model}")]
125 Unsupported {
126 operation: EconomicOperation,
127 model: EconomicsModelId,
128 },
129 #[error("multiple implementations support {operation:?} for model {model}")]
130 Ambiguous {
131 operation: EconomicOperation,
132 model: EconomicsModelId,
133 implementations: Vec<EconomicsImplementationId>,
134 },
135}