Can you create a script that triggers with a hotkey (F2) and automatically places a stop-loss and take-profit order based on the ATR value of the candle at the moment the key is pressed?
The logic should work like this:
• When F2 is pressed, the script calculates the ATR of the current candle.
• That ATR value is then rounded:
• If the decimal part is less than 0.06 (e.g., 5.45), round down to the nearest 0.10 (result: 5.40).
• If it is 0.06 or higher (e.g., 5.46), round up to the next 0.10 (result: 5.50).
• Multiply the rounded value by 10 to get the base tick amount (e.g., 5.40 × 10 = 54).
• Add 10 ticks for margin (e.g., 54 + 10 = 64 ticks).
• This final tick value will be used for both the stop-loss and take-profit, ensuring a 1:1 risk-to-reward ratio.
• The trade should be sized to risk exactly $100, meaning the number of contracts must be calculated based on the tick value and tick size of the instrument.
• All of this should happen automatically when pressing F2 on the chart.
This setup is intended for futures trading, where positions are based on ticks and contracts.
Then this code is result:
using NinjaTrader.NinjaScript;
using NinjaTrader.NinjaScript.Strategies;
using NinjaTrader.NinjaScript.Indicators;
using NinjaTrader.NinjaScript.AddOns;
namespace NinjaTrader.NinjaScript.Strategies
{
public class ATRHotkeyStrategy : Strategy
{
private double riskPerTrade = 100;
private double tickValue;
private double tickSize;
private double currentATR;
private int stopTicks;
private int contracts;
protected override void OnStateChange()
{
if (State == State.SetDefaults)
{
Name = "ATR Hotkey Strategy";
Calculate = MarketCalculate.OnBarClose;
IsOverlay = false;
EntriesPerDirection = 1;
EntryHandling = EntryHandling.AllEntries;
IsExitOnSessionCloseStrategy = true;
ExitOnSessionCloseSeconds = 30;
IncludeCommission = true;
IsUnmanaged = false;
}
else if (State == State.Configure)
{
// Add 1-minute bars or adjust if needed
AddDataSeries(Data.BarsPeriodType.Minute, 1);
}
}
protected override void OnBarUpdate()
{
if (CurrentBar < 20) return;
if (BarsInProgress != 0) return;
// Only react in real-time and once per bar
if (State != State.Realtime || !Bars.IsLastBarOfChart) return;
// Check global hotkey trigger set by AddOn
if (!F2HotkeyTriggerAddOn.TriggerSignal)
return;
// Reset trigger immediately
F2HotkeyTriggerAddOn.TriggerSignal = false;
ExecuteTradeWithATR();
}
private void ExecuteTradeWithATR()
{
tickSize = TickSize;
tickValue = Instrument.MasterInstrument.PointValue * tickSize;
currentATR = ATR(14)[0];
// Round ATR to nearest 0.10 based on rules
double roundedATR = Math.Floor(currentATR * 10) / 10.0;
if ((currentATR * 10) % 10 >= 6)
roundedATR = Math.Ceiling(currentATR * 10) / 10.0;
// Calculate stop in ticks and risk per contract
stopTicks = (int)(roundedATR * 10 + 10);
double dollarPerContractRisk = stopTicks * tickValue;
// Calculate number of contracts to stay within fixed $100 risk
contracts = (int)Math.Floor(riskPerTrade / dollarPerContractRisk);
if (contracts < 1)
{
Print("ATR too small or tick value too high to allow $100 risk with even 1 contract.");
return;
}
// Close any open positions first
if (Position.MarketPosition != MarketPosition.Flat)
{
ExitLong("ExitLong");
ExitShort("ExitShort");
}
// Place a long entry with stop loss and profit target
EnterLong(contracts, "F2Entry");
SetStopLoss("F2Entry", CalculationMode.Ticks, stopTicks, false);
SetProfitTarget("F2Entry", CalculationMode.Ticks, stopTicks);
}
}
}

Comment