# Configuration Export/Import - Implementation Specification

**For:** Kilocode AI Agent  
**Priority:** HIGH  
**Mode:** Code Mode  
**Estimated Time:** 1.5-2 hours  
**Files to Edit:** 1 file (NT8StrategyBase.cs)  
**Files to Create:** 1 file (StrategyConfigExporter.cs)  

---

## 🎯 Objective

Add ability to export NT8 strategy configuration as JSON for:
- Easy sharing with support/debugging
- Version control of strategy settings
- Configuration backup/restore
- Reproducible backtests

---

## 📋 What We're Adding

### 1. Export Configuration Button/Method
User can click a button (or call a method) to export all strategy settings as JSON file.

### 2. Import Configuration Method
User can load settings from a previously exported JSON file.

### 3. Automatic Export on Strategy Start
Optionally auto-export config to a timestamped file when strategy starts.

---

## 🔧 Implementation

### Component 1: StrategyConfigExporter.cs

**Location:** `src/NT8.Adapters/Strategies/StrategyConfigExporter.cs`

**Purpose:** Static helper class to serialize/deserialize strategy configurations

```csharp
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;

namespace NT8.Adapters.Strategies
{
    /// <summary>
    /// Helper class to export/import NT8 strategy configurations as JSON.
    /// Enables configuration sharing, backup, and reproducible testing.
    /// </summary>
    public static class StrategyConfigExporter
    {
        /// <summary>
        /// Export strategy configuration to JSON string.
        /// </summary>
        public static string ExportToJson(Dictionary<string, object> config)
        {
            if (config == null || config.Count == 0)
                return "{}";

            var sb = new StringBuilder();
            sb.AppendLine("{");

            var first = true;
            foreach (var kvp in config)
            {
                if (!first)
                    sb.AppendLine(",");
                first = false;

                sb.Append("  \"");
                sb.Append(EscapeJsonString(kvp.Key));
                sb.Append("\": ");

                AppendValue(sb, kvp.Value);
            }

            sb.AppendLine();
            sb.Append("}");

            return sb.ToString();
        }

        /// <summary>
        /// Save configuration to JSON file.
        /// </summary>
        public static void ExportToFile(Dictionary<string, object> config, string filepath)
        {
            var json = ExportToJson(config);
            File.WriteAllText(filepath, json);
        }

        /// <summary>
        /// Import configuration from JSON string.
        /// Simple parser for basic types (string, int, double, bool).
        /// </summary>
        public static Dictionary<string, object> ImportFromJson(string json)
        {
            var config = new Dictionary<string, object>();

            if (string.IsNullOrWhiteSpace(json))
                return config;

            // Remove outer braces and whitespace
            json = json.Trim();
            if (json.StartsWith("{"))
                json = json.Substring(1);
            if (json.EndsWith("}"))
                json = json.Substring(0, json.Length - 1);

            // Split by commas (simple parser - doesn't handle nested objects)
            var lines = json.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);

            foreach (var line in lines)
            {
                var colonIndex = line.IndexOf(':');
                if (colonIndex < 0)
                    continue;

                var key = line.Substring(0, colonIndex).Trim().Trim('"');
                var valueStr = line.Substring(colonIndex + 1).Trim();

                var value = ParseValue(valueStr);
                config[key] = value;
            }

            return config;
        }

        /// <summary>
        /// Import configuration from JSON file.
        /// </summary>
        public static Dictionary<string, object> ImportFromFile(string filepath)
        {
            if (!File.Exists(filepath))
                throw new FileNotFoundException("Config file not found", filepath);

            var json = File.ReadAllText(filepath);
            return ImportFromJson(json);
        }

        #region Helper Methods

        private static void AppendValue(StringBuilder sb, object value)
        {
            if (value == null)
            {
                sb.Append("null");
            }
            else if (value is string)
            {
                sb.Append("\"");
                sb.Append(EscapeJsonString(value.ToString()));
                sb.Append("\"");
            }
            else if (value is bool)
            {
                sb.Append(((bool)value) ? "true" : "false");
            }
            else if (value is int || value is long || value is double || value is decimal || value is float)
            {
                sb.Append(value.ToString());
            }
            else if (value is DateTime)
            {
                sb.Append("\"");
                sb.Append(((DateTime)value).ToString("yyyy-MM-dd HH:mm:ss"));
                sb.Append("\"");
            }
            else
            {
                // Fallback: ToString()
                sb.Append("\"");
                sb.Append(EscapeJsonString(value.ToString()));
                sb.Append("\"");
            }
        }

        private static string EscapeJsonString(string str)
        {
            if (string.IsNullOrEmpty(str))
                return str;

            return str
                .Replace("\\", "\\\\")
                .Replace("\"", "\\\"")
                .Replace("\n", "\\n")
                .Replace("\r", "\\r")
                .Replace("\t", "\\t");
        }

        private static object ParseValue(string valueStr)
        {
            valueStr = valueStr.Trim();

            // Remove trailing comma if present
            if (valueStr.EndsWith(","))
                valueStr = valueStr.Substring(0, valueStr.Length - 1).Trim();

            // Null
            if (valueStr == "null")
                return null;

            // Boolean
            if (valueStr == "true")
                return true;
            if (valueStr == "false")
                return false;

            // String (quoted)
            if (valueStr.StartsWith("\"") && valueStr.EndsWith("\""))
            {
                var str = valueStr.Substring(1, valueStr.Length - 2);
                return UnescapeJsonString(str);
            }

            // Number - try int, then double
            int intVal;
            if (int.TryParse(valueStr, out intVal))
                return intVal;

            double doubleVal;
            if (double.TryParse(valueStr, out doubleVal))
                return doubleVal;

            // Fallback: return as string
            return valueStr;
        }

        private static string UnescapeJsonString(string str)
        {
            if (string.IsNullOrEmpty(str))
                return str;

            return str
                .Replace("\\\"", "\"")
                .Replace("\\\\", "\\")
                .Replace("\\n", "\n")
                .Replace("\\r", "\r")
                .Replace("\\t", "\t");
        }

        #endregion
    }
}
```

---

### Component 2: Add Export Methods to NT8StrategyBase.cs

**File:** `src/NT8.Adapters/Strategies/NT8StrategyBase.cs`

**Add these properties and methods:**

```csharp
#region Configuration Export/Import

[NinjaScriptProperty]
[Display(Name = "Auto Export Config", GroupName = "SDK", Order = 10)]
public bool AutoExportConfig { get; set; }

[NinjaScriptProperty]
[Display(Name = "Config Export Path", GroupName = "SDK", Order = 11)]
public string ConfigExportPath { get; set; }

/// <summary>
/// Export current strategy configuration to JSON string.
/// Can be called from derived strategies or used for debugging.
/// </summary>
public string ExportConfigurationJson()
{
    var config = new Dictionary<string, object>();

    // Basic info
    config["StrategyName"] = Name;
    config["ExportedAt"] = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
    config["Instrument"] = Instrument != null ? Instrument.FullName : "Not Set";
    config["BarsPeriod"] = BarsPeriod != null ? BarsPeriod.ToString() : "Not Set";

    // SDK settings
    config["EnableSDK"] = EnableSDK;
    config["AutoExportConfig"] = AutoExportConfig;
    config["ConfigExportPath"] = ConfigExportPath ?? "";

    // Risk settings
    config["DailyLossLimit"] = DailyLossLimit;
    config["MaxTradeRisk"] = MaxTradeRisk;
    config["MaxOpenPositions"] = MaxOpenPositions;

    // Sizing settings
    config["RiskPerTrade"] = RiskPerTrade;
    config["MinContracts"] = MinContracts;
    config["MaxContracts"] = MaxContracts;

    // NT8 settings
    config["BarsRequiredToTrade"] = BarsRequiredToTrade;
    config["Calculate"] = Calculate.ToString();
    config["EntriesPerDirection"] = EntriesPerDirection;
    config["StartBehavior"] = StartBehavior.ToString();

    return StrategyConfigExporter.ExportToJson(config);
}

/// <summary>
/// Export configuration to file.
/// </summary>
public void ExportConfigurationToFile(string filepath)
{
    var config = GetConfigurationDictionary();
    StrategyConfigExporter.ExportToFile(config, filepath);
    Print(string.Format("[SDK] Configuration exported to: {0}", filepath));
}

/// <summary>
/// Get configuration as dictionary for export.
/// </summary>
protected Dictionary<string, object> GetConfigurationDictionary()
{
    var config = new Dictionary<string, object>();

    config["StrategyName"] = Name;
    config["ExportedAt"] = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
    config["Instrument"] = Instrument != null ? Instrument.FullName : "Not Set";
    config["BarsPeriod"] = BarsPeriod != null ? BarsPeriod.ToString() : "Not Set";

    config["EnableSDK"] = EnableSDK;
    config["AutoExportConfig"] = AutoExportConfig;
    config["ConfigExportPath"] = ConfigExportPath ?? "";

    config["DailyLossLimit"] = DailyLossLimit;
    config["MaxTradeRisk"] = MaxTradeRisk;
    config["MaxOpenPositions"] = MaxOpenPositions;

    config["RiskPerTrade"] = RiskPerTrade;
    config["MinContracts"] = MinContracts;
    config["MaxContracts"] = MaxContracts;

    config["BarsRequiredToTrade"] = BarsRequiredToTrade;
    config["Calculate"] = Calculate.ToString();
    config["EntriesPerDirection"] = EntriesPerDirection;
    config["StartBehavior"] = StartBehavior.ToString();

    return config;
}

/// <summary>
/// Print configuration to Output window for easy copy/paste.
/// </summary>
public void PrintConfiguration()
{
    var json = ExportConfigurationJson();
    Print("=== Strategy Configuration ===");
    Print(json);
    Print("=== End Configuration ===");
}

#endregion
```

**Update OnStateChange() to handle auto-export:**

Find the `State.DataLoaded` section and add auto-export:

```csharp
else if (State == State.DataLoaded)
{
    if (EnableSDK)
    {
        try
        {
            InitializeSdkComponents();
            _sdkInitialized = true;
            
            Print(string.Format("[SDK] {0} initialized successfully", Name));
            
            // Auto-export configuration if enabled
            if (AutoExportConfig)
            {
                var exportPath = ConfigExportPath;
                
                // Default path if not specified
                if (string.IsNullOrEmpty(exportPath))
                {
                    var timestamp = DateTime.Now.ToString("yyyyMMdd-HHmmss");
                    var filename = string.Format("{0}_{1}_config.json", Name, timestamp);
                    exportPath = System.IO.Path.Combine(
                        Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
                        "NinjaTrader 8",
                        "logs",
                        filename
                    );
                }
                
                try
                {
                    ExportConfigurationToFile(exportPath);
                }
                catch (Exception ex)
                {
                    Print(string.Format("[SDK] Failed to export config: {0}", ex.Message));
                }
            }
            
            // Print config to Output window for easy access
            PrintConfiguration();
        }
        catch (Exception ex)
        {
            Print(string.Format("[SDK ERROR] Initialization failed: {0}", ex.Message));
            Log(string.Format("[SDK ERROR] {0}", ex.ToString()), LogLevel.Error);
            _sdkInitialized = false;
        }
    }
}
```

**Update State.SetDefaults to include new properties:**

```csharp
if (State == State.SetDefaults)
{
    // ... existing code ...
    
    // SDK configuration export
    AutoExportConfig = false;  // Off by default
    ConfigExportPath = "";     // Empty = auto-generate path
}
```

---

### Component 3: Update SimpleORBNT8.cs

**Add SimpleORB-specific configuration export:**

```csharp
/// <summary>
/// Export SimpleORB-specific configuration.
/// Overrides base to include ORB parameters.
/// </summary>
protected new Dictionary<string, object> GetConfigurationDictionary()
{
    var config = base.GetConfigurationDictionary();
    
    // Add ORB-specific settings
    config["OpeningRangeMinutes"] = OpeningRangeMinutes;
    config["StdDevMultiplier"] = StdDevMultiplier;
    config["StopTicks"] = StopTicks;
    config["TargetTicks"] = TargetTicks;
    
    return config;
}
```

---

## ✅ Verification

### Manual Test

1. **Build:**
```bash
dotnet build src\NT8.Adapters\NT8.Adapters.csproj --configuration Release
```

2. **Deploy:**
```powershell
.\deployment\Deploy-To-NT8.ps1
```

3. **Test in NT8:**
   - Add SimpleORBNT8 to Strategy Analyzer
   - Enable strategy
   - Check Output window - should see:
   ```
   [SDK] Simple ORB NT8 initialized successfully
   === Strategy Configuration ===
   {
     "StrategyName": "Simple ORB NT8",
     "ExportedAt": "2026-02-17 14:30:00",
     "Instrument": "ES 03-26",
     "BarsPeriod": "5 Minute",
     "EnableSDK": true,
     "DailyLossLimit": 1000,
     ...
   }
   === End Configuration ===
   ```

4. **Copy JSON from Output window** - ready to share!

5. **Test Auto-Export:**
   - Set `AutoExportConfig = true`
   - Re-enable strategy
   - Check `Documents\NinjaTrader 8\logs\` folder
   - Should see `SimpleORBNT8_[timestamp]_config.json`

---

## 📋 Success Criteria

- [ ] StrategyConfigExporter.cs created
- [ ] Export methods added to NT8StrategyBase
- [ ] Auto-export on strategy start works
- [ ] PrintConfiguration() shows JSON in Output window
- [ ] SimpleORBNT8 includes ORB-specific parameters
- [ ] JSON format is valid and readable
- [ ] Zero compilation errors
- [ ] All 319 existing tests still pass

---

## 🚨 Constraints

- C# 5.0 syntax only (no modern JSON libraries)
- Simple manual JSON serialization (no Newtonsoft.Json dependency)
- Thread-safe (no async file I/O)
- Minimal allocations
- Clear error messages

---

## 📋 Git Commit

```bash
git add src/NT8.Adapters/Strategies/StrategyConfigExporter.cs
git add src/NT8.Adapters/Strategies/NT8StrategyBase.cs
git add src/NT8.Adapters/Strategies/SimpleORBNT8.cs
git commit -m "feat: Add configuration export/import

- Add StrategyConfigExporter helper class
- Add ExportConfigurationJson() method
- Add PrintConfiguration() to Output window
- Add auto-export on strategy start
- Add AutoExportConfig property
- Simple JSON serialization (C# 5.0 compatible)

Enables easy configuration sharing for debugging"
```

---

**READY FOR KILOCODE - CODE MODE** ✅

**Time: 1.5-2 hours**
