Strategy Development Patterns
A strategy owns execution decisions. Keep signal calculation, order intent, and asynchronous order state separate so historical and live behavior can be compared.
Select and verify the intended account before enabling a strategy. Develop with historical data, then playback or simulation on an explicitly selected LocalPaper account. Playback does not change the selected account, but the current release-candidate guard rejects strategy order mutations for Broker and Server Paper accounts while Playback is active. Treat that guard as a backstop, not as permission to leave an external account selected.
Configure once, decide on updates
Set safe defaults and protection in lifecycle setup, then make bar decisions:
public override void OnStateChanged()
{
if (State == State.SetDefaults)
{
Name = "Managed Cross";
Calculate = CalculateMode.OnBarClose;
IsManagedOrderMode = true;
}
else if (State == State.Configured)
{
SetStopLossTicks("Long", 12);
SetProfitTargetTicks("Long", 24);
}
}
public override void OnBarUpdate()
{
if (BarsInProgress != 0 || CurrentBar < 50)
return;
if (Ctx.Position.IsFlat && LongSignal())
EnterLong(1, "Long");
}
Use a stable signalName and the matching fromEntrySignal so managed exits and protection remain attributable to the entry.
Managed order surface
Managed helpers cover:
EnterLongandEnterShortmarket entries.EnterLongLimit,EnterShortLimit.EnterLongStopMarket,EnterShortStopMarket.ExitLong,ExitShortand their limit/stop-market variants.SetStopLoss/SetStopLossTicks.SetProfitTarget/SetProfitTargetTicks.
In managed mode, stored stop/target settings create OCO-linked protection after an entry fill. Configure protection before submitting the entry. Clear or replace a setting deliberately when it should no longer apply.
The Ctx.Orders facade exposes equivalent methods named
SetManagedStopLoss... and SetManagedProfitTarget..., but their argument
order differs. Prefer the inherited methods above for ordinary strategy code;
see the Strategy And Order Reference
before using the facade.
Direct submission
Use SubmitOrder(...) when the managed surface cannot express the required ownership and price behavior:
Order SubmitOrder(
int selectedBarsInProgress,
OrderAction orderAction,
OrderType orderType,
double quantity,
double limitPrice,
double stopPrice,
string? oco,
string signalName,
string? comment = null,
bool allowMoneyManagement = false,
Action<Order> beforeFirstOrderUpdate = null);
The current documented/tested public paths are market, limit, and stop-market orders. Do not infer complete provider support merely because the OrderType enum contains another value.
allowMoneyManagement remains in the signature for compatibility but is not an opt-in switch in the active release-candidate source. A selected money-management module runs automatically for Buy and SellShort entries, including managed entries; exits are not resized. See Research Extensions and verify the signed target build because this Preview behavior changed during release preparation.
Use CreateOcoGroup(...) for direct paired exits. Keep ownership explicit: strategy-scoped cancellation is safer than account-wide cancellation.
Submission is asynchronous
The returned Order is an identity and current snapshot, not proof of acceptance or fill.
public override void OnOrderUpdate(Order order)
{
// Track accepted, working, canceled, rejected, and filled states.
}
public override void OnExecutionUpdate(Order order)
{
// Reconcile fills and partial fills.
}
- Prevent the same signal from submitting repeatedly.
- Handle partial fills, changed quantity, rejection, cancellation, and replacement.
- Clear local order references only after a terminal state.
- Reconcile position and working orders after reconnect.
- Never treat a bar signal as an execution callback.
Runtime fault containment
A live strategy calculation error skips that update. After ten consecutive live calculation errors, HyperionX suspends new entries while leaving exits and protection available.
Inspect:
AreEntriesSuspended.LastRuntimeError.ConsecutiveRuntimeErrors.RuntimeStatusText.
Call ResumeEntriesAfterFault() only after correcting the cause and reconciling account, position, and working orders. Historical and validation failures can abort the run instead of applying the live policy.
Stop and recompile behavior
Override OnStrategyStopping() to release explicit subscriptions, timers, and background work. Do not depend on State.Finalized or State.Terminated.
An enabled strategy can remain attached to its old assembly during a compile and is marked out of date. Disable and recreate it after runtime activation. Toggling the same existing object off and on is not proof that the newly compiled type is running.
Historical-to-live position sync
The current release-candidate source includes a Preview HistoricalPositionSyncMode:
Disabledis the default.AdoptOwnedExactMatchcan adopt only an exact, owned position match in the expected strategy scope.- A mismatch blocks new entries; it does not create, flatten, or repair a position.
Because this surface is still in the unreleased working tree, do not make a distributed 1.1.10 extension require it until the packaged build is frozen and verified.
Validation ladder
- Run a deterministic historical case with written expected trades.
- Include supported commission and warm-up settings, use realistic session data, and record or sensitivity-test the current lack of configurable slippage.
- Test no-data, disconnect, rejected order, partial fill, and restart paths.
- Run playback with an explicitly selected
LocalPaperaccount. - Run simulation with the intended provider and connection.
- Compare orders, executions, position, protection, and performance across modes.
- Require a separate operational review before enabling a live account.
Continue with the Strategy and Order reference, Backtesting, Validation, and Risk and Security.