use crate::orders::{
Action, AuctionStrategy, OcaType, Order, OrderComboLeg, TagValue, TimeInForce, VolatilityType, COMPETE_AGAINST_BEST_OFFSET_UP_TO_MID,
};
pub fn at_auction(action: Action, quantity: f64, price: f64) -> Order {
Order {
action,
tif: TimeInForce::Auction,
order_type: "MTL".to_owned(),
total_quantity: quantity,
limit_price: Some(price),
..Order::default()
}
}
pub fn discretionary(action: Action, quantity: f64, price: f64, discretionary_amount: f64) -> Order {
Order {
action,
order_type: "LMT".to_owned(),
total_quantity: quantity,
limit_price: Some(price),
discretionary_amt: discretionary_amount,
..Order::default()
}
}
pub fn market_order(action: Action, quantity: f64) -> Order {
Order {
action,
order_type: "MKT".to_owned(),
total_quantity: quantity,
..Order::default()
}
}
pub fn market_if_touched(action: Action, quantity: f64, price: f64) -> Order {
Order {
action,
order_type: "MIT".to_owned(),
total_quantity: quantity,
aux_price: Some(price),
..Order::default()
}
}
pub fn market_on_close(action: Action, quantity: f64) -> Order {
Order {
action,
order_type: "MOC".to_owned(),
total_quantity: quantity,
..Order::default()
}
}
pub fn market_on_open(action: Action, quantity: f64) -> Order {
Order {
action,
order_type: "MKT".to_owned(),
total_quantity: quantity,
tif: TimeInForce::OnOpen,
..Order::default()
}
}
pub fn midpoint_match(action: Action, quantity: f64) -> Order {
Order {
action,
order_type: "MKT".to_owned(),
total_quantity: quantity,
..Order::default()
}
}
pub fn midprice(action: Action, quantity: f64, price_cap: Option<f64>) -> Order {
Order {
action,
order_type: "MIDPRICE".to_owned(),
total_quantity: quantity,
limit_price: price_cap,
..Order::default()
}
}
pub fn pegged_to_market(action: Action, quantity: f64, market_offset: f64) -> Order {
Order {
action,
order_type: "PEG MKT".to_owned(),
total_quantity: quantity,
aux_price: Some(market_offset),
..Order::default()
}
}
pub fn pegged_to_stock(action: Action, quantity: f64, delta: f64, stock_reference_price: f64, starting_price: f64) -> Order {
Order {
action,
order_type: "PEG STK".to_owned(),
total_quantity: quantity,
delta: Some(delta),
stock_ref_price: Some(stock_reference_price),
starting_price: Some(starting_price),
..Order::default()
}
}
pub fn relative_pegged_to_primary(action: Action, quantity: f64, price_cap: f64, offset_amount: f64) -> Order {
Order {
action,
order_type: "REL".to_owned(),
total_quantity: quantity,
limit_price: Some(price_cap),
aux_price: Some(offset_amount),
..Order::default()
}
}
pub fn sweep_to_fill(action: Action, quantity: f64, price: f64) -> Order {
Order {
action,
order_type: "LMT".to_owned(),
total_quantity: quantity,
limit_price: Some(price),
sweep_to_fill: true,
..Order::default()
}
}
pub fn auction_limit(action: Action, quantity: f64, price: f64, auction_strategy: AuctionStrategy) -> Order {
Order {
action,
order_type: "LMT".to_owned(),
total_quantity: quantity,
limit_price: Some(price),
auction_strategy: Some(auction_strategy),
..Order::default()
}
}
pub fn auction_pegged_to_stock(action: Action, quantity: f64, starting_price: f64, delta: f64) -> Order {
Order {
action,
order_type: "PEG STK".to_owned(),
total_quantity: quantity,
delta: Some(delta),
starting_price: Some(starting_price),
..Order::default()
}
}
pub fn auction_relative(action: Action, quantity: f64, offset: f64) -> Order {
Order {
action,
order_type: "REL".to_owned(),
total_quantity: quantity,
aux_price: Some(offset),
..Order::default()
}
}
pub fn block(action: Action, quantity: f64, price: f64) -> Order {
Order {
action,
order_type: "LMT".to_owned(),
total_quantity: quantity,
limit_price: Some(price),
block_order: true,
..Order::default()
}
}
pub fn box_top(action: Action, quantity: f64) -> Order {
Order {
action,
order_type: "BOX TOP".to_owned(),
total_quantity: quantity,
..Order::default()
}
}
pub fn limit_order(action: Action, quantity: f64, limit_price: f64) -> Order {
Order {
action,
order_type: "LMT".to_owned(),
total_quantity: quantity,
limit_price: Some(limit_price),
..Order::default()
}
}
pub fn limit_order_with_cash_qty(action: Action, limit_price: f64, cash_qty: f64) -> Order {
Order {
action,
order_type: "LMT".to_owned(),
limit_price: Some(limit_price),
cash_qty: Some(cash_qty),
..Order::default()
}
}
pub fn limit_if_touched(action: Action, quantity: f64, limit_price: f64, trigger_price: f64) -> Order {
Order {
action,
order_type: "LIT".to_owned(),
total_quantity: quantity,
limit_price: Some(limit_price),
aux_price: Some(trigger_price),
..Order::default()
}
}
pub fn limit_on_close(action: Action, quantity: f64, limit_price: f64) -> Order {
Order {
action,
order_type: "LOC".to_owned(),
total_quantity: quantity,
limit_price: Some(limit_price),
..Order::default()
}
}
pub fn limit_on_open(action: Action, quantity: f64, limit_price: f64) -> Order {
Order {
action,
order_type: "LMT".to_owned(),
total_quantity: quantity,
limit_price: Some(limit_price),
tif: TimeInForce::OnOpen,
..Order::default()
}
}
pub fn passive_relative(action: Action, quantity: f64, offset: f64) -> Order {
Order {
action,
order_type: "PASSV REL".to_owned(),
total_quantity: quantity,
aux_price: Some(offset),
..Order::default()
}
}
pub fn pegged_to_midpoint(action: Action, quantity: f64, offset: f64, limit_price: f64) -> Order {
Order {
action,
order_type: "PEG MID".to_owned(),
total_quantity: quantity,
aux_price: Some(offset),
limit_price: Some(limit_price),
..Order::default()
}
}
pub fn bracket_order(
parent_order_id: i32,
action: Action,
quantity: f64,
limit_price: f64,
take_profit_limit_price: f64,
stop_loss_price: f64,
) -> Vec<Order> {
let parent = Order {
order_id: parent_order_id,
action,
order_type: "LMT".to_owned(),
total_quantity: quantity,
limit_price: Some(limit_price),
transmit: false,
..Order::default()
};
let take_profit = Order {
order_id: parent.order_id + 1,
action: action.reverse(),
order_type: "LMT".to_owned(),
total_quantity: quantity,
limit_price: Some(take_profit_limit_price),
parent_id: parent_order_id,
transmit: false,
..Order::default()
};
let stop_loss = Order {
order_id: parent.order_id + 2,
action: action.reverse(),
order_type: "STP".to_owned(),
aux_price: Some(stop_loss_price),
total_quantity: quantity,
parent_id: parent_order_id,
transmit: true,
..Order::default()
};
vec![parent, take_profit, stop_loss]
}
pub fn market_to_limit(action: Action, quantity: f64) -> Order {
Order {
action,
order_type: "MTL".to_owned(),
total_quantity: quantity,
..Order::default()
}
}
pub fn market_with_protection(action: Action, quantity: f64) -> Order {
Order {
action,
order_type: "MKT PRT".to_owned(),
total_quantity: quantity,
..Order::default()
}
}
pub fn stop(action: Action, quantity: f64, stop_price: f64) -> Order {
Order {
action,
order_type: "STP".to_owned(),
total_quantity: quantity,
aux_price: Some(stop_price),
..Order::default()
}
}
pub fn stop_limit(action: Action, quantity: f64, limit_price: f64, stop_price: f64) -> Order {
Order {
action,
order_type: "STP LMT".to_owned(),
total_quantity: quantity,
limit_price: Some(limit_price),
aux_price: Some(stop_price),
..Order::default()
}
}
pub fn stop_with_protection(action: Action, quantity: f64, stop_price: f64) -> Order {
Order {
action,
order_type: "STP PRT".to_owned(),
total_quantity: quantity,
aux_price: Some(stop_price),
..Order::default()
}
}
pub fn trailing_stop(action: Action, quantity: f64, trailing_percent: f64, trail_stop_price: f64) -> Order {
Order {
action,
order_type: "TRAIL".to_owned(),
total_quantity: quantity,
trailing_percent: Some(trailing_percent),
trail_stop_price: Some(trail_stop_price),
..Order::default()
}
}
pub fn trailing_stop_limit(action: Action, quantity: f64, lmt_price_offset: f64, trailing_amount: f64, trail_stop_price: f64) -> Order {
Order {
action,
order_type: "TRAIL LIMIT".to_owned(),
total_quantity: quantity,
trail_stop_price: Some(trail_stop_price),
limit_price_offset: Some(lmt_price_offset),
aux_price: Some(trailing_amount),
..Order::default()
}
}
pub fn combo_limit_order(action: Action, quantity: f64, limit_price: f64, non_guaranteed: bool) -> Order {
let mut order = Order {
action,
order_type: "LMT".to_owned(),
total_quantity: quantity,
limit_price: Some(limit_price),
..Order::default()
};
if non_guaranteed {
order = tag_order_non_guaranteed(order)
}
order
}
fn tag_order_non_guaranteed(mut order: Order) -> Order {
order.smart_combo_routing_params = vec![];
order.smart_combo_routing_params.push(TagValue {
tag: "NonGuaranteed".to_owned(),
value: "1".to_owned(),
});
order
}
pub fn combo_market_order(action: Action, quantity: f64, non_guaranteed: bool) -> Order {
let mut order = Order {
action,
order_type: "MKT".to_owned(),
total_quantity: quantity,
..Order::default()
};
if non_guaranteed {
order = tag_order_non_guaranteed(order)
}
order
}
pub fn limit_order_for_combo_with_leg_prices(action: Action, quantity: f64, leg_prices: Vec<f64>, non_guaranteed: bool) -> Order {
let mut order = Order {
action,
order_type: "LMT".to_owned(),
total_quantity: quantity,
order_combo_legs: vec![],
..Order::default()
};
for price in leg_prices {
order.order_combo_legs.push(OrderComboLeg { price: Some(price) });
}
if non_guaranteed {
order = tag_order_non_guaranteed(order)
}
order
}
pub fn relative_limit_combo(action: Action, quantity: f64, limit_price: f64, non_guaranteed: bool) -> Order {
let mut order = Order {
action,
order_type: "REL + LMT".to_owned(),
total_quantity: quantity,
limit_price: Some(limit_price),
..Order::default()
};
if non_guaranteed {
order = tag_order_non_guaranteed(order)
}
order
}
pub fn relative_market_combo(action: Action, quantity: f64, non_guaranteed: bool) -> Order {
let mut order = Order {
action,
order_type: "REL + MKT".to_owned(),
total_quantity: quantity,
..Order::default()
};
if non_guaranteed {
order = tag_order_non_guaranteed(order)
}
order
}
pub fn one_cancels_all(oca_group: &str, mut oca_orders: Vec<Order>, oca_type: OcaType) -> Vec<Order> {
for order in &mut oca_orders {
order.oca_group = oca_group.to_owned();
order.oca_type = oca_type;
}
oca_orders
}
pub fn volatility(action: Action, quantity: f64, volatility_percent: f64, volatility_type: VolatilityType) -> Order {
Order {
action,
order_type: "VOL".to_owned(),
total_quantity: quantity,
volatility: Some(volatility_percent), volatility_type: Some(volatility_type),
..Order::default()
}
}
pub fn market_f_hedge(parent_order_id: i32, action: Action) -> Order {
let mut order = market_order(action, 0.0);
order.parent_id = parent_order_id;
order.hedge_type = "F".to_owned();
order
}
#[allow(clippy::too_many_arguments)]
pub fn pegged_to_benchmark(
action: Action,
quantity: f64,
starting_price: f64,
pegged_change_amount_decrease: bool,
pegged_change_amount: f64,
reference_change_amount: f64,
reference_contract_id: i32,
reference_exchange: &str,
stock_reference_price: f64,
reference_contract_lower_range: f64,
reference_contract_upper_range: f64,
) -> Order {
Order {
action,
order_type: "PEG BENCH".to_owned(),
total_quantity: quantity,
starting_price: Some(starting_price),
is_pegged_change_amount_decrease: pegged_change_amount_decrease,
pegged_change_amount: Some(pegged_change_amount), reference_change_amount: Some(reference_change_amount), reference_contract_id, reference_exchange: reference_exchange.to_owned(), stock_ref_price: Some(stock_reference_price), stock_range_lower: Some(reference_contract_lower_range),
stock_range_upper: Some(reference_contract_upper_range),
..Order::default()
}
}
pub fn attach_adjustable_to_stop(parent: &Order, attached_order_stop_price: f64, trigger_price: f64, adjusted_stop_price: f64) -> Order {
let mut order = stop(parent.action.reverse(), parent.total_quantity, attached_order_stop_price);
order.parent_id = parent.order_id;
order.trigger_price = Some(trigger_price); order.adjusted_order_type = "STP".to_owned(); order.adjusted_stop_price = Some(adjusted_stop_price);
order
}
pub fn attach_adjustable_to_stop_limit(
parent: &Order,
attached_order_stop_price: f64,
trigger_price: f64,
adjusted_stop_price: f64,
adjusted_stop_limit_price: f64,
) -> Order {
let mut order = stop(parent.action.reverse(), parent.total_quantity, attached_order_stop_price);
order.parent_id = parent.order_id;
order.trigger_price = Some(trigger_price); order.adjusted_order_type = "STP LMT".to_owned(); order.adjusted_stop_price = Some(adjusted_stop_price); order.adjusted_stop_limit_price = Some(adjusted_stop_limit_price);
order
}
pub fn attach_adjustable_to_trail(
parent: &Order,
attached_order_stop_price: f64,
trigger_price: f64,
adjusted_stop_price: f64,
adjusted_trail_amount: f64,
trail_unit: i32,
) -> Order {
let mut order = stop(parent.action.reverse(), parent.total_quantity, attached_order_stop_price);
order.parent_id = parent.order_id;
order.trigger_price = Some(trigger_price); "TRAIL".clone_into(&mut order.adjusted_order_type); order.adjusted_stop_price = Some(adjusted_stop_price); order.adjustable_trailing_unit = trail_unit; order.adjusted_trailing_amount = Some(adjusted_trail_amount);
order
}
pub fn what_if_limit_order(action: Action, quantity: f64, limit_price: f64) -> Order {
let mut order = limit_order(action, quantity, limit_price);
order.what_if = true;
order
}
pub fn limit_ibkrats(action: Action, quantity: f64, limit_price: f64) -> Order {
Order {
action,
order_type: "LMT".to_owned(),
total_quantity: quantity,
limit_price: Some(limit_price),
not_held: true,
..Order::default()
}
}
pub fn limit_order_with_manual_order_time(action: Action, quantity: f64, limit_price: f64, manual_order_time: &str) -> Order {
let mut order = limit_order(action, quantity, limit_price);
manual_order_time.clone_into(&mut order.manual_order_time);
order
}
pub fn peg_best_up_to_mid_order(
action: Action,
quantity: f64,
limit_price: f64,
min_trade_qty: i32,
min_compete_size: i32,
mid_offset_at_whole: f64,
mid_offset_at_half: f64,
) -> Order {
Order {
action,
order_type: "PEG BEST".to_owned(),
total_quantity: quantity,
limit_price: Some(limit_price),
not_held: true,
min_trade_qty: Some(min_trade_qty),
min_compete_size: Some(min_compete_size),
compete_against_best_offset: COMPETE_AGAINST_BEST_OFFSET_UP_TO_MID,
mid_offset_at_whole: Some(mid_offset_at_whole),
mid_offset_at_half: Some(mid_offset_at_half),
..Order::default()
}
}
pub fn peg_best_order(
action: Action,
quantity: f64,
limit_price: f64,
min_trade_qty: i32,
min_compete_size: i32,
compete_against_best_offset: f64,
) -> Order {
Order {
action,
order_type: "PEG BEST".to_owned(),
total_quantity: quantity,
limit_price: Some(limit_price),
not_held: true,
min_trade_qty: Some(min_trade_qty),
min_compete_size: Some(min_compete_size),
compete_against_best_offset: Some(compete_against_best_offset),
..Order::default()
}
}
pub fn peg_mid_order(
action: Action,
quantity: f64,
limit_price: f64,
min_trade_qty: i32,
mid_offset_at_whole: f64,
mid_offset_at_half: f64,
) -> Order {
Order {
action,
order_type: "PEG MID".to_owned(),
total_quantity: quantity,
limit_price: Some(limit_price),
not_held: true,
min_trade_qty: Some(min_trade_qty),
mid_offset_at_whole: Some(mid_offset_at_whole),
mid_offset_at_half: Some(mid_offset_at_half),
..Order::default()
}
}
#[cfg(test)]
mod tests {
use crate::orders::common::order_builder::*;
use crate::orders::{Action, COMPETE_AGAINST_BEST_OFFSET_UP_TO_MID};
#[cfg(test)]
mod basic_order_tests {
use super::*;
#[test]
fn test_market_order() {
let order = market_order(Action::Buy, 100.0);
assert_eq!(order.action, Action::Buy);
assert_eq!(order.order_type, "MKT");
assert_eq!(order.total_quantity, 100.0);
assert_eq!(order.limit_price, None);
assert_eq!(order.aux_price, None);
let order = market_order(Action::Sell, 200.0);
assert_eq!(order.action, Action::Sell);
assert_eq!(order.total_quantity, 200.0);
}
#[test]
fn test_limit_order() {
let order = limit_order(Action::Buy, 100.0, 50.25);
assert_eq!(order.action, Action::Buy);
assert_eq!(order.order_type, "LMT");
assert_eq!(order.total_quantity, 100.0);
assert_eq!(order.limit_price, Some(50.25));
let order = limit_order(Action::Sell, 200.0, 60.50);
assert_eq!(order.action, Action::Sell);
assert_eq!(order.limit_price, Some(60.50));
}
#[test]
fn test_stop_order() {
let order = stop(Action::Sell, 100.0, 45.0);
assert_eq!(order.action, Action::Sell);
assert_eq!(order.order_type, "STP");
assert_eq!(order.total_quantity, 100.0);
assert_eq!(order.aux_price, Some(45.0)); assert_eq!(order.limit_price, None);
}
#[test]
fn test_stop_limit_order() {
let order = stop_limit(Action::Sell, 100.0, 45.0, 44.0);
assert_eq!(order.action, Action::Sell);
assert_eq!(order.order_type, "STP LMT");
assert_eq!(order.total_quantity, 100.0);
assert_eq!(order.limit_price, Some(45.0));
assert_eq!(order.aux_price, Some(44.0)); }
#[test]
fn test_limit_if_touched() {
let order = limit_if_touched(Action::Buy, 100.0, 52.0, 50.0);
assert_eq!(order.action, Action::Buy);
assert_eq!(order.order_type, "LIT");
assert_eq!(order.total_quantity, 100.0);
assert_eq!(order.limit_price, Some(52.0));
assert_eq!(order.aux_price, Some(50.0)); }
#[test]
fn test_market_if_touched() {
let order = market_if_touched(Action::Buy, 100.0, 50.0);
assert_eq!(order.action, Action::Buy);
assert_eq!(order.order_type, "MIT");
assert_eq!(order.total_quantity, 100.0);
assert_eq!(order.aux_price, Some(50.0)); }
}
#[cfg(test)]
mod time_based_order_tests {
use super::*;
#[test]
fn test_market_on_close() {
let order = market_on_close(Action::Buy, 100.0);
assert_eq!(order.action, Action::Buy);
assert_eq!(order.order_type, "MOC");
assert_eq!(order.total_quantity, 100.0);
}
#[test]
fn test_market_on_open() {
let order = market_on_open(Action::Buy, 100.0);
assert_eq!(order.action, Action::Buy);
assert_eq!(order.order_type, "MKT");
assert_eq!(order.total_quantity, 100.0);
assert_eq!(order.tif, TimeInForce::OnOpen);
}
#[test]
fn test_limit_on_close() {
let order = limit_on_close(Action::Buy, 100.0, 50.0);
assert_eq!(order.action, Action::Buy);
assert_eq!(order.order_type, "LOC");
assert_eq!(order.total_quantity, 100.0);
assert_eq!(order.limit_price, Some(50.0));
}
#[test]
fn test_limit_on_open() {
let order = limit_on_open(Action::Buy, 100.0, 50.0);
assert_eq!(order.action, Action::Buy);
assert_eq!(order.order_type, "LMT");
assert_eq!(order.total_quantity, 100.0);
assert_eq!(order.limit_price, Some(50.0));
assert_eq!(order.tif, TimeInForce::OnOpen);
}
}
#[cfg(test)]
mod complex_order_tests {
use super::*;
#[test]
fn test_bracket_order() {
let orders = bracket_order(1000, Action::Buy, 100.0, 50.0, 55.0, 45.0);
assert_eq!(orders.len(), 3);
let parent = &orders[0];
assert_eq!(parent.order_id, 1000);
assert_eq!(parent.action, Action::Buy);
assert_eq!(parent.order_type, "LMT");
assert_eq!(parent.total_quantity, 100.0);
assert_eq!(parent.limit_price, Some(50.0));
assert!(!parent.transmit);
let take_profit = &orders[1];
assert_eq!(take_profit.order_id, 1001);
assert_eq!(take_profit.action, Action::Sell);
assert_eq!(take_profit.order_type, "LMT");
assert_eq!(take_profit.total_quantity, 100.0);
assert_eq!(take_profit.limit_price, Some(55.0));
assert_eq!(take_profit.parent_id, 1000);
assert!(!take_profit.transmit);
let stop_loss = &orders[2];
assert_eq!(stop_loss.order_id, 1002);
assert_eq!(stop_loss.action, Action::Sell);
assert_eq!(stop_loss.order_type, "STP");
assert_eq!(stop_loss.total_quantity, 100.0);
assert_eq!(stop_loss.aux_price, Some(45.0));
assert_eq!(stop_loss.parent_id, 1000);
assert!(stop_loss.transmit);
}
#[test]
fn test_one_cancels_all() {
let order1 = limit_order(Action::Buy, 100.0, 50.0);
let order2 = limit_order(Action::Sell, 100.0, 52.0);
let orders = one_cancels_all("TestOCA", vec![order1, order2], OcaType::ReduceWithBlock);
for order in &orders {
assert_eq!(order.oca_group, "TestOCA");
assert_eq!(order.oca_type, OcaType::ReduceWithBlock);
}
assert_eq!(orders[0].action, Action::Buy);
assert_eq!(orders[0].limit_price, Some(50.0));
assert_eq!(orders[1].action, Action::Sell);
assert_eq!(orders[1].limit_price, Some(52.0));
}
#[test]
fn test_trailing_stop_order() {
let order = trailing_stop(Action::Sell, 100.0, 5.0, 45.0);
assert_eq!(order.action, Action::Sell);
assert_eq!(order.order_type, "TRAIL");
assert_eq!(order.total_quantity, 100.0);
assert_eq!(order.trailing_percent, Some(5.0));
assert_eq!(order.trail_stop_price, Some(45.0));
}
#[test]
fn test_trailing_stop_limit_order() {
let order = trailing_stop_limit(Action::Sell, 100.0, 2.0, 5.0, 45.0);
assert_eq!(order.action, Action::Sell);
assert_eq!(order.order_type, "TRAIL LIMIT");
assert_eq!(order.total_quantity, 100.0);
assert_eq!(order.limit_price_offset, Some(2.0));
assert_eq!(order.aux_price, Some(5.0)); assert_eq!(order.trail_stop_price, Some(45.0));
}
}
#[cfg(test)]
mod combo_order_tests {
use super::*;
#[test]
fn test_combo_market_order() {
let order = combo_market_order(Action::Buy, 100.0, true);
assert_eq!(order.action, Action::Buy);
assert_eq!(order.order_type, "MKT");
assert_eq!(order.total_quantity, 100.0);
assert_eq!(order.smart_combo_routing_params.len(), 1);
assert_eq!(order.smart_combo_routing_params[0].tag, "NonGuaranteed");
assert_eq!(order.smart_combo_routing_params[0].value, "1");
}
#[test]
fn test_combo_limit_order() {
let order = combo_limit_order(Action::Buy, 100.0, 50.0, true);
assert_eq!(order.action, Action::Buy);
assert_eq!(order.order_type, "LMT");
assert_eq!(order.total_quantity, 100.0);
assert_eq!(order.limit_price, Some(50.0));
assert_eq!(order.smart_combo_routing_params.len(), 1);
assert_eq!(order.smart_combo_routing_params[0].tag, "NonGuaranteed");
assert_eq!(order.smart_combo_routing_params[0].value, "1");
}
#[test]
fn test_relative_limit_combo() {
let order = relative_limit_combo(Action::Buy, 100.0, 50.0, true);
assert_eq!(order.action, Action::Buy);
assert_eq!(order.order_type, "REL + LMT");
assert_eq!(order.total_quantity, 100.0);
assert_eq!(order.limit_price, Some(50.0));
assert_eq!(order.smart_combo_routing_params.len(), 1);
assert_eq!(order.smart_combo_routing_params[0].tag, "NonGuaranteed");
assert_eq!(order.smart_combo_routing_params[0].value, "1");
}
#[test]
fn test_limit_order_for_combo_with_leg_prices() {
let leg_prices = vec![50.0, 45.0];
let order = limit_order_for_combo_with_leg_prices(Action::Buy, 100.0, leg_prices, true);
assert_eq!(order.action, Action::Buy);
assert_eq!(order.order_type, "LMT");
assert_eq!(order.total_quantity, 100.0);
assert_eq!(order.order_combo_legs.len(), 2);
assert_eq!(order.order_combo_legs[0].price, Some(50.0));
assert_eq!(order.order_combo_legs[1].price, Some(45.0));
assert_eq!(order.smart_combo_routing_params.len(), 1);
assert_eq!(order.smart_combo_routing_params[0].tag, "NonGuaranteed");
assert_eq!(order.smart_combo_routing_params[0].value, "1");
}
}
#[cfg(test)]
mod specialized_order_tests {
use super::*;
#[test]
fn test_pegged_to_market() {
let order = pegged_to_market(Action::Buy, 100.0, 0.05);
assert_eq!(order.action, Action::Buy);
assert_eq!(order.order_type, "PEG MKT");
assert_eq!(order.total_quantity, 100.0);
assert_eq!(order.aux_price, Some(0.05));
}
#[test]
fn test_volatility_order() {
let order = volatility(Action::Buy, 100.0, 0.04, VolatilityType::Daily);
assert_eq!(order.action, Action::Buy);
assert_eq!(order.order_type, "VOL");
assert_eq!(order.total_quantity, 100.0);
assert_eq!(order.volatility, Some(0.04));
assert_eq!(order.volatility_type, Some(VolatilityType::Daily));
}
#[test]
fn test_auction_limit() {
let order = auction_limit(Action::Buy, 100.0, 50.0, AuctionStrategy::Improvement);
assert_eq!(order.action, Action::Buy);
assert_eq!(order.order_type, "LMT");
assert_eq!(order.total_quantity, 100.0);
assert_eq!(order.limit_price, Some(50.0));
assert_eq!(order.auction_strategy, Some(AuctionStrategy::Improvement));
}
#[test]
fn test_auction_relative() {
let order = auction_relative(Action::Buy, 100.0, 0.05);
assert_eq!(order.action, Action::Buy);
assert_eq!(order.order_type, "REL");
assert_eq!(order.total_quantity, 100.0);
assert_eq!(order.aux_price, Some(0.05));
}
#[test]
fn test_block_order() {
let order = block(Action::Buy, 100.0, 50.0);
assert_eq!(order.action, Action::Buy);
assert_eq!(order.order_type, "LMT");
assert_eq!(order.total_quantity, 100.0);
assert_eq!(order.limit_price, Some(50.0));
assert!(order.block_order);
}
#[test]
fn test_box_top() {
let order = box_top(Action::Buy, 100.0);
assert_eq!(order.action, Action::Buy);
assert_eq!(order.order_type, "BOX TOP");
assert_eq!(order.total_quantity, 100.0);
}
#[test]
fn test_sweep_to_fill() {
let order = sweep_to_fill(Action::Buy, 100.0, 50.0);
assert_eq!(order.action, Action::Buy);
assert_eq!(order.order_type, "LMT");
assert_eq!(order.total_quantity, 100.0);
assert_eq!(order.limit_price, Some(50.0));
assert!(order.sweep_to_fill);
}
#[test]
fn test_discretionary() {
let order = discretionary(Action::Buy, 100.0, 50.0, 0.1);
assert_eq!(order.action, Action::Buy);
assert_eq!(order.order_type, "LMT");
assert_eq!(order.total_quantity, 100.0);
assert_eq!(order.limit_price, Some(50.0));
assert_eq!(order.discretionary_amt, 0.1);
}
#[test]
fn test_midpoint_match() {
let order = midpoint_match(Action::Buy, 100.0);
assert_eq!(order.action, Action::Buy);
assert_eq!(order.order_type, "MKT");
assert_eq!(order.total_quantity, 100.0);
}
#[test]
fn test_midprice_with_cap() {
let order = midprice(Action::Buy, 100.0, Some(50.0));
assert_eq!(order.action, Action::Buy);
assert_eq!(order.order_type, "MIDPRICE");
assert_eq!(order.total_quantity, 100.0);
assert_eq!(order.limit_price, Some(50.0));
}
#[test]
fn test_midprice_without_cap() {
let order = midprice(Action::Buy, 100.0, None);
assert_eq!(order.action, Action::Buy);
assert_eq!(order.order_type, "MIDPRICE");
assert_eq!(order.total_quantity, 100.0);
assert_eq!(order.limit_price, None);
}
#[test]
fn test_pegged_to_benchmark() {
let order = pegged_to_benchmark(
Action::Buy,
100.0,
50.0, false, 0.02, 0.01, 12345, "ISLAND", 49.0, 48.0, 52.0, );
assert_eq!(order.action, Action::Buy);
assert_eq!(order.order_type, "PEG BENCH");
assert_eq!(order.total_quantity, 100.0);
assert_eq!(order.starting_price, Some(50.0));
assert!(!order.is_pegged_change_amount_decrease);
assert_eq!(order.pegged_change_amount, Some(0.02));
assert_eq!(order.reference_change_amount, Some(0.01));
assert_eq!(order.reference_contract_id, 12345);
assert_eq!(order.reference_exchange, "ISLAND");
assert_eq!(order.stock_ref_price, Some(49.0));
assert_eq!(order.stock_range_lower, Some(48.0));
assert_eq!(order.stock_range_upper, Some(52.0));
}
}
#[cfg(test)]
mod pegged_order_tests {
use super::*;
#[test]
fn test_peg_best_order() {
let order = peg_best_order(
Action::Buy,
100.0, 50.0, 10, 20, 0.01, );
assert_eq!(order.action, Action::Buy);
assert_eq!(order.order_type, "PEG BEST");
assert_eq!(order.total_quantity, 100.0);
assert_eq!(order.limit_price, Some(50.0));
assert!(order.not_held);
assert_eq!(order.min_trade_qty, Some(10));
assert_eq!(order.min_compete_size, Some(20));
assert_eq!(order.compete_against_best_offset, Some(0.01));
}
#[test]
fn test_peg_best_up_to_mid() {
let order = peg_best_up_to_mid_order(
Action::Buy,
100.0, 50.0, 10, 20, 0.01, 0.005, );
assert_eq!(order.action, Action::Buy);
assert_eq!(order.order_type, "PEG BEST");
assert_eq!(order.total_quantity, 100.0);
assert_eq!(order.limit_price, Some(50.0));
assert!(order.not_held);
assert_eq!(order.min_trade_qty, Some(10));
assert_eq!(order.min_compete_size, Some(20));
assert_eq!(order.compete_against_best_offset, COMPETE_AGAINST_BEST_OFFSET_UP_TO_MID);
assert_eq!(order.mid_offset_at_whole, Some(0.01));
assert_eq!(order.mid_offset_at_half, Some(0.005));
}
#[test]
fn test_peg_mid_order() {
let order = peg_mid_order(
Action::Buy,
100.0, 50.0, 10, 0.01, 0.005, );
assert_eq!(order.action, Action::Buy);
assert_eq!(order.order_type, "PEG MID");
assert_eq!(order.total_quantity, 100.0);
assert_eq!(order.limit_price, Some(50.0));
assert!(order.not_held);
assert_eq!(order.min_trade_qty, Some(10));
assert_eq!(order.mid_offset_at_whole, Some(0.01));
assert_eq!(order.mid_offset_at_half, Some(0.005));
}
}
#[cfg(test)]
mod miscellaneous_order_tests {
use super::*;
#[test]
fn test_limit_order_with_cash_qty() {
let order = limit_order_with_cash_qty(Action::Buy, 50.0, 5000.0);
assert_eq!(order.action, Action::Buy);
assert_eq!(order.order_type, "LMT");
assert_eq!(order.limit_price, Some(50.0));
assert_eq!(order.cash_qty, Some(5000.0));
}
#[test]
fn test_limit_order_with_manual_order_time() {
let order = limit_order_with_manual_order_time(Action::Buy, 100.0, 50.0, "20240101 10:00:00");
assert_eq!(order.action, Action::Buy);
assert_eq!(order.order_type, "LMT");
assert_eq!(order.total_quantity, 100.0);
assert_eq!(order.limit_price, Some(50.0));
assert_eq!(order.manual_order_time, "20240101 10:00:00");
}
#[test]
fn test_market_with_protection() {
let order = market_with_protection(Action::Buy, 100.0);
assert_eq!(order.action, Action::Buy);
assert_eq!(order.order_type, "MKT PRT");
assert_eq!(order.total_quantity, 100.0);
}
#[test]
fn test_stop_with_protection() {
let order = stop_with_protection(Action::Sell, 100.0, 45.0);
assert_eq!(order.action, Action::Sell);
assert_eq!(order.order_type, "STP PRT");
assert_eq!(order.total_quantity, 100.0);
assert_eq!(order.aux_price, Some(45.0));
}
#[test]
fn test_ibkrats_limit_order() {
let order = limit_ibkrats(Action::Buy, 100.0, 50.0);
assert_eq!(order.action, Action::Buy);
assert_eq!(order.order_type, "LMT");
assert_eq!(order.total_quantity, 100.0);
assert_eq!(order.limit_price, Some(50.0));
assert!(order.not_held);
}
#[test]
fn test_market_f_hedge() {
let order = market_f_hedge(1001, Action::Buy);
assert_eq!(order.action, Action::Buy);
assert_eq!(order.order_type, "MKT");
assert_eq!(order.total_quantity, 0.0);
assert_eq!(order.parent_id, 1001);
assert_eq!(order.hedge_type, "F");
}
}
#[cfg(test)]
mod adjustable_order_tests {
use super::*;
#[test]
fn test_attach_adjustable_to_stop() {
let parent = stop(Action::Buy, 100.0, 50.0);
let order = attach_adjustable_to_stop(
&parent, 45.0, 48.0, 46.0, );
assert_eq!(order.action, Action::Sell); assert_eq!(order.order_type, "STP");
assert_eq!(order.total_quantity, 100.0);
assert_eq!(order.aux_price, Some(45.0));
assert_eq!(order.parent_id, parent.order_id);
assert_eq!(order.trigger_price, Some(48.0));
assert_eq!(order.adjusted_order_type, "STP");
assert_eq!(order.adjusted_stop_price, Some(46.0));
}
#[test]
fn test_attach_adjustable_to_stop_limit() {
let parent = stop(Action::Buy, 100.0, 50.0);
let order = attach_adjustable_to_stop_limit(
&parent, 45.0, 48.0, 46.0, 47.0, );
assert_eq!(order.action, Action::Sell); assert_eq!(order.order_type, "STP");
assert_eq!(order.total_quantity, 100.0);
assert_eq!(order.aux_price, Some(45.0));
assert_eq!(order.parent_id, parent.order_id);
assert_eq!(order.trigger_price, Some(48.0));
assert_eq!(order.adjusted_order_type, "STP LMT");
assert_eq!(order.adjusted_stop_price, Some(46.0));
assert_eq!(order.adjusted_stop_limit_price, Some(47.0));
}
#[test]
fn test_attach_adjustable_to_trail() {
let parent = stop(Action::Buy, 100.0, 50.0);
let order = attach_adjustable_to_trail(
&parent, 45.0, 48.0, 46.0, 0.02, 100, );
assert_eq!(order.action, Action::Sell); assert_eq!(order.order_type, "STP");
assert_eq!(order.total_quantity, 100.0);
assert_eq!(order.aux_price, Some(45.0));
assert_eq!(order.parent_id, parent.order_id);
assert_eq!(order.trigger_price, Some(48.0));
assert_eq!(order.adjusted_order_type, "TRAIL");
assert_eq!(order.adjusted_stop_price, Some(46.0));
assert_eq!(order.adjusted_trailing_amount, Some(0.02));
assert_eq!(order.adjustable_trailing_unit, 100);
}
}
#[cfg(test)]
mod additional_specialized_order_tests {
use super::*;
#[test]
fn test_relative_market_combo() {
let order = relative_market_combo(Action::Buy, 100.0, true);
assert_eq!(order.action, Action::Buy);
assert_eq!(order.order_type, "REL + MKT");
assert_eq!(order.total_quantity, 100.0);
assert_eq!(order.smart_combo_routing_params.len(), 1);
assert_eq!(order.smart_combo_routing_params[0].tag, "NonGuaranteed");
assert_eq!(order.smart_combo_routing_params[0].value, "1");
}
#[test]
fn test_auction_pegged_to_stock() {
let order = auction_pegged_to_stock(
Action::Buy,
100.0, 50.0, 0.5, );
assert_eq!(order.action, Action::Buy);
assert_eq!(order.order_type, "PEG STK");
assert_eq!(order.total_quantity, 100.0);
assert_eq!(order.starting_price, Some(50.0));
assert_eq!(order.delta, Some(0.5));
}
#[test]
fn test_pegged_to_stock() {
let order = pegged_to_stock(
Action::Buy,
100.0, 0.5, 50.0, 49.0, );
assert_eq!(order.action, Action::Buy);
assert_eq!(order.order_type, "PEG STK");
assert_eq!(order.total_quantity, 100.0);
assert_eq!(order.delta, Some(0.5));
assert_eq!(order.stock_ref_price, Some(50.0));
assert_eq!(order.starting_price, Some(49.0));
}
#[test]
fn test_relative_pegged_to_primary() {
let order = relative_pegged_to_primary(
Action::Buy,
100.0, 50.0, 0.01, );
assert_eq!(order.action, Action::Buy);
assert_eq!(order.order_type, "REL");
assert_eq!(order.total_quantity, 100.0);
assert_eq!(order.limit_price, Some(50.0));
assert_eq!(order.aux_price, Some(0.01));
}
#[test]
fn test_passive_relative() {
let order = passive_relative(
Action::Buy,
100.0, 0.01, );
assert_eq!(order.action, Action::Buy);
assert_eq!(order.order_type, "PASSV REL");
assert_eq!(order.total_quantity, 100.0);
assert_eq!(order.aux_price, Some(0.01));
}
#[test]
fn test_at_auction() {
let order = at_auction(
Action::Buy,
100.0, 50.0, );
assert_eq!(order.action, Action::Buy);
assert_eq!(order.order_type, "MTL");
assert_eq!(order.total_quantity, 100.0);
assert_eq!(order.limit_price, Some(50.0));
assert_eq!(order.tif, TimeInForce::Auction);
}
#[test]
fn test_what_if_limit_order() {
let order = what_if_limit_order(
Action::Buy,
100.0, 50.0, );
assert_eq!(order.action, Action::Buy);
assert_eq!(order.order_type, "LMT");
assert_eq!(order.total_quantity, 100.0);
assert_eq!(order.limit_price, Some(50.0));
assert!(order.what_if);
}
}
}