a lot of stuff
This commit is contained in:
		
							parent
							
								
									d6cd0f1f20
								
							
						
					
					
						commit
						ea7c8394a3
					
				| @ -21,6 +21,15 @@ pub struct EventMetadata { | |||||||
|     order_id: Option<u64>, |     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)] | #[derive(Copy, Clone, PartialEq, Eq, Hash)] | ||||||
| pub enum EventKind { | pub enum EventKind { | ||||||
|     NewMinimum, |     NewMinimum, | ||||||
|  | |||||||
| @ -32,12 +32,13 @@ impl PairStatus { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn add_position(&mut self, position: Position) { |     pub fn add_position(&mut self, position: Position) { | ||||||
|         let (pw, events) = { |         let (pw, events, signals) = { | ||||||
|             match &self.strategy { |             match &self.strategy { | ||||||
|                 Some(strategy) => strategy.position_on_new_tick(&position, &self), |                 Some(strategy) => strategy.position_on_new_tick(&position, &self), | ||||||
|                 None => ( |                 None => ( | ||||||
|                     PositionWrapper::new(position.clone(), position.pl(), position.pl_perc(), None), |                     PositionWrapper::new(position.clone(), position.pl(), position.pl_perc(), None), | ||||||
|                     vec![], |                     vec![], | ||||||
|  |                     vec![], | ||||||
|                 ), |                 ), | ||||||
|             } |             } | ||||||
|         }; |         }; | ||||||
| @ -61,4 +62,14 @@ impl PairStatus { | |||||||
| 
 | 
 | ||||||
|         self.dispatcher.call_event_handlers(&event, &self); |         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)) | ||||||
|  |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,9 +1,120 @@ | |||||||
|  | use std::collections::HashMap; | ||||||
|  | 
 | ||||||
| use bitfinex::positions::Position; | use bitfinex::positions::Position; | ||||||
| 
 | 
 | ||||||
| use crate::events::Event; | use crate::events::{Event, EventKind, EventMetadata, SignalKind}; | ||||||
| use crate::positions::PositionWrapper; |  | ||||||
| use crate::pairs::PairStatus; | use crate::pairs::PairStatus; | ||||||
|  | use crate::positions::{PositionState, PositionWrapper}; | ||||||
| 
 | 
 | ||||||
| pub trait Strategy { | 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); | ||||||
|  |     } | ||||||
| } | } | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user