drm_core/models/
position.rs1use serde::{Deserialize, Serialize};
2use std::collections::HashMap;
3
4#[derive(Debug, Clone, Serialize, Deserialize)]
5pub struct Position {
6 pub market_id: String,
7 pub outcome: String,
8 pub size: f64,
9 pub average_price: f64,
10 pub current_price: f64,
11}
12
13impl Position {
14 pub fn cost_basis(&self) -> f64 {
15 self.size * self.average_price
16 }
17
18 pub fn current_value(&self) -> f64 {
19 self.size * self.current_price
20 }
21
22 pub fn unrealized_pnl(&self) -> f64 {
23 self.current_value() - self.cost_basis()
24 }
25
26 pub fn unrealized_pnl_percent(&self) -> f64 {
27 let cost = self.cost_basis();
28 if cost == 0.0 {
29 return 0.0;
30 }
31 (self.unrealized_pnl() / cost) * 100.0
32 }
33}
34
35#[derive(Debug, Clone, Default, Serialize, Deserialize)]
36pub struct DeltaInfo {
37 pub delta: f64,
38 pub max_outcome: Option<String>,
39 pub max_position: f64,
40}
41
42pub fn calculate_delta(positions: &HashMap<String, f64>) -> DeltaInfo {
43 if positions.is_empty() {
44 return DeltaInfo::default();
45 }
46
47 let mut max_outcome: Option<String> = None;
48 let mut max_position: f64 = 0.0;
49
50 for (outcome, &size) in positions {
51 if size > max_position {
52 max_position = size;
53 max_outcome = Some(outcome.clone());
54 }
55 }
56
57 let delta = if positions.len() == 2 {
58 let values: Vec<f64> = positions.values().copied().collect();
59 (values[0] - values[1]).abs()
60 } else {
61 max_position
62 };
63
64 DeltaInfo {
65 delta,
66 max_outcome,
67 max_position,
68 }
69}
70
71#[derive(Debug, Clone, Default, Serialize, Deserialize)]
72pub struct PositionBreakdown {
73 pub outcome: String,
74 pub size: f64,
75 pub current_price: f64,
76 pub value: f64,
77}
78
79#[derive(Debug, Clone, Default, Serialize, Deserialize)]
80pub struct Nav {
81 pub nav: f64,
82 pub cash: f64,
83 pub positions_value: f64,
84 pub positions: Vec<PositionBreakdown>,
85}
86
87impl Nav {
88 pub fn calculate(cash: f64, positions: &[Position]) -> Self {
89 let mut positions_value = 0.0;
90 let mut breakdown = Vec::with_capacity(positions.len());
91
92 for pos in positions {
93 let value = pos.current_value();
94 positions_value += value;
95 breakdown.push(PositionBreakdown {
96 outcome: pos.outcome.clone(),
97 size: pos.size,
98 current_price: pos.current_price,
99 value,
100 });
101 }
102
103 Self {
104 nav: cash + positions_value,
105 cash,
106 positions_value,
107 positions: breakdown,
108 }
109 }
110}