HOW NewsStraddleOrchestrator WORKS - Detailed AnalysisΒΆ
π― Document PurposeΒΆ
Show WHAT the orchestrator consists of and HOW EXACTLY it works at the code, methods and data level. Special attention is paid to the timing of order placement before news and handling three breakout scenarios.
π¦ What the orchestrator is made ofΒΆ
1. Class structure (lines 13-28)ΒΆ
public class NewsStraddleOrchestrator
{
// β SINGLE DEPENDENCY
// ββββββββββββββββββββββββββββββββββββββββββ
private readonly MT5Service _service;
// β 7 CONFIGURABLE PARAMETERS
// ββββββββββββββββββββββββββββββββββββββββββ
public string Symbol { get; set; } = "EURUSD";
public int StraddleDistancePoints { get; set; } = 15;
public double Volume { get; set; } = 0.02;
public int StopLossPoints { get; set; } = 20;
public int TakeProfitPoints { get; set; } = 40;
public int SecondsBeforeNews { get; set; } = 60; // β Countdown timer
public int MaxWaitAfterNewsSeconds { get; set; } = 180; // β Breakout timeout
public NewsStraddleOrchestrator(MT5Service service)
{
_service = service;
}
}
Dependency visualizationΒΆ
β NewsStraddleOrchestrator
β
β β private readonly MT5Service _service
β ββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββ
βββββββββββββββββββββββββββΌββββββββββββββββββββββββββββββββββ
β
βΌ
β MT5Service
β
β β private MT5Account _account
β ββββββββββββββββ¬ββββββββββββββββ
βββββββββββββββββββΌββββββββββββββββββββ
β
βΌ
β MT5Account
β
β β gRPC Client
β ββββββββββββββββββββ
ββββββββββββββββββββββββββ
β
βΌ
[MT5 Terminal]
π How ExecuteAsync() works - step by stepΒΆ
Phase 1: Initialization (lines 30-41)ΒΆ
public async Task<double> ExecuteAsync(CancellationToken ct = default)
{
Console.WriteLine("\n+============================================================+");
Console.WriteLine("| NEWS STRADDLE ORCHESTRATOR |");
Console.WriteLine("+============================================================+\n");
var initialBalance = await _service.GetBalanceAsync();
Console.WriteLine($" Starting balance: ${initialBalance:F2}");
Console.WriteLine($" Symbol: {Symbol}");
Console.WriteLine($" Straddle distance: {StraddleDistancePoints} pts");
Console.WriteLine($" Volume: {Volume:F2} lots");
Console.WriteLine($" SL: {StopLossPoints} pts | TP: {TakeProfitPoints} pts\n");
}
Phase 2: Countdown until news (lines 44-51)ΒΆ
try
{
// β CRITICAL TIMING:
// β Wait SecondsBeforeNews seconds until the event
// ββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Console.WriteLine($" β² Waiting {SecondsBeforeNews}s before news event...\n");
await Task.Delay(SecondsBeforeNews * 1000, ct);
// β Get current price IMMEDIATELY before
// β placing orders (maximum accuracy)
// ββββββββββββββββββββββββββββββββββββββββββββββββββββββ
var tick = await _service.SymbolInfoTickAsync(Symbol);
Console.WriteLine($" π° NEWS EVENT IMMINENT!");
Console.WriteLine($" Current: Bid={tick.Bid:F5}, Ask={tick.Ask:F5}\n");
}
Key timing moment:
EXAMPLE: NFP releases at 13:30:00 UTC
Orchestrator launch:
User: await orchestrator.ExecuteAsync() @ 13:29:00
Countdown:
SecondsBeforeNews = 60
Task.Delay(60000) β wait 60 seconds
Order placement:
@ 13:30:00 (exactly when news releases!)
IMPORTANT:
- Too early β risk triggering from noise
- Too late β miss the beginning of movement
- 60 seconds = optimal balance
Phase 3: Placing the straddle (lines 53-91)ΒΆ
3.1. Placing BuyStop (upper order)ΒΆ
// β BUY STOP: Catches upward breakout
// ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Console.WriteLine(" Placing BUY STOP (upper straddle)...");
var buyStopResult = await _service.BuyStopPoints(
symbol: Symbol, // "EURUSD"
volume: Volume, // 0.02
priceOffsetPoints: StraddleDistancePoints, // +15 (POSITIVE!)
slPoints: StopLossPoints, // 20
tpPoints: TakeProfitPoints, // 40
comment: "News-Buy"
);
if (buyStopResult.ReturnedCode != 10009)
{
Console.WriteLine($" β BUY STOP failed: {buyStopResult.Comment}\n");
return 0; // β EMERGENCY EXIT
}
Console.WriteLine($" β BUY STOP: #{buyStopResult.Order}\n");
How BuyStopPoints() works for straddleΒΆ
// MT5Sugar.cs (extension method)
public static async Task<OrderSendData> BuyStopPoints(
this MT5Service service,
string symbol,
double volume,
int priceOffsetPoints, // β RECEIVES +15
int slPoints = 0,
int tpPoints = 0,
string comment = ""
)
{
// β STEP 1: Get current Ask price
// ββββββββββββββββββββββββββββββββββββββββββββββββββββββ
var tick = await service.SymbolInfoTickAsync(symbol);
double askPrice = tick.Ask; // For example: 1.10002
// β STEP 2: Get point size
// ββββββββββββββββββββββββββββββββββββββββββββββββββββββ
var symbolInfo = await service.SymbolInfoAsync(symbol);
double point = symbolInfo.Point; // 0.00001
// β STEP 3: Calculate BUY STOP price
// β BUY STOP is placed ABOVE current price
// β
// β priceOffsetPoints = +15 (POSITIVE!)
// β price = askPrice + (priceOffsetPoints Γ point)
// β = 1.10002 + (15 Γ 0.00001)
// β = 1.10002 + 0.00015
// β = 1.10017
// ββββββββββββββββββββββββββββββββββββββββββββββββββββββ
double price = askPrice + (priceOffsetPoints * point);
// β STEP 4: Calculate SL and TP for BUY STOP
// β
// β sl = price - (slPoints Γ point)
// β = 1.10017 - (20 Γ 0.00001)
// β = 1.09997
// β
// β tp = price + (tpPoints Γ point)
// β = 1.10017 + (40 Γ 0.00001)
// β = 1.10057
// ββββββββββββββββββββββββββββββββββββββββββββββββββββββ
double sl = slPoints > 0 ? price - (slPoints * point) : 0;
double tp = tpPoints > 0 ? price + (tpPoints * point) : 0;
// β STEP 5: Call low-level BuyStopAsync
// ββββββββββββββββββββββββββββββββββββββββββββββββββββββ
return await service.BuyStopAsync(
symbol: symbol,
volume: volume,
price: price, // 1.10017
sl: sl, // 1.09997
tp: tp, // 1.10057
comment: comment
);
}
3.2. Placing SellStop (lower order)ΒΆ
// β SELL STOP: Catches downward breakout
// ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Console.WriteLine(" Placing SELL STOP (lower straddle)...");
var sellStopResult = await _service.SellStopPoints(
symbol: Symbol,
volume: Volume,
priceOffsetPoints: -StraddleDistancePoints, // -15 (NEGATIVE!)
slPoints: StopLossPoints,
tpPoints: TakeProfitPoints,
comment: "News-Sell"
);
if (sellStopResult.ReturnedCode != 10009)
{
Console.WriteLine($" β SELL STOP failed: {sellStopResult.Comment}");
Console.WriteLine(" Canceling BUY STOP...");
// β CRITICALLY IMPORTANT:
// β If second order failed β cancel first one
// ββββββββββββββββββββββββββββββββββββββββββββββββββ
await _service.CloseByTicket(buyStopResult.Order);
return 0;
}
Console.WriteLine($" β SELL STOP: #{sellStopResult.Order}\n");
Console.WriteLine(" β
STRADDLE ACTIVE - Waiting for news spike!\n");
SellStop price calculationΒΆ
Current Bid price: 1.10000
StraddleDistancePoints: 15 (but we use -15)
point: 0.00001
price = bidPrice + (priceOffsetPoints Γ point)
= 1.10000 + (-15 Γ 0.00001)
= 1.10000 - 0.00015
= 1.09985
sl = price + (slPoints Γ point) β PLUS for SELL!
= 1.09985 + (20 Γ 0.00001)
= 1.10005
tp = price - (tpPoints Γ point) β MINUS for SELL!
= 1.09985 - (40 Γ 0.00001)
= 1.09945
Result of straddle placementΒΆ
MT5 Terminal state AFTER straddle placement:
ββββββββββββββββββββ¬βββββββββββββββββββββββββββββ
β PENDING ORDERS β OPEN POSITIONS
ββββββββββββββββββββΌβββββββββββββββββββββββββββββ
β #123456789: β (empty)
β BUY STOP 0.02 β
β @ 1.10017 β
β SL: 1.09997 β
β TP: 1.10057 β
β β
β #123456790: β
β SELL STOP 0.02 β
β @ 1.09985 β
β SL: 1.10005 β
β TP: 1.09945 β
ββββββββββββββββββββ΄βββββββββββββββββββββββββββββ
VISUALIZATION:
β Price rises
β
1.10057 ββββ TP for BuyStop
1.10017 ββββ BUY STOP (upward breakout)
1.09997 ββββ SL for BuyStop
β
1.10002 ββββ Current Ask
1.10000 ββββ Current Bid
β
1.10005 ββββ SL for SellStop
1.09985 ββββ SELL STOP (downward breakout)
1.09945 ββββ TP for SellStop
β
β Price falls
Phase 4: Monitoring for breakout (lines 94-136)ΒΆ
This is the key phase - determining which order triggered after news release.
var monitorStart = DateTime.UtcNow;
var timeout = TimeSpan.FromSeconds(MaxWaitAfterNewsSeconds);
ulong? executedOrder = null;
ulong? pendingOrder = null;
string direction = "";
// β MONITORING LOOP (every 1 sec, max 3 minutes)
// β FASTER than PendingBreakout (news requires speed!)
// ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
while (DateTime.UtcNow - monitorStart < timeout && !ct.IsCancellationRequested)
{
await Task.Delay(1000, ct); // Every second!
// β Get list of PENDING ORDERS
// ββββββββββββββββββββββββββββββββββββββββββββββββββ
var tickets = await _service.OpenedOrdersTicketsAsync();
bool buyStillPending = false;
bool sellStillPending = false;
// β Check if our orders are in the list
// ββββββββββββββββββββββββββββββββββββββββββββββββββ
foreach (var ticket in tickets.OpenedOrdersTickets)
{
if (ticket == (long)buyStopResult.Order) buyStillPending = true;
if (ticket == (long)sellStopResult.Order) sellStillPending = true;
}
// β BREAKOUT SCENARIO DETECTION (4 options)
// ββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// SCENARIO 1: UPWARD BREAKOUT
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
if (!buyStillPending && sellStillPending)
{
// BuyStop DISAPPEARED (executed) β became position
// SellStop STILL PENDING β not executed
executedOrder = buyStopResult.Order;
pendingOrder = sellStopResult.Order;
direction = "UPWARD";
break;
}
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// SCENARIO 2: DOWNWARD BREAKOUT
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
else if (buyStillPending && !sellStillPending)
{
// SellStop DISAPPEARED (executed)
// BuyStop STILL PENDING
executedOrder = sellStopResult.Order;
pendingOrder = buyStopResult.Order;
direction = "DOWNWARD";
break;
}
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// SCENARIO 3: BOTH TRIGGERED (extreme volatility!)
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
else if (!buyStillPending && !sellStillPending)
{
// Both orders DISAPPEARED β both became positions!
// Price whipsawed up AND down very quickly
Console.WriteLine(" β‘ BOTH ORDERS TRIGGERED - Extreme volatility!");
direction = "BOTH";
break;
}
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// SCENARIO 4: BOTH STILL PENDING (continue waiting)
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// else: both orders still in list β news didn't cause breakout
}
Detailed breakout detection logicΒΆ
STATE BEFORE NEWS (T=0):
MT5 Terminal:
ββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββββββ
β PENDING ORDERS β OPEN POSITIONS β
ββββββββββββββββββββΌβββββββββββββββββββββββββββββββββββββββββ€
β 789: BUY STOP β (empty) β
β 790: SELL STOP β β
ββββββββββββββββββββ΄βββββββββββββββββββββββββββββββββββββββββ
OpenedOrdersTicketsAsync() β OpenedOrdersTickets: [789, 790]
buyStillPending = true (789 found)
sellStillPending = true (790 found)
β Both pending β continue waiting
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
NEWS RELEASED (T=1s): NFP better than expected β price up!
Price: 1.10000 β 1.10010 β 1.10017 β 1.10020...
MT5 Terminal (T=2s):
ββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββββββ
β PENDING ORDERS β OPEN POSITIONS β
ββββββββββββββββββββΌβββββββββββββββββββββββββββββββββββββββββ€
β 790: SELL STOP β 789: BUY 0.02 @ 1.10017 β
β β (BuyStop triggered!) β
ββββββββββββββββββββ΄βββββββββββββββββββββββββββββββββββββββββ
OpenedOrdersTicketsAsync() β OpenedOrdersTickets: [790]
(BuyStop 789 DISAPPEARED!)
buyStillPending = false β 789 NOT found!
sellStillPending = true β 790 still in list
if (!buyStillPending && sellStillPending) β TRUE!
{
direction = "UPWARD";
executedOrder = 789;
pendingOrder = 790;
break; β Exit monitoring
}
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
SCENARIO 3: Extreme volatility
News released UNEXPECTEDLY β price jerked DOWN:
1.10000 β 1.09985 (SellStop triggered!)
Then SHARPLY UP (correction):
1.09985 β 1.10017 (BuyStop also triggered!)
MT5 Terminal:
ββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββββββ
β PENDING ORDERS β OPEN POSITIONS β
ββββββββββββββββββββΌβββββββββββββββββββββββββββββββββββββββββ€
β (empty) β 789: BUY 0.02 @ 1.10017 β
β β 790: SELL 0.02 @ 1.09985 β
ββββββββββββββββββββ΄βββββββββββββββββββββββββββββββββββββββββ
OpenedOrdersTicketsAsync() β OpenedOrdersTickets: []
(BOTH DISAPPEARED!)
buyStillPending = false
sellStillPending = false
if (!buyStillPending && !sellStillPending) β TRUE!
{
Console.WriteLine("β‘ BOTH ORDERS TRIGGERED - Extreme volatility!");
direction = "BOTH";
break;
}
Phase 5: Handling breakout result (lines 138-161)ΒΆ
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// SCENARIO A: ONE ORDER TRIGGERED (normal breakout)
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
if (executedOrder.HasValue && pendingOrder.HasValue)
{
Console.WriteLine($" π {direction} BREAKOUT DETECTED!");
Console.WriteLine($" Position opened: #{executedOrder.Value}");
Console.WriteLine($" Canceling opposite order #{pendingOrder.Value}...");
// β OCO mechanism: cancel opposite order
// ββββββββββββββββββββββββββββββββββββββββββββββββββ
await _service.CloseByTicket(pendingOrder.Value);
Console.WriteLine(" β Opposite order canceled\n");
// β Hold position for 60 seconds
// β SL or TP may trigger during this time
// ββββββββββββββββββββββββββββββββββββββββββββββββββ
Console.WriteLine(" β³ Holding position for 60 seconds...");
await Task.Delay(60000, ct);
}
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// SCENARIO B: BOTH ORDERS TRIGGERED
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
else if (direction == "BOTH")
{
// TWO positions opened (BUY and SELL) β this is a HEDGE!
// Hold for shorter time (30 sec instead of 60)
Console.WriteLine(" β³ Holding both positions for 30 seconds...");
await Task.Delay(30000, ct);
}
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// SCENARIO C: TIMEOUT (breakout didn't happen)
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
else
{
Console.WriteLine($" β± No breakout after {MaxWaitAfterNewsSeconds}s");
Console.WriteLine(" Canceling both pending orders...");
// β Cancel BOTH orders
// ββββββββββββββββββββββββββββββββββββββββββββββββββ
await _service.CloseByTicket(buyStopResult.Order);
await _service.CloseByTicket(sellStopResult.Order);
}
Phase 6: Final closing (lines 163-176)ΒΆ
// β Close all remaining positions
// ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Console.WriteLine("\n Closing all remaining positions...");
await _service.CloseAll(Symbol);
Console.WriteLine(" β All closed");
var finalBalance = await _service.GetBalanceAsync();
var profit = finalBalance - initialBalance;
Console.WriteLine($"\n Final balance: ${finalBalance:F2}");
Console.WriteLine($" Profit/Loss: ${profit:F2}");
Console.WriteLine($" Direction: {(string.IsNullOrEmpty(direction) ? "None" : direction)}");
return profit;
π Complete Life Cycle (Upward breakout scenario)ΒΆ
Execution timelineΒΆ
T=-60s START ExecuteAsync()
β
βββΊ GetBalanceAsync() β $10000.00
β
βββΊ "Waiting 60s before news event..."
βββΊ Task.Delay(60000) β COUNTDOWN
β
β USER sees countdown until news
β
T=0 βββΊ Task.Delay COMPLETED
β
βββΊ "NEWS EVENT IMMINENT!"
βββΊ SymbolInfoTickAsync()
β βββΊ Bid=1.10000, Ask=1.10002
β
T=1s βββΊ BuyStopPoints(+15)
β βββΊ Created BuyStop @ 1.10017
β SL: 1.09997, TP: 1.10057
β
T=2s βββΊ SellStopPoints(-15)
β βββΊ Created SellStop @ 1.09985
β SL: 1.10005, TP: 1.09945
β
β "β
STRADDLE ACTIVE"
β
β MT5 Terminal state:
β ββββββββββββββββββ¬βββββββββββββββ
β β PENDING ORDERS β POSITIONS β
β ββββββββββββββββββΌβββββββββββββββ€
β β 789: BUY STOP β (empty) β
β β 790: SELL STOP β β
β ββββββββββββββββββ΄βββββββββββββββ
β
T=3s βββΊ MONITORING START (max 180 sec)
β
T=4s βββΊ Task.Delay(1000)
β OpenedOrdersTicketsAsync() β [789, 790]
β buyStillPending = true
β sellStillPending = true
β β Both pending β continue
β
β ββββββββββββββββββββββββββββββββββ
β β NEWS RELEASED! β
β β NFP: +350K jobs (forecast +200K)β
β β Much better than expected! β
β ββββββββββββββββββββββββββββββββββ
β
β MARKET: Price sharply UP!
β 1.10000 β 1.10010 β 1.10017 β 1.10020...
β
T=5s βββΊ MT5 Terminal: Price reached 1.10017!
β BuyStop TRIGGERED!
β ββββββββββββββββββββββββββββββββββββ
β β Opened position BUY 0.02 β
β β Entry: 1.10017 β
β β SL: 1.09997 β
β β TP: 1.10057 β
β ββββββββββββββββββββββββββββββββββββ
β
T=6s βββΊ Task.Delay(1000)
β OpenedOrdersTicketsAsync() β [790]
β buyStillPending = false β 789 DISAPPEARED!
β sellStillPending = true
β
β if (!buy && sell) β TRUE!
β {
β direction = "UPWARD";
β executedOrder = 789;
β pendingOrder = 790;
β break; β Exit monitoring
β }
β
βββΊ "π UPWARD BREAKOUT DETECTED!"
β
βββΊ CloseByTicket(790) β Cancel SellStop
β βββΊ OrderDeleteAsync(790)
β
β MT5 Terminal state:
β ββββββββββββββββββ¬βββββββββββββββββββββββ
β β PENDING ORDERS β POSITIONS β
β ββββββββββββββββββΌβββββββββββββββββββββββ€
β β (empty) β 789: BUY 0.02 β
β β β @ 1.10017 β
β ββββββββββββββββββ΄βββββββββββββββββββββββ
β
βββΊ "Holding position for 60 seconds..."
βββΊ Task.Delay(60000)
β
β MARKET: Price continues rising...
β 1.10020 β 1.10040 β 1.10057...
β
T=35s β MT5 Terminal: Price reached 1.10057!
β TP TRIGGERED!
β ββββββββββββββββββββββββββββββββββββ
β β Position closed automatically β
β β Entry: 1.10017 β
β β Exit: 1.10057 β
β β Profit: +40 pts Γ 0.02 = +$8.00 β
β ββββββββββββββββββββββββββββββββββββ
β
T=66s βββΊ Task.Delay(60000) finished
β
βββΊ CloseAll("EURUSD")
β βββΊ Position already closed (TP triggered)
β
T=67s βββΊ GetBalanceAsync() β $10008.00
βββΊ profit = 10008.00 - 10000.00 = +$8.00
β
βββΊ RETURN profit = 8.00
TOTAL: Caught news breakout WITHOUT predicting direction!
Profit: +$8.00
π What the result is made ofΒΆ
Profit calculation (upward breakout, TP triggered)ΒΆ
INITIAL BALANCE: $10000.00
STRADDLE PLACED:
- BuyStop @ 1.10017 (SL: 1.09997, TP: 1.10057)
- SellStop @ 1.09985 (canceled after upward breakout)
UPWARD BREAKOUT:
- BuyStop triggered @ 1.10017
- Opened position BUY 0.02 lots
TP TRIGGERED:
- Exit @ 1.10057
- Pips: (1.10057 - 1.10017) / 0.00001 = 40 points
PROFIT CALCULATION:
- Profit = Pips Γ Volume Γ PointValue
- PointValue for EURUSD (0.02 lots) = 0.02 Γ $10 = $0.20 per point
- Profit = 40 Γ $0.20 = +$8.00
FINAL BALANCE: $10008.00
PROFIT = $8.00
return 8.00;
P/L calculation (scenario "BOTH" - both orders triggered)ΒΆ
EXTREME VOLATILITY:
News caused whipsaw (jerked both directions):
1. Price fell to 1.09985 β SellStop triggered
2. Price rose to 1.10017 β BuyStop triggered
TWO POSITIONS OPENED:
- BUY 0.02 @ 1.10017
- SELL 0.02 @ 1.09985
FINAL PRICE (after 30 sec): 1.10005
CLOSING:
BUY position:
Entry: 1.10017
Exit: 1.10005
Pips: (1.10005 - 1.10017) / 0.00001 = -12 points
P/L: -12 Γ $0.20 = -$2.40
SELL position:
Entry: 1.09985
Exit: 1.10005
Pips: (1.09985 - 1.10005) / 0.00001 = -20 points
P/L: -20 Γ $0.20 = -$4.00
TOTAL:
BUY: -$2.40
SELL: -$4.00
βββββββββββββ
TOTAL: -$6.40
FINAL BALANCE: $9993.60
PROFIT = -$6.40
This is the WORST scenario (whipsaw) - both orders triggered, both in loss.
Probability: ~5-10% for strong news.
P/L calculation (timeout - breakout didn't happen)ΒΆ
WEAK NEWS:
News released, but data within forecast.
Price moves in narrow range:
1.10000 β 1.10005 β 1.09998 β 1.10003...
NO ORDER TRIGGERED:
- BuyStop @ 1.10017 (price didn't reach)
- SellStop @ 1.09985 (price didn't reach)
TIMEOUT (180 seconds):
- Both orders STILL pending
- direction = ""
- executedOrder = null
- pendingOrder = null
CANCELING BOTH ORDERS:
- CloseByTicket(789) β BuyStop canceled
- CloseByTicket(790) β SellStop canceled
FINAL BALANCE: $10000.00
PROFIT = $0.00
Orders didn't execute β no losses!
π§© Components and their rolesΒΆ
1. NewsStraddleOrchestratorΒΆ
Role: News straddle strategy coordinator
Tasks:
- Manages timing (countdown until news)
- Places symmetric straddle (BuyStop + SellStop)
- MONITORS every SECOND (faster than regular PendingBreakout)
- Detects 3 breakout scenarios (UPWARD, DOWNWARD, BOTH)
- Cancels opposite order (OCO mechanism)
- Handles timeout
2. Key timing parametersΒΆ
public int SecondsBeforeNews { get; set; } = 60;
// β Countdown until news
// Launch orchestrator 60 seconds before exact time
public int MaxWaitAfterNewsSeconds { get; set; } = 180;
// β Maximum time waiting for breakout
// News acts fast β 3 minutes is enough
3. MT5Sugar Extension MethodsΒΆ
// Straddle placement:
BuyStopPoints(priceOffsetPoints: +15) // Above price
SellStopPoints(priceOffsetPoints: -15) // Below price
// Cancellation:
CloseByTicket(ticket) // Cancel pending order
CloseAll(symbol) // Close all positions
4. Breakout detection logicΒΆ
KEY MECHANISM: Check ticket presence in pending list
OpenedOrdersTicketsAsync() returns list of ONLY pending orders.
When order EXECUTES β it becomes POSITION β disappears from list.
if (!buyStillPending && sellStillPending)
β BuyStop DISAPPEARED (executed) β UPWARD breakout
else if (buyStillPending && !sellStillPending)
β SellStop DISAPPEARED (executed) β DOWNWARD breakout
else if (!buyStillPending && !sellStillPending)
β BOTH DISAPPEARED β BOTH (extreme volatility)
π Final Dependency DiagramΒΆ
β USER CODE
β var orch = new NewsStraddleOrchestrator(service);
β orch.SecondsBeforeNews = 60; β Launch 60 sec before
β await orch.ExecuteAsync(); β @ 13:29:00 (NFP @ 13:30)
ββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββ
β
βΌ
β NewsStraddleOrchestrator
β
β β ExecuteAsync() {
β β 1. Task.Delay(SecondsBeforeNews Γ 1000)
β β 2. SymbolInfoTickAsync() β current price
β β 3. BuyStopPoints(+StraddleDistance)
β β 4. SellStopPoints(-StraddleDistance)
β β 5. LOOP (every 1 sec, max 3 min):
β β - OpenedOrdersTicketsAsync()
β β - Check: which order disappeared?
β β - IF one disappeared β CloseByTicket(other)
β β 6. Task.Delay(60000) β Hold position
β β 7. CloseAll()
β β }
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
ββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββ
β
βΌ
β MT5Sugar Extension Methods
β - BuyStopPoints(+offsetPoints) β above Ask
β - SellStopPoints(-offsetPoints) β below Bid
β - CloseByTicket(ticket) β OCO cancellation
β - CloseAll(symbol) β final closing
ββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββ
β
βΌ
[MT5 Terminal]
π― SummaryΒΆ
NewsStraddleOrchestrator is made of:
-
1 dependency:
MT5Service _service -
7 parameters: Symbol, StraddleDistancePoints, Volume, SL, TP, SecondsBeforeNews, MaxWaitAfterNewsSeconds
-
Key logic:
-
Countdown until news (Task.Delay)
- Symmetric straddle (BuyStop + SellStop)
- Monitoring every second (faster than regular breakout!)
- 3 scenarios: UPWARD, DOWNWARD, BOTH
- OCO mechanism (cancel opposite)
Works through:
- Timing: launch 60 seconds before news
- Placing straddle right before news
- Fast monitoring (1 second instead of 3)
- Detecting breakout through ticket disappearance from pending list
- Automatic opposite order cancellation
Returns:
- double profit - difference between final and initial balance
Key insight:
Straddle allows catching news volatility WITHOUT predicting direction. By placing orders in both directions, we're guaranteed to catch the movement if it's strong enough. Fast monitoring (every second) is critically important for news - they act INSTANTLY!
Success mathematics: