Risk config
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
use hypersdk::hypercore::Side;
|
use hypersdk::{dec, hypercore::Side};
|
||||||
use rust_decimal::Decimal;
|
use rust_decimal::Decimal;
|
||||||
|
|
||||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||||
@@ -30,6 +30,12 @@ pub enum Mode {
|
|||||||
Manual,
|
Manual,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum Allocation {
|
||||||
|
Fixed(Decimal),
|
||||||
|
Percent(Decimal),
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||||
pub struct Signal {
|
pub struct Signal {
|
||||||
pub symbol: String,
|
pub symbol: String,
|
||||||
@@ -101,3 +107,66 @@ impl std::fmt::Display for ItemState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'de> serde::Deserialize<'de> for Allocation {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: serde::Deserializer<'de>,
|
||||||
|
{
|
||||||
|
struct AllocationVisitor;
|
||||||
|
|
||||||
|
impl<'de> serde::de::Visitor<'de> for AllocationVisitor {
|
||||||
|
type Value = Allocation;
|
||||||
|
|
||||||
|
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
|
formatter.write_str("a number or percentage string")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_f64<E>(self, value: f64) -> Result<Self::Value, E>
|
||||||
|
where
|
||||||
|
E: serde::de::Error,
|
||||||
|
{
|
||||||
|
Ok(Allocation::Fixed(Decimal::from_f64_retain(value).unwrap()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
|
||||||
|
where
|
||||||
|
E: serde::de::Error,
|
||||||
|
{
|
||||||
|
if let Some(percent) = value.strip_suffix('%') {
|
||||||
|
let value = percent.parse::<Decimal>().map_err(E::custom)?;
|
||||||
|
|
||||||
|
Ok(Allocation::Percent(value))
|
||||||
|
} else {
|
||||||
|
Err(E::custom("invalid allocation format"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deserializer.deserialize_any(AllocationVisitor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl serde::Serialize for Allocation {
|
||||||
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: serde::Serializer,
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Allocation::Fixed(value) => serde::Serialize::serialize(value, serializer),
|
||||||
|
Allocation::Percent(value) => {
|
||||||
|
let s = format!("{}%", value);
|
||||||
|
serializer.serialize_str(&s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Allocation {
|
||||||
|
pub fn get(&self, full_alloc: Decimal) -> Decimal {
|
||||||
|
match self {
|
||||||
|
Self::Fixed(f) => *f,
|
||||||
|
Self::Percent(p) => (*p / dec!(100.0)) * full_alloc,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,10 +1,20 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use pulse_sdk::general::Allocation;
|
||||||
|
|
||||||
|
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
||||||
|
pub struct RiskConfig {
|
||||||
|
pub risk_per_trade: Allocation,
|
||||||
|
pub max_open_positions: u32,
|
||||||
|
pub max_daily_loss: Allocation,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
pub description: Option<String>,
|
pub description: Option<String>,
|
||||||
pub watchlist: Vec<String>,
|
pub watchlist: Vec<String>,
|
||||||
pub strategy: String,
|
pub strategy: String,
|
||||||
|
pub risk: RiskConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
||||||
@@ -15,12 +25,23 @@ pub struct ConfigManager {
|
|||||||
pub configs: HashMap<String, Config>,
|
pub configs: HashMap<String, Config>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for RiskConfig {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
risk_per_trade: Allocation::Percent(10.into()),
|
||||||
|
max_daily_loss: Allocation::Percent(20.into()),
|
||||||
|
max_open_positions: 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Default for Config {
|
impl Default for Config {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
description: None,
|
description: None,
|
||||||
watchlist: vec!["BTC".to_string(), "SOL".to_string(), "ETH".to_string()],
|
watchlist: vec!["BTC".to_string(), "SOL".to_string(), "ETH".to_string()],
|
||||||
strategy: String::new(),
|
strategy: String::new(),
|
||||||
|
risk: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user