Announcement

Collapse
No announcement yet.

Partner 728x90

Collapse

Password Protected Risk Management Add On

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

    Password Protected Risk Management Add On

    I lack discipline so Im trying to create an add on that is password protected and controls my risk. Too often I will change my risk parameters before my daily loss limit is hit and it has resulted in greater losses. Im having a hard time creating a code that can directly access my account value or performance. I have my ninja trader account and then I have multiple accounts with apex and or topstep. Is anyone aware of a way to gain access to these methods or properties? Here is the beginning of the code Im trying to use but it doesn't work. I would post the rest but I can not post but so many characters.


    ​using System;
    using System.Linq;
    using System.Collections.Generic;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Controls.Primitives;
    using System.Windows.Threading;
    using System.Windows.Media;
    using NinjaTrader.Cbi;
    using NinjaTrader.Gui.Tools;
    using NinjaTrader.NinjaScript;
    using NinjaTrader.Gui; // For ControlCenter
    using NinjaTrader.Core; // <-- Make sure this reference is added

    namespace NinjaTrader.NinjaScript.AddOns
    {
    public class RiskManagementAddOn : AddOnBase
    {
    region UI & Risk Setting Fields

    // Risk Manager window and its UI elements.
    private Window riskWindow;
    private PasswordBox passwordBox;
    private Label statusLabel;

    // Global (default) loss limit value.
    private double dailyLossLimit = 500;

    // Global “apply to all” controls.
    private CheckBox applyToAllCheckBox;
    private TextBox globalLossLimitBox;

    // For per-account daily loss limits (keyed by account name).
    private Dictionary<string, TextBox> accountLossLimitTextBoxes = new Dictionary<string, TextBox>();

    // Flag for whether settings are unlocked.
    private bool isUnlocked = false;
    // MD5 hash for the correct password ("password" in this example).
    private string hashedPassword = "5f4dcc3b5aa765d61d8327deb882cf99";

    // Timer to periodically check account risk.
    private DispatcherTimer riskTimer;

    // Dictionary to track locked accounts (by name) until the next trading day.
    private Dictionary<string, DateTime> lockedAccounts = new Dictionary<string, DateTime>();

    #endregion

    region OnStateChange

    protected override void OnStateChange()
    {
    if (State == State.SetDefaults)
    {
    Name = "Risk Management Add-On";
    }
    else if (State == State.Configure)
    {
    // Attempt to add a menu item to the Control Center (unsupported technique).
    MenuItem menuItem = new MenuItem() { Header = "Risk Manager" };
    menuItem.Click += (s, e) => ShowRiskManager();
    AddMenuItemToControlCenter(menuItem);
    }
    else if (State == State.Active)
    {
    // Start the risk-monitoring timer (every 3 seconds).
    riskTimer = new DispatcherTimer();
    riskTimer.Interval = TimeSpan.FromSeconds(3);
    riskTimer.Tick += RiskTimer_Tick;
    riskTimer.Start();
    }
    else if (State == State.Terminated)
    {
    if (riskTimer != null)
    riskTimer.Stop();
    }
    }

    #endregion

    region Risk Monitoring

    /// <summary>
    /// Timer tick event: For each connected account, check its daily realized PnL.
    /// If the realized loss exceeds its limit, flatten positions immediately and lock the account.
    /// Also, while locked, any new positions are flattened immediately.
    /// </summary>
    private void RiskTimer_Tick(object sender, EventArgs e)
    {
    DateTime now = DateTime.Now;
    foreach (var account in Account.All)
    {
    // If the account is locked, flatten any new positions and skip further checks.
    if (lockedAccounts.ContainsKey(account.Name))
    {
    if (now < lockedAccounts[account.Name])
    {
    if (account.Positions.Count > 0)
    {
    FlattenAccount(account);
    }
    continue;
    }
    else
    {
    // Lock expired.
    lockedAccounts.Remove(account.Name);
    }
    }

    // Determine which loss limit to use.
    double accountLimit = dailyLossLimit;
    if (applyToAllCheckBox != null && applyToAllCheckBox.IsChecked == true)
    {
    if (globalLossLimitBox != null && double.TryParse(globalLossLimitBox.Text, out double globalLimit))
    {
    accountLimit = globalLimit;
    }
    }
    else
    {
    if (accountLossLimitTextBoxes.TryGetValue(account.Nam e, out TextBox tb) &&
    double.TryParse(tb.Text, out double perAccountLimit))
    {
    accountLimit = perAccountLimit;
    }
    }

    // Retrieve the account's gross realized profit/loss using the extension method.
    double realizedPnL = Convert.ToDouble(account.GetAccountValue(Cbi.Accou ntItem.GrossRealizedProfitLoss));

    // If the loss exceeds the limit (P/L is less than -limit), flatten positions and lock the account.
    if (realizedPnL < -accountLimit)
    {
    if (account.Positions.Count > 0)
    {
    FlattenAccount(account);
    }
    lockedAccounts[account.Name] = DateTime.Today.AddDays(1);
    }
    }
    }

    /// <summary>
    /// Flattens an account by closing all open positions.
    /// </summary>
    private void FlattenAccount(Account account)
    {
    try
    {
    foreach (var position in account.Positions)
    {
    account.Flatten(new List<Instrument> { position.Instrument });
    }
    }
    catch (Exception ex)
    {
    MessageBox.Show($"Error flattening account {account.Name}: {ex.Message}");
    }
    }

    #endregion

    region UI Creation

    /// <summary>
    /// Attempts to locate the Control Center window and add a menu item.
    /// (This technique is unsupported and may not work in all versions.)
    /// </summary>
    private void AddMenuItemToControlCenter(MenuItem menuItem)
    {
    try
    {
    var cc = Application.Current.Windows.OfType<ControlCenter>( ).FirstOrDefault();
    if (cc != null)
    {
    var mainMenu = cc.FindName("MainMenu") as Menu;
    if (mainMenu != null)
    {
    mainMenu.Items.Add(menuItem);
    }
    else
    {
    MessageBox.Show("Main menu not found in Control Center. Risk Manager menu item not added.");
    }
    }
    else
    {
    MessageBox.Show("Control Center window not found. Risk Manager menu item not added.");
    }
    }
    catch (Exception ex)
    {
    MessageBox.Show("Error adding menu item: " + ex.Message);
    }
    }

    /// <summary>
    /// Opens (or activates) the Risk Manager window.
    /// </summary>
    private void ShowRiskManager()
    {
    if (riskWindow != null)
    {
    riskWindow.Activate();
    return;
    }

    riskWindow = new Window
    {
    Title = "Risk Manager",
    Width = 800,
    Height = 600,
    Content = CreateRiskManagerUI(),
    Topmost = true
    };

    riskWindow.Closed += (s, e) => riskWindow = null;
    riskWindow.Show();
    }

    /// <summary>
    /// Creates the UI for the Risk Manager window.
    /// </summary>
    private UIElement CreateRiskManagerUI()
    {
    // Create a grid for the UI.
    Grid grid = new Grid { Margin = new Thickness(10) };

    // Define columns: Account Name, Status, Per-Account Loss Limit, Flatten Button.
    grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(2, GridUnitType.Star) });
    grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(1, GridUnitType.Star) });
    grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(1, GridUnitType.Star) });
    grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(1, GridUnitType.Star) });

    int row = 0;
    // Header row.
    grid.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto });
    AddToGrid(grid, new TextBlock { Text = "Account", FontWeight = FontWeights.Bold }, 0, row);
    AddToGrid(grid, new TextBlock { Text = "Status", FontWeight = FontWeights.Bold }, 1, row);
    AddToGrid(grid, new TextBlock { Text = "Daily Loss Limit ($)", FontWeight = FontWeights.Bold }, 2, row);
    AddToGrid(grid, new TextBlock { Text = "Flatten", FontWeight = FontWeights.Bold }, 3, row);
    row++;

    // One row per account.
    foreach (var account in Account.All)
    {
    grid.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto });

    // Account Name.
    AddToGrid(grid, new TextBlock { Text = account.Name }, 0, row);

    // Status toggle button (placeholder).
    ToggleButton toggle = new ToggleButton { Content = "OFF", IsChecked = false };
    toggle.Checked += (s, e) => EnableAccount(account);
    toggle.Unchecked += (s, e) => DisableAccount(account);
    AddToGrid(grid, toggle, 1, row);

    // Per-account loss limit textbox.
    TextBox perAccountLossLimitBox = new TextBox { Text = dailyLossLimit.ToString(), IsEnabled = false };
    AddToGrid(grid, perAccountLossLimitBox, 2, row);
    accountLossLimitTextBoxes[account.Name] = perAccountLossLimitBox;

    // Manual Flatten button.
    Button flattenButton = new Button { Content = "FLATTEN", Background = Brushes.Red };
    flattenButton.Click += (s, e) => FlattenAccount(account);
    AddToGrid(grid, flattenButton, 3, row);

    row++;
    }

    // Global settings section.
    grid.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto });
    AddToGrid(grid, new TextBlock { Text = "Apply same daily loss limit for all accounts:" }, 0, row);
    applyToAllCheckBox = new CheckBox { IsChecked = false, IsEnabled = false };
    applyToAllCheckBox.Checked += (s, e) =>
    {
    foreach (var tb in accountLossLimitTextBoxes.Values)
    tb.IsEnabled = false;
    if (isUnlocked && globalLossLimitBox != null)
    globalLossLimitBox.IsEnabled = true;
    };
    applyToAllCheckBox.Unchecked += (s, e) =>
    {
    foreach (var tb in accountLossLimitTextBoxes.Values)
    tb.IsEnabled = isUnlocked;
    if (globalLossLimitBox != null)
    globalLossLimitBox.IsEnabled = false;
    };
    AddToGrid(grid, applyToAllCheckBox, 1, row);
    row++;

    grid.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto });
    AddToGrid(grid, new TextBlock { Text = "Global Daily Loss Limit ($):" }, 0, row);
    globalLossLimitBox = new TextBox { Text = dailyLossLimit.ToString(), IsEnabled = false };
    AddToGrid(grid, globalLossLimitBox, 1, row);
    row++;

    grid.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto });
    AddToGrid(grid, new TextBlock { Text = "Password to Unlock Settings:" }, 0, row);
    passwordBox = new PasswordBox();
    passwordBox.PasswordChanged += (s, e) => UnlockSettings();
    AddToGrid(grid, passwordBox, 1, row);
    row++;

    grid.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto });
    statusLabel = new Label { Content = "Settings Locked", Foreground = Brushes.Red };
    AddToGrid(grid, statusLabel, 0, row);
    Grid.SetColumnSpan(statusLabel, 4);


Latest Posts

Collapse

Topics Statistics Last Post
Started by Geovanny Suaza, 02-11-2026, 06:32 PM
0 responses
557 views
0 likes
Last Post Geovanny Suaza  
Started by Geovanny Suaza, 02-11-2026, 05:51 PM
0 responses
324 views
1 like
Last Post Geovanny Suaza  
Started by Mindset, 02-09-2026, 11:44 AM
0 responses
101 views
0 likes
Last Post Mindset
by Mindset
 
Started by Geovanny Suaza, 02-02-2026, 12:30 PM
0 responses
545 views
1 like
Last Post Geovanny Suaza  
Started by RFrosty, 01-28-2026, 06:49 PM
0 responses
547 views
1 like
Last Post RFrosty
by RFrosty
 
Working...
X