From 207caeac017cf26ee5c0550778c1577118c2fd06 Mon Sep 17 00:00:00 2001 From: aeyalcinoglu Date: Sun, 2 Oct 2022 10:06:38 +0200 Subject: [PATCH 1/3] Add initial controller --- src/actors/controller.rs | 47 ++++++++++++++++++++++++++++++++++++++++ src/policy_maker.rs | 36 +++++++++++++++++++++++++++--- src/util.rs | 4 ++++ 3 files changed, 84 insertions(+), 3 deletions(-) create mode 100644 src/actors/controller.rs diff --git a/src/actors/controller.rs b/src/actors/controller.rs new file mode 100644 index 0000000..5ce052d --- /dev/null +++ b/src/actors/controller.rs @@ -0,0 +1,47 @@ +use actix::{Actor, Addr, Context, Handler, Recipient}; +use std::collections::HashMap; +use trade::Buy; + +pub struct Controller { + scaling_coefficient: f64, + subscribers: Vec>, +} + +impl Controller { + pub fn new(subscribers: Vec>) -> Self { + Self { + scaling_coefficient: 1., + subscribers, + } + } +} + +impl Actor for Controller { + type Context = Context; +} + +impl Handler for Controller { + type Result = ControllerCommand; + + fn handle( + &mut self, + msg: PolicyDecision, + ctx: &mut Context, + ) -> Self::Result { + let artificial_spread_coefficient; + match msg { + PolicyDecision::BuyAction => { + artificial_spread_coefficient = 1 / scaling_coefficient + } + PolicyDecision::SellAction => { + artificial_spread_coefficient = scaling_coefficient + } + PolicyDecision::HoldAction => artificial_spread_coefficient = 1, + } + for s in &self.subscribers { + s.do_send(ControllerCommand(artificial_spread_coefficient)); + } + + artificial_spread_coefficient + } +} diff --git a/src/policy_maker.rs b/src/policy_maker.rs index eb13ddc..0d09e3f 100644 --- a/src/policy_maker.rs +++ b/src/policy_maker.rs @@ -2,7 +2,9 @@ use crate::actors::mid_price::MidPrice; use crate::actors::mid_price::MidPriceResponse; use crate::trade::{Buy, Hold, Sell}; -use crate::util::{deserialize_from_str, MovingAverageMessage}; +use crate::util::{ + deserialize_from_str, ControllerCommand, MovingAverageMessage, +}; use actix::{Actor, Context, Handler, Message, MessageResult, Recipient}; use chrono::Utc; use serde::Deserialize; @@ -34,6 +36,7 @@ pub struct PolicyFrame { true_price_gradient: f64, moving_average_price: f64, true_price: f64, + artificial_spread_coefficient: f64, prev_decision: Option, } @@ -56,6 +59,7 @@ impl PolicyMaker { true_price_gradient: 0.0, moving_average_price: 0.0, true_price: 0.0, + artificial_spread_coefficient: 1.0, prev_decision: None, }, recipients, @@ -139,6 +143,7 @@ impl Handler for PolicyMaker { prev_decision: self.frame.prev_decision.take(), // TODO: update moving_average_gradient: 0., + artificial_spread_coefficient: 1., moving_average_price: 0., }; self.frame = frame; @@ -168,15 +173,38 @@ impl Handler for PolicyMaker { } } +impl Handler for PolicyMaker { + type Result = f64; + // Handle moving average message. Receive message then make a policy decision + fn handle( + &mut self, + msg: ControllerCommand, + _ctx: &mut Context, + ) -> f64 { + let _prev_moving_price = self.frame.moving_average_price; + + self.frame.moving_average_gradient = + msg.0 - self.frame.moving_average_price; + self.frame.moving_average_price = msg.0; + + let decision = self.make_policy_decision(&self.frame); + log::error!("Decision: {:?}", decision); + self.propagate_decision(decision); + msg.0 + } +} + fn should_buy(frame: &PolicyFrame) -> bool { is_rising_trend(frame) - && frame.moving_average_price < frame.true_price + && frame.moving_average_price + < frame.true_price * frame.artificial_spread_coefficient && !(matches!(frame.prev_decision, Some(PolicyDecision::BuyAction(_)))) } fn should_sell(frame: &PolicyFrame) -> bool { is_downward_trend(frame) - && frame.moving_average_price > frame.true_price + && frame.moving_average_price * frame.artificial_spread_coefficient + > frame.true_price && !(matches!(frame.prev_decision, Some(PolicyDecision::SellAction(_)))) } @@ -245,6 +273,7 @@ mod test { true_price_gradient: 1.0, moving_average_price: 10.0, true_price: 20.0, + artificial_spread_coefficient: 1.0, prev_decision: Some(PolicyDecision::SellAction(sell)), }; @@ -270,6 +299,7 @@ mod test { true_price_gradient: 1.0, moving_average_price: 10.0, true_price: 20.0, + artificial_spread_coefficient: 1.0, prev_decision: Some(PolicyDecision::BuyAction(buy)), }; diff --git a/src/util.rs b/src/util.rs index 7cb382d..a2a6de5 100644 --- a/src/util.rs +++ b/src/util.rs @@ -17,6 +17,10 @@ pub struct Return(pub f64); #[rtype(result = "f64")] pub struct MovingAverageMessage(pub f64); +#[derive(Message)] +#[rtype(result = "f64")] +pub struct ControllerCommand(pub f64); + #[derive(Message)] #[rtype(result = "Option")] pub struct SharpeRatio(pub f64); From ea08130f43d37a34335b81b34c8beffd2711b90d Mon Sep 17 00:00:00 2001 From: aeyalcinoglu Date: Sun, 2 Oct 2022 10:15:14 +0200 Subject: [PATCH 2/3] Fix ControllerCommand handle method --- src/policy_maker.rs | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/policy_maker.rs b/src/policy_maker.rs index 0d09e3f..4513396 100644 --- a/src/policy_maker.rs +++ b/src/policy_maker.rs @@ -175,21 +175,12 @@ impl Handler for PolicyMaker { impl Handler for PolicyMaker { type Result = f64; - // Handle moving average message. Receive message then make a policy decision fn handle( &mut self, msg: ControllerCommand, _ctx: &mut Context, ) -> f64 { - let _prev_moving_price = self.frame.moving_average_price; - - self.frame.moving_average_gradient = - msg.0 - self.frame.moving_average_price; - self.frame.moving_average_price = msg.0; - - let decision = self.make_policy_decision(&self.frame); - log::error!("Decision: {:?}", decision); - self.propagate_decision(decision); + self.frame.artificial_spread_coefficient = msg.0; msg.0 } } From 68ba34bff773125e434d55ed3255a34259e1bfc5 Mon Sep 17 00:00:00 2001 From: aeyalcinoglu Date: Sun, 2 Oct 2022 10:20:00 +0200 Subject: [PATCH 3/3] Fix coefficient logic --- src/policy_maker.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/policy_maker.rs b/src/policy_maker.rs index 4513396..46652c5 100644 --- a/src/policy_maker.rs +++ b/src/policy_maker.rs @@ -194,8 +194,8 @@ fn should_buy(frame: &PolicyFrame) -> bool { fn should_sell(frame: &PolicyFrame) -> bool { is_downward_trend(frame) - && frame.moving_average_price * frame.artificial_spread_coefficient - > frame.true_price + && frame.moving_average_price + > frame.true_price * frame.artificial_spread_coefficient && !(matches!(frame.prev_decision, Some(PolicyDecision::SellAction(_)))) }