position manager working

This commit is contained in:
Giulio De Pasquale 2021-01-14 18:36:56 +00:00
parent 3eca8aef2d
commit 2c151ae6c1
5 changed files with 99 additions and 27 deletions

View File

@ -33,21 +33,21 @@ impl BfxBot {
tick_duration: Duration, tick_duration: Duration,
) -> Self { ) -> Self {
let clients: Vec<_> = exchanges.iter().map(|x| Client::new(x)).collect(); let clients: Vec<_> = exchanges.iter().map(|x| Client::new(x)).collect();
let pairs: Vec<_> = trading_symbols
.iter()
.map(|x| SymbolPair::new(quote.clone(), x.clone()))
.collect();
let mut pos_managers = Vec::new(); let mut pos_managers = Vec::new();
let mut order_managers = Vec::new(); let mut order_managers = Vec::new();
let mut pair_statuses = Vec::new(); let mut pair_statuses = Vec::new();
for c in clients { for c in clients {
pos_managers.push(PositionManager::new(c.clone())); for p in &pairs {
order_managers.push(OrderManager::new(c.clone())); pos_managers.push(PositionManager::new(p.clone(), c.clone()));
pair_statuses.extend( order_managers.push(OrderManager::new(p.clone(), c.clone()));
trading_symbols pair_statuses.push(PriceManager::new(p.clone(), c.clone()));
.iter() }
.map(|x| SymbolPair::new(quote.clone(), x.clone()))
.map(|x| PriceManager::new(x, c.clone()))
.collect::<Vec<PriceManager>>(),
)
} }
BfxBot { BfxBot {
@ -79,10 +79,23 @@ impl BfxBot {
async fn update_managers(&mut self) -> Result<(), BoxError> { async fn update_managers(&mut self) -> Result<(), BoxError> {
self.update_price_managers().await?; self.update_price_managers().await?;
self.update_position_managers().await?;
Ok(()) Ok(())
} }
async fn update_position_managers(&mut self) -> Result<Option<Vec<Event>>, BoxError> {
for mgr in &mut self.pos_managers {
let tick = self.ticker.current_tick();
mgr.update(tick).await?;
println!("{:?}", mgr);
}
Ok(None)
}
async fn update_price_managers(&mut self) -> Result<Option<Vec<Event>>, BoxError> { async fn update_price_managers(&mut self) -> Result<Option<Vec<Event>>, BoxError> {
let futures: Vec<_> = self let futures: Vec<_> = self
.price_managers .price_managers

View File

@ -45,7 +45,10 @@ impl Client {
} }
} }
pub async fn active_positions(&self, pair: &SymbolPair) -> Result<Vec<Position>, BoxError> { pub async fn active_positions(
&self,
pair: &SymbolPair,
) -> Result<Option<Vec<Position>>, BoxError> {
self.inner.active_positions(pair).await self.inner.active_positions(pair).await
} }
@ -70,7 +73,7 @@ impl Client {
#[async_trait] #[async_trait]
pub trait Connector: Send + Sync { pub trait Connector: Send + Sync {
async fn active_positions(&self, pair: &SymbolPair) -> Result<Vec<Position>, BoxError>; async fn active_positions(&self, pair: &SymbolPair) -> Result<Option<Vec<Position>>, BoxError>;
async fn current_prices(&self, pair: &SymbolPair) -> Result<TradingPairTicker, BoxError>; async fn current_prices(&self, pair: &SymbolPair) -> Result<TradingPairTicker, BoxError>;
async fn active_orders(&self, pair: &SymbolPair) -> Result<Vec<Order>, BoxError>; async fn active_orders(&self, pair: &SymbolPair) -> Result<Vec<Order>, BoxError>;
async fn submit_order( async fn submit_order(
@ -123,14 +126,20 @@ impl BitfinexConnector {
#[async_trait] #[async_trait]
impl Connector for BitfinexConnector { impl Connector for BitfinexConnector {
async fn active_positions(&self, pair: &SymbolPair) -> Result<Vec<Position>, BoxError> { async fn active_positions(&self, pair: &SymbolPair) -> Result<Option<Vec<Position>>, BoxError> {
let active_positions = self.bfx.positions.active_positions().await?; let active_positions = self.bfx.positions.active_positions().await?;
Ok(active_positions let positions: Vec<_> = active_positions
.into_iter() .into_iter()
.filter_map(|x| x.try_into().ok()) .filter_map(|x| x.try_into().ok())
.filter(|x: &Position| x.pair() == pair) .filter(|x: &Position| x.pair() == pair)
.collect()) .collect();
if positions.is_empty() {
Ok(None)
} else {
Ok(Some(positions))
}
} }
async fn current_prices(&self, pair: &SymbolPair) -> Result<TradingPairTicker, BoxError> { async fn current_prices(&self, pair: &SymbolPair) -> Result<TradingPairTicker, BoxError> {

View File

@ -147,18 +147,21 @@ impl PriceEntry {
} }
} }
#[derive(Debug)]
pub struct PositionManager { pub struct PositionManager {
queue: VecDeque<Position>, pair: SymbolPair,
open_positions: Vec<Position>, positions_history: HashMap<u64, Position>,
active_position: Option<Position>,
client: Client, client: Client,
strategy: Option<Box<dyn PositionStrategy>>, strategy: Option<Box<dyn PositionStrategy>>,
} }
impl PositionManager { impl PositionManager {
pub fn new(client: Client) -> Self { pub fn new(pair: SymbolPair, client: Client) -> Self {
PositionManager { PositionManager {
queue: VecDeque::new(), pair,
open_positions: Vec::new(), positions_history: HashMap::new(),
active_position: None,
client, client,
strategy: None, strategy: None,
} }
@ -169,21 +172,61 @@ impl PositionManager {
self self
} }
pub fn update(&self) -> Option<Vec<Event>> { pub async fn update(&mut self, tick: u64) -> Result<Option<Vec<Event>>, BoxError> {
unimplemented!() let mut opt_active_positions = self.client.active_positions(&self.pair).await?;
let mut events = vec![];
if opt_active_positions.is_none() {
return Ok(None);
}
// we assume there is only ONE active position per pair
match opt_active_positions
.unwrap()
.into_iter()
.filter(|x| x.pair() == &self.pair)
.next()
{
Some(position) => {
// applying strategy to position
let active_position = {
match &self.strategy {
Some(strategy) => {
let (pos, strategy_events, _) = strategy.on_new_tick(&position, &self);
events.extend(strategy_events);
pos
}
None => position,
}
};
self.positions_history.insert(tick, active_position.clone());
self.active_position = Some(active_position);
}
None => {
self.active_position = None;
}
}
if events.is_empty() {
Ok(None)
} else {
Ok(Some(events))
}
} }
} }
pub struct OrderManager { pub struct OrderManager {
queue: VecDeque<Order>, pair: SymbolPair,
open_orders: Vec<Order>, open_orders: Vec<Order>,
client: Client, client: Client,
} }
impl OrderManager { impl OrderManager {
pub fn new(client: Client) -> Self { pub fn new(pair: SymbolPair, client: Client) -> Self {
OrderManager { OrderManager {
queue: VecDeque::new(), pair,
open_orders: Vec::new(), open_orders: Vec::new(),
client, client,
} }

View File

@ -66,7 +66,7 @@ pub enum OrderKind {
* Positions * Positions
***************/ ***************/
#[derive(Clone, Debug)] #[derive(Clone, Debug, PartialEq)]
pub struct Position { pub struct Position {
pair: SymbolPair, pair: SymbolPair,
state: PositionState, state: PositionState,

View File

@ -1,18 +1,25 @@
use std::collections::HashMap; use std::collections::HashMap;
use crate::events::{Event, EventKind, EventMetadata, SignalKind}; use crate::events::{Event, EventKind, EventMetadata, SignalKind};
use crate::managers::PriceManager; use crate::managers::{PositionManager, PriceManager};
use crate::models::{Position, PositionProfitState}; use crate::models::{Position, PositionProfitState};
use dyn_clone::DynClone; use dyn_clone::DynClone;
use std::fmt::{Debug, Formatter};
pub trait PositionStrategy: DynClone { pub trait PositionStrategy: DynClone {
fn on_new_tick( fn on_new_tick(
&self, &self,
position: &Position, position: &Position,
status: &PriceManager, manager: &PositionManager,
) -> (Position, Vec<Event>, Vec<SignalKind>); ) -> (Position, Vec<Event>, Vec<SignalKind>);
} }
impl Debug for dyn PositionStrategy {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
write!(f, "PositionStrategy")
}
}
// #[derive(Clone, Debug)] // #[derive(Clone, Debug)]
// pub struct TrailingStop { // pub struct TrailingStop {
// stop_percentages: HashMap<u64, f64>, // stop_percentages: HashMap<u64, f64>,