sharpebench_protocol/
lib.rs1#![forbid(unsafe_code)]
11
12use std::collections::BTreeMap;
13
14use serde::{Deserialize, Serialize};
15
16#[derive(Clone, Debug, Serialize, Deserialize)]
18pub struct MarketObservation {
19 pub date: String,
21 pub cash: f64,
22 pub symbols: Vec<SymbolSnapshot>,
23 pub portfolio: Vec<PositionState>,
24}
25
26#[derive(Clone, Debug, Serialize, Deserialize)]
28pub struct SymbolSnapshot {
29 pub symbol: String,
30 pub close_history: Vec<f64>,
32 #[serde(default)]
34 pub fundamentals: BTreeMap<String, f64>,
35 #[serde(default)]
37 pub news: Vec<String>,
38}
39
40#[derive(Clone, Debug, Serialize, Deserialize)]
42pub struct PositionState {
43 pub symbol: String,
44 pub shares: f64,
45 pub avg_price: f64,
46}
47
48#[derive(Clone, Debug, Serialize, Deserialize)]
50pub struct Decision {
51 pub orders: Vec<Order>,
52 #[serde(default)]
54 pub reasoning: String,
55}
56
57#[derive(Clone, Debug, Serialize, Deserialize)]
59pub struct Order {
60 pub symbol: String,
61 pub action: Action,
62 pub target_weight: f64,
64 #[serde(default = "default_confidence")]
66 pub confidence: f64,
67}
68
69#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq)]
71#[serde(rename_all = "snake_case")]
72pub enum Action {
73 Buy,
74 Sell,
75 Hold,
76 Close,
77}
78
79fn default_confidence() -> f64 {
80 0.5
81}
82
83#[cfg(test)]
84mod tests {
85 use super::*;
86
87 #[test]
88 fn observation_and_decision_roundtrip() {
89 let obs = MarketObservation {
90 date: "2025-01-01".to_string(),
91 cash: 1.0,
92 symbols: vec![SymbolSnapshot {
93 symbol: "A".to_string(),
94 close_history: vec![1.0, 2.0],
95 fundamentals: Default::default(),
96 news: vec!["headline".to_string()],
97 }],
98 portfolio: vec![PositionState {
99 symbol: "A".to_string(),
100 shares: 1.0,
101 avg_price: 2.0,
102 }],
103 };
104 let back: MarketObservation =
105 serde_json::from_str(&serde_json::to_string(&obs).unwrap()).unwrap();
106 assert_eq!(back.symbols[0].symbol, "A");
107
108 let d = Decision {
109 orders: vec![Order {
110 symbol: "A".to_string(),
111 action: Action::Buy,
112 target_weight: 0.5,
113 confidence: 0.9,
114 }],
115 reasoning: "r".to_string(),
116 };
117 let db: Decision = serde_json::from_str(&serde_json::to_string(&d).unwrap()).unwrap();
118 assert_eq!(db.orders[0].action, Action::Buy);
119 }
120}