use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
pub enum FeeModel {
Zero,
Flat(f64),
MakerTaker {
maker: f64,
taker: f64,
},
}
impl Default for FeeModel {
fn default() -> Self {
Self::Flat(0.0005)
}
}
impl FeeModel {
pub fn fee_for(self, fill_price: f64, size: f64, is_taker: bool) -> f64 {
let notional = fill_price * size;
match self {
Self::Zero => 0.0,
Self::Flat(rate) => notional * rate,
Self::MakerTaker { maker, taker } => notional * if is_taker { taker } else { maker },
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn zero_returns_zero() {
assert_eq!(FeeModel::Zero.fee_for(100.0, 1.0, true), 0.0);
}
#[test]
fn flat_proportional_to_notional() {
let f = FeeModel::Flat(0.001);
assert!((f.fee_for(100.0, 1.0, true) - 0.1).abs() < 1e-9);
assert!((f.fee_for(100.0, 2.0, true) - 0.2).abs() < 1e-9);
assert!((f.fee_for(50.0, 4.0, true) - 0.2).abs() < 1e-9);
}
#[test]
fn maker_taker_distinguishes() {
let f = FeeModel::MakerTaker {
maker: 0.0002,
taker: 0.0006,
};
let maker = f.fee_for(100.0, 1.0, false);
let taker = f.fee_for(100.0, 1.0, true);
assert!((maker - 0.02).abs() < 1e-9);
assert!((taker - 0.06).abs() < 1e-9);
}
}