core/rustybot/src/models.rs

314 lines
7.4 KiB
Rust
Raw Normal View History

2021-01-16 11:43:16 +00:00
use std::fmt::Display;
use chrono::{DateTime, TimeZone};
use crate::currency::SymbolPair;
2021-01-15 10:49:44 +00:00
use crate::BoxError;
2021-01-16 11:43:16 +00:00
use std::hash::{Hash, Hasher};
2021-01-14 12:42:23 +00:00
/***************
* Prices
***************/
#[derive(Copy, Clone, Debug)]
pub struct PriceTicker {
pub bid: f64,
pub bid_size: f64,
pub ask: f64,
pub ask_size: f64,
pub daily_change: f64,
pub daily_change_perc: f64,
pub last_price: f64,
pub volume: f64,
pub high: f64,
pub low: f64,
}
/***************
* Orders
***************/
#[derive(Clone, Debug)]
2021-01-16 11:43:16 +00:00
pub struct ExecutedOrder {
pub id: i64,
pub group_id: Option<i32>,
pub client_id: i64,
pub symbol: String,
pub creation_timestamp: i64,
pub update_timestamp: i64,
pub amount: f64,
pub amount_original: f64,
pub order_type: String,
pub previous_order_type: Option<String>,
pub flags: Option<i32>,
pub order_status: Option<String>,
pub price: f64,
pub price_avg: f64,
pub price_trailing: Option<f64>,
pub price_aux_limit: Option<f64>,
pub notify: i32,
pub hidden: i32,
pub placed_id: Option<i32>,
}
2021-01-16 11:43:16 +00:00
impl Hash for ExecutedOrder {
fn hash<H: Hasher>(&self, state: &mut H) {
state.write(&self.id.to_le_bytes())
}
}
#[derive(Copy, Clone, Debug, Hash)]
pub enum OrderKind {
Limit,
ExchangeLimit,
Market,
ExchangeMarket,
Stop,
ExchangeStop,
StopLimit,
ExchangeStopLimit,
TrailingStop,
Fok,
ExchangeFok,
Ioc,
ExchangeIoc,
}
2021-01-15 10:51:02 +00:00
#[derive(Clone)]
2021-01-15 10:49:44 +00:00
pub struct OrderForm {
/// Order Type: LIMIT, EXCHANGE LIMIT, MARKET, EXCHANGE MARKET,
/// STOP, EXCHANGE STOP, STOP LIMIT, EXCHANGE STOP LIMIT,
/// TRAILING STOP, EXCHANGE TRAILING STOP, FOK,
/// EXCHANGE FOK, IOC, EXCHANGE IOC
kind: OrderKind,
/// Symbol for desired pair
2021-01-16 11:43:16 +00:00
pair: SymbolPair,
2021-01-15 10:49:44 +00:00
/// Price of order
2021-01-16 11:43:16 +00:00
price: f64,
2021-01-15 10:49:44 +00:00
/// Amount of order (positive for buy, negative for sell)
2021-01-16 11:43:16 +00:00
amount: f64,
2021-01-15 10:49:44 +00:00
/// Set the leverage for a derivative order, supported by derivative symbol orders only.
/// The value should be between 1 and 100 inclusive.
/// The field is optional, if omitted the default leverage value of 10 will be used.
leverage: Option<u32>,
/// The trailing price for a trailing stop order
price_trailing: Option<String>,
/// Auxiliary Limit price (for STOP LIMIT)
price_aux_limit: Option<String>,
/// Time-In-Force: datetime for automatic order cancellation (ie. 2020-01-01 10:45:23) )
tif: Option<String>,
}
impl OrderForm {
2021-01-16 11:43:16 +00:00
pub fn new(pair: &SymbolPair, price: f64, amount: f64, kind: OrderKind) -> Self {
2021-01-15 10:49:44 +00:00
OrderForm {
kind,
2021-01-16 11:43:16 +00:00
pair: pair.clone(),
price,
amount,
2021-01-15 10:49:44 +00:00
leverage: None,
price_trailing: None,
price_aux_limit: None,
tif: None,
}
}
pub fn with_leverage(mut self, leverage: u32) -> Self {
self.leverage = Some(leverage);
self
}
pub fn with_price_trailing(mut self, trailing: f64) -> Result<Self, BoxError> {
match self.kind {
OrderKind::TrailingStop => {
self.price_trailing = Some(trailing.to_string());
Ok(self)
}
_ => Err("Invalid order type.".into()),
}
}
2021-01-16 11:43:16 +00:00
pub fn with_price_aux_limit(mut self, limit: f64) -> Result<Self, BoxError> {
2021-01-15 10:49:44 +00:00
match self.kind {
OrderKind::StopLimit | OrderKind::ExchangeStopLimit => {
self.price_aux_limit = Some(limit.to_string());
Ok(self)
}
_ => Err("Invalid order type.".into()),
}
}
pub fn with_tif<T: TimeZone>(mut self, tif: DateTime<T>) -> Self
where
T::Offset: Display,
{
self.tif = Some(tif.format("%Y-%m-%d %H:%M:%S").to_string());
self
}
2021-01-16 11:43:16 +00:00
pub fn kind(&self) -> OrderKind {
self.kind
}
pub fn pair(&self) -> &SymbolPair {
&self.pair
}
pub fn price(&self) -> &f64 {
&self.price
}
pub fn amount(&self) -> &f64 {
&self.amount
}
pub fn leverage(&self) -> Option<u32> {
self.leverage
}
pub fn price_trailing(&self) -> &Option<String> {
&self.price_trailing
}
pub fn price_aux_limit(&self) -> &Option<String> {
&self.price_aux_limit
}
pub fn tif(&self) -> &Option<String> {
&self.tif
}
2021-01-15 10:49:44 +00:00
}
2021-01-14 12:42:23 +00:00
/***************
* Positions
***************/
2021-01-16 11:43:16 +00:00
#[derive(Clone, Debug)]
pub struct Position {
pair: SymbolPair,
state: PositionState,
profit_state: Option<PositionProfitState>,
amount: f64,
base_price: f64,
pl: f64,
pl_perc: f64,
price_liq: f64,
position_id: u64,
creation_date: Option<u64>,
creation_update: Option<u64>,
}
impl Position {
pub fn new(
pair: SymbolPair,
state: PositionState,
amount: f64,
base_price: f64,
pl: f64,
pl_perc: f64,
price_liq: f64,
position_id: u64,
) -> Self {
Position {
pair,
state,
amount,
base_price,
pl,
pl_perc,
price_liq,
position_id,
creation_date: None,
creation_update: None,
profit_state: None,
}
}
pub fn with_creation_date(mut self, creation_date: Option<u64>) -> Self {
self.creation_date = creation_date;
self
}
pub fn with_creation_update(mut self, creation_update: Option<u64>) -> Self {
self.creation_update = creation_update;
self
}
pub fn with_profit_state(mut self, profit_state: Option<PositionProfitState>) -> Self {
self.profit_state = profit_state;
self
}
pub fn pair(&self) -> &SymbolPair {
&self.pair
}
pub fn state(&self) -> PositionState {
self.state
}
pub fn amount(&self) -> f64 {
self.amount
}
pub fn base_price(&self) -> f64 {
self.base_price
}
pub fn pl(&self) -> f64 {
self.pl
}
pub fn pl_perc(&self) -> f64 {
self.pl_perc
}
pub fn price_liq(&self) -> f64 {
self.price_liq
}
2021-01-16 11:43:16 +00:00
pub fn id(&self) -> u64 {
self.position_id
}
pub fn profit_state(&self) -> Option<PositionProfitState> {
self.profit_state
}
pub fn creation_date(&self) -> Option<u64> {
self.creation_date
}
pub fn creation_update(&self) -> Option<u64> {
self.creation_update
}
2021-01-16 11:43:16 +00:00
pub fn is_short(&self) -> bool {
self.amount.is_sign_negative()
}
pub fn is_long(&self) -> bool {
self.amount.is_sign_positive()
}
}
impl Hash for Position {
fn hash<H: Hasher>(&self, state: &mut H) {
state.write(&self.id().to_le_bytes())
}
}
impl PartialEq for Position {
fn eq(&self, other: &Self) -> bool {
self.id() == other.id()
}
}
2021-01-16 11:43:16 +00:00
impl Eq for Position {}
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub enum PositionProfitState {
Critical,
Loss,
BreakEven,
MinimumProfit,
Profit,
}
impl PositionProfitState {
fn color(self) -> String {
match self {
PositionProfitState::Critical | PositionProfitState::Loss => "red",
PositionProfitState::BreakEven => "yellow",
PositionProfitState::MinimumProfit | PositionProfitState::Profit => "green",
}
.into()
}
}
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub enum PositionState {
Closed,
Open,
}