| Overall Statistics |
|
Total Orders 2 Average Win 0% Average Loss 0% Compounding Annual Return 0% Drawdown 0% Expectancy 0 Start Equity 100000 End Equity 99908.2 Net Profit 0% Sharpe Ratio 0 Sortino Ratio 0 Probabilistic Sharpe Ratio 0% Loss Rate 0% Win Rate 0% Profit-Loss Ratio 0 Alpha 0 Beta 0 Annual Standard Deviation 0 Annual Variance 0 Information Ratio 0 Tracking Error 0 Treynor Ratio 0 Total Fees $4.30 Estimated Strategy Capacity $29000000.00 Lowest Capacity Asset ES YJHOAMPYKQGX Portfolio Turnover 265.59% |
from AlgorithmImports import *
class CustomFutureFillModelAlgorithm(QCAlgorithm):
def Initialize(self):
self.set_start_date(2024, 6, 3)
self.set_end_date(2024, 6, 4)
self.set_security_initializer(CustomSecurityInitializer(self))
self.es = self.add_future("ES", extended_market_hours=True)
self.ticket = None
def on_data(self, slice):
if not self.ticket:
self.market_order(self.es.mapped, 1)
self.ticket = self.trailing_stop_order(self.es.mapped, -1, 5, False)
if self.ticket and self.ticket.status != OrderStatus.FILLED:
self.plot(self.es.mapped.value, 'Price', self.es.price)
self.plot(self.es.mapped.value, 'Stop', self.ticket.get(OrderField.STOP_PRICE))
class CustomSecurityInitializer(BrokerageModelSecurityInitializer):
def __init__(self, algorithm):
super().__init__(algorithm.brokerage_model, SecuritySeeder.NULL)
def initialize(self, security):
super().initialize(security)
security.set_fill_model(CustomFutureFillModel())
class CustomFutureFillModel(FutureFillModel):
def trailing_stop_fill(self, asset, order):
utc_time = Extensions.convert_to_utc(asset.local_time, asset.exchange.time_zone)
fill = OrderEvent(order, utc_time, OrderFee.ZERO)
if order.Status == OrderStatus.CANCELED:
return fill
bar = asset.cache.get_data[TradeBar]()
# Do not fill on stale data
if Extensions.convert_to_utc(bar.end_time, asset.exchange.time_zone) <= order.time:
return fill
if order.direction == OrderDirection.BUY and bar.high >= order.stop_price:
fill.Status = OrderStatus.FILLED
fill.FillQuantity = order.quantity
# Assuming worse case scenario fill - fill at highest of the stop & asset bid price.
slip = asset.SlippageModel.GetSlippageApproximation(asset, order)
fill.FillPrice = max(order.stop_price, asset.ask_price + slip)
if order.direction == OrderDirection.SELL and bar.low <= order.stop_price:
fill.Status = OrderStatus.FILLED
fill.FillQuantity = order.quantity
# Assuming worse case scenario fill - fill at lowest of the stop & asset bid price.
slip = asset.SlippageModel.GetSlippageApproximation(asset, order)
fill.FillPrice = min(order.stop_price, asset.bid_price - slip)
if fill.Status != OrderStatus.FILLED:
current_market_price = bar.high if order.direction == OrderDirection.SELL else bar.low
is_update, updated_stop_price = TrailingStopOrder.try_update_stop_price(current_market_price, order.stop_price, order.trailing_amount, order.trailing_as_percentage, order.Direction, 0)
if is_update:
order.stop_price = updated_stop_price
self.parameters.on_order_updated(order)
return fill