a lot of stuff

This commit is contained in:
Giulio De Pasquale 2021-01-04 19:29:01 +00:00
parent d6cd0f1f20
commit ea7c8394a3
3 changed files with 136 additions and 5 deletions

View File

@ -21,6 +21,15 @@ pub struct EventMetadata {
order_id: Option<u64>,
}
impl EventMetadata {
pub fn new(position_id: Option<u64>, order_id: Option<u64>) -> Self {
EventMetadata {
position_id,
order_id,
}
}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub enum EventKind {
NewMinimum,

View File

@ -32,12 +32,13 @@ impl PairStatus {
}
pub fn add_position(&mut self, position: Position) {
let (pw, events) = {
let (pw, events, signals) = {
match &self.strategy {
Some(strategy) => strategy.position_on_new_tick(&position, &self),
None => (
PositionWrapper::new(position.clone(), position.pl(), position.pl_perc(), None),
vec![],
vec![],
),
}
};
@ -61,4 +62,14 @@ impl PairStatus {
self.dispatcher.call_event_handlers(&event, &self);
}
pub fn current_tick(&self) -> u64 {
self.current_tick
}
pub fn previous_pw(&self, id: u64) -> Option<&PositionWrapper> {
self.positions
.get(&(self.current_tick - 1))
.and_then(|x| x.iter().find(|x| x.position().position_id() == id))
}
}

View File

@ -1,9 +1,120 @@
use std::collections::HashMap;
use bitfinex::positions::Position;
use crate::events::Event;
use crate::positions::PositionWrapper;
use crate::events::{Event, EventKind, EventMetadata, SignalKind};
use crate::pairs::PairStatus;
use crate::positions::{PositionState, PositionWrapper};
pub trait Strategy {
fn position_on_new_tick(&self, position: &Position, status: &PairStatus) -> (PositionWrapper, Vec<Event>);
fn position_on_new_tick(
&self,
position: &Position,
status: &PairStatus,
) -> (PositionWrapper, Vec<Event>, Vec<SignalKind>);
}
struct TrailingStop {
stop_percentages: HashMap<u64, f64>,
}
impl TrailingStop {
const BREAK_EVEN_PERC: f64 = 0.2;
const MIN_PROFIT_PERC: f64 = TrailingStop::BREAK_EVEN_PERC + 0.3;
const GOOD_PROFIT_PERC: f64 = TrailingStop::MIN_PROFIT_PERC * 2.5;
const MAX_LOSS_PERC: f64 = -1.7;
const TAKER_FEE: f64 = 0.2;
pub fn new() -> Self {
TrailingStop {
stop_percentages: HashMap::new(),
}
}
fn net_pl_percentage(pl: f64, fee: f64) -> f64 {
pl - fee
}
}
impl Strategy for TrailingStop {
fn position_on_new_tick(
&self,
position: &Position,
status: &PairStatus,
) -> (PositionWrapper, Vec<Event>, Vec<SignalKind>) {
let mut signals = vec![];
let pl_perc = TrailingStop::net_pl_percentage(position.pl_perc(), TrailingStop::TAKER_FEE);
let events = vec![];
let state = {
if pl_perc > TrailingStop::GOOD_PROFIT_PERC {
PositionState::Profit
} else if TrailingStop::MIN_PROFIT_PERC <= pl_perc
&& pl_perc < TrailingStop::GOOD_PROFIT_PERC
{
PositionState::MinimumProfit
} else if 0.0 <= pl_perc && pl_perc < TrailingStop::MIN_PROFIT_PERC {
PositionState::BreakEven
} else if TrailingStop::MAX_LOSS_PERC < pl_perc && pl_perc < 0.0 {
PositionState::Loss
} else {
signals.push(SignalKind::ClosePosition);
PositionState::Critical
}
};
let opt_pre_pw = status.previous_pw(position.position_id());
let event_metadata = EventMetadata::new(Some(position.position_id()), None);
let pw = PositionWrapper::new(position.clone(), position.pl(), pl_perc, Some(state));
match opt_pre_pw {
Some(prev) => {
if prev.state() == Some(state) {
return (pw, events, signals);
}
}
None => return (pw, events, signals),
};
let events = {
let mut events = vec![];
if state == PositionState::Profit {
events.push(Event::new(
EventKind::ReachedGoodProfit,
status.current_tick(),
Some(event_metadata),
));
} else if state == PositionState::MinimumProfit {
events.push(Event::new(
EventKind::ReachedMinProfit,
status.current_tick(),
Some(event_metadata),
));
} else if state == PositionState::BreakEven {
events.push(Event::new(
EventKind::ReachedBreakEven,
status.current_tick(),
Some(event_metadata),
));
} else if state == PositionState::Loss {
events.push(Event::new(
EventKind::ReachedLoss,
status.current_tick(),
Some(event_metadata),
));
} else {
events.push(Event::new(
EventKind::ReachedMaxLoss,
status.current_tick(),
Some(event_metadata),
));
}
events
};
return (pw, events, signals);
}
}