Removed risk

This commit is contained in:
2026-07-30 02:50:22 +02:00
parent f3406c7b97
commit d0f683b4ca
9 changed files with 33 additions and 250 deletions
+1 -31
View File
@@ -6,7 +6,7 @@ pub use hypersdk;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use crate::plugin::{RiskEngineMessage, StrategyEngineMessage};
use crate::plugin::StrategyEngineMessage;
pub mod prelude {
pub use crate::general::*;
@@ -112,33 +112,3 @@ pub trait Strategy {
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.signal_request(signal).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<()> {
unimplemented!("Risk::signal_request")
}
}
+1 -51
View File
@@ -1,7 +1,6 @@
use crate::{
general::{EventLog, Signal},
terminal::MarketItem,
units::Direction,
};
use hypersdk::hypercore::{Candle, CandleInterval, Incoming, Subscription};
@@ -13,17 +12,6 @@ pub struct StrategyManifest {
pub version: String,
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct RiskManifest {
pub name: String,
pub description: String,
pub author: String,
pub version: String,
pub max_loss: u8,
pub cooldown: CandleInterval,
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub enum StrategyMessage {
Log(EventLog),
@@ -42,16 +30,7 @@ pub enum StrategyMessage {
UnsubscribeAll,
Signal(StrategySignal),
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub enum RiskMessage {
Log(EventLog),
GetWatchList,
Signal(RiskSignal),
Signal(Signal),
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
@@ -73,32 +52,3 @@ pub enum StrategyEngineMessage {
candles: Vec<Candle>,
},
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub enum RiskEngineMessage {
Initialize,
WatchList(Vec<MarketItem>),
Command { command: String, args: Vec<String> },
Signal(StrategySignal),
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct StrategySignal {
pub symbol: String,
pub side: Direction,
pub confidence: f32,
pub price: Option<f64>,
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub enum RiskSignal {
Approve(Signal),
Reject {
signal: StrategySignal,
rejection_confidence: f32,
reason: String,
},
}
+3 -4
View File
@@ -1,11 +1,11 @@
use crate::{
general::{EventLog, MarketTrend, Position},
plugin::{RiskManifest, RiskSignal, StrategyManifest},
general::{EventLog, MarketTrend, Position, Signal},
plugin::StrategyManifest,
units::{Symbol, USD, Volatility},
};
use hypersdk::{Decimal, hypercore::CandleInterval};
pub type SignalStatus = Result<RiskSignal, RiskSignal>;
pub type SignalStatus = Result<Signal, Signal>;
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub enum TerminalServerMessage {
@@ -110,7 +110,6 @@ pub enum ItemState {
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct Strategy {
pub strategy: StrategyManifest,
pub risk: RiskManifest,
pub mode: Mode,
pub state: ItemState,
+2 -28
View File
@@ -69,32 +69,6 @@ impl Engine {
.await?;
}
"risk" | "rs" => {
set_cfg!(id, {
let id: String = id;
if !crate::store::pulse_plugin(&id)?
.join("risk.toml")
.exists()
{
return self
.terminal_server
.error(
"config::set::risk",
&format!("Non existent risk `{id}`"),
)
.await;
}
self.strategy.reload_risk(id.as_str()).await?;
self.config.lock().await.risk = id;
});
self.terminal_server
.info("config::set", "risk set successfully, use `config save` to persist changes")
.await?;
}
"cooldown" | "cool" | "cd" => {
set_cfg!(cooldown, {
self.config.lock().await.cooldown = cooldown;
@@ -102,7 +76,7 @@ impl Engine {
self.terminal_server.broadcast(
pulse_sdk::terminal::TerminalServerMessage::StrategyUpdated(Strategy {
strategy: self.strategy.strategy.manifest.lock().await.clone(),
risk: self.strategy.risk.manifest.lock().await.clone(),
mode: Mode::Auto,
state: ItemState::Running,
cooldown,
@@ -114,7 +88,7 @@ impl Engine {
_ => {
self.terminal_server
.error("config::set", "Invalid usage, available options: watchlist, strategy, risk, cooldown")
.error("config::set", "Invalid usage, available options: watchlist, strategy, cooldown")
.await?;
}
}
+1 -1
View File
@@ -31,7 +31,7 @@ impl Engine {
pub async fn new() -> tokio::io::Result<Arc<Self>> {
let config = Config::new().await?;
let strategy = StrategyEngine::new(&config.strategy, &config.risk).await?;
let strategy = StrategyEngine::new(&config.strategy).await?;
let accounts = Arc::new(Mutex::new(AccountList::new().await?));
let config = Arc::new(Mutex::new(config));
+19 -92
View File
@@ -20,7 +20,6 @@ use crate::{
pub struct StrategyEngine {
pub strategy: Arc<Plugin<StrategyEngineMessage, StrategyMessage, StrategyManifest>>,
pub risk: Arc<Plugin<RiskEngineMessage, RiskMessage, RiskManifest>>,
pub engine: Weak<Engine>,
pub ws: WebSocket,
@@ -28,9 +27,8 @@ pub struct StrategyEngine {
}
impl StrategyEngine {
pub async fn new(strategy_id: &str, risk_id: &str) -> tokio::io::Result<Self> {
pub async fn new(strategy_id: &str) -> tokio::io::Result<Self> {
let strategy = pulse_plugin(strategy_id)?;
let risk = pulse_plugin(risk_id)?;
let (strategy, strategy_manifest) = get_manifest_plugin_pair(
&strategy,
@@ -38,15 +36,8 @@ impl StrategyEngine {
&fs::read(strategy.join("strategy.toml")).await?,
)?;
let (risk, risk_manifest) = get_manifest_plugin_pair(
&risk,
&risk.join("risk.bash"),
&fs::read(risk.join("risk.toml")).await?,
)?;
Ok(Self {
strategy: Arc::new(Plugin::new(strategy, strategy_manifest)),
risk: Arc::new(Plugin::new(risk, risk_manifest)),
engine: Weak::new(),
ws: hypercore::mainnet_ws(),
subscriptions: Mutex::new(HashSet::new()),
@@ -87,7 +78,24 @@ impl StrategyEngine {
}
Some(StrategyMessage::Signal(signal)) => {
self.risk.send(&RiskEngineMessage::Signal(signal)).await?;
match engine.execute_signal(&signal).await {
Ok(_) => engine.signals.lock().await.push(Ok(signal)),
Err(e) => {
engine.signals.lock().await.push(Err(signal));
engine
.terminal_server
.error("signal", &format!("Failed to execute signal: {e}"))
.await?
}
}
engine
.terminal_server
.broadcast(TerminalServerMessage::SignalsUpdated(
engine.signals.lock().await.clone(),
))
.await?;
}
Some(StrategyMessage::Subscribe(subscription)) => {
@@ -153,74 +161,10 @@ impl StrategyEngine {
}
}
pub async fn run_risk(&self) -> tokio::io::Result<()> {
let engine = self
.engine
.upgrade()
.expect("Failed to upgrade engine (StrategyEngine)");
self.risk.send(&RiskEngineMessage::Initialize).await?;
loop {
match self.risk.recv().await? {
None => {}
Some(RiskMessage::GetWatchList) => {
self.risk
.send(&&RiskEngineMessage::WatchList(
engine.watch_list.lock().await.clone().items,
))
.await?;
}
Some(RiskMessage::Log(mut log)) => {
log.name.insert_str(0, "risk::");
engine.terminal_server.log_raw(log).await?;
}
Some(RiskMessage::Signal(ref sig @ RiskSignal::Approve(ref signal))) => {
match engine.execute_signal(signal).await {
Ok(_) => engine.signals.lock().await.push(Ok(sig.clone())),
Err(e) => {
engine.signals.lock().await.push(Err(sig.clone()));
engine
.terminal_server
.error("signal", &format!("Failed to execute signal: {e}"))
.await?
}
}
engine
.terminal_server
.broadcast(TerminalServerMessage::SignalsUpdated(
engine.signals.lock().await.clone(),
))
.await?;
}
Some(RiskMessage::Signal(reject)) => {
engine.signals.lock().await.push(Ok(reject));
engine
.terminal_server
.broadcast(TerminalServerMessage::SignalsUpdated(
engine.signals.lock().await.clone(),
))
.await?;
}
}
}
}
pub async fn spawn(self: &Arc<Self>) {
let engine = self.clone();
tokio::spawn(async move { engine.run_strategy().await });
let engine = self.clone();
tokio::spawn(async move { engine.run_risk().await });
}
pub async fn reload_strategy(self: &Arc<Self>, id: &str) -> tokio::io::Result<()> {
@@ -239,23 +183,6 @@ impl StrategyEngine {
Ok(())
}
pub async fn reload_risk(self: &Arc<Self>, id: &str) -> tokio::io::Result<()> {
let plugin = pulse_plugin(id)?;
let (child, manifest) = get_manifest_plugin_pair(
&plugin,
&plugin.join("risk.bash"),
&fs::read(plugin.join("risk.toml")).await?,
)?;
self.risk.reload(child, manifest).await?;
let engine = self.clone();
tokio::spawn(async move { engine.run_risk().await });
Ok(())
}
}
pub fn get_manifest_plugin_pair<'de, M: serde::Deserialize<'de>>(
-2
View File
@@ -4,7 +4,6 @@ use hypersdk::hypercore::CandleInterval;
pub struct Config {
pub watchlist: Vec<String>,
pub strategy: String,
pub risk: String,
pub cooldown: CandleInterval,
}
@@ -13,7 +12,6 @@ impl Default for Config {
Self {
watchlist: vec!["BTC".to_string(), "SOL".to_string(), "ETH".to_string()],
strategy: String::new(),
risk: String::new(),
cooldown: CandleInterval::ThirtyMinutes,
}
}
-1
View File
@@ -66,7 +66,6 @@ impl TerminalServer {
id,
pulse_sdk::terminal::TerminalServerMessage::StrategyUpdated(Strategy {
strategy: engine.strategy.strategy.manifest.lock().await.clone(),
risk: engine.strategy.risk.manifest.lock().await.clone(),
mode: Mode::Auto,
state: ItemState::Running,
cooldown: engine.config.lock().await.cooldown,
+6 -40
View File
@@ -61,7 +61,7 @@ impl Formatted for EventLog {
impl Formatted for SignalStatus {
fn get_formatted(&self) -> Vec<String> {
match self {
Ok(RiskSignal::Approve(signal)) => {
Ok(signal) => {
vec![
format!("\x1b[33mOK\x1b[0m"),
if matches!(signal.kind, Direction::Buy) {
@@ -74,25 +74,8 @@ impl Formatted for SignalStatus {
format!("\x1b[33mAPR {}\x1b[0m", signal.confidence),
]
}
Ok(RiskSignal::Reject {
signal,
rejection_confidence,
reason,
}) => {
vec![
format!("\x1b[33mOK\x1b[0m"),
if matches!(signal.side, Direction::Buy) {
format!("\x1b[32mBUY\x1b[0m")
} else {
format!("\x1b[31mSELL\x1b[0m")
},
format!("\x1b[35m{}\x1b[0m", signal.symbol),
format!("\x1b[31mREJ {}\x1b[0m", rejection_confidence),
reason.to_owned(),
]
}
Err(RiskSignal::Approve(signal)) => {
Err(signal) => {
vec![
format!("\x1b[31mERR\x1b[0m"),
if matches!(signal.kind, Direction::Buy) {
@@ -105,23 +88,6 @@ impl Formatted for SignalStatus {
format!("\x1b[33mAPR {}\x1b[0m", signal.confidence),
]
}
Err(RiskSignal::Reject {
signal,
rejection_confidence,
reason,
}) => {
vec![
format!("\x1b[31mERR\x1b[0m"),
if matches!(signal.side, Direction::Buy) {
format!("\x1b[32mBUY\x1b[0m")
} else {
format!("\x1b[31mSELL\x1b[0m")
},
format!("\x1b[35m{}\x1b[0m", signal.symbol),
format!("\x1b[31mREJ {}\x1b[0m", rejection_confidence),
reason.to_owned(),
]
}
}
}
}
@@ -291,7 +257,7 @@ impl Formatted for Strategy {
),
Triple(
&format!("\x1b[97m{}\x1b[0m", self.strategy.name),
&format!("\x1b[93m{}\x1b[0m", self.risk.name),
&format!("\x1b[93m{}\x1b[0m", ""),
&format!("\x1b[90m{}\x1b[0m", self.strategy.version),
),
Triple("", "", ""),
@@ -303,7 +269,7 @@ impl Formatted for Strategy {
Triple(
&self.mode.to_string(),
&self.state.to_string(),
&format!("\x1b[90m{}\x1b[0m", self.risk.version),
&format!("\x1b[90m{}\x1b[0m", ""),
),
Triple("", "", ""),
Triple(
@@ -314,10 +280,10 @@ impl Formatted for Strategy {
Triple(
&format!(
"\x1b[96m{}\x1b[0m (\x1b[90m{} rec\x1b[0m)",
self.cooldown, self.risk.cooldown
self.cooldown, ""
),
&format!("\x1b[96m{:?}\x1b[0m", self.strategy.author),
&format!("\x1b[93m{}%\x1b[0m", self.risk.max_loss),
&format!("\x1b[93m{}%\x1b[0m", ""),
),
]
.get_formatted()