Add order runtime lookup
This commit is contained in:
@@ -9,7 +9,7 @@ use chrono::{Datelike, Duration, NaiveDate, NaiveDateTime, NaiveTime};
|
||||
use crate::cost::ChinaAShareCostModel;
|
||||
use crate::data::{DailyMarketSnapshot, DataSet, IntradayExecutionQuote, PriceBar, PriceField};
|
||||
use crate::engine::BacktestError;
|
||||
use crate::events::{OrderSide, OrderStatus, ProcessEvent};
|
||||
use crate::events::{FillEvent, OrderEvent, OrderSide, OrderStatus, ProcessEvent};
|
||||
use crate::instrument::Instrument;
|
||||
use crate::portfolio::PortfolioState;
|
||||
use crate::scheduler::ScheduleRule;
|
||||
@@ -80,6 +80,21 @@ pub struct OpenOrderView {
|
||||
pub reason: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct OrderRuntimeView {
|
||||
pub order_id: u64,
|
||||
pub symbol: String,
|
||||
pub side: OrderSide,
|
||||
pub requested_quantity: u32,
|
||||
pub filled_quantity: u32,
|
||||
pub unfilled_quantity: u32,
|
||||
pub status: OrderStatus,
|
||||
pub avg_price: f64,
|
||||
pub transaction_cost: f64,
|
||||
pub limit_price: f64,
|
||||
pub reason: String,
|
||||
}
|
||||
|
||||
pub struct StrategyContext<'a> {
|
||||
pub execution_date: NaiveDate,
|
||||
pub decision_date: NaiveDate,
|
||||
@@ -92,6 +107,8 @@ pub struct StrategyContext<'a> {
|
||||
pub process_events: &'a [ProcessEvent],
|
||||
pub active_process_event: Option<&'a ProcessEvent>,
|
||||
pub active_datetime: Option<NaiveDateTime>,
|
||||
pub order_events: &'a [OrderEvent],
|
||||
pub fills: &'a [FillEvent],
|
||||
}
|
||||
|
||||
impl StrategyContext<'_> {
|
||||
@@ -215,6 +232,97 @@ impl StrategyContext<'_> {
|
||||
.unwrap_or(0)
|
||||
}
|
||||
|
||||
pub fn order(&self, order_id: u64) -> Option<OrderRuntimeView> {
|
||||
let fills = self
|
||||
.fills
|
||||
.iter()
|
||||
.filter(|fill| fill.order_id == Some(order_id))
|
||||
.collect::<Vec<_>>();
|
||||
let filled_quantity = fills.iter().map(|fill| fill.quantity).sum::<u32>();
|
||||
let gross_amount = fills.iter().map(|fill| fill.gross_amount).sum::<f64>();
|
||||
let transaction_cost = fills
|
||||
.iter()
|
||||
.map(|fill| fill.commission + fill.stamp_tax)
|
||||
.sum::<f64>();
|
||||
let avg_price = if filled_quantity == 0 {
|
||||
0.0
|
||||
} else {
|
||||
gross_amount / filled_quantity as f64
|
||||
};
|
||||
|
||||
if let Some(order) = self
|
||||
.open_orders
|
||||
.iter()
|
||||
.find(|order| order.order_id == order_id)
|
||||
{
|
||||
let filled_quantity = order.filled_quantity.max(filled_quantity);
|
||||
return Some(OrderRuntimeView {
|
||||
order_id,
|
||||
symbol: order.symbol.clone(),
|
||||
side: order.side,
|
||||
requested_quantity: order.requested_quantity,
|
||||
filled_quantity,
|
||||
unfilled_quantity: order
|
||||
.unfilled_quantity
|
||||
.min(order.requested_quantity.saturating_sub(filled_quantity)),
|
||||
status: order.status,
|
||||
avg_price: if avg_price > 0.0 {
|
||||
avg_price
|
||||
} else {
|
||||
order.avg_price
|
||||
},
|
||||
transaction_cost: if transaction_cost > 0.0 {
|
||||
transaction_cost
|
||||
} else {
|
||||
order.transaction_cost
|
||||
},
|
||||
limit_price: order.limit_price,
|
||||
reason: order.reason.clone(),
|
||||
});
|
||||
}
|
||||
|
||||
let latest_event = self
|
||||
.order_events
|
||||
.iter()
|
||||
.rev()
|
||||
.filter(|event| event.order_id == Some(order_id))
|
||||
.next()?;
|
||||
let filled_quantity = latest_event.filled_quantity.max(filled_quantity);
|
||||
Some(OrderRuntimeView {
|
||||
order_id,
|
||||
symbol: latest_event.symbol.clone(),
|
||||
side: latest_event.side,
|
||||
requested_quantity: latest_event.requested_quantity,
|
||||
filled_quantity,
|
||||
unfilled_quantity: latest_event
|
||||
.requested_quantity
|
||||
.saturating_sub(filled_quantity),
|
||||
status: latest_event.status,
|
||||
avg_price,
|
||||
transaction_cost,
|
||||
limit_price: 0.0,
|
||||
reason: latest_event.reason.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn order_status(&self, order_id: u64) -> &'static str {
|
||||
self.order(order_id)
|
||||
.map(|order| order.status.as_str())
|
||||
.unwrap_or("")
|
||||
}
|
||||
|
||||
pub fn order_avg_price(&self, order_id: u64) -> f64 {
|
||||
self.order(order_id)
|
||||
.map(|order| order.avg_price)
|
||||
.unwrap_or(0.0)
|
||||
}
|
||||
|
||||
pub fn order_transaction_cost(&self, order_id: u64) -> f64 {
|
||||
self.order(order_id)
|
||||
.map(|order| order.transaction_cost)
|
||||
.unwrap_or(0.0)
|
||||
}
|
||||
|
||||
pub fn available_sellable_qty(&self, symbol: &str, raw_sellable_qty: u32) -> u32 {
|
||||
raw_sellable_qty.saturating_sub(self.symbol_open_sell_quantity(symbol))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user