pub(crate) mod common;
pub mod builder;
pub mod conditions;
mod exercise_options_builder;
pub use common::order_builder;
pub use crate::client::ids::OrderId;
pub use builder::order_builder::{AttachedOrdersBuilder, BracketOrderBuilder, ClientBound, Detached, OrderBuilder};
pub use builder::types::{AttachedOrderIds, BracketOrderIds};
pub use exercise_options_builder::ExerciseOptionsBuilder;
pub use conditions::{
ExecutionCondition, ExecutionConditionBuilder, MarginCondition, MarginConditionBuilder, PercentChangeCondition, PercentChangeConditionBuilder,
PriceCondition, PriceConditionBuilder, TimeCondition, TimeConditionBuilder, UnknownCondition, VolumeCondition, VolumeConditionBuilder,
};
use std::convert::From;
use std::fmt::Debug;
use serde::{Deserialize, Serialize};
use crate::contracts::Contract;
use crate::contracts::TagValue;
pub(crate) const COMPETE_AGAINST_BEST_OFFSET_UP_TO_MID: Option<f64> = Some(f64::INFINITY);
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct Order {
pub order_id: i32,
pub solicited: bool,
pub client_id: i32,
pub perm_id: i64,
pub action: Action,
pub total_quantity: f64,
pub order_type: String,
pub limit_price: Option<f64>,
pub aux_price: Option<f64>,
pub tif: TimeInForce,
pub oca_group: String,
pub oca_type: OcaType,
pub order_ref: String,
pub transmit: bool,
pub deactivate: bool,
pub parent_id: i32,
pub preset_stop_loss_order_id: Option<i32>,
pub preset_profit_taker_order_id: Option<i32>,
pub block_order: bool,
pub sweep_to_fill: bool,
pub display_size: Option<i32>,
pub trigger_method: conditions::TriggerMethod,
pub outside_rth: bool,
pub hidden: bool,
pub good_after_time: String,
pub good_till_date: String,
pub override_percentage_constraints: bool,
pub rule_80_a: Option<Rule80A>,
pub all_or_none: bool,
pub min_qty: Option<i32>,
pub percent_offset: Option<f64>,
pub trail_stop_price: Option<f64>,
pub trailing_percent: Option<f64>,
pub fa_group: String,
pub fa_profile: String,
pub fa_method: String,
pub fa_percentage: String,
pub open_close: Option<OrderOpenClose>,
pub origin: OrderOrigin,
pub short_sale_slot: ShortSaleSlot,
pub designated_location: String,
pub exempt_code: i32,
pub discretionary_amt: f64,
pub opt_out_smart_routing: bool,
pub starting_price: Option<f64>,
pub stock_ref_price: Option<f64>,
pub delta: Option<f64>,
pub stock_range_lower: Option<f64>,
pub stock_range_upper: Option<f64>,
pub volatility: Option<f64>,
pub volatility_type: Option<VolatilityType>,
pub continuous_update: bool,
pub reference_price_type: Option<ReferencePriceType>,
pub delta_neutral_order_type: String,
pub delta_neutral_aux_price: Option<f64>,
pub delta_neutral_con_id: i32,
pub delta_neutral_settling_firm: String,
pub delta_neutral_clearing_account: String,
pub delta_neutral_clearing_intent: String,
pub delta_neutral_open_close: String,
pub delta_neutral_short_sale: bool,
pub delta_neutral_short_sale_slot: i32,
pub delta_neutral_designated_location: String,
pub basis_points: Option<f64>,
pub basis_points_type: Option<i32>,
pub scale_init_level_size: Option<i32>,
pub scale_subs_level_size: Option<i32>,
pub scale_price_increment: Option<f64>,
pub scale_price_adjust_value: Option<f64>,
pub scale_price_adjust_interval: Option<i32>,
pub scale_profit_offset: Option<f64>,
pub scale_auto_reset: bool,
pub scale_init_position: Option<i32>,
pub scale_init_fill_qty: Option<i32>,
pub scale_random_percent: bool,
pub hedge_type: String,
pub hedge_param: String,
pub hedge_max_size: Option<i32>,
pub account: String,
pub settling_firm: String,
pub clearing_account: String,
pub clearing_intent: String,
pub algo_strategy: String,
pub algo_params: Vec<TagValue>,
pub what_if: bool,
pub algo_id: String,
pub not_held: bool,
pub smart_combo_routing_params: Vec<TagValue>,
pub order_combo_legs: Vec<OrderComboLeg>,
pub order_misc_options: Vec<TagValue>,
pub active_start_time: String,
pub active_stop_time: String,
pub scale_table: String,
pub model_code: String,
pub ext_operator: String,
pub cash_qty: Option<f64>,
pub mifid2_decision_maker: String,
pub mifid2_decision_algo: String,
pub mifid2_execution_trader: String,
pub mifid2_execution_algo: String,
pub dont_use_auto_price_for_hedge: bool,
pub auto_cancel_date: String,
pub filled_quantity: f64,
pub ref_futures_con_id: Option<i32>,
pub auto_cancel_parent: bool,
pub shareholder: String,
pub imbalance_only: bool,
pub route_marketable_to_bbo: bool,
pub parent_perm_id: Option<i64>,
pub advanced_error_override: String,
pub manual_order_time: String,
pub min_trade_qty: Option<i32>,
pub min_compete_size: Option<i32>,
pub compete_against_best_offset: Option<f64>,
pub mid_offset_at_whole: Option<f64>,
pub mid_offset_at_half: Option<f64>,
pub randomize_size: bool,
pub randomize_price: bool,
pub reference_contract_id: i32,
pub is_pegged_change_amount_decrease: bool,
pub pegged_change_amount: Option<f64>,
pub reference_change_amount: Option<f64>,
pub reference_exchange: String,
pub adjusted_order_type: String,
pub trigger_price: Option<f64>,
pub limit_price_offset: Option<f64>,
pub adjusted_stop_price: Option<f64>,
pub adjusted_stop_limit_price: Option<f64>,
pub adjusted_trailing_amount: Option<f64>,
pub adjustable_trailing_unit: i32,
pub conditions: Vec<OrderCondition>,
pub conditions_ignore_rth: bool,
pub conditions_cancel_order: bool,
pub conditions_include_overnight: bool,
pub soft_dollar_tier: SoftDollarTier,
pub is_oms_container: bool,
pub discretionary_up_to_limit_price: bool,
pub use_price_mgmt_algo: bool,
pub duration: Option<i32>,
pub post_to_ats: Option<i32>,
pub customer_account: String,
pub professional_customer: bool,
pub bond_accrued_interest: String,
pub include_overnight: bool,
pub manual_order_indicator: Option<i32>,
pub submitter: String,
}
impl Default for Order {
fn default() -> Self {
Self {
order_id: 0,
solicited: false,
client_id: 0,
perm_id: 0,
action: Action::Buy,
total_quantity: 0.0,
order_type: "".to_owned(),
limit_price: None,
aux_price: None,
tif: TimeInForce::Day,
oca_group: "".to_owned(),
oca_type: OcaType::None,
order_ref: "".to_owned(),
transmit: true,
deactivate: false,
parent_id: 0,
preset_stop_loss_order_id: None,
preset_profit_taker_order_id: None,
block_order: false,
sweep_to_fill: false,
display_size: Some(0),
trigger_method: conditions::TriggerMethod::Default,
outside_rth: false,
hidden: false,
good_after_time: "".to_owned(),
good_till_date: "".to_owned(),
override_percentage_constraints: false,
rule_80_a: None,
all_or_none: false,
min_qty: None,
percent_offset: None,
trail_stop_price: None,
trailing_percent: None,
fa_group: "".to_owned(),
fa_profile: "".to_owned(),
fa_method: "".to_owned(),
fa_percentage: "".to_owned(),
open_close: None,
origin: OrderOrigin::Customer,
short_sale_slot: ShortSaleSlot::None,
designated_location: "".to_owned(),
exempt_code: -1,
discretionary_amt: 0.0,
opt_out_smart_routing: false,
starting_price: None,
stock_ref_price: None,
delta: None,
stock_range_lower: None,
stock_range_upper: None,
volatility: None,
volatility_type: None,
continuous_update: false,
reference_price_type: None,
delta_neutral_order_type: "".to_owned(),
delta_neutral_aux_price: None,
delta_neutral_con_id: 0,
delta_neutral_settling_firm: "".to_owned(),
delta_neutral_clearing_account: "".to_owned(),
delta_neutral_clearing_intent: "".to_owned(),
delta_neutral_open_close: "".to_owned(),
delta_neutral_short_sale: false,
delta_neutral_short_sale_slot: 0,
delta_neutral_designated_location: "".to_owned(),
basis_points: Some(0.0),
basis_points_type: Some(0),
scale_init_level_size: None,
scale_subs_level_size: None,
scale_price_increment: None,
scale_price_adjust_value: None,
scale_price_adjust_interval: None,
scale_profit_offset: None,
scale_auto_reset: false,
scale_init_position: None,
scale_init_fill_qty: None,
scale_random_percent: false,
hedge_type: "".to_owned(),
hedge_param: "".to_owned(),
hedge_max_size: None,
account: "".to_owned(),
settling_firm: "".to_owned(),
clearing_account: "".to_owned(),
clearing_intent: "".to_owned(),
algo_strategy: "".to_owned(),
algo_params: vec![],
what_if: false,
algo_id: "".to_owned(),
not_held: false,
smart_combo_routing_params: vec![],
order_combo_legs: vec![],
order_misc_options: vec![],
active_start_time: "".to_owned(),
active_stop_time: "".to_owned(),
scale_table: "".to_owned(),
model_code: "".to_owned(),
ext_operator: "".to_owned(),
cash_qty: None,
mifid2_decision_maker: "".to_owned(),
mifid2_decision_algo: "".to_owned(),
mifid2_execution_trader: "".to_owned(),
mifid2_execution_algo: "".to_owned(),
dont_use_auto_price_for_hedge: false,
auto_cancel_date: "".to_owned(),
filled_quantity: 0.0,
ref_futures_con_id: Some(0),
auto_cancel_parent: false,
shareholder: "".to_owned(),
imbalance_only: false,
route_marketable_to_bbo: false,
parent_perm_id: None,
advanced_error_override: "".to_owned(),
manual_order_time: "".to_owned(),
min_trade_qty: None,
min_compete_size: None,
compete_against_best_offset: None,
mid_offset_at_whole: None,
mid_offset_at_half: None,
randomize_size: false,
randomize_price: false,
reference_contract_id: 0,
is_pegged_change_amount_decrease: false,
pegged_change_amount: Some(0.0),
reference_change_amount: Some(0.0),
reference_exchange: "".to_owned(),
adjusted_order_type: "".to_owned(),
trigger_price: None,
limit_price_offset: None,
adjusted_stop_price: None,
adjusted_stop_limit_price: None,
adjusted_trailing_amount: None,
adjustable_trailing_unit: 0,
conditions: vec![],
conditions_ignore_rth: false,
conditions_cancel_order: false,
conditions_include_overnight: false,
soft_dollar_tier: SoftDollarTier::default(),
is_oms_container: false,
discretionary_up_to_limit_price: false,
use_price_mgmt_algo: false,
duration: None,
post_to_ats: None,
customer_account: String::new(),
professional_customer: false,
bond_accrued_interest: String::new(),
include_overnight: false,
manual_order_indicator: None,
submitter: String::new(),
}
}
}
impl Order {
pub fn is_delta_neutral(&self) -> bool {
!self.delta_neutral_order_type.is_empty()
}
pub fn is_scale_order(&self) -> bool {
match self.scale_price_increment {
Some(price_increment) => price_increment > 0.0,
_ => false,
}
}
}
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[derive(Clone, Debug, Default, PartialEq, Eq, Copy, Serialize, Deserialize)]
pub enum Action {
#[default]
Buy,
Sell,
SellShort,
SellLong,
}
impl Action {
pub fn reverse(self) -> Action {
match self {
Action::Buy => Action::Sell,
Action::Sell => Action::Buy,
Action::SellShort => Action::SellLong,
Action::SellLong => Action::SellShort,
}
}
pub fn as_str(&self) -> &'static str {
match self {
Action::Buy => "BUY",
Action::Sell => "SELL",
Action::SellShort => "SSHORT",
Action::SellLong => "SLONG",
}
}
fn from_wire(s: &str) -> Option<Self> {
match s {
"BUY" => Some(Self::Buy),
"SELL" => Some(Self::Sell),
"SSHORT" => Some(Self::SellShort),
"SLONG" => Some(Self::SellLong),
_ => None,
}
}
}
impl_wire_enum!(Action);
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub enum OrderStatusKind {
ApiPending,
PendingSubmit,
PendingCancel,
PreSubmitted,
#[default]
Submitted,
ApiCancelled,
Cancelled,
Filled,
Inactive,
Unknown(String),
}
impl OrderStatusKind {
pub fn as_str(&self) -> &str {
match self {
OrderStatusKind::ApiPending => "ApiPending",
OrderStatusKind::PendingSubmit => "PendingSubmit",
OrderStatusKind::PendingCancel => "PendingCancel",
OrderStatusKind::PreSubmitted => "PreSubmitted",
OrderStatusKind::Submitted => "Submitted",
OrderStatusKind::ApiCancelled => "ApiCancelled",
OrderStatusKind::Cancelled => "Cancelled",
OrderStatusKind::Filled => "Filled",
OrderStatusKind::Inactive => "Inactive",
OrderStatusKind::Unknown(raw) => raw,
}
}
fn from_wire(s: &str) -> Option<Self> {
match s {
"ApiPending" => Some(Self::ApiPending),
"PendingSubmit" => Some(Self::PendingSubmit),
"PendingCancel" => Some(Self::PendingCancel),
"PreSubmitted" => Some(Self::PreSubmitted),
"Submitted" => Some(Self::Submitted),
"ApiCancelled" => Some(Self::ApiCancelled),
"Cancelled" => Some(Self::Cancelled),
"Filled" => Some(Self::Filled),
"Inactive" => Some(Self::Inactive),
_ => None,
}
}
pub fn is_active(&self) -> bool {
matches!(self, Self::PreSubmitted | Self::PendingSubmit | Self::PendingCancel | Self::Submitted)
}
pub fn is_terminal(&self) -> bool {
matches!(self, Self::Filled | Self::Cancelled | Self::ApiCancelled | Self::Inactive)
}
}
impl_wire_enum!(OrderStatusKind, fallback Unknown);
#[cfg(feature = "utoipa")]
impl utoipa::PartialSchema for OrderStatusKind {
fn schema() -> utoipa::openapi::RefOr<utoipa::openapi::schema::Schema> {
String::schema()
}
}
#[cfg(feature = "utoipa")]
impl utoipa::ToSchema for OrderStatusKind {}
impl Serialize for OrderStatusKind {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
serializer.serialize_str(self.as_str())
}
}
impl<'de> Deserialize<'de> for OrderStatusKind {
fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let s = String::deserialize(deserializer)?;
s.parse().map_err(serde::de::Error::custom)
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub enum TimeInForce {
#[default]
Day,
GoodTillCanceled,
ImmediateOrCancel,
GoodTillDate,
OnOpen,
FillOrKill,
DayTillCanceled,
Auction,
GoodTillCrossing,
Unknown(String),
}
impl TimeInForce {
pub fn as_str(&self) -> &str {
match self {
TimeInForce::Day => "DAY",
TimeInForce::GoodTillCanceled => "GTC",
TimeInForce::ImmediateOrCancel => "IOC",
TimeInForce::GoodTillDate => "GTD",
TimeInForce::OnOpen => "OPG",
TimeInForce::FillOrKill => "FOK",
TimeInForce::DayTillCanceled => "DTC",
TimeInForce::Auction => "AUC",
TimeInForce::GoodTillCrossing => "GTX",
TimeInForce::Unknown(raw) => raw,
}
}
fn from_wire(s: &str) -> Option<Self> {
match s {
"DAY" => Some(TimeInForce::Day),
"GTC" => Some(TimeInForce::GoodTillCanceled),
"IOC" => Some(TimeInForce::ImmediateOrCancel),
"GTD" => Some(TimeInForce::GoodTillDate),
"OPG" => Some(TimeInForce::OnOpen),
"FOK" => Some(TimeInForce::FillOrKill),
"DTC" => Some(TimeInForce::DayTillCanceled),
"AUC" => Some(TimeInForce::Auction),
"GTX" => Some(TimeInForce::GoodTillCrossing),
_ => None,
}
}
}
impl_wire_enum!(TimeInForce, fallback Unknown);
#[cfg(feature = "utoipa")]
impl utoipa::PartialSchema for TimeInForce {
fn schema() -> utoipa::openapi::RefOr<utoipa::openapi::schema::Schema> {
String::schema()
}
}
#[cfg(feature = "utoipa")]
impl utoipa::ToSchema for TimeInForce {}
impl Serialize for TimeInForce {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
serializer.serialize_str(self.as_str())
}
}
impl<'de> Deserialize<'de> for TimeInForce {
fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let s = String::deserialize(deserializer)?;
s.parse().map_err(serde::de::Error::custom)
}
}
impl From<String> for TimeInForce {
fn from(value: String) -> Self {
Self::from(value.as_str())
}
}
impl From<&str> for TimeInForce {
fn from(value: &str) -> Self {
Self::from_wire(value).unwrap_or_else(|| TimeInForce::Unknown(value.to_string()))
}
}
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
pub enum OcaType {
#[default]
None,
CancelWithBlock,
ReduceWithBlock,
ReduceWithoutBlock,
Unknown(i32),
}
impl From<OcaType> for i32 {
fn from(value: OcaType) -> i32 {
match value {
OcaType::None => 0,
OcaType::CancelWithBlock => 1,
OcaType::ReduceWithBlock => 2,
OcaType::ReduceWithoutBlock => 3,
OcaType::Unknown(code) => code,
}
}
}
impl From<i32> for OcaType {
fn from(value: i32) -> Self {
match value {
0 => OcaType::None,
1 => OcaType::CancelWithBlock,
2 => OcaType::ReduceWithBlock,
3 => OcaType::ReduceWithoutBlock,
code => OcaType::Unknown(code),
}
}
}
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
pub enum OrderOrigin {
#[default]
Customer,
Firm,
Unknown(i32),
}
impl From<OrderOrigin> for i32 {
fn from(value: OrderOrigin) -> i32 {
match value {
OrderOrigin::Customer => 0,
OrderOrigin::Firm => 1,
OrderOrigin::Unknown(code) => code,
}
}
}
impl From<i32> for OrderOrigin {
fn from(value: i32) -> Self {
match value {
0 => OrderOrigin::Customer,
1 => OrderOrigin::Firm,
code => OrderOrigin::Unknown(code),
}
}
}
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
pub enum ShortSaleSlot {
#[default]
None,
Broker,
ThirdParty,
Unknown(i32),
}
impl From<ShortSaleSlot> for i32 {
fn from(value: ShortSaleSlot) -> i32 {
match value {
ShortSaleSlot::None => 0,
ShortSaleSlot::Broker => 1,
ShortSaleSlot::ThirdParty => 2,
ShortSaleSlot::Unknown(code) => code,
}
}
}
impl From<i32> for ShortSaleSlot {
fn from(value: i32) -> Self {
match value {
0 => ShortSaleSlot::None,
1 => ShortSaleSlot::Broker,
2 => ShortSaleSlot::ThirdParty,
code => ShortSaleSlot::Unknown(code),
}
}
}
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum VolatilityType {
Daily,
Annual,
Unknown(i32),
}
impl From<VolatilityType> for i32 {
fn from(value: VolatilityType) -> i32 {
match value {
VolatilityType::Daily => 1,
VolatilityType::Annual => 2,
VolatilityType::Unknown(code) => code,
}
}
}
impl From<i32> for VolatilityType {
fn from(value: i32) -> Self {
match value {
1 => VolatilityType::Daily,
2 => VolatilityType::Annual,
code => VolatilityType::Unknown(code),
}
}
}
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum ReferencePriceType {
AverageOfNBBO,
NBBO,
Unknown(i32),
}
impl From<ReferencePriceType> for i32 {
fn from(value: ReferencePriceType) -> i32 {
match value {
ReferencePriceType::AverageOfNBBO => 1,
ReferencePriceType::NBBO => 2,
ReferencePriceType::Unknown(code) => code,
}
}
}
impl From<i32> for ReferencePriceType {
fn from(value: i32) -> Self {
match value {
1 => ReferencePriceType::AverageOfNBBO,
2 => ReferencePriceType::NBBO,
code => ReferencePriceType::Unknown(code),
}
}
}
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum Rule80A {
Individual,
Agency,
AgentOtherMember,
IndividualPTIA,
AgencyPTIA,
AgentOtherMemberPTIA,
IndividualPT,
AgencyPT,
AgentOtherMemberPT,
Unknown(String),
}
impl Rule80A {
pub fn as_str(&self) -> &str {
match self {
Rule80A::Individual => "I",
Rule80A::Agency => "A",
Rule80A::AgentOtherMember => "W",
Rule80A::IndividualPTIA => "J",
Rule80A::AgencyPTIA => "U",
Rule80A::AgentOtherMemberPTIA => "M",
Rule80A::IndividualPT => "K",
Rule80A::AgencyPT => "Y",
Rule80A::AgentOtherMemberPT => "N",
Rule80A::Unknown(raw) => raw,
}
}
fn from_wire(s: &str) -> Option<Self> {
match s {
"I" => Some(Rule80A::Individual),
"A" => Some(Rule80A::Agency),
"W" => Some(Rule80A::AgentOtherMember),
"J" => Some(Rule80A::IndividualPTIA),
"U" => Some(Rule80A::AgencyPTIA),
"M" => Some(Rule80A::AgentOtherMemberPTIA),
"K" => Some(Rule80A::IndividualPT),
"Y" => Some(Rule80A::AgencyPT),
"N" => Some(Rule80A::AgentOtherMemberPT),
_ => None,
}
}
}
impl_wire_enum!(Rule80A, fallback Unknown);
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
pub struct OrderComboLeg {
pub price: Option<f64>,
}
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum OrderCondition {
Price(PriceCondition),
Time(TimeCondition),
Margin(MarginCondition),
Execution(ExecutionCondition),
Volume(VolumeCondition),
PercentChange(PercentChangeCondition),
Unknown(UnknownCondition),
}
impl OrderCondition {
pub fn condition_type(&self) -> i32 {
match self {
Self::Price(_) => 1,
Self::Time(_) => 3,
Self::Margin(_) => 4,
Self::Execution(_) => 5,
Self::Volume(_) => 6,
Self::PercentChange(_) => 7,
Self::Unknown(c) => c.condition_type,
}
}
pub fn is_conjunction(&self) -> bool {
match self {
Self::Price(c) => c.is_conjunction,
Self::Time(c) => c.is_conjunction,
Self::Margin(c) => c.is_conjunction,
Self::Execution(c) => c.is_conjunction,
Self::Volume(c) => c.is_conjunction,
Self::PercentChange(c) => c.is_conjunction,
Self::Unknown(c) => c.is_conjunction,
}
}
}
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
pub struct SoftDollarTier {
pub name: String,
pub value: String,
pub display_name: String,
}
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
pub struct OrderData {
pub order_id: i32,
pub contract: Contract,
pub order: Order,
pub order_state: OrderState,
}
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
pub struct OrderState {
pub status: OrderStatusKind,
pub initial_margin_before: Option<f64>,
pub maintenance_margin_before: Option<f64>,
pub equity_with_loan_before: Option<f64>,
pub initial_margin_change: Option<f64>,
pub maintenance_margin_change: Option<f64>,
pub equity_with_loan_change: Option<f64>,
pub initial_margin_after: Option<f64>,
pub maintenance_margin_after: Option<f64>,
pub equity_with_loan_after: Option<f64>,
pub commission: Option<f64>,
pub minimum_commission: Option<f64>,
pub maximum_commission: Option<f64>,
pub commission_currency: String,
pub margin_currency: String,
pub initial_margin_before_outside_rth: Option<f64>,
pub maintenance_margin_before_outside_rth: Option<f64>,
pub equity_with_loan_before_outside_rth: Option<f64>,
pub initial_margin_change_outside_rth: Option<f64>,
pub maintenance_margin_change_outside_rth: Option<f64>,
pub equity_with_loan_change_outside_rth: Option<f64>,
pub initial_margin_after_outside_rth: Option<f64>,
pub maintenance_margin_after_outside_rth: Option<f64>,
pub equity_with_loan_after_outside_rth: Option<f64>,
pub suggested_size: Option<f64>,
pub reject_reason: String,
pub order_allocations: Vec<OrderAllocation>,
pub warning_text: String,
pub completed_time: String,
pub completed_status: String,
}
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
pub struct OrderAllocation {
pub account: String,
pub position: Option<f64>,
pub position_desired: Option<f64>,
pub position_after: Option<f64>,
pub desired_alloc_qty: Option<f64>,
pub allowed_alloc_qty: Option<f64>,
pub is_monetary: bool,
}
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum OrderOpenClose {
Open,
Close,
Unknown(String),
}
impl OrderOpenClose {
pub fn as_str(&self) -> &str {
match self {
OrderOpenClose::Open => "O",
OrderOpenClose::Close => "C",
OrderOpenClose::Unknown(raw) => raw,
}
}
fn from_wire(s: &str) -> Option<Self> {
match s {
"O" => Some(OrderOpenClose::Open),
"C" => Some(OrderOpenClose::Close),
_ => None,
}
}
}
impl_wire_enum!(OrderOpenClose, fallback Unknown);
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[derive(Clone, Debug, Default)]
pub struct CommissionReport {
pub execution_id: String,
pub commission: f64,
pub currency: String,
pub realized_pnl: Option<f64>,
pub yields: Option<f64>,
pub yield_redemption_date: String,
}
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[derive(Clone, Debug, Default, PartialEq)]
pub enum Liquidity {
#[default]
None,
AddedLiquidity,
RemovedLiquidity,
LiquidityRoutedOut,
Unknown(i32),
}
impl From<i32> for Liquidity {
fn from(val: i32) -> Self {
match val {
0 => Liquidity::None,
1 => Liquidity::AddedLiquidity,
2 => Liquidity::RemovedLiquidity,
3 => Liquidity::LiquidityRoutedOut,
value => Liquidity::Unknown(value),
}
}
}
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[derive(Clone, Debug, Default)]
pub struct Execution {
pub order_id: i32,
pub client_id: i32,
pub execution_id: String,
pub time: String,
pub account_number: String,
pub exchange: String,
pub side: ExecutionSide,
pub shares: f64,
pub price: f64,
pub perm_id: i64,
pub liquidation: i32,
pub cumulative_quantity: f64,
pub average_price: f64,
pub order_reference: String,
pub ev_rule: String,
pub ev_multiplier: Option<f64>,
pub model_code: String,
pub last_liquidity: Liquidity,
pub pending_price_revision: bool,
pub submitter: String,
}
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[derive(Clone, Debug, Default)]
pub struct ExecutionData {
pub request_id: i32,
pub contract: Contract,
pub execution: Execution,
}
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[derive(Clone, Debug)]
#[allow(clippy::large_enum_variant)]
pub enum PlaceOrder {
OrderStatus(OrderStatus),
OpenOrder(OrderData),
ExecutionData(ExecutionData),
CommissionReport(CommissionReport),
}
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[derive(Clone, Debug)]
#[allow(clippy::large_enum_variant)]
pub enum OrderUpdate {
OrderStatus(OrderStatus),
OpenOrder(OrderData),
OrderBound(OrderBound),
ExecutionData(ExecutionData),
CommissionReport(CommissionReport),
}
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq)]
pub struct OrderBound {
pub perm_id: i64,
pub client_id: i32,
pub order_id: i32,
}
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq)]
pub struct OrderStatus {
pub order_id: i32,
pub status: OrderStatusKind,
pub filled: f64,
pub remaining: f64,
pub average_fill_price: Option<f64>,
pub perm_id: i64,
pub parent_id: i32,
pub last_fill_price: Option<f64>,
pub client_id: i32,
pub why_held: String,
pub market_cap_price: Option<f64>,
}
impl OrderStatus {
pub fn outcome(&self) -> Option<OrderOutcome> {
if self.status == OrderStatusKind::Filled || (self.remaining == 0.0 && self.filled > 0.0) {
Some(OrderOutcome::Filled(self.clone()))
} else if self.status.is_terminal() {
Some(OrderOutcome::Ended(self.clone()))
} else {
None
}
}
}
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum OrderOutcome {
Filled(OrderStatus),
Ended(OrderStatus),
TimedOut(Option<OrderStatus>),
Rejected(crate::Notice),
}
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[derive(Debug)]
pub enum CancelOrder {
OrderStatus(OrderStatus),
}
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[derive(Debug)]
#[allow(clippy::large_enum_variant)]
pub enum Orders {
OrderData(OrderData),
OrderStatus(OrderStatus),
}
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[non_exhaustive]
pub enum ExecutionFilterSide {
Buy,
Sell,
}
impl ExecutionFilterSide {
pub fn as_str(&self) -> &'static str {
match self {
ExecutionFilterSide::Buy => "BUY",
ExecutionFilterSide::Sell => "SELL",
}
}
fn from_wire(s: &str) -> Option<Self> {
match s {
"BUY" => Some(Self::Buy),
"SELL" => Some(Self::Sell),
_ => None,
}
}
}
impl_wire_enum!(ExecutionFilterSide);
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
pub enum ExecutionSide {
#[default]
Bought,
Sold,
}
impl ExecutionSide {
pub fn as_str(&self) -> &'static str {
match self {
ExecutionSide::Bought => "BOT",
ExecutionSide::Sold => "SLD",
}
}
fn from_wire(s: &str) -> Option<Self> {
match s {
"BOT" => Some(Self::Bought),
"SLD" => Some(Self::Sold),
_ => None,
}
}
}
impl_wire_enum!(ExecutionSide);
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[derive(Debug, Default)]
pub struct ExecutionFilter {
pub client_id: Option<i32>,
pub account_code: String,
pub time: String,
pub symbol: String,
pub security_type: String,
pub exchange: String,
pub side: Option<ExecutionFilterSide>,
pub last_n_days: i32,
pub specific_dates: Vec<String>,
}
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[derive(Debug)]
#[allow(clippy::large_enum_variant)]
pub enum Executions {
ExecutionData(ExecutionData),
CommissionReport(CommissionReport),
}
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[derive(Debug, Clone, Copy)]
pub enum ExerciseAction {
Exercise = 1,
Lapse = 2,
}
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[allow(clippy::large_enum_variant)]
pub enum ExerciseOptions {
OpenOrder(OrderData),
OrderStatus(OrderStatus),
}
#[cfg(feature = "sync")]
mod sync;
#[cfg(feature = "async")]
mod r#async;
#[cfg(test)]
mod tests;