positionmanager is now an actor as well

This commit is contained in:
Giulio De Pasquale 2021-01-17 18:18:16 +00:00
parent 03e9c94b3b
commit 503c542a5f
4 changed files with 81 additions and 56 deletions

View File

@ -44,16 +44,6 @@ impl BfxBot {
} }
} }
pub fn with_position_strategy(mut self, strategy: Box<dyn PositionStrategy>) -> Self {
self.exchange_managers = self
.exchange_managers
.into_iter()
.map(|x| x.with_position_strategy(dyn_clone::clone_box(&*strategy)))
.collect();
self
}
pub async fn start_loop(&mut self) -> Result<(), BoxError> { pub async fn start_loop(&mut self) -> Result<(), BoxError> {
self.update_exchanges().await?; self.update_exchanges().await?;

View File

@ -38,8 +38,7 @@ async fn main() -> Result<(), BoxError> {
vec![Symbol::TESTBTC], vec![Symbol::TESTBTC],
Symbol::TESTUSD, Symbol::TESTUSD,
Duration::new(1, 0), Duration::new(1, 0),
) );
.with_position_strategy(Box::new(TrailingStop::new()));
Ok(bot.start_loop().await?) Ok(bot.start_loop().await?)
} }

View File

@ -2,7 +2,10 @@ use std::collections::HashMap;
use std::ops::Neg; use std::ops::Neg;
use bitfinex::ticker::TradingPairTicker; use bitfinex::ticker::TradingPairTicker;
use futures_util::stream::FuturesUnordered;
use futures_util::StreamExt;
use log::{debug, error}; use log::{debug, error};
use tokio::signal::unix::Signal;
use tokio::sync::mpsc::channel; use tokio::sync::mpsc::channel;
use tokio::sync::mpsc::{Receiver, Sender}; use tokio::sync::mpsc::{Receiver, Sender};
@ -10,15 +13,17 @@ use crate::connectors::{Client, ExchangeKind};
use crate::currency::SymbolPair; use crate::currency::SymbolPair;
use crate::events::{Dispatcher, Event, SignalKind}; use crate::events::{Dispatcher, Event, SignalKind};
use crate::models::{ExecutedOrder, OrderForm, OrderKind, Position, PriceTicker}; use crate::models::{ExecutedOrder, OrderForm, OrderKind, Position, PriceTicker};
use crate::strategy::{FastOrderStrategy, OrderStrategy, PositionStrategy}; use crate::strategy::{FastOrderStrategy, OrderStrategy, PositionStrategy, TrailingStop};
use crate::BoxError; use crate::BoxError;
use futures_util::stream::FuturesUnordered;
use futures_util::StreamExt;
pub struct EventManager { pub struct EventManager {
events: Vec<Event>, events: Vec<Event>,
} }
/******************
* PRICES
******************/
#[derive(Debug)] #[derive(Debug)]
pub struct PriceManager { pub struct PriceManager {
receiver: Receiver<SignalKind>, receiver: Receiver<SignalKind>,
@ -27,22 +32,22 @@ pub struct PriceManager {
client: Client, client: Client,
} }
async fn run_price_manager(mut manager: PriceManager) {
while let Some(msg) = manager.receiver.recv().await {
manager.handle_message(msg).await.unwrap();
}
}
pub struct PriceManagerHandle { pub struct PriceManagerHandle {
sender: Sender<SignalKind>, sender: Sender<SignalKind>,
} }
impl PriceManagerHandle { impl PriceManagerHandle {
async fn run_price_manager(mut manager: PriceManager) {
while let Some(msg) = manager.receiver.recv().await {
manager.handle_message(msg).await.unwrap();
}
}
pub fn new(pair: SymbolPair, client: Client) -> Self { pub fn new(pair: SymbolPair, client: Client) -> Self {
let (sender, receiver) = channel(8); let (sender, receiver) = channel(8);
let price_manager = PriceManager::new(receiver, pair, client); let price_manager = PriceManager::new(receiver, pair, client);
tokio::spawn(run_price_manager(price_manager)); tokio::spawn(PriceManagerHandle::run_price_manager(price_manager));
Self { sender } Self { sender }
} }
@ -148,37 +153,79 @@ impl PriceEntry {
} }
} }
/******************
* POSITIONS
******************/
pub struct PositionManagerHandle {
sender: Sender<SignalKind>,
}
impl PositionManagerHandle {
async fn run_position_manager(mut manager: PositionManager) {
while let Some(msg) = manager.receiver.recv().await {
manager.handle_message(msg).await.unwrap();
}
}
pub fn new(pair: SymbolPair, client: Client, strategy: Box<dyn PositionStrategy>) -> Self {
let (sender, receiver) = channel(8);
let manager = PositionManager::new(receiver, pair, client, strategy);
tokio::spawn(PositionManagerHandle::run_position_manager(manager));
Self { sender }
}
pub async fn update(&mut self, tick: u64) {
self.sender.send(SignalKind::Update(tick)).await.unwrap();
}
}
#[derive(Debug)] #[derive(Debug)]
pub struct PositionManager { pub struct PositionManager {
receiver: Receiver<SignalKind>,
current_tick: u64, current_tick: u64,
pair: SymbolPair, pair: SymbolPair,
positions_history: HashMap<u64, Position>, positions_history: HashMap<u64, Position>,
active_position: Option<Position>, active_position: Option<Position>,
client: Client, client: Client,
strategy: Option<Box<dyn PositionStrategy>>, strategy: Box<dyn PositionStrategy>,
} }
impl PositionManager { impl PositionManager {
pub fn new(pair: SymbolPair, client: Client) -> Self { pub fn new(
receiver: Receiver<SignalKind>,
pair: SymbolPair,
client: Client,
strategy: Box<dyn PositionStrategy>,
) -> Self {
PositionManager { PositionManager {
receiver,
current_tick: 0, current_tick: 0,
pair, pair,
positions_history: HashMap::new(), positions_history: HashMap::new(),
active_position: None, active_position: None,
client, client,
strategy: None, strategy,
} }
} }
pub fn with_strategy(mut self, strategy: Box<dyn PositionStrategy>) -> Self {
self.strategy = Some(strategy);
self
}
pub fn current_tick(&self) -> u64 { pub fn current_tick(&self) -> u64 {
self.current_tick self.current_tick
} }
pub async fn handle_message(&mut self, msg: SignalKind) -> Result<(), BoxError> {
match msg {
SignalKind::Update(tick) => {
self.update(tick).await?;
}
_ => {}
};
Ok(())
}
pub async fn update( pub async fn update(
&mut self, &mut self,
tick: u64, tick: u64,
@ -205,19 +252,10 @@ impl PositionManager {
// applying strategy to open position and saving into struct // applying strategy to open position and saving into struct
Some(position) => { Some(position) => {
let position_after_strategy = { let (position_after_strategy, strategy_events, _) =
match &self.strategy { self.strategy.on_new_tick(position, &self);
Some(strategy) => {
let (pos, strategy_events, _) =
strategy.on_new_tick(position, &self);
events.extend(strategy_events); events.extend(strategy_events);
pos
}
None => position,
}
};
self.positions_history self.positions_history
.insert(self.current_tick(), position_after_strategy.clone()); .insert(self.current_tick(), position_after_strategy.clone());
@ -249,6 +287,10 @@ impl PositionManager {
} }
} }
/******************
* ORDERS
******************/
pub type TrackedPositionsMap = HashMap<u64, ExecutedOrder>; pub type TrackedPositionsMap = HashMap<u64, ExecutedOrder>;
pub struct OrderManager { pub struct OrderManager {
@ -340,7 +382,7 @@ pub struct ExchangeManager {
kind: ExchangeKind, kind: ExchangeKind,
price_managers: Vec<PriceManagerHandle>, price_managers: Vec<PriceManagerHandle>,
order_managers: Vec<OrderManager>, order_managers: Vec<OrderManager>,
position_managers: Vec<PositionManager>, position_managers: Vec<PositionManagerHandle>,
dispatcher: Dispatcher, dispatcher: Dispatcher,
client: Client, client: Client,
} }
@ -354,7 +396,11 @@ impl ExchangeManager {
let mut price_managers = Vec::new(); let mut price_managers = Vec::new();
for p in pairs { for p in pairs {
position_managers.push(PositionManager::new(p.clone(), client.clone())); position_managers.push(PositionManagerHandle::new(
p.clone(),
client.clone(),
Box::new(TrailingStop::new()),
));
order_managers.push(OrderManager::new( order_managers.push(OrderManager::new(
p.clone(), p.clone(),
client.clone(), client.clone(),
@ -373,16 +419,6 @@ impl ExchangeManager {
} }
} }
pub fn with_position_strategy(mut self, strategy: Box<dyn PositionStrategy>) -> Self {
self.position_managers = self
.position_managers
.into_iter()
.map(|x| x.with_strategy(dyn_clone::clone_box(&*strategy)))
.collect();
self
}
pub async fn update_managers(&mut self, tick: u64) -> Result<(), BoxError> { pub async fn update_managers(&mut self, tick: u64) -> Result<(), BoxError> {
self.update_price_managers(tick).await?; self.update_price_managers(tick).await?;
self.update_position_managers(tick).await?; self.update_position_managers(tick).await?;

View File

@ -11,7 +11,7 @@ use crate::models::{ExecutedOrder, OrderForm, Position, PositionProfitState};
* DEFINITIONS * DEFINITIONS
***************/ ***************/
pub trait PositionStrategy: DynClone { pub trait PositionStrategy: DynClone + Send {
fn name(&self) -> String; fn name(&self) -> String;
fn on_new_tick( fn on_new_tick(
&self, &self,
@ -26,7 +26,7 @@ impl Debug for dyn PositionStrategy {
} }
} }
pub trait OrderStrategy: DynClone { pub trait OrderStrategy: DynClone + Send {
/// The name of the strategy, used for debugging purposes /// The name of the strategy, used for debugging purposes
fn name(&self) -> String; fn name(&self) -> String;
/// This method is called when the OrderManager checks the open orders on a new tick. /// This method is called when the OrderManager checks the open orders on a new tick.