1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
use fpdec::{Dec, Decimal};
use getset::{CopyGetters, Getters, Setters};
use crate::{
leverage,
prelude::{ConfigError, Currency, Maker, PriceFilter, QuantityFilter, Taker},
types::{Fee, Leverage},
};
/// Specifies the details of the futures contract
#[derive(Debug, Clone, Getters, CopyGetters, Setters)]
pub struct ContractSpecification<Q>
where
Q: Currency,
{
/// Identifying ticker symbol
#[getset(get = "pub", set = "pub")]
ticker: String,
/// The initial deposit required to open a new futures position.
/// Expressed as a fraction.
/// Eg. 1% (0.01) initial margin requirement, which is equal to 100x leverage.
#[getset(get_copy = "pub")]
init_margin_req: Decimal,
/// The minimum amount that must be maintained in the traders account to
/// keep existing positions open.
/// Expressed as a fraction.
/// Eg. 0.5% (0.005).
#[getset(get_copy = "pub")]
maintenance_margin: Decimal,
/// The method for computing `mark-to-market`.
#[getset(get_copy = "pub", set = "pub")]
mark_method: MarkMethod,
/// Pricing rules
#[getset(get = "pub")]
price_filter: PriceFilter,
/// Quantity rules
#[getset(get = "pub")]
quantity_filter: QuantityFilter<Q>,
/// The maker fee as parts per 100_000
#[getset(get_copy = "pub")]
fee_maker: Fee<Maker>,
/// The taker fee as parts per 100_000
#[getset(get_copy = "pub")]
fee_taker: Fee<Taker>,
}
impl<Q> ContractSpecification<Q>
where
Q: Currency,
{
/// Create a new `ContractSpecification` from the most basic parameters.
///
/// # Arguments:
/// `leverage`: The leverage dictates the margin requirements of a position.
/// When a trader sets a user-defined leverage setting, they're essentially adjusting the margin requirements for their account.
/// higher leverage setting means lower margin requirements, while a lower leverage setting means higher margin requirements.
/// `maintenance_margin_fraction`: The fraction (in range [0..1]) that the maintenance margin will be relative to the computed `initial_margin`.
/// `price_filter`: The rules for prices in the market
/// `quantity_filter`: The rules for quantities in the market.
/// `fee_maker`: The fee a maker pays.
/// `fee_taker`: The fee a taker pays.
pub fn new(
leverage: Leverage,
maintenance_margin_fraction: Decimal,
price_filter: PriceFilter,
quantity_filter: QuantityFilter<Q>,
fee_maker: Fee<Maker>,
fee_taker: Fee<Taker>,
) -> Result<Self, ConfigError> {
if maintenance_margin_fraction > Dec!(1) || maintenance_margin_fraction <= Dec!(0) {
return Err(ConfigError::InvalidMaintenanceMarginFraction);
}
let initial_margin = Dec!(1) / leverage;
Ok(Self {
ticker: String::new(),
init_margin_req: initial_margin,
maintenance_margin: initial_margin * maintenance_margin_fraction,
mark_method: MarkMethod::default(),
price_filter,
quantity_filter,
fee_maker,
fee_taker,
})
}
}
impl<Q> Default for ContractSpecification<Q>
where
Q: Currency,
{
fn default() -> Self {
Self::new(
leverage!(1),
Dec!(0.5),
PriceFilter::default(),
QuantityFilter::default(),
Fee::from_basis_points(2),
Fee::from_basis_points(6),
)
.expect("Is valid")
}
}
// TODO: actually switch between the methods.
/// Which price to use in `mark-to-market` calculations
#[derive(Debug, Clone, Copy)]
pub enum MarkMethod {
/// Take the last mid price of the market.
MidPrice,
/// Use the best bid and ask to mark the position to market.
BidAsk,
/// Use Fair Price Marking to avoid unnecessary liquidations in highly leveraged products.
/// Without this system, unnecessary liquidations may occur if the market is being manipulated,
/// is illiquid, or the Mark Price swings unnecessarily relative to its Index Price.
/// The system is able to achieve this by setting the Mark Price of the contract to the `FairPrice` instead of the `LastPrice`.
FairPrice,
}
impl Default for MarkMethod {
fn default() -> Self {
Self::BidAsk
}
}