Strategy and Risk sdk

This commit is contained in:
2026-07-29 01:35:36 +02:00
parent 85ea3c3b1b
commit 9c29695728
4 changed files with 146 additions and 17 deletions
+132 -5
View File
@@ -1,25 +1,152 @@
#[cfg(target_os = "macos")]
use std::path::PathBuf;
pub mod general;
pub mod plugin;
pub mod terminal;
pub mod units;
pub use hypersdk;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use crate::plugin::{RiskEngineMessage, StrategyEngineMessage};
pub mod prelude {
pub use crate::general::*;
pub use crate::plugin::*;
pub use crate::server_path;
pub use crate::terminal::*;
pub use crate::units::*;
pub use hypersdk;
pub use postcard;
}
pub fn server_path() -> PathBuf {
PathBuf::from("/tmp/pulse-engine.sock")
pub fn server_path() -> std::path::PathBuf {
std::path::PathBuf::from("/tmp/pulse-engine.sock")
}
pub fn map_postcard_err<T>(res: postcard::Result<T>) -> tokio::io::Result<T> {
res.map_err(|e| tokio::io::Error::new(std::io::ErrorKind::Other, e))
}
pub async fn send_raw(data: &[u8]) -> tokio::io::Result<()> {
let mut stdout = tokio::io::stdout();
stdout.write_all(&data.len().to_le_bytes()).await?;
stdout.write_all(data).await?;
stdout.flush().await?;
Ok(())
}
macro_rules! engine_methods {
($t:ty) => {
async fn start(&self) -> tokio::io::Result<()> {
let mut stdin = tokio::io::stdin();
loop {
let mut len_buf = [0u8; size_of::<usize>()];
let size = stdin.read_exact(&mut len_buf).await?;
let len = usize::from_le_bytes(len_buf);
if size == 0 || len == 0 {
break Ok(());
}
let mut buffer = vec![0u8; len];
stdin.read_exact(&mut buffer).await?;
self.on_raw(&buffer).await?;
}
}
async fn send(&self, msg: &$t) -> tokio::io::Result<()> {
$crate::send_raw(&$crate::map_postcard_err(
$crate::prelude::postcard::to_allocvec(msg),
)?)
.await
}
};
}
#[allow(async_fn_in_trait)]
pub trait Strategy {
engine_methods!(prelude::StrategyMessage);
async fn on_raw(&self, data: &[u8]) -> tokio::io::Result<()> {
match map_postcard_err(postcard::from_bytes(&data))? {
StrategyEngineMessage::Initialize => self.initialize().await,
StrategyEngineMessage::Command { command, args } => self.command(command, args).await,
StrategyEngineMessage::WatchList(watchlist) => self.watchlist(watchlist).await,
StrategyEngineMessage::Incoming(incoming) => self.incoming(incoming).await,
StrategyEngineMessage::Candlestick {
symbol,
interval,
candles,
} => self.candlestick(symbol, interval, candles).await,
}
}
async fn initialize(&self) -> tokio::io::Result<()> {
unimplemented!("Strategy::initialize")
}
async fn command(&self, _command: String, _args: Vec<String>) -> tokio::io::Result<()> {
unimplemented!("Strategy::command")
}
async fn watchlist(&self, _watchlist: Vec<prelude::MarketItem>) -> tokio::io::Result<()> {
unimplemented!("Strategy::watchlist")
}
async fn incoming(&self, _incoming: hypersdk::hypercore::Incoming) -> tokio::io::Result<()> {
unimplemented!("Strategy::event")
}
async fn candlestick(
&self,
_symbol: String,
_interval: hypersdk::hypercore::CandleInterval,
_candles: Vec<hypersdk::hypercore::Candle>,
) -> tokio::io::Result<()> {
unimplemented!("Strategy::candlestick")
}
}
#[allow(async_fn_in_trait)]
pub trait Risk {
engine_methods!(prelude::RiskMessage);
async fn on_raw(&self, data: &[u8]) -> tokio::io::Result<()> {
match map_postcard_err(postcard::from_bytes(&data))? {
RiskEngineMessage::Initialize => self.initialize().await,
RiskEngineMessage::Command { command, args } => self.command(command, args).await,
RiskEngineMessage::WatchList(watchlist) => self.watchlist(watchlist).await,
RiskEngineMessage::Signal(signal) => {
self.send(&prelude::RiskMessage::Signal(
self.signal_request(signal).await?,
))
.await
}
}
}
async fn initialize(&self) -> tokio::io::Result<()> {
unimplemented!("Risk::initialize")
}
async fn command(&self, _command: String, _args: Vec<String>) -> tokio::io::Result<()> {
unimplemented!("Risk::command")
}
async fn watchlist(&self, _watchlist: Vec<prelude::MarketItem>) -> tokio::io::Result<()> {
unimplemented!("Risk::watchlist")
}
async fn signal_request(
&self,
_signal: prelude::StrategySignal,
) -> tokio::io::Result<prelude::RiskSignal> {
unimplemented!("Risk::signal_request")
}
}
+12 -9
View File
@@ -3,7 +3,7 @@ use crate::{
terminal::MarketItem,
units::Direction,
};
use hypersdk::hypercore::{Candle, CandleInterval, Subscription};
use hypersdk::hypercore::{Candle, CandleInterval, Incoming, Subscription};
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct StrategyManifest {
@@ -51,9 +51,7 @@ pub enum RiskMessage {
GetWatchList,
Approve(Signal),
Reject { reason: String },
Signal(RiskSignal),
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
@@ -67,11 +65,7 @@ pub enum StrategyEngineMessage {
args: Vec<String>,
},
CandleUpdate {
symbol: String,
interval: CandleInterval,
candle: Candle,
},
Incoming(Incoming),
Candlestick {
symbol: String,
@@ -98,3 +92,12 @@ pub struct StrategySignal {
pub confidence: f32,
pub price: Option<f64>,
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub enum RiskSignal {
Approve(Signal),
Reject {
rejection_confidence: f32,
reason: String,
},
}