implemented trades from orders and orders history
This commit is contained in:
parent
c930dce131
commit
d383328ebb
@ -5,20 +5,23 @@ use std::sync::Arc;
|
|||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use bitfinex::api::Bitfinex;
|
use bitfinex::api::Bitfinex;
|
||||||
|
use bitfinex::book::{Book, BookPrecision};
|
||||||
use bitfinex::orders::{CancelOrderForm, OrderMeta};
|
use bitfinex::orders::{CancelOrderForm, OrderMeta};
|
||||||
|
use bitfinex::responses::{OrderResponse, TradeResponse};
|
||||||
use bitfinex::ticker::TradingPairTicker;
|
use bitfinex::ticker::TradingPairTicker;
|
||||||
use futures_retry::{FutureRetry, RetryPolicy};
|
use futures_retry::{FutureRetry, RetryPolicy};
|
||||||
use log::trace;
|
use log::trace;
|
||||||
use tokio::macros::support::Future;
|
use tokio::macros::support::Future;
|
||||||
use tokio::time::Duration;
|
use tokio::time::Duration;
|
||||||
|
use tokio_tungstenite::stream::Stream::Plain;
|
||||||
|
|
||||||
use crate::currency::{Symbol, SymbolPair};
|
use crate::currency::{Symbol, SymbolPair};
|
||||||
|
use crate::models::TradingPlatform::Margin;
|
||||||
use crate::models::{
|
use crate::models::{
|
||||||
ActiveOrder, OrderBook, OrderBookEntry, OrderForm, OrderKind, Position, PositionState,
|
ActiveOrder, OrderBook, OrderBookEntry, OrderDetails, OrderFee, OrderForm, OrderKind, Position,
|
||||||
PriceTicker, TradingPlatform, WalletKind,
|
PositionState, PriceTicker, Trade, TradingPlatform, WalletKind,
|
||||||
};
|
};
|
||||||
use crate::BoxError;
|
use crate::BoxError;
|
||||||
use bitfinex::responses::OrderResponse;
|
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||||
pub enum Exchange {
|
pub enum Exchange {
|
||||||
@ -114,6 +117,20 @@ impl Client {
|
|||||||
.transfer_between_wallets(from, to, symbol, amount)
|
.transfer_between_wallets(from, to, symbol, amount)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn trades_from_order(
|
||||||
|
&self,
|
||||||
|
order: &OrderDetails,
|
||||||
|
) -> Result<Option<Vec<Trade>>, BoxError> {
|
||||||
|
self.inner.trades_from_order(order).await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn orders_history(
|
||||||
|
&self,
|
||||||
|
pair: &SymbolPair,
|
||||||
|
) -> Result<Option<Vec<OrderDetails>>, BoxError> {
|
||||||
|
self.inner.orders_history(pair).await
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
@ -132,6 +149,12 @@ pub trait Connector: Send + Sync {
|
|||||||
symbol: Symbol,
|
symbol: Symbol,
|
||||||
amount: f64,
|
amount: f64,
|
||||||
) -> Result<(), BoxError>;
|
) -> Result<(), BoxError>;
|
||||||
|
async fn trades_from_order(&self, order: &OrderDetails)
|
||||||
|
-> Result<Option<Vec<Trade>>, BoxError>;
|
||||||
|
async fn orders_history(
|
||||||
|
&self,
|
||||||
|
pair: &SymbolPair,
|
||||||
|
) -> Result<Option<Vec<OrderDetails>>, BoxError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for dyn Connector {
|
impl Debug for dyn Connector {
|
||||||
@ -171,6 +194,31 @@ impl BitfinexConnector {
|
|||||||
format!("{}{}", pair.base(), pair.quote())
|
format!("{}{}", pair.base(), pair.quote())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// retry to submit the request until it succeeds.
|
||||||
|
// the function may fail due to concurrent signed requests
|
||||||
|
// parsed in different times by the server
|
||||||
|
async fn retry_nonce<F, Fut, O>(mut func: F) -> Result<O, BoxError>
|
||||||
|
where
|
||||||
|
F: FnMut() -> Fut,
|
||||||
|
Fut: Future<Output = Result<O, BoxError>>,
|
||||||
|
{
|
||||||
|
let response = {
|
||||||
|
loop {
|
||||||
|
match func().await {
|
||||||
|
Ok(response) => break response,
|
||||||
|
Err(e) => {
|
||||||
|
if !e.to_string().contains("nonce: small") {
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
|
tokio::time::sleep(Duration::from_nanos(1)).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(response)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
@ -180,12 +228,8 @@ impl Connector for BitfinexConnector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn active_positions(&self, pair: &SymbolPair) -> Result<Option<Vec<Position>>, BoxError> {
|
async fn active_positions(&self, pair: &SymbolPair) -> Result<Option<Vec<Position>>, BoxError> {
|
||||||
let (active_positions, _) = FutureRetry::new(
|
let active_positions =
|
||||||
move || self.bfx.positions.active_positions(),
|
BitfinexConnector::retry_nonce(|| self.bfx.positions.active_positions()).await?;
|
||||||
BitfinexConnector::handle_small_nonce_error,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.map_err(|(e, _attempts)| e)?;
|
|
||||||
|
|
||||||
let positions: Vec<_> = active_positions
|
let positions: Vec<_> = active_positions
|
||||||
.into_iter()
|
.into_iter()
|
||||||
@ -205,13 +249,28 @@ impl Connector for BitfinexConnector {
|
|||||||
Ok(ticker)
|
Ok(ticker)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn order_book(&self, pair: &SymbolPair) -> Result<OrderBook, BoxError> {
|
||||||
|
let symbol_name = BitfinexConnector::format_trading_pair(pair);
|
||||||
|
|
||||||
|
let response = BitfinexConnector::retry_nonce(|| {
|
||||||
|
self.bfx.book.trading_pair(&symbol_name, BookPrecision::P0)
|
||||||
|
})
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
let entries = response
|
||||||
|
.into_iter()
|
||||||
|
.map(|x| OrderBookEntry::Trading {
|
||||||
|
price: x.price,
|
||||||
|
count: x.count as u64,
|
||||||
|
amount: x.amount,
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
Ok(OrderBook::new(pair.clone()).with_entries(entries))
|
||||||
|
}
|
||||||
|
|
||||||
async fn active_orders(&self, _: &SymbolPair) -> Result<Vec<ActiveOrder>, BoxError> {
|
async fn active_orders(&self, _: &SymbolPair) -> Result<Vec<ActiveOrder>, BoxError> {
|
||||||
let (response, _) = FutureRetry::new(
|
let response = BitfinexConnector::retry_nonce(|| self.bfx.orders.active_orders()).await?;
|
||||||
move || self.bfx.orders.active_orders(),
|
|
||||||
BitfinexConnector::handle_small_nonce_error,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.map_err(|(e, _attempts)| e)?;
|
|
||||||
|
|
||||||
Ok(response.iter().map(Into::into).collect())
|
Ok(response.iter().map(Into::into).collect())
|
||||||
}
|
}
|
||||||
@ -250,76 +309,17 @@ impl Connector for BitfinexConnector {
|
|||||||
BitfinexConnector::AFFILIATE_CODE.to_string(),
|
BitfinexConnector::AFFILIATE_CODE.to_string(),
|
||||||
));
|
));
|
||||||
|
|
||||||
// retry to submit the order until it succeeds.
|
let response =
|
||||||
// the function may fail due to concurrent signed requests
|
BitfinexConnector::retry_nonce(|| self.bfx.orders.submit_order(&order_form)).await?;
|
||||||
// parsed in different times by the server
|
|
||||||
let response = {
|
|
||||||
loop {
|
|
||||||
match self.bfx.orders.submit_order(&order_form).await {
|
|
||||||
Ok(response) => break response,
|
|
||||||
Err(e) => {
|
|
||||||
if !e.to_string().contains("nonce: small") {
|
|
||||||
return Err(e);
|
|
||||||
}
|
|
||||||
tokio::time::sleep(Duration::from_nanos(1)).await;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok((&response).try_into()?)
|
Ok((&response).try_into()?)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn order_book(&self, pair: &SymbolPair) -> Result<OrderBook, BoxError> {
|
|
||||||
let symbol_name = BitfinexConnector::format_trading_pair(pair);
|
|
||||||
|
|
||||||
let response = {
|
|
||||||
loop {
|
|
||||||
match self
|
|
||||||
.bfx
|
|
||||||
.book
|
|
||||||
.trading_pair(symbol_name.clone(), bitfinex::book::BookPrecision::P0)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(response) => break response,
|
|
||||||
Err(e) => {
|
|
||||||
if !e.to_string().contains("nonce: small") {
|
|
||||||
return Err(e);
|
|
||||||
}
|
|
||||||
tokio::time::sleep(Duration::from_nanos(1)).await;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let entries = response
|
|
||||||
.into_iter()
|
|
||||||
.map(|x| OrderBookEntry::Trading {
|
|
||||||
price: x.price,
|
|
||||||
count: x.count as u64,
|
|
||||||
amount: x.amount,
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
Ok(OrderBook::new(pair.clone()).with_entries(entries))
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn cancel_order(&self, order: &ActiveOrder) -> Result<ActiveOrder, BoxError> {
|
async fn cancel_order(&self, order: &ActiveOrder) -> Result<ActiveOrder, BoxError> {
|
||||||
let cancel_form = order.into();
|
let cancel_form = order.into();
|
||||||
|
|
||||||
let response = {
|
let response =
|
||||||
loop {
|
BitfinexConnector::retry_nonce(|| self.bfx.orders.cancel_order(&cancel_form)).await?;
|
||||||
match self.bfx.orders.cancel_order(&cancel_form).await {
|
|
||||||
Ok(response) => break response,
|
|
||||||
Err(e) => {
|
|
||||||
if !e.to_string().contains("nonce: small") {
|
|
||||||
return Err(e);
|
|
||||||
}
|
|
||||||
tokio::time::sleep(Duration::from_nanos(1)).await;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok((&response).try_into()?)
|
Ok((&response).try_into()?)
|
||||||
}
|
}
|
||||||
@ -331,16 +331,48 @@ impl Connector for BitfinexConnector {
|
|||||||
symbol: Symbol,
|
symbol: Symbol,
|
||||||
amount: f64,
|
amount: f64,
|
||||||
) -> Result<(), BoxError> {
|
) -> Result<(), BoxError> {
|
||||||
let result = self
|
BitfinexConnector::retry_nonce(|| {
|
||||||
.bfx
|
self.bfx.account.transfer_between_wallets(
|
||||||
.account
|
from.into(),
|
||||||
.transfer_between_wallets(from.into(), to.into(), symbol.to_string(), amount)
|
to.into(),
|
||||||
.await?;
|
symbol.to_string(),
|
||||||
|
amount,
|
||||||
println!("{:?}", result);
|
)
|
||||||
|
})
|
||||||
|
.await?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn trades_from_order(
|
||||||
|
&self,
|
||||||
|
order: &OrderDetails,
|
||||||
|
) -> Result<Option<Vec<Trade>>, BoxError> {
|
||||||
|
let response = BitfinexConnector::retry_nonce(|| {
|
||||||
|
self.bfx
|
||||||
|
.trades
|
||||||
|
.generated_by_order(order.pair().trading_repr(), order.id())
|
||||||
|
})
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
if response.is_empty() {
|
||||||
|
Ok(None)
|
||||||
|
} else {
|
||||||
|
Ok(Some(response.iter().map(Into::into).collect()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn orders_history(
|
||||||
|
&self,
|
||||||
|
pair: &SymbolPair,
|
||||||
|
) -> Result<Option<Vec<OrderDetails>>, BoxError> {
|
||||||
|
let response =
|
||||||
|
BitfinexConnector::retry_nonce(|| self.bfx.orders.history(Some(pair.trading_repr())))
|
||||||
|
.await?;
|
||||||
|
let mapped_vec: Vec<_> = response.iter().map(Into::into).collect();
|
||||||
|
|
||||||
|
Ok((!mapped_vec.is_empty()).then_some(mapped_vec))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&ActiveOrder> for CancelOrderForm {
|
impl From<&ActiveOrder> for CancelOrderForm {
|
||||||
@ -359,7 +391,7 @@ impl TryFrom<&bitfinex::responses::OrderResponse> for ActiveOrder {
|
|||||||
group_id: response.gid(),
|
group_id: response.gid(),
|
||||||
client_id: Some(response.cid()),
|
client_id: Some(response.cid()),
|
||||||
symbol: SymbolPair::from_str(response.symbol())?,
|
symbol: SymbolPair::from_str(response.symbol())?,
|
||||||
current_form: OrderForm::new(
|
details: OrderForm::new(
|
||||||
SymbolPair::from_str(response.symbol())?,
|
SymbolPair::from_str(response.symbol())?,
|
||||||
response.into(),
|
response.into(),
|
||||||
response.into(),
|
response.into(),
|
||||||
@ -557,7 +589,7 @@ impl From<&bitfinex::orders::ActiveOrder> for ActiveOrder {
|
|||||||
group_id: order.group_id().map(|x| x as u64),
|
group_id: order.group_id().map(|x| x as u64),
|
||||||
client_id: Some(order.client_id()),
|
client_id: Some(order.client_id()),
|
||||||
symbol: pair.clone(),
|
symbol: pair.clone(),
|
||||||
current_form: OrderForm::new(pair, order.into(), order.into()),
|
details: OrderForm::new(pair, order.into(), order.into()),
|
||||||
creation_timestamp: order.creation_timestamp(),
|
creation_timestamp: order.creation_timestamp(),
|
||||||
update_timestamp: order.update_timestamp(),
|
update_timestamp: order.update_timestamp(),
|
||||||
}
|
}
|
||||||
@ -590,3 +622,40 @@ impl From<&WalletKind> for &bitfinex::account::WalletKind {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<&bitfinex::orders::ActiveOrder> for OrderDetails {
|
||||||
|
fn from(order: &bitfinex::orders::ActiveOrder) -> Self {
|
||||||
|
Self::new(
|
||||||
|
Exchange::Bitfinex,
|
||||||
|
order.id(),
|
||||||
|
SymbolPair::from_str(order.symbol()).unwrap(),
|
||||||
|
order.into(),
|
||||||
|
order.into(),
|
||||||
|
order.update_timestamp(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: fields are hardcoded, to fix
|
||||||
|
impl From<&bitfinex::responses::TradeResponse> for Trade {
|
||||||
|
fn from(response: &TradeResponse) -> Self {
|
||||||
|
let pair = SymbolPair::from_str(&response.symbol).unwrap();
|
||||||
|
let fee = {
|
||||||
|
if response.is_maker {
|
||||||
|
OrderFee::Maker(response.fee)
|
||||||
|
} else {
|
||||||
|
OrderFee::Taker(response.fee)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Self {
|
||||||
|
trade_id: response.trade_id,
|
||||||
|
pair,
|
||||||
|
execution_timestamp: response.execution_timestamp,
|
||||||
|
price: response.execution_price,
|
||||||
|
amount: response.execution_amount,
|
||||||
|
fee,
|
||||||
|
fee_currency: Symbol::new(response.symbol.clone()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -71,10 +71,10 @@ impl SymbolPair {
|
|||||||
SymbolPair { quote, base }
|
SymbolPair { quote, base }
|
||||||
}
|
}
|
||||||
pub fn trading_repr(&self) -> String {
|
pub fn trading_repr(&self) -> String {
|
||||||
format!("t{}{}", self.quote, self.base)
|
format!("t{}{}", self.base, self.quote)
|
||||||
}
|
}
|
||||||
pub fn funding_repr(&self) -> String {
|
pub fn funding_repr(&self) -> String {
|
||||||
format!("f{}{}", self.quote, self.base)
|
format!("f{}{}", self.base, self.quote)
|
||||||
}
|
}
|
||||||
pub fn quote(&self) -> &Symbol {
|
pub fn quote(&self) -> &Symbol {
|
||||||
&self.quote
|
&self.quote
|
||||||
|
@ -422,7 +422,7 @@ impl OrderManager {
|
|||||||
if let Some(position) = open_positions.into_iter().find(|x| x.id() == position_id) {
|
if let Some(position) = open_positions.into_iter().find(|x| x.id() == position_id) {
|
||||||
let opt_position_order = open_orders
|
let opt_position_order = open_orders
|
||||||
.iter()
|
.iter()
|
||||||
.find(|x| x.current_form.amount().neg() == position.amount());
|
.find(|x| x.details.amount().neg() == position.amount());
|
||||||
|
|
||||||
// checking if the position has an open order.
|
// checking if the position has an open order.
|
||||||
// If so, don't do anything since the order is taken care of
|
// If so, don't do anything since the order is taken care of
|
||||||
|
@ -3,7 +3,7 @@ use std::fmt::{Display, Formatter};
|
|||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
|
|
||||||
use crate::connectors::Exchange;
|
use crate::connectors::Exchange;
|
||||||
use crate::currency::SymbolPair;
|
use crate::currency::{Symbol, SymbolPair};
|
||||||
|
|
||||||
/***************
|
/***************
|
||||||
* Prices
|
* Prices
|
||||||
@ -104,6 +104,62 @@ impl OrderBook {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum OrderFee {
|
||||||
|
Maker(f64),
|
||||||
|
Taker(f64),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct OrderDetails {
|
||||||
|
exchange: Exchange,
|
||||||
|
pair: SymbolPair,
|
||||||
|
platform: TradingPlatform,
|
||||||
|
kind: OrderKind,
|
||||||
|
execution_timestamp: u64,
|
||||||
|
id: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OrderDetails {
|
||||||
|
pub fn new(
|
||||||
|
exchange: Exchange,
|
||||||
|
id: u64,
|
||||||
|
pair: SymbolPair,
|
||||||
|
platform: TradingPlatform,
|
||||||
|
kind: OrderKind,
|
||||||
|
execution_timestamp: u64,
|
||||||
|
) -> Self {
|
||||||
|
OrderDetails {
|
||||||
|
exchange,
|
||||||
|
pair,
|
||||||
|
platform,
|
||||||
|
kind,
|
||||||
|
execution_timestamp,
|
||||||
|
id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn exchange(&self) -> Exchange {
|
||||||
|
self.exchange
|
||||||
|
}
|
||||||
|
pub fn platform(&self) -> TradingPlatform {
|
||||||
|
self.platform
|
||||||
|
}
|
||||||
|
pub fn kind(&self) -> OrderKind {
|
||||||
|
self.kind
|
||||||
|
}
|
||||||
|
pub fn execution_timestamp(&self) -> u64 {
|
||||||
|
self.execution_timestamp
|
||||||
|
}
|
||||||
|
pub fn id(&self) -> u64 {
|
||||||
|
self.id
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pair(&self) -> &SymbolPair {
|
||||||
|
&self.pair
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct ActiveOrder {
|
pub struct ActiveOrder {
|
||||||
pub(crate) exchange: Exchange,
|
pub(crate) exchange: Exchange,
|
||||||
@ -111,7 +167,7 @@ pub struct ActiveOrder {
|
|||||||
pub(crate) group_id: Option<u64>,
|
pub(crate) group_id: Option<u64>,
|
||||||
pub(crate) client_id: Option<u64>,
|
pub(crate) client_id: Option<u64>,
|
||||||
pub(crate) symbol: SymbolPair,
|
pub(crate) symbol: SymbolPair,
|
||||||
pub(crate) current_form: OrderForm,
|
pub(crate) details: OrderForm,
|
||||||
pub(crate) creation_timestamp: u64,
|
pub(crate) creation_timestamp: u64,
|
||||||
pub(crate) update_timestamp: u64,
|
pub(crate) update_timestamp: u64,
|
||||||
}
|
}
|
||||||
@ -496,3 +552,14 @@ pub enum WalletKind {
|
|||||||
Margin,
|
Margin,
|
||||||
Funding,
|
Funding,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Trade {
|
||||||
|
pub trade_id: u64,
|
||||||
|
pub pair: SymbolPair,
|
||||||
|
pub execution_timestamp: u64,
|
||||||
|
pub price: f64,
|
||||||
|
pub amount: f64,
|
||||||
|
pub fee: OrderFee,
|
||||||
|
pub fee_currency: Symbol,
|
||||||
|
}
|
||||||
|
@ -75,9 +75,9 @@ pub struct TrailingStop {
|
|||||||
|
|
||||||
impl TrailingStop {
|
impl TrailingStop {
|
||||||
const BREAK_EVEN_PERC: f64 = 0.1;
|
const BREAK_EVEN_PERC: f64 = 0.1;
|
||||||
const MIN_PROFIT_PERC: f64 = 0.7;
|
const MIN_PROFIT_PERC: f64 = 0.5;
|
||||||
const GOOD_PROFIT_PERC: f64 = TrailingStop::MIN_PROFIT_PERC * 1.75;
|
const GOOD_PROFIT_PERC: f64 = TrailingStop::MIN_PROFIT_PERC * 1.75;
|
||||||
const MAX_LOSS_PERC: f64 = -1.75;
|
const MAX_LOSS_PERC: f64 = -4.0;
|
||||||
|
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
TrailingStop {
|
TrailingStop {
|
||||||
@ -276,7 +276,7 @@ impl OrderStrategy for FastOrderStrategy {
|
|||||||
|
|
||||||
// long
|
// long
|
||||||
let offer_comparison = {
|
let offer_comparison = {
|
||||||
if order.current_form.amount() > 0.0 {
|
if order.details.amount() > 0.0 {
|
||||||
order_book.highest_bid()
|
order_book.highest_bid()
|
||||||
} else {
|
} else {
|
||||||
order_book.lowest_ask()
|
order_book.lowest_ask()
|
||||||
@ -286,7 +286,7 @@ impl OrderStrategy for FastOrderStrategy {
|
|||||||
// if the best offer is higher than our threshold,
|
// if the best offer is higher than our threshold,
|
||||||
// ask the manager to close the position with a market order
|
// ask the manager to close the position with a market order
|
||||||
let order_price = order
|
let order_price = order
|
||||||
.current_form
|
.details
|
||||||
.price()
|
.price()
|
||||||
.ok_or("The active order does not have a price!")?;
|
.ok_or("The active order does not have a price!")?;
|
||||||
let delta = (1.0 - (offer_comparison / order_price)).abs() * 100.0;
|
let delta = (1.0 - (offer_comparison / order_price)).abs() * 100.0;
|
||||||
@ -296,9 +296,9 @@ impl OrderStrategy for FastOrderStrategy {
|
|||||||
order: OrderForm::new(
|
order: OrderForm::new(
|
||||||
order.symbol.clone(),
|
order.symbol.clone(),
|
||||||
OrderKind::Market {
|
OrderKind::Market {
|
||||||
amount: order.current_form.amount(),
|
amount: order.details.amount(),
|
||||||
},
|
},
|
||||||
order.current_form.platform().clone(),
|
order.details.platform().clone(),
|
||||||
),
|
),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user