# [Build Your First Strategy](https://www.hyperionx.support/developers/first-strategy)

> Create, compile, load, and simulation-test a HyperionX strategy with managed entries, stops, targets, and exits.

This is the shortest supported path from a blank Code Lab file to a strategy that can submit managed orders. The example is intentionally complete so a developer or AI coding assistant can adapt it without borrowing APIs from another trading platform.

| Difficulty | Time | Applies to |
| --- | --- | --- |
| Beginner | About 20 minutes | HyperionX 1.1.10 and the documented release-candidate custom runtime |

:::danger Use LocalPaper
A strategy can place real orders when enabled on an external account. Compile first, then test on a chart with an explicitly selected `LocalPaper` account. Playback changes market data; it does not select `LocalPaper` for you.
:::

## What You Will Build

The strategy:

- calculates fast and slow moving averages;
- enters long or short when they cross;
- registers a stop loss and profit target before each entry;
- closes an open position on the opposite cross;
- exposes editable quantity and risk parameters;
- prints order-state and execution updates for verification.

This is an API example, not a profitable-trading claim.

## 1. Create The Strategy File

1. In HyperionX, open **Tools > Code Lab**.
2. Select **Strategy** as the script type.
3. Select **Blank strategy** as the template.
4. Select **New**.
5. Replace the generated source with the complete example below.

Code Lab stores strategy source under:

```text
%USERPROFILE%\Documents\HyperionX\Bin\Custom\Strategies
```

Keep the class name unique. A duplicate public class anywhere in the custom project can block the entire custom assembly.

## 2. Use A Complete Managed Strategy

```csharp
using System.ComponentModel.DataAnnotations;
using HyperionX.Core.Attributes;
using HyperionX.Core.Enums;
using HyperionX.Core.Market;

namespace HyperionX.Custom.Strategies;

public class FirstManagedStrategy : Strategy
{
    private const string LongEntry = "Long Entry";
    private const string ShortEntry = "Short Entry";

    [HyperionXProperty]
    [Display(Name = "Fast period", GroupName = "Signals", Order = 1)]
    [Range(1, 200)]
    public int FastPeriod { get; set; }

    [HyperionXProperty]
    [Display(Name = "Slow period", GroupName = "Signals", Order = 2)]
    [Range(2, 500)]
    public int SlowPeriod { get; set; }

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

    [HyperionXProperty]
    [Display(Name = "Stop ticks", GroupName = "Risk", Order = 11)]
    [Range(1, 10000)]
    public double StopTicks { get; set; }

    [HyperionXProperty]
    [Display(Name = "Target ticks", GroupName = "Risk", Order = 12)]
    [Range(1, 10000)]
    public double TargetTicks { get; set; }

    public override void OnStateChanged()
    {
        if (State == State.SetDefaults)
        {
            Name = "First Managed Strategy";
            Version = "1.0";
            Calculate = CalculateMode.OnBarClose;
            IsManagedOrderMode = true;

            FastPeriod = 9;
            SlowPeriod = 21;
            Quantity = 1;
            StopTicks = 20;
            TargetTicks = 40;
        }
    }

    public override void OnBarUpdate()
    {
        if (BarsInProgress != 0 || CurrentBar < SlowPeriod + 1)
            return;

        double fast = AverageClose(FastPeriod);
        double slow = AverageClose(SlowPeriod);
        double priorFast = AverageClose(FastPeriod, 1);
        double priorSlow = AverageClose(SlowPeriod, 1);

        bool crossedUp = priorFast <= priorSlow && fast > slow;
        bool crossedDown = priorFast >= priorSlow && fast < slow;

        if (Ctx.Position.IsFlat && crossedUp)
        {
            SetStopLossTicks(LongEntry, StopTicks);
            SetProfitTargetTicks(LongEntry, TargetTicks);
            EnterLong(Quantity, LongEntry);
        }
        else if (Ctx.Position.IsFlat && crossedDown)
        {
            SetStopLossTicks(ShortEntry, StopTicks);
            SetProfitTargetTicks(ShortEntry, TargetTicks);
            EnterShort(Quantity, ShortEntry);
        }
        else if (Ctx.Position.MarketPosition == MarketPosition.Long && crossedDown)
        {
            ExitLong(0, "Long Cross Exit", LongEntry);
        }
        else if (Ctx.Position.MarketPosition == MarketPosition.Short && crossedUp)
        {
            ExitShort(0, "Short Cross Exit", ShortEntry);
        }
    }

    public override void OnOrderUpdate(Order order)
    {
        if (order == null)
            return;

        Print(
            $"ORDER {order.Name}: {order.OrderState}, " +
            $"quantity={order.Quantity}, filled={order.FilledQuantity}");
    }

    public override void OnExecutionUpdate(Order order)
    {
        if (order == null)
            return;

        Print(
            $"FILL {order.Name}: filled={order.FilledQuantity}, " +
            $"price={order.FillPrice}");
    }

    private double AverageClose(int period, int barsAgo = 0)
    {
        double sum = 0;

        for (int index = barsAgo; index < barsAgo + period; index++)
            sum += Close[index];

        return sum / period;
    }
}
```

## 3. Understand The Order Calls

The order sequence is deliberate:

```csharp
SetStopLossTicks(LongEntry, StopTicks);
SetProfitTargetTicks(LongEntry, TargetTicks);
EnterLong(Quantity, LongEntry);
```

| Call | Meaning |
| --- | --- |
| `SetStopLossTicks("Long Entry", 20)` | Register protection 20 ticks from the fill for the entry named `Long Entry`. |
| `SetProfitTargetTicks("Long Entry", 40)` | Register a target 40 ticks from the fill for that same entry. |
| `EnterLong(1, "Long Entry")` | Submit a managed market entry for quantity 1. |

`"Long Entry"` is not a comment. It is the relationship key between the entry and its protection. The value must match exactly, including spaces and capitalization.

Do not confuse these two uses of “stop”:

| Intent | Supported managed call |
| --- | --- |
| Enter only after price rises to a breakout level | `EnterLongStopMarket(quantity, stopPrice, signalName)` |
| Enter only after price falls to a downside breakout level | `EnterShortStopMarket(quantity, stopPrice, signalName)` |
| Protect an entry after it fills | `SetStopLoss(...)` or `SetStopLossTicks(...)` before the entry |

## 4. Compile The Complete Custom Project

1. Save the strategy.
2. Disable any affected strategy that is already running.
3. Select **Build** or **Compile Project**.
4. Fix every compile error, including errors in unrelated custom files.
5. Confirm the build completes successfully.

Code Lab compiles all custom source into one `HyperionX.Custom.dll`. One broken indicator or duplicate class can prevent this strategy from appearing.

## 5. Load It On A Test Chart

1. Open a chart with historical data.
2. Use the chart's **Strategies** toolbar button or chart context menu.
3. Select **First Managed Strategy**.
4. Select and verify a `LocalPaper` account.
5. Review the instrument, timeframe, quantity, stop ticks, and target ticks.
6. Enable the strategy.
7. Keep **Orders**, **Positions**, **Strategies**, and **Output** visible.

Do not use the main **New > Strategy** command for a local Code Lab strategy. That command opens the server-provisioned catalog.

After rebuilding, remove and add the strategy again, or reload its owning chart or strategy host. Toggling the old object off and on can keep the old assembly.

## 6. Verify Behavior

Before changing the signal logic, prove the order lifecycle:

1. The strategy appears in the chart selector.
2. It calculates without runtime errors.
3. At most one entry is submitted for a cross.
4. The entry signal name is correct.
5. A stop and target appear after the entry fills.
6. The stop and target use the intended prices and quantity.
7. Filling one protective order cancels its OCO peer.
8. `OnOrderUpdate` reports submitted, working, filled, cancelled, or rejected states.
9. `OnExecutionUpdate` reports actual fills.
10. Disabling the strategy produces the expected provider-side order and position state.

`LocalPaper` is a simplified full-fill simulator. Repeat provider-specific tests in the intended paper environment before considering live routing.

## Entry And Exit Recipes

Use these inherited managed helpers for ordinary strategies:

```csharp
// Market entries
EnterLong(1, "Long");
EnterShort(1, "Short");

// Limit entries
EnterLongLimit(1, buyLimitPrice, "Long Limit");
EnterShortLimit(1, sellLimitPrice, "Short Limit");

// Stop-market entries
EnterLongStopMarket(1, buyStopPrice, "Long Breakout");
EnterShortStopMarket(1, sellStopPrice, "Short Breakout");

// Exit the available position quantity; 0 resolves the current quantity.
ExitLong(0, "Exit Long", "Long");
ExitShort(0, "Exit Short", "Short");
```

For the complete overload list and lower-level order methods, use the [Strategy And Order Reference](https://www.hyperionx.support/reference-strategies-orders).

## Give These Sources To An AI

An AI assistant should read the Markdown versions, in this order:

1. [Build Your First Strategy](https://www.hyperionx.support/_llm/developers/first-strategy.md)
2. [Strategy And Order Reference](https://www.hyperionx.support/_llm/reference-strategies-orders.md)
3. [Strategy Development](https://www.hyperionx.support/_llm/strategy-development.md)
4. [Script Troubleshooting](https://www.hyperionx.support/_llm/troubleshooting-scripts.md)

Copy and adapt this prompt:

```text
Read the four HyperionX Markdown pages linked above before writing code.

Build one complete HyperionX Code Lab strategy in namespace
HyperionX.Custom.Strategies that derives from Strategy.

Use only APIs documented on those pages. Prefer inherited managed methods:
EnterLong/EnterShort, their Limit and StopMarket variants, ExitLong/ExitShort,
SetStopLoss or SetStopLossTicks, and SetProfitTarget or
SetProfitTargetTicks. Set protection before its matching entry and use the
exact same signal name. Guard early bars and BarsInProgress. Expose bounded
parameters with HyperionXProperty and Range. Include OnOrderUpdate and
OnExecutionUpdate when order state matters.

Do not use NinjaTrader, QuantConnect, TradingView, broker-SDK, Buy, Sell,
ShortSell, Cover, OnStateChange, OnData, or invented HyperionX methods.
Return one complete compilable .cs file, then list any behavior or provider
assumption that still requires simulation testing.

Strategy rules:
[describe entries, filters, exits, sizing, stop, target, and timeframe here]
```

If an AI proposes an unfamiliar helper, verify it against the [Strategy And Order Reference](https://www.hyperionx.support/reference-strategies-orders) before compiling.
