positionmanager is now an actor as well
This commit is contained in:
parent
03e9c94b3b
commit
503c542a5f
@ -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?;
|
||||||
|
|
||||||
|
@ -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?)
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct PriceManagerHandle {
|
||||||
|
sender: Sender<SignalKind>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PriceManagerHandle {
|
||||||
async fn run_price_manager(mut manager: PriceManager) {
|
async fn run_price_manager(mut manager: PriceManager) {
|
||||||
while let Some(msg) = manager.receiver.recv().await {
|
while let Some(msg) = manager.receiver.recv().await {
|
||||||
manager.handle_message(msg).await.unwrap();
|
manager.handle_message(msg).await.unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct PriceManagerHandle {
|
|
||||||
sender: Sender<SignalKind>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PriceManagerHandle {
|
|
||||||
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,20 +252,11 @@ 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());
|
||||||
self.active_position = Some(position_after_strategy);
|
self.active_position = Some(position_after_strategy);
|
||||||
@ -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?;
|
||||||
|
@ -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.
|
||||||
|
Loading…
Reference in New Issue
Block a user