mango-v4/programs/mango-v4/src/state/orderbook/order_type.rs

205 lines
5.6 KiB
Rust

use anchor_lang::prelude::*;
use num_enum::{IntoPrimitive, TryFromPrimitive};
use super::*;
use crate::error::*;
use crate::error_msg;
#[derive(
Eq,
PartialEq,
Copy,
Clone,
TryFromPrimitive,
IntoPrimitive,
Debug,
AnchorSerialize,
AnchorDeserialize,
)]
#[repr(u8)]
pub enum PlaceOrderType {
/// Take existing orders up to price, max_base_quantity and max_quote_quantity.
/// If any base_quantity or quote_quantity remains, place an order on the book
Limit = 0,
/// Take existing orders up to price, max_base_quantity and max_quote_quantity.
/// Never place an order on the book.
ImmediateOrCancel = 1,
/// Never take any existing orders, post the order on the book if possible.
/// If existing orders can match with this order, do nothing.
PostOnly = 2,
/// Ignore price and take orders up to max_base_quantity and max_quote_quantity.
/// Never place an order on the book.
///
/// Equivalent to ImmediateOrCancel with price=i64::MAX.
Market = 3,
/// If existing orders match with this order, adjust the price to just barely
/// not match. Always places an order on the book.
PostOnlySlide = 4,
}
impl PlaceOrderType {
pub fn to_post_order_type(&self) -> Result<PostOrderType> {
match *self {
Self::Market => Err(error_msg!("Market is not a PostOrderType")),
Self::ImmediateOrCancel => Err(error_msg!("ImmediateOrCancel is not a PostOrderType")),
Self::Limit => Ok(PostOrderType::Limit),
Self::PostOnly => Ok(PostOrderType::PostOnly),
Self::PostOnlySlide => Ok(PostOrderType::PostOnlySlide),
}
}
}
#[derive(
Eq,
PartialEq,
Copy,
Clone,
TryFromPrimitive,
IntoPrimitive,
Debug,
AnchorSerialize,
AnchorDeserialize,
)]
#[repr(u8)]
pub enum PostOrderType {
/// Take existing orders up to price, max_base_quantity and max_quote_quantity.
/// If any base_quantity or quote_quantity remains, place an order on the book
Limit = 0,
/// Never take any existing orders, post the order on the book if possible.
/// If existing orders can match with this order, do nothing.
PostOnly = 2,
/// If existing orders match with this order, adjust the price to just barely
/// not match. Always places an order on the book.
PostOnlySlide = 4,
}
#[derive(
Eq,
PartialEq,
Copy,
Clone,
Default,
TryFromPrimitive,
IntoPrimitive,
Debug,
AnchorSerialize,
AnchorDeserialize,
)]
#[repr(u8)]
/// Self trade behavior controls how taker orders interact with resting limit orders of the same account.
/// This setting has no influence on placing a resting or oracle pegged limit order that does not match
/// immediately, instead it's the responsibility of the user to correctly configure his taker orders.
pub enum SelfTradeBehavior {
/// Both the maker and taker sides of the matched orders are decremented.
/// This is equivalent to a normal order match, except for the fact that no fees are applied.
#[default]
DecrementTake = 0,
/// Cancels the maker side of the trade, the taker side gets matched with other maker's orders.
CancelProvide = 1,
/// Cancels the whole transaction as soon as a self-matching scenario is encountered.
AbortTransaction = 2,
}
#[derive(
Eq,
PartialEq,
Copy,
Clone,
TryFromPrimitive,
IntoPrimitive,
Debug,
AnchorSerialize,
AnchorDeserialize,
)]
#[repr(u8)]
pub enum Side {
Bid = 0,
Ask = 1,
}
impl Side {
pub fn invert_side(self: &Side) -> Side {
match self {
Side::Bid => Side::Ask,
Side::Ask => Side::Bid,
}
}
/// Is `lhs` is a better order for `side` than `rhs`?
pub fn is_price_data_better(self: &Side, lhs: u64, rhs: u64) -> bool {
match self {
Side::Bid => lhs > rhs,
Side::Ask => lhs < rhs,
}
}
/// Is `lhs` is a better order for `side` than `rhs`?
pub fn is_price_better(self: &Side, lhs: i64, rhs: i64) -> bool {
match self {
Side::Bid => lhs > rhs,
Side::Ask => lhs < rhs,
}
}
/// Is `price` acceptable for a `limit` order on `side`?
pub fn is_price_within_limit(self: &Side, price: i64, limit: i64) -> bool {
match self {
Side::Bid => price <= limit,
Side::Ask => price >= limit,
}
}
}
/// SideAndOrderTree is a storage optimization, so we don't need two bytes for the data
#[derive(
Eq,
PartialEq,
Copy,
Clone,
TryFromPrimitive,
IntoPrimitive,
Debug,
AnchorSerialize,
AnchorDeserialize,
)]
#[repr(u8)]
pub enum SideAndOrderTree {
BidFixed = 0,
AskFixed = 1,
BidOraclePegged = 2,
AskOraclePegged = 3,
}
impl SideAndOrderTree {
pub fn new(side: Side, order_tree: BookSideOrderTree) -> Self {
match (side, order_tree) {
(Side::Bid, BookSideOrderTree::Fixed) => Self::BidFixed,
(Side::Ask, BookSideOrderTree::Fixed) => Self::AskFixed,
(Side::Bid, BookSideOrderTree::OraclePegged) => Self::BidOraclePegged,
(Side::Ask, BookSideOrderTree::OraclePegged) => Self::AskOraclePegged,
}
}
pub fn side(&self) -> Side {
match self {
Self::BidFixed | Self::BidOraclePegged => Side::Bid,
Self::AskFixed | Self::AskOraclePegged => Side::Ask,
}
}
pub fn order_tree(&self) -> BookSideOrderTree {
match self {
Self::BidFixed | Self::AskFixed => BookSideOrderTree::Fixed,
Self::BidOraclePegged | Self::AskOraclePegged => BookSideOrderTree::OraclePegged,
}
}
}