Fix deploy script: add NT8.Strategies.dll to deployment pipeline
Some checks failed
Build and Test / build (push) Has been cancelled

This commit is contained in:
2026-03-22 17:28:03 -04:00
parent 2f623dc2f8
commit a2af272d73
8 changed files with 393 additions and 40 deletions

View File

@@ -203,9 +203,12 @@ namespace NinjaTrader.NinjaScript.Strategies
{
try
{
InitFileLog();
InitializeSdkComponents();
_sdkInitialized = true;
Print(string.Format("[SDK] {0} initialized successfully", Name));
WriteSettingsFile();
WriteSessionHeader();
}
catch (Exception ex)
{
@@ -217,8 +220,7 @@ namespace NinjaTrader.NinjaScript.Strategies
}
else if (State == State.Realtime)
{
InitFileLog();
WriteSessionHeader();
WriteSettingsFile();
}
else if (State == State.Terminated)
{
@@ -229,6 +231,12 @@ namespace NinjaTrader.NinjaScript.Strategies
protected override void OnBarUpdate()
{
// Only process primary bar series — ignore secondary data series updates.
// Secondary series (e.g. daily bars for confluence) trigger OnBarUpdate separately
// and must never generate strategy signals.
if (BarsInProgress != 0)
return;
if (!_sdkInitialized || _sdkStrategy == null)
{
return;
@@ -244,6 +252,9 @@ namespace NinjaTrader.NinjaScript.Strategies
_lastBarTime = Time[0];
// Sync actual open position to portfolio manager on every bar
PortfolioRiskManager.Instance.UpdateOpenContracts(Name, Math.Abs(Position.Quantity));
// Kill switch — checked AFTER bar guards so ExitLong/ExitShort are valid
if (EnableKillSwitch)
{
@@ -272,6 +283,34 @@ namespace NinjaTrader.NinjaScript.Strategies
return;
}
// Hard RTH guard using NT8 bar time converted from CT to ET.
// Belt-and-suspenders against SDK session timezone issues.
DateTime ntBarTimeEt;
try
{
var centralZone = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time");
var easternZone = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
DateTime utcTime = TimeZoneInfo.ConvertTimeToUtc(
DateTime.SpecifyKind(Time[0], DateTimeKind.Unspecified),
centralZone);
ntBarTimeEt = TimeZoneInfo.ConvertTimeFromUtc(utcTime, easternZone);
}
catch
{
ntBarTimeEt = Time[0];
}
bool isRthBar = ntBarTimeEt.TimeOfDay >= new TimeSpan(9, 30, 0)
&& ntBarTimeEt.TimeOfDay < new TimeSpan(16, 0, 0);
if (!isRthBar)
{
if (EnableVerboseLogging && CurrentBar % 500 == 0)
Print(string.Format("[SDK] Skipping ETH bar {0} at {1:HH:mm} ET",
CurrentBar, ntBarTimeEt));
return;
}
// Log first processable bar and every 100th bar.
if (CurrentBar == BarsRequiredToTrade || CurrentBar % 100 == 0)
{
@@ -384,34 +423,35 @@ namespace NinjaTrader.NinjaScript.Strategies
/// <summary>
/// Handles broker connection status changes. Halts new orders on disconnect,
/// logs reconnect, and resets the connection flag when restored.
/// NinjaScript signature: single ConnectionStatusEventArgs parameter.
/// </summary>
protected override void OnConnectionStatusUpdate(
Connection connection,
ConnectionStatus status,
DateTime time)
ConnectionStatusEventArgs connectionStatusUpdate)
{
if (connection == null) return;
if (connectionStatusUpdate == null) return;
if (status == ConnectionStatus.Connected)
if (connectionStatusUpdate.Status == ConnectionStatus.Connected)
{
if (_connectionLost)
{
_connectionLost = false;
Print(string.Format("[NT8-SDK] Connection RESTORED at {0} — trading resumed.",
time.ToString("HH:mm:ss")));
FileLog(string.Format("CONNECTION RESTORED at {0}", time.ToString("HH:mm:ss")));
DateTime.Now.ToString("HH:mm:ss")));
FileLog(string.Format("CONNECTION RESTORED at {0}", DateTime.Now.ToString("HH:mm:ss")));
}
}
else if (status == ConnectionStatus.Disconnected ||
status == ConnectionStatus.ConnectionLost)
else if (connectionStatusUpdate.Status == ConnectionStatus.Disconnected ||
connectionStatusUpdate.Status == ConnectionStatus.ConnectionLost)
{
if (!_connectionLost)
{
_connectionLost = true;
Print(string.Format("[NT8-SDK] Connection LOST at {0} — halting new orders. Status={1}",
time.ToString("HH:mm:ss"),
status));
FileLog(string.Format("CONNECTION LOST at {0} Status={1}", time.ToString("HH:mm:ss"), status));
DateTime.Now.ToString("HH:mm:ss"),
connectionStatusUpdate.Status));
FileLog(string.Format("CONNECTION LOST at {0} Status={1}",
DateTime.Now.ToString("HH:mm:ss"),
connectionStatusUpdate.Status));
}
}
}
@@ -465,6 +505,7 @@ namespace NinjaTrader.NinjaScript.Strategies
private void WriteSessionHeader()
{
FileLog("=== SESSION START " + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + " ===");
FileLog(string.Format("Mode : {0}", State == State.Historical ? "BACKTEST" : "LIVE/SIM"));
FileLog(string.Format("Strategy : {0}", Name));
FileLog(string.Format("Account : {0}", Account != null ? Account.Name : "N/A"));
FileLog(string.Format("Symbol : {0}", Instrument != null ? Instrument.FullName : "N/A"));
@@ -566,8 +607,12 @@ namespace NinjaTrader.NinjaScript.Strategies
DateTime etTime;
try
{
var centralZone = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time");
var easternZone = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
etTime = TimeZoneInfo.ConvertTime(Time[0], easternZone);
DateTime utcTime = TimeZoneInfo.ConvertTimeToUtc(
DateTime.SpecifyKind(Time[0], DateTimeKind.Unspecified),
centralZone);
etTime = TimeZoneInfo.ConvertTimeFromUtc(utcTime, easternZone);
}
catch
{
@@ -630,16 +675,37 @@ namespace NinjaTrader.NinjaScript.Strategies
DateTime etTime;
try
{
var centralZone = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time");
var easternZone = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
etTime = TimeZoneInfo.ConvertTime(Time[0], easternZone);
DateTime utcTime = TimeZoneInfo.ConvertTimeToUtc(
DateTime.SpecifyKind(Time[0], DateTimeKind.Unspecified),
centralZone);
etTime = TimeZoneInfo.ConvertTimeFromUtc(utcTime, easternZone);
}
catch
{
etTime = Time[0];
}
var sessionStart = etTime.Date.AddHours(9).AddMinutes(30);
var sessionEnd = etTime.Date.AddHours(16);
// Futures trade nearly 24 hours. Bars at/after 17:00 ET belong to the next
// calendar day's RTH trading session.
DateTime tradingDate;
if (etTime.TimeOfDay >= new TimeSpan(17, 0, 0))
tradingDate = etTime.Date.AddDays(1);
else
tradingDate = etTime.Date;
if (EnableVerboseLogging && (CurrentBar == BarsRequiredToTrade || CurrentBar % 500 == 0))
{
Print(string.Format("[SDK-TZ] Bar {0}: NT8 Time[0]={1:yyyy-MM-dd HH:mm:ss} | etTime={2:yyyy-MM-dd HH:mm:ss} | isRth={3}",
CurrentBar,
Time[0],
etTime,
etTime.TimeOfDay >= TimeSpan.FromHours(9.5) && etTime.TimeOfDay < TimeSpan.FromHours(16.0)));
}
var sessionStart = tradingDate.AddHours(9).AddMinutes(30);
var sessionEnd = tradingDate.AddHours(16);
var isRth = etTime.TimeOfDay >= TimeSpan.FromHours(9.5)
&& etTime.TimeOfDay < TimeSpan.FromHours(16.0);
@@ -843,5 +909,82 @@ namespace NinjaTrader.NinjaScript.Strategies
return null;
return _executionAdapter.GetOrderStatus(orderName);
}
/// <summary>
/// Returns all strategy parameter lines for the settings export file.
/// Override in subclasses to append strategy-specific parameters.
/// Call base.GetStrategySettingsLines() first then add to the list.
/// </summary>
protected virtual List<string> GetStrategySettingsLines()
{
var lines = new List<string>();
lines.Add("=== STRATEGY SETTINGS EXPORT ===");
lines.Add(string.Format("ExportTime : {0:yyyy-MM-dd HH:mm:ss}", DateTime.Now));
lines.Add(string.Format("StrategyName : {0}", Name));
lines.Add(string.Format("Description : {0}", Description));
lines.Add(string.Format("Account : {0}", Account != null ? Account.Name : "N/A"));
lines.Add(string.Format("Instrument : {0}", Instrument != null ? Instrument.FullName : "N/A"));
lines.Add(string.Format("BarsPeriod : {0} {1}", BarsPeriod != null ? BarsPeriod.Value.ToString() : "N/A", BarsPeriod != null ? BarsPeriod.BarsPeriodType.ToString() : string.Empty));
lines.Add(string.Format("BarsRequiredToTrade: {0}", BarsRequiredToTrade));
lines.Add(string.Format("Calculate : {0}", Calculate));
lines.Add("--- Risk ---");
lines.Add(string.Format("DailyLossLimit : {0:C}", DailyLossLimit));
lines.Add(string.Format("MaxTradeRisk : {0:C}", MaxTradeRisk));
lines.Add(string.Format("MaxOpenPositions : {0}", MaxOpenPositions));
lines.Add(string.Format("RiskPerTrade : {0:C}", RiskPerTrade));
lines.Add("--- Sizing ---");
lines.Add(string.Format("MinContracts : {0}", MinContracts));
lines.Add(string.Format("MaxContracts : {0}", MaxContracts));
lines.Add("--- Direction ---");
lines.Add(string.Format("EnableLongTrades : {0}", EnableLongTrades));
lines.Add(string.Format("EnableShortTrades : {0}", EnableShortTrades));
lines.Add("--- Controls ---");
lines.Add(string.Format("EnableKillSwitch : {0}", EnableKillSwitch));
lines.Add(string.Format("EnableVerboseLogging: {0}", EnableVerboseLogging));
lines.Add(string.Format("EnableFileLogging : {0}", EnableFileLogging));
lines.Add(string.Format("LogDirectory : {0}", string.IsNullOrEmpty(LogDirectory) ? "(default)" : LogDirectory));
lines.Add("--- Portfolio ---");
lines.Add(string.Format("PortfolioStatus : {0}", PortfolioRiskManager.Instance.GetStatusSnapshot()));
lines.Add("=== END SETTINGS ===");
return lines;
}
/// <summary>
/// Writes a settings export file to the same directory as the session log.
/// File is named settings_STRATEGYNAME_YYYYMMDD_HHmmss.txt.
/// Only writes when EnableVerboseLogging is true.
/// </summary>
private void WriteSettingsFile()
{
if (!EnableVerboseLogging) return;
try
{
string dir = string.IsNullOrEmpty(LogDirectory)
? System.IO.Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
"NinjaTrader 8", "log", "nt8-sdk")
: LogDirectory;
System.IO.Directory.CreateDirectory(dir);
string safeName = Name.Replace(" ", "_").Replace("/", "_").Replace("\\", "_");
string path = System.IO.Path.Combine(dir,
string.Format("settings_{0}_{1}.txt",
safeName,
DateTime.Now.ToString("yyyyMMdd_HHmmss")));
var lines = GetStrategySettingsLines();
System.IO.File.WriteAllLines(path, lines.ToArray());
Print(string.Format("[NT8-SDK] Settings exported: {0}", path));
FileLog(string.Format("SETTINGS FILE: {0}", path));
}
catch (Exception ex)
{
Print(string.Format("[NT8-SDK] WARNING: Could not write settings file: {0}", ex.Message));
}
}
}
}