1#![allow(unsafe_code)]
83
84use std::marker::PhantomData;
85
86use nautilus_common::{signal::Signal, timer::TimeEvent};
87use nautilus_model::{
88 data::{
89 Bar, FundingRateUpdate, IndexPriceUpdate, InstrumentClose, InstrumentStatus,
90 MarkPriceUpdate, OptionChainSlice, OptionGreeks, OrderBookDelta, OrderBookDeltas,
91 OrderBookDepth10, QuoteTick, TradeTick,
92 },
93 events::{
94 OrderAccepted, OrderCancelRejected, OrderCanceled, OrderDenied, OrderEmulated,
95 OrderExpired, OrderFilled, OrderInitialized, OrderModifyRejected, OrderPendingCancel,
96 OrderPendingUpdate, OrderRejected, OrderReleased, OrderSubmitted, OrderTriggered,
97 OrderUpdated, PositionChanged, PositionClosed, PositionOpened,
98 },
99 instruments::InstrumentAny,
100 orderbook::OrderBook,
101};
102
103use crate::{
104 boundary::{BorrowedStr, PluginError, PluginErrorCode, PluginResult, Slice},
105 host::{HostContext, HostVTable},
106 normalize::BoundaryNormalize,
107 panic::{guard, guard_infallible},
108 surfaces::{
109 book::{OrderBookDeltasHandle, OrderBookHandle},
110 custom_data::PluginCustomDataRef,
111 instrument::InstrumentAnyHandle,
112 option_chain::OptionChainSliceHandle,
113 },
114};
115
116#[repr(C)]
118pub struct PluginStrategyHandle {
119 _opaque: [u8; 0],
120}
121
122#[repr(C)]
139pub struct StrategyVTable {
140 pub create: Option<
150 unsafe extern "C" fn(
151 host: *const HostVTable,
152 ctx: *const HostContext,
153 config_json: BorrowedStr<'_>,
154 ) -> *mut PluginStrategyHandle,
155 >,
156
157 pub drop_handle: Option<unsafe extern "C" fn(handle: *mut PluginStrategyHandle)>,
159
160 pub type_name: Option<unsafe extern "C" fn() -> BorrowedStr<'static>>,
162
163 pub on_start:
164 Option<unsafe extern "C" fn(handle: *mut PluginStrategyHandle) -> PluginResult<()>>,
165 pub on_stop:
166 Option<unsafe extern "C" fn(handle: *mut PluginStrategyHandle) -> PluginResult<()>>,
167 pub on_resume:
168 Option<unsafe extern "C" fn(handle: *mut PluginStrategyHandle) -> PluginResult<()>>,
169 pub on_reset:
170 Option<unsafe extern "C" fn(handle: *mut PluginStrategyHandle) -> PluginResult<()>>,
171 pub on_dispose:
172 Option<unsafe extern "C" fn(handle: *mut PluginStrategyHandle) -> PluginResult<()>>,
173 pub on_degrade:
174 Option<unsafe extern "C" fn(handle: *mut PluginStrategyHandle) -> PluginResult<()>>,
175 pub on_fault:
176 Option<unsafe extern "C" fn(handle: *mut PluginStrategyHandle) -> PluginResult<()>>,
177
178 pub on_time_event: Option<
179 unsafe extern "C" fn(
180 handle: *mut PluginStrategyHandle,
181 event: *const TimeEvent,
182 ) -> PluginResult<()>,
183 >,
184 pub on_data: Option<
185 unsafe extern "C" fn(
186 handle: *mut PluginStrategyHandle,
187 data: PluginCustomDataRef,
188 ) -> PluginResult<()>,
189 >,
190
191 pub on_instrument: Option<
192 unsafe extern "C" fn(
193 handle: *mut PluginStrategyHandle,
194 instrument: *const InstrumentAnyHandle,
195 ) -> PluginResult<()>,
196 >,
197 pub on_book_deltas: Option<
198 unsafe extern "C" fn(
199 handle: *mut PluginStrategyHandle,
200 deltas: *const OrderBookDeltasHandle,
201 ) -> PluginResult<()>,
202 >,
203 pub on_book: Option<
204 unsafe extern "C" fn(
205 handle: *mut PluginStrategyHandle,
206 book: *const OrderBookHandle,
207 ) -> PluginResult<()>,
208 >,
209 pub on_quote: Option<
210 unsafe extern "C" fn(
211 handle: *mut PluginStrategyHandle,
212 quote: *const QuoteTick,
213 ) -> PluginResult<()>,
214 >,
215 pub on_trade: Option<
216 unsafe extern "C" fn(
217 handle: *mut PluginStrategyHandle,
218 trade: *const TradeTick,
219 ) -> PluginResult<()>,
220 >,
221 pub on_bar: Option<
222 unsafe extern "C" fn(
223 handle: *mut PluginStrategyHandle,
224 bar: *const Bar,
225 ) -> PluginResult<()>,
226 >,
227 pub on_mark_price: Option<
228 unsafe extern "C" fn(
229 handle: *mut PluginStrategyHandle,
230 mark_price: *const MarkPriceUpdate,
231 ) -> PluginResult<()>,
232 >,
233 pub on_index_price: Option<
234 unsafe extern "C" fn(
235 handle: *mut PluginStrategyHandle,
236 index_price: *const IndexPriceUpdate,
237 ) -> PluginResult<()>,
238 >,
239 pub on_funding_rate: Option<
240 unsafe extern "C" fn(
241 handle: *mut PluginStrategyHandle,
242 funding_rate: *const FundingRateUpdate,
243 ) -> PluginResult<()>,
244 >,
245 pub on_option_greeks: Option<
246 unsafe extern "C" fn(
247 handle: *mut PluginStrategyHandle,
248 greeks: *const OptionGreeks,
249 ) -> PluginResult<()>,
250 >,
251 pub on_option_chain: Option<
252 unsafe extern "C" fn(
253 handle: *mut PluginStrategyHandle,
254 chain: *const OptionChainSliceHandle,
255 ) -> PluginResult<()>,
256 >,
257 pub on_instrument_status: Option<
258 unsafe extern "C" fn(
259 handle: *mut PluginStrategyHandle,
260 status: *const InstrumentStatus,
261 ) -> PluginResult<()>,
262 >,
263 pub on_instrument_close: Option<
264 unsafe extern "C" fn(
265 handle: *mut PluginStrategyHandle,
266 close: *const InstrumentClose,
267 ) -> PluginResult<()>,
268 >,
269 pub on_signal: Option<
270 unsafe extern "C" fn(
271 handle: *mut PluginStrategyHandle,
272 signal: *const Signal,
273 ) -> PluginResult<()>,
274 >,
275
276 pub on_order_initialized: Option<
277 unsafe extern "C" fn(
278 handle: *mut PluginStrategyHandle,
279 event: *const OrderInitialized,
280 ) -> PluginResult<()>,
281 >,
282 pub on_order_submitted: Option<
283 unsafe extern "C" fn(
284 handle: *mut PluginStrategyHandle,
285 event: *const OrderSubmitted,
286 ) -> PluginResult<()>,
287 >,
288 pub on_order_accepted: Option<
289 unsafe extern "C" fn(
290 handle: *mut PluginStrategyHandle,
291 event: *const OrderAccepted,
292 ) -> PluginResult<()>,
293 >,
294 pub on_order_rejected: Option<
295 unsafe extern "C" fn(
296 handle: *mut PluginStrategyHandle,
297 event: *const OrderRejected,
298 ) -> PluginResult<()>,
299 >,
300 pub on_order_filled: Option<
301 unsafe extern "C" fn(
302 handle: *mut PluginStrategyHandle,
303 event: *const OrderFilled,
304 ) -> PluginResult<()>,
305 >,
306 pub on_order_canceled: Option<
307 unsafe extern "C" fn(
308 handle: *mut PluginStrategyHandle,
309 event: *const OrderCanceled,
310 ) -> PluginResult<()>,
311 >,
312 pub on_order_expired: Option<
313 unsafe extern "C" fn(
314 handle: *mut PluginStrategyHandle,
315 event: *const OrderExpired,
316 ) -> PluginResult<()>,
317 >,
318 pub on_order_triggered: Option<
319 unsafe extern "C" fn(
320 handle: *mut PluginStrategyHandle,
321 event: *const OrderTriggered,
322 ) -> PluginResult<()>,
323 >,
324 pub on_order_denied: Option<
325 unsafe extern "C" fn(
326 handle: *mut PluginStrategyHandle,
327 event: *const OrderDenied,
328 ) -> PluginResult<()>,
329 >,
330 pub on_order_emulated: Option<
331 unsafe extern "C" fn(
332 handle: *mut PluginStrategyHandle,
333 event: *const OrderEmulated,
334 ) -> PluginResult<()>,
335 >,
336 pub on_order_released: Option<
337 unsafe extern "C" fn(
338 handle: *mut PluginStrategyHandle,
339 event: *const OrderReleased,
340 ) -> PluginResult<()>,
341 >,
342 pub on_order_pending_update: Option<
343 unsafe extern "C" fn(
344 handle: *mut PluginStrategyHandle,
345 event: *const OrderPendingUpdate,
346 ) -> PluginResult<()>,
347 >,
348 pub on_order_pending_cancel: Option<
349 unsafe extern "C" fn(
350 handle: *mut PluginStrategyHandle,
351 event: *const OrderPendingCancel,
352 ) -> PluginResult<()>,
353 >,
354 pub on_order_modify_rejected: Option<
355 unsafe extern "C" fn(
356 handle: *mut PluginStrategyHandle,
357 event: *const OrderModifyRejected,
358 ) -> PluginResult<()>,
359 >,
360 pub on_order_cancel_rejected: Option<
361 unsafe extern "C" fn(
362 handle: *mut PluginStrategyHandle,
363 event: *const OrderCancelRejected,
364 ) -> PluginResult<()>,
365 >,
366 pub on_order_updated: Option<
367 unsafe extern "C" fn(
368 handle: *mut PluginStrategyHandle,
369 event: *const OrderUpdated,
370 ) -> PluginResult<()>,
371 >,
372
373 pub on_position_opened: Option<
374 unsafe extern "C" fn(
375 handle: *mut PluginStrategyHandle,
376 event: *const PositionOpened,
377 ) -> PluginResult<()>,
378 >,
379 pub on_position_changed: Option<
380 unsafe extern "C" fn(
381 handle: *mut PluginStrategyHandle,
382 event: *const PositionChanged,
383 ) -> PluginResult<()>,
384 >,
385 pub on_position_closed: Option<
386 unsafe extern "C" fn(
387 handle: *mut PluginStrategyHandle,
388 event: *const PositionClosed,
389 ) -> PluginResult<()>,
390 >,
391
392 pub on_market_exit:
393 Option<unsafe extern "C" fn(handle: *mut PluginStrategyHandle) -> PluginResult<()>>,
394
395 pub on_historical_book_deltas: Option<
396 unsafe extern "C" fn(
397 handle: *mut PluginStrategyHandle,
398 deltas: Slice<'_, OrderBookDelta>,
399 ) -> PluginResult<()>,
400 >,
401 pub on_historical_book_depth: Option<
402 unsafe extern "C" fn(
403 handle: *mut PluginStrategyHandle,
404 depths: Slice<'_, OrderBookDepth10>,
405 ) -> PluginResult<()>,
406 >,
407 pub on_historical_quotes: Option<
408 unsafe extern "C" fn(
409 handle: *mut PluginStrategyHandle,
410 quotes: Slice<'_, QuoteTick>,
411 ) -> PluginResult<()>,
412 >,
413 pub on_historical_trades: Option<
414 unsafe extern "C" fn(
415 handle: *mut PluginStrategyHandle,
416 trades: Slice<'_, TradeTick>,
417 ) -> PluginResult<()>,
418 >,
419 pub on_historical_bars: Option<
420 unsafe extern "C" fn(
421 handle: *mut PluginStrategyHandle,
422 bars: Slice<'_, Bar>,
423 ) -> PluginResult<()>,
424 >,
425 pub on_historical_mark_prices: Option<
426 unsafe extern "C" fn(
427 handle: *mut PluginStrategyHandle,
428 mark_prices: Slice<'_, MarkPriceUpdate>,
429 ) -> PluginResult<()>,
430 >,
431 pub on_historical_index_prices: Option<
432 unsafe extern "C" fn(
433 handle: *mut PluginStrategyHandle,
434 index_prices: Slice<'_, IndexPriceUpdate>,
435 ) -> PluginResult<()>,
436 >,
437 pub on_historical_funding_rates: Option<
438 unsafe extern "C" fn(
439 handle: *mut PluginStrategyHandle,
440 funding_rates: Slice<'_, FundingRateUpdate>,
441 ) -> PluginResult<()>,
442 >,
443}
444
445pub trait PluginStrategy: 'static + Send + Sized {
453 const TYPE_NAME: &'static str;
455
456 fn new(host: *const HostVTable, ctx: *const HostContext, config_json: &str) -> Self;
466
467 #[allow(unused_variables)]
468 fn on_start(&mut self) -> anyhow::Result<()> {
469 Ok(())
470 }
471
472 #[allow(unused_variables)]
473 fn on_stop(&mut self) -> anyhow::Result<()> {
474 Ok(())
475 }
476
477 #[allow(unused_variables)]
478 fn on_resume(&mut self) -> anyhow::Result<()> {
479 Ok(())
480 }
481
482 #[allow(unused_variables)]
483 fn on_reset(&mut self) -> anyhow::Result<()> {
484 Ok(())
485 }
486
487 #[allow(unused_variables)]
488 fn on_dispose(&mut self) -> anyhow::Result<()> {
489 Ok(())
490 }
491
492 #[allow(unused_variables)]
493 fn on_degrade(&mut self) -> anyhow::Result<()> {
494 Ok(())
495 }
496
497 #[allow(unused_variables)]
498 fn on_fault(&mut self) -> anyhow::Result<()> {
499 Ok(())
500 }
501
502 #[allow(unused_variables)]
503 fn on_time_event(&mut self, event: &TimeEvent) -> anyhow::Result<()> {
504 Ok(())
505 }
506
507 #[allow(unused_variables)]
508 fn on_data(&mut self, data: PluginCustomDataRef) -> anyhow::Result<()> {
509 Ok(())
510 }
511
512 #[allow(unused_variables)]
513 fn on_instrument(&mut self, instrument: &InstrumentAny) -> anyhow::Result<()> {
514 Ok(())
515 }
516
517 #[allow(unused_variables)]
518 fn on_book_deltas(&mut self, deltas: &OrderBookDeltas) -> anyhow::Result<()> {
519 Ok(())
520 }
521
522 #[allow(unused_variables)]
523 fn on_book(&mut self, book: &OrderBook) -> anyhow::Result<()> {
524 Ok(())
525 }
526
527 #[allow(unused_variables)]
528 fn on_quote(&mut self, quote: &QuoteTick) -> anyhow::Result<()> {
529 Ok(())
530 }
531
532 #[allow(unused_variables)]
533 fn on_trade(&mut self, trade: &TradeTick) -> anyhow::Result<()> {
534 Ok(())
535 }
536
537 #[allow(unused_variables)]
538 fn on_bar(&mut self, bar: &Bar) -> anyhow::Result<()> {
539 Ok(())
540 }
541
542 #[allow(unused_variables)]
543 fn on_mark_price(&mut self, mark_price: &MarkPriceUpdate) -> anyhow::Result<()> {
544 Ok(())
545 }
546
547 #[allow(unused_variables)]
548 fn on_index_price(&mut self, index_price: &IndexPriceUpdate) -> anyhow::Result<()> {
549 Ok(())
550 }
551
552 #[allow(unused_variables)]
553 fn on_funding_rate(&mut self, funding_rate: &FundingRateUpdate) -> anyhow::Result<()> {
554 Ok(())
555 }
556
557 #[allow(unused_variables)]
558 fn on_option_greeks(&mut self, greeks: &OptionGreeks) -> anyhow::Result<()> {
559 Ok(())
560 }
561
562 #[allow(unused_variables)]
563 fn on_option_chain(&mut self, chain: &OptionChainSlice) -> anyhow::Result<()> {
564 Ok(())
565 }
566
567 #[allow(unused_variables)]
568 fn on_instrument_status(&mut self, status: &InstrumentStatus) -> anyhow::Result<()> {
569 Ok(())
570 }
571
572 #[allow(unused_variables)]
573 fn on_instrument_close(&mut self, close: &InstrumentClose) -> anyhow::Result<()> {
574 Ok(())
575 }
576
577 #[allow(unused_variables)]
578 fn on_signal(&mut self, signal: &Signal) -> anyhow::Result<()> {
579 Ok(())
580 }
581
582 #[allow(unused_variables)]
583 fn on_order_initialized(&mut self, event: &OrderInitialized) -> anyhow::Result<()> {
584 Ok(())
585 }
586
587 #[allow(unused_variables)]
588 fn on_order_submitted(&mut self, event: &OrderSubmitted) -> anyhow::Result<()> {
589 Ok(())
590 }
591
592 #[allow(unused_variables)]
593 fn on_order_accepted(&mut self, event: &OrderAccepted) -> anyhow::Result<()> {
594 Ok(())
595 }
596
597 #[allow(unused_variables)]
598 fn on_order_rejected(&mut self, event: &OrderRejected) -> anyhow::Result<()> {
599 Ok(())
600 }
601
602 #[allow(unused_variables)]
603 fn on_order_filled(&mut self, event: &OrderFilled) -> anyhow::Result<()> {
604 Ok(())
605 }
606
607 #[allow(unused_variables)]
608 fn on_order_canceled(&mut self, event: &OrderCanceled) -> anyhow::Result<()> {
609 Ok(())
610 }
611
612 #[allow(unused_variables)]
613 fn on_order_expired(&mut self, event: &OrderExpired) -> anyhow::Result<()> {
614 Ok(())
615 }
616
617 #[allow(unused_variables)]
618 fn on_order_triggered(&mut self, event: &OrderTriggered) -> anyhow::Result<()> {
619 Ok(())
620 }
621
622 #[allow(unused_variables)]
623 fn on_order_denied(&mut self, event: &OrderDenied) -> anyhow::Result<()> {
624 Ok(())
625 }
626
627 #[allow(unused_variables)]
628 fn on_order_emulated(&mut self, event: &OrderEmulated) -> anyhow::Result<()> {
629 Ok(())
630 }
631
632 #[allow(unused_variables)]
633 fn on_order_released(&mut self, event: &OrderReleased) -> anyhow::Result<()> {
634 Ok(())
635 }
636
637 #[allow(unused_variables)]
638 fn on_order_pending_update(&mut self, event: &OrderPendingUpdate) -> anyhow::Result<()> {
639 Ok(())
640 }
641
642 #[allow(unused_variables)]
643 fn on_order_pending_cancel(&mut self, event: &OrderPendingCancel) -> anyhow::Result<()> {
644 Ok(())
645 }
646
647 #[allow(unused_variables)]
648 fn on_order_modify_rejected(&mut self, event: &OrderModifyRejected) -> anyhow::Result<()> {
649 Ok(())
650 }
651
652 #[allow(unused_variables)]
653 fn on_order_cancel_rejected(&mut self, event: &OrderCancelRejected) -> anyhow::Result<()> {
654 Ok(())
655 }
656
657 #[allow(unused_variables)]
658 fn on_order_updated(&mut self, event: &OrderUpdated) -> anyhow::Result<()> {
659 Ok(())
660 }
661
662 #[allow(unused_variables)]
663 fn on_position_opened(&mut self, event: &PositionOpened) -> anyhow::Result<()> {
664 Ok(())
665 }
666
667 #[allow(unused_variables)]
668 fn on_position_changed(&mut self, event: &PositionChanged) -> anyhow::Result<()> {
669 Ok(())
670 }
671
672 #[allow(unused_variables)]
673 fn on_position_closed(&mut self, event: &PositionClosed) -> anyhow::Result<()> {
674 Ok(())
675 }
676
677 #[allow(unused_variables)]
678 fn on_market_exit(&mut self) -> anyhow::Result<()> {
679 Ok(())
680 }
681
682 #[allow(unused_variables)]
683 fn on_historical_book_deltas(&mut self, deltas: &[OrderBookDelta]) -> anyhow::Result<()> {
684 Ok(())
685 }
686
687 #[allow(unused_variables)]
688 fn on_historical_book_depth(&mut self, depths: &[OrderBookDepth10]) -> anyhow::Result<()> {
689 Ok(())
690 }
691
692 #[allow(unused_variables)]
693 fn on_historical_quotes(&mut self, quotes: &[QuoteTick]) -> anyhow::Result<()> {
694 Ok(())
695 }
696
697 #[allow(unused_variables)]
698 fn on_historical_trades(&mut self, trades: &[TradeTick]) -> anyhow::Result<()> {
699 Ok(())
700 }
701
702 #[allow(unused_variables)]
703 fn on_historical_bars(&mut self, bars: &[Bar]) -> anyhow::Result<()> {
704 Ok(())
705 }
706
707 #[allow(unused_variables)]
708 fn on_historical_mark_prices(&mut self, mark_prices: &[MarkPriceUpdate]) -> anyhow::Result<()> {
709 Ok(())
710 }
711
712 #[allow(unused_variables)]
713 fn on_historical_index_prices(
714 &mut self,
715 index_prices: &[IndexPriceUpdate],
716 ) -> anyhow::Result<()> {
717 Ok(())
718 }
719
720 #[allow(unused_variables)]
721 fn on_historical_funding_rates(
722 &mut self,
723 funding_rates: &[FundingRateUpdate],
724 ) -> anyhow::Result<()> {
725 Ok(())
726 }
727}
728
729#[must_use]
734pub fn strategy_vtable<T>() -> *const StrategyVTable
735where
736 T: PluginStrategy,
737{
738 &VTableTag::<T>::VTABLE
739}
740
741struct VTableTag<T>(PhantomData<T>);
742
743impl<T> VTableTag<T>
744where
745 T: PluginStrategy,
746{
747 const VTABLE: StrategyVTable = StrategyVTable {
748 create: Some(create_thunk::<T>),
749 drop_handle: Some(drop_handle_thunk::<T>),
750 type_name: Some(type_name_thunk::<T>),
751 on_start: Some(on_start_thunk::<T>),
752 on_stop: Some(on_stop_thunk::<T>),
753 on_resume: Some(on_resume_thunk::<T>),
754 on_reset: Some(on_reset_thunk::<T>),
755 on_dispose: Some(on_dispose_thunk::<T>),
756 on_degrade: Some(on_degrade_thunk::<T>),
757 on_fault: Some(on_fault_thunk::<T>),
758 on_time_event: Some(on_time_event_thunk::<T>),
759 on_data: Some(on_data_thunk::<T>),
760 on_instrument: Some(on_instrument_thunk::<T>),
761 on_book_deltas: Some(on_book_deltas_thunk::<T>),
762 on_book: Some(on_book_thunk::<T>),
763 on_quote: Some(on_quote_thunk::<T>),
764 on_trade: Some(on_trade_thunk::<T>),
765 on_bar: Some(on_bar_thunk::<T>),
766 on_mark_price: Some(on_mark_price_thunk::<T>),
767 on_index_price: Some(on_index_price_thunk::<T>),
768 on_funding_rate: Some(on_funding_rate_thunk::<T>),
769 on_option_greeks: Some(on_option_greeks_thunk::<T>),
770 on_option_chain: Some(on_option_chain_thunk::<T>),
771 on_instrument_status: Some(on_instrument_status_thunk::<T>),
772 on_instrument_close: Some(on_instrument_close_thunk::<T>),
773 on_signal: Some(on_signal_thunk::<T>),
774 on_order_initialized: Some(on_order_initialized_thunk::<T>),
775 on_order_submitted: Some(on_order_submitted_thunk::<T>),
776 on_order_accepted: Some(on_order_accepted_thunk::<T>),
777 on_order_rejected: Some(on_order_rejected_thunk::<T>),
778 on_order_filled: Some(on_order_filled_thunk::<T>),
779 on_order_canceled: Some(on_order_canceled_thunk::<T>),
780 on_order_expired: Some(on_order_expired_thunk::<T>),
781 on_order_triggered: Some(on_order_triggered_thunk::<T>),
782 on_order_denied: Some(on_order_denied_thunk::<T>),
783 on_order_emulated: Some(on_order_emulated_thunk::<T>),
784 on_order_released: Some(on_order_released_thunk::<T>),
785 on_order_pending_update: Some(on_order_pending_update_thunk::<T>),
786 on_order_pending_cancel: Some(on_order_pending_cancel_thunk::<T>),
787 on_order_modify_rejected: Some(on_order_modify_rejected_thunk::<T>),
788 on_order_cancel_rejected: Some(on_order_cancel_rejected_thunk::<T>),
789 on_order_updated: Some(on_order_updated_thunk::<T>),
790 on_position_opened: Some(on_position_opened_thunk::<T>),
791 on_position_changed: Some(on_position_changed_thunk::<T>),
792 on_position_closed: Some(on_position_closed_thunk::<T>),
793 on_market_exit: Some(on_market_exit_thunk::<T>),
794 on_historical_book_deltas: Some(on_historical_book_deltas_thunk::<T>),
795 on_historical_book_depth: Some(on_historical_book_depth_thunk::<T>),
796 on_historical_quotes: Some(on_historical_quotes_thunk::<T>),
797 on_historical_trades: Some(on_historical_trades_thunk::<T>),
798 on_historical_bars: Some(on_historical_bars_thunk::<T>),
799 on_historical_mark_prices: Some(on_historical_mark_prices_thunk::<T>),
800 on_historical_index_prices: Some(on_historical_index_prices_thunk::<T>),
801 on_historical_funding_rates: Some(on_historical_funding_rates_thunk::<T>),
802 };
803}
804
805unsafe extern "C" fn create_thunk<T: PluginStrategy>(
806 host: *const HostVTable,
807 ctx: *const HostContext,
808 config_json: BorrowedStr<'_>,
809) -> *mut PluginStrategyHandle {
810 guard_infallible("strategy::create", || {
811 let cfg = unsafe { config_json.as_str() };
814 Box::into_raw(Box::new(T::new(host, ctx, cfg))).cast::<PluginStrategyHandle>()
815 })
816}
817
818unsafe extern "C" fn drop_handle_thunk<T: PluginStrategy>(handle: *mut PluginStrategyHandle) {
819 if handle.is_null() {
820 return;
821 }
822 guard_infallible("strategy::drop", || {
823 unsafe {
825 drop(Box::from_raw(handle.cast::<T>()));
826 }
827 });
828}
829
830unsafe extern "C" fn type_name_thunk<T: PluginStrategy>() -> BorrowedStr<'static> {
831 BorrowedStr::from_str(T::TYPE_NAME)
832}
833
834fn handle_as_mut<'a, T: PluginStrategy>(handle: *mut PluginStrategyHandle) -> &'a mut T {
835 unsafe { &mut *handle.cast::<T>() }
838}
839
840fn ok_or_err<E: ::core::fmt::Display>(r: Result<(), E>) -> Result<(), PluginError> {
841 r.map_err(|e| PluginError::new(PluginErrorCode::Generic, e.to_string()))
842}
843
844macro_rules! lifecycle_thunk {
845 ($name:ident, $method:ident) => {
846 unsafe extern "C" fn $name<T: PluginStrategy>(
847 handle: *mut PluginStrategyHandle,
848 ) -> PluginResult<()> {
849 guard(|| {
850 let strategy = handle_as_mut::<T>(handle);
851 ok_or_err(strategy.$method())
852 })
853 }
854 };
855}
856
857lifecycle_thunk!(on_start_thunk, on_start);
858lifecycle_thunk!(on_stop_thunk, on_stop);
859lifecycle_thunk!(on_resume_thunk, on_resume);
860lifecycle_thunk!(on_reset_thunk, on_reset);
861lifecycle_thunk!(on_dispose_thunk, on_dispose);
862lifecycle_thunk!(on_degrade_thunk, on_degrade);
863lifecycle_thunk!(on_fault_thunk, on_fault);
864lifecycle_thunk!(on_market_exit_thunk, on_market_exit);
865
866macro_rules! event_thunk {
867 ($name:ident, $method:ident, $ty:ty) => {
868 unsafe extern "C" fn $name<T: PluginStrategy>(
869 handle: *mut PluginStrategyHandle,
870 value: *const $ty,
871 ) -> PluginResult<()> {
872 guard(|| {
873 let v = unsafe { &*value }.boundary_normalized();
876 let strategy = handle_as_mut::<T>(handle);
877 ok_or_err(strategy.$method(&v))
878 })
879 }
880 };
881}
882
883event_thunk!(on_time_event_thunk, on_time_event, TimeEvent);
884
885unsafe extern "C" fn on_data_thunk<T: PluginStrategy>(
886 handle: *mut PluginStrategyHandle,
887 data: PluginCustomDataRef,
888) -> PluginResult<()> {
889 guard(|| {
890 let strategy = handle_as_mut::<T>(handle);
891 ok_or_err(strategy.on_data(data))
892 })
893}
894
895unsafe extern "C" fn on_instrument_thunk<T: PluginStrategy>(
896 handle: *mut PluginStrategyHandle,
897 instrument: *const InstrumentAnyHandle,
898) -> PluginResult<()> {
899 guard(|| {
900 let v: InstrumentAny = unsafe { (*instrument).instrument() }.boundary_normalized();
903 let strategy = handle_as_mut::<T>(handle);
904 ok_or_err(strategy.on_instrument(&v))
905 })
906}
907
908unsafe extern "C" fn on_book_deltas_thunk<T: PluginStrategy>(
909 handle: *mut PluginStrategyHandle,
910 deltas: *const OrderBookDeltasHandle,
911) -> PluginResult<()> {
912 guard(|| {
913 let v: OrderBookDeltas = unsafe { (*deltas).deltas() }.boundary_normalized();
916 let strategy = handle_as_mut::<T>(handle);
917 ok_or_err(strategy.on_book_deltas(&v))
918 })
919}
920
921unsafe extern "C" fn on_book_thunk<T: PluginStrategy>(
922 handle: *mut PluginStrategyHandle,
923 book: *const OrderBookHandle,
924) -> PluginResult<()> {
925 guard(|| {
926 let v: OrderBook = unsafe { (*book).book() }.boundary_normalized();
929 let strategy = handle_as_mut::<T>(handle);
930 ok_or_err(strategy.on_book(&v))
931 })
932}
933
934event_thunk!(on_quote_thunk, on_quote, QuoteTick);
935event_thunk!(on_trade_thunk, on_trade, TradeTick);
936event_thunk!(on_bar_thunk, on_bar, Bar);
937event_thunk!(on_mark_price_thunk, on_mark_price, MarkPriceUpdate);
938event_thunk!(on_index_price_thunk, on_index_price, IndexPriceUpdate);
939event_thunk!(on_funding_rate_thunk, on_funding_rate, FundingRateUpdate);
940event_thunk!(on_option_greeks_thunk, on_option_greeks, OptionGreeks);
941
942unsafe extern "C" fn on_option_chain_thunk<T: PluginStrategy>(
943 handle: *mut PluginStrategyHandle,
944 chain: *const OptionChainSliceHandle,
945) -> PluginResult<()> {
946 guard(|| {
947 let v: OptionChainSlice = unsafe { (*chain).chain() }.boundary_normalized();
950 let strategy = handle_as_mut::<T>(handle);
951 ok_or_err(strategy.on_option_chain(&v))
952 })
953}
954
955event_thunk!(
956 on_instrument_status_thunk,
957 on_instrument_status,
958 InstrumentStatus
959);
960event_thunk!(
961 on_instrument_close_thunk,
962 on_instrument_close,
963 InstrumentClose
964);
965event_thunk!(on_signal_thunk, on_signal, Signal);
966
967event_thunk!(
968 on_order_initialized_thunk,
969 on_order_initialized,
970 OrderInitialized
971);
972event_thunk!(on_order_submitted_thunk, on_order_submitted, OrderSubmitted);
973event_thunk!(on_order_accepted_thunk, on_order_accepted, OrderAccepted);
974event_thunk!(on_order_rejected_thunk, on_order_rejected, OrderRejected);
975event_thunk!(on_order_filled_thunk, on_order_filled, OrderFilled);
976event_thunk!(on_order_canceled_thunk, on_order_canceled, OrderCanceled);
977event_thunk!(on_order_expired_thunk, on_order_expired, OrderExpired);
978event_thunk!(on_order_triggered_thunk, on_order_triggered, OrderTriggered);
979event_thunk!(on_order_denied_thunk, on_order_denied, OrderDenied);
980event_thunk!(on_order_emulated_thunk, on_order_emulated, OrderEmulated);
981event_thunk!(on_order_released_thunk, on_order_released, OrderReleased);
982event_thunk!(
983 on_order_pending_update_thunk,
984 on_order_pending_update,
985 OrderPendingUpdate
986);
987event_thunk!(
988 on_order_pending_cancel_thunk,
989 on_order_pending_cancel,
990 OrderPendingCancel
991);
992event_thunk!(
993 on_order_modify_rejected_thunk,
994 on_order_modify_rejected,
995 OrderModifyRejected
996);
997event_thunk!(
998 on_order_cancel_rejected_thunk,
999 on_order_cancel_rejected,
1000 OrderCancelRejected
1001);
1002event_thunk!(on_order_updated_thunk, on_order_updated, OrderUpdated);
1003
1004event_thunk!(on_position_opened_thunk, on_position_opened, PositionOpened);
1005event_thunk!(
1006 on_position_changed_thunk,
1007 on_position_changed,
1008 PositionChanged
1009);
1010event_thunk!(on_position_closed_thunk, on_position_closed, PositionClosed);
1011
1012macro_rules! slice_thunk {
1013 ($name:ident, $method:ident, $ty:ty) => {
1014 unsafe extern "C" fn $name<T: PluginStrategy>(
1015 handle: *mut PluginStrategyHandle,
1016 values: Slice<'_, $ty>,
1017 ) -> PluginResult<()> {
1018 guard(|| {
1019 let v: Vec<$ty> = unsafe { values.as_slice() }
1022 .iter()
1023 .map(BoundaryNormalize::boundary_normalized)
1024 .collect();
1025 let strategy = handle_as_mut::<T>(handle);
1026 ok_or_err(strategy.$method(&v))
1027 })
1028 }
1029 };
1030}
1031
1032slice_thunk!(
1033 on_historical_book_deltas_thunk,
1034 on_historical_book_deltas,
1035 OrderBookDelta
1036);
1037slice_thunk!(
1038 on_historical_book_depth_thunk,
1039 on_historical_book_depth,
1040 OrderBookDepth10
1041);
1042slice_thunk!(on_historical_quotes_thunk, on_historical_quotes, QuoteTick);
1043slice_thunk!(on_historical_trades_thunk, on_historical_trades, TradeTick);
1044slice_thunk!(on_historical_bars_thunk, on_historical_bars, Bar);
1045slice_thunk!(
1046 on_historical_mark_prices_thunk,
1047 on_historical_mark_prices,
1048 MarkPriceUpdate
1049);
1050slice_thunk!(
1051 on_historical_index_prices_thunk,
1052 on_historical_index_prices,
1053 IndexPriceUpdate
1054);
1055slice_thunk!(
1056 on_historical_funding_rates_thunk,
1057 on_historical_funding_rates,
1058 FundingRateUpdate
1059);