Skip to main content

HX103 Strategies

HX103 converts the strategy lessons into HyperionX's order model. The sequence is market entry, limit entry, stop entry, filters, fixed exits, dynamic exits, conditional exits, then a complete modular system.

Lesson 1: Clean Strategy Shape

Keep strategy logic in modules:

OnBarUpdate
-> EntryModule
-> FilterModule
-> ExitModule
-> RiskModule

This prevents one large OnBarUpdate() method from becoming impossible to debug.

Lesson 2: Market Entry

Use managed helpers first. They are easier to read and let HyperionX handle common order registration.

using System.ComponentModel.DataAnnotations;
using HyperionX.Core.Attributes;
using HyperionX.Core.Enums;
using HyperionX.Core.Market;
using HyperionX.Custom.Indicators;

namespace HyperionX.Custom.Strategies;

public class HXMaCrossCourse : Strategy
{
private SMA _fast;
private SMA _slow;

[HyperionXProperty]
[Display(Name = "Fast Period", GroupName = "Entry", Order = 0)]
public int FastPeriod { get; set; }

[HyperionXProperty]
[Display(Name = "Slow Period", GroupName = "Entry", Order = 1)]
public int SlowPeriod { get; set; }

[HyperionXProperty]
[Display(Name = "Quantity", GroupName = "Risk", Order = 0)]
public double Quantity { get; set; }

public override void OnStateChanged()
{
if (State == State.SetDefaults)
{
Name = "HX MA Cross Course";
Version = "1.0";
FastPeriod = 9;
SlowPeriod = 21;
Quantity = 1;
IsManagedOrderMode = true;
}
else if (State == State.Configured)
{
_fast = SMA(FastPeriod);
_slow = SMA(SlowPeriod);
SetStopLossTicks(20);
SetProfitTargetTicks(40);
}
}

public override void OnBarUpdate()
{
if (CurrentBar < SlowPeriod + 1)
return;

bool crossedUp = _fast[0] > _slow[0] && _fast[1] <= _slow[1];
bool crossedDown = _fast[0] < _slow[0] && _fast[1] >= _slow[1];

if (LastPosition.MarketPosition == MarketPosition.Flat && crossedUp)
EnterLong(Quantity, "MA Cross Long");

if (LastPosition.MarketPosition == MarketPosition.Long && crossedDown)
ExitLong("MA Cross Exit", "MA Cross Long");
}
}

Lesson 3: Filters

Filters should return true when trading is allowed or false when blocked.

private bool PassesTimeFilter()
{
int hour = DateTime[0].Hour;
return hour >= 9 && hour < 16;
}

Call filters before placing an entry order.

Lesson 4: Limit Entry

Limit orders need state and timeout handling.

private Order _entryOrder;
private int _entryOrderBar = -1;

private void PlaceLongLimit(double limitPrice)
{
_entryOrder = SubmitOrder(0, OrderAction.Buy, OrderType.Limit, 1, limitPrice, 0, "", "Long Limit");
_entryOrderBar = CurrentBar;
}

private void CancelStaleEntry()
{
if (_entryOrder == null)
return;

if (CurrentBar - _entryOrderBar >= 3)
{
CancelOrder(_entryOrder);
_entryOrder = null;
_entryOrderBar = -1;
}
}

Lesson 5: Stop Entry

Stop entries are for breakout logic.

double breakoutPrice = High[1] + TickSize;
SubmitOrder(0, OrderAction.Buy, OrderType.StopMarket, 1, 0, breakoutPrice, "", "Breakout Long");

Use direct orders when you need exact order type control.

Lesson 6: Fixed Exits

Begin with managed exits:

SetStopLossTicks("MA Cross Long", 20);
SetProfitTargetTicks("MA Cross Long", 40);

Use direct SubmitOrder exits only when teaching OCO strings, scale-outs, partial exits, or custom order state.

Lesson 7: Dynamic Exits

Dynamic exits change as the trade moves. Keep the rules explicit:

  • Break-even trigger.
  • Trail trigger.
  • Trail distance.
  • Whether the stop has already moved.
  • The order being replaced.

Completion check:

  • Entry logic is separated from filters and exits.
  • No duplicate entry is sent while already in a position.
  • Limit and stop orders are cancelled when stale.
  • State is reset on full exit.
  • Every order has a useful signal name.