1417 lines
102 KiB
MQL5
1417 lines
102 KiB
MQL5
//+---------------------------------------------------------------------------+
|
|
//| EQ Dashboard.mq5 |
|
|
//| Copyright 2025, by Ivan Butko |
|
|
//| https://www.mql5.com/ru/users/capitalplus |
|
|
//+---------------------------------------------------------------------------+
|
|
//| Historical equity of virtual positions with dynamic |
|
|
//| interactive dashboard |
|
|
//|---------------------------------------------------------------------------|
|
|
//| PURPOSE: |
|
|
//| - Calculate virtual equity of a portfolio |
|
|
//| - Provide a dynamic, interactive dashboard for managing symbols, |
|
|
//| volumes, and directions |
|
|
//| - Facilitate identification of volatile-flat structures |
|
|
//| - Analyze spread trading efficiency |
|
|
//| - Help determine entry/exit points for equity trading |
|
|
//| |
|
|
//| OPERATION PRINCIPLE: |
|
|
//| - Users activate/deactivate symbols via dashboard buttons |
|
|
//| - Adjust volumes and trade directions interactively |
|
|
//| - Equity line dynamically recalculates based on current selections |
|
|
//| - Cumulative profit/loss from all active positions is displayed |
|
|
//| - Dashboard provides quick control of settings and visualization |
|
|
//| |
|
|
//| HOW TO USE: |
|
|
//| 1. Use the dashboard to select symbols and set buy/sell directions |
|
|
//| 2. Adjust lot sizes using volume controls in the dashboard |
|
|
//| 3. Configure history depth and initial balance in inputs |
|
|
//| 4. Monitor historical virtual equity line and adjust parameters as needed |
|
|
//+---------------------------------------------------------------------------+
|
|
|
|
#property copyright "Copyright © 2025, iboot@yandex.ru, https://t.me/bootelega"
|
|
#property link "https://www.mql5.com/ru/users/capitalplus/seller"
|
|
#property version "1.1"
|
|
#property strict
|
|
|
|
//--- Indicator description ------------------------------------------
|
|
#property description "Historical virtual equity indicator with dynamic dashboard"
|
|
#property description "Purpose:"
|
|
#property description "- Model portfolio behavior with interactive symbol management"
|
|
#property description "- Visualize combined instrument movements with adjustable settings"
|
|
#property description "Applications:"
|
|
#property description "- Identify volatility-flat patterns for spread and equity trading"
|
|
#property description "- Evaluate spread and equity trading strategies using visual feedback"
|
|
#property description "- Dynamic control of portfolio components via on-chart dashboard"
|
|
|
|
#property indicator_separate_window
|
|
#property indicator_buffers 1
|
|
#property indicator_plots 1
|
|
#property indicator_type1 DRAW_LINE
|
|
#property indicator_color1 clrDodgerBlue
|
|
#property indicator_width1 1
|
|
#property indicator_label1 "Virtual Equity"
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| === Calculation Settings === |
|
|
//+------------------------------------------------------------------+
|
|
input group " -------- Calculation Settings -------- "
|
|
input int Bars_to_calculate = 1000; // Number of bars to calculate
|
|
input double Initial_balance = 0; // Initial virtual balance
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| === Dashboard Positioning Parameters === |
|
|
//+------------------------------------------------------------------+
|
|
input group " -------- Dashboard Positioning Parameters -------- "
|
|
input int Dashboard_Base_X = 50; // Base X coordinate
|
|
input int Dashboard_Base_Y = 50; // Base Y coordinate
|
|
|
|
// === Symbols ===
|
|
input group " -------- Symbols -------- "
|
|
input color Sym_ActiveClr = C'102,187,106'; // Active button color (bright grass green)
|
|
input color Sym_InactiveClr = C'240,243,248'; // Inactive button background (very light)
|
|
input color Sym_TextClr = C'36,42,56'; // Button text color
|
|
input int SymbolBut_Height = 25; // Button height
|
|
input int FntSize_SymbolButs = 10; // Button font size
|
|
|
|
// === Buy/Sell Buttons ===
|
|
input group " -------- Buy/Sell Buttons -------- "
|
|
input color BuySell_BuyClr = C'100,160,210'; // Buy button background color (light steel blue)
|
|
input color BuySell_SellClr = C'255,138,128'; // Sell button background color (light scarlet)
|
|
input color BuySell_TextClr = C'36,42,56'; // Buy/Sell button text color
|
|
input int BuySellBut_Width = 40; // Button width
|
|
input int BuySellBut_Height = 25; // Button height
|
|
input string BuySell_BuyText = "BUY"; // Buy button text
|
|
input string BuySell_SellText = "SELL"; // Sell button text
|
|
input int FntSize_BuySellButs = 10; // Button font size
|
|
|
|
// === Volume Management Buttons ===
|
|
input group " -------- Volume Management Buttons -------- "
|
|
input color VolMng_ButClr = C'240,243,248'; // Background color (light gray-blue)
|
|
input color VolMng_TextClr = C'36,42,56'; // Text color
|
|
input int VolMng_ButWidth = 20; // Button width
|
|
input int VolMng_ButHeight = 25; // Button height
|
|
input string VolMng_LotMns01Text = "«"; // Lot decrease by 0.1 button text
|
|
input string VolMng_LotMns001Text = "‹"; // Lot decrease by 0.01 button text
|
|
input string VolMng_LotPls001Text = "›"; // Lot increase by 0.01 button text
|
|
input string VolMng_LotPls01Text = "»"; // Lot increase by 0.1 button text
|
|
input int FntSize_VolButs = 15; // Font size
|
|
|
|
// === Input Field ===
|
|
input group " -------- Input Field -------- "
|
|
input int LotInput_Width = 50; // Input field width
|
|
input int LotInput_Height = 25; // Input field height
|
|
input color InputField_BgdClr = C'245,245,245'; // Background color
|
|
input color InputField_TextClr = C'36,42,56'; // Text color
|
|
input int FntSize_InputField = 11; // Font size
|
|
|
|
// === Columns Background ===
|
|
input group " -------- Columns Background -------- "
|
|
input color Bgd_Clr = C'220,225,230'; // Background color (soft bluish)
|
|
input color Bgd_BrdClr = C'180,185,195'; // Border color (slightly darker)
|
|
input int Bgd_Width = 280; // Width
|
|
input int Bgd_Height = 80; // Height
|
|
|
|
// === Dashboard Header ===
|
|
input group " -------- Dashboard Header -------- "
|
|
input color Hdr_BgdClr = C'245,247,250'; // Background color
|
|
input color Hdr_BrdClr = C'220,224,230'; // Border color
|
|
input string Hdr_Title = "EQ"; // Title text
|
|
input color Hdr_TitleClr = C'40,44,52'; // Title color
|
|
input int Hdr_Width = 280; // Width
|
|
input int Hdr_Height = 25; // Height
|
|
input int FntSize_HdrAndTopButs = 10; // Font size for header and top buttons
|
|
|
|
// === Reset Settings Button ===
|
|
input group " -------- Reset Settings Button -------- "
|
|
input color RstSet_ButClr = C'255,138,128'; // Background color (light red)
|
|
input color RstSet_TextClr = C'255,255,255'; // Text color (white)
|
|
input int RstAllBut_Width = 20; // Width
|
|
input int RstAllBut_Height = 20; // Height
|
|
input string RstAllBut_Text = "R"; // Text
|
|
|
|
// === Theme Switch Button ===
|
|
input group " -------- Theme Switch Button -------- "
|
|
input color ThemeSwitch_ButClr = C'144,176,160'; // Background color (light moss green)
|
|
input color ThemeSwitch_TextClr = C'255,255,255'; // Text color (white)
|
|
input int ThemeSwitchBut_Width = 20; // Width
|
|
input int ThemeSwitchBut_Height= 20; // Height
|
|
input string ThemeSwitchBut_Text = "☼"; // Text
|
|
|
|
// === Dashboard Scaling Buttons ===
|
|
input group " -------- Dashboard Scaling Buttons -------- "
|
|
input color SclPlsBut_Clr = C'170,210,240'; // Background color (light blue)
|
|
input color SclPlsBut_TextClr = C'36,42,56'; // Text color
|
|
input int SclPlsBut_Width = 20; // Width
|
|
input int SclPlsBut_Height = 20; // Height
|
|
input string SclPlsBut_Text = "+"; // Text
|
|
|
|
input color SclMnsBut_Clr = C'170,210,240'; // Background color (light blue)
|
|
input color SclMnsBut_TextClr = C'36,42,56'; // Text color
|
|
input int SclMnsBut_Width = 20; // Width
|
|
input int SclMnsBut_Height = 20; // Height
|
|
input string SclMnsBut_Text = "–"; // Text
|
|
|
|
input int FntSize_SclButs = 10; // Font size
|
|
|
|
// === Column Management Buttons ===
|
|
input group " -------- Column Management Buttons -------- "
|
|
input color ClnMng_ButClr = C'180,190,210'; // Background color (light gray-purple)
|
|
input color ClnMng_TextClr = C'36,42,56'; // Text color
|
|
input int DcrClnsBut_Width = 20; // Decrease columns button width
|
|
input int DcrClnsBut_Height = 20; // Decrease columns button height
|
|
input string DcrClnsBut_Text = "<"; // Decrease columns button text
|
|
input int IcrClnsBut_Width = 20; // Increase columns button width
|
|
input int IcrClnsBut_Height = 20; // Increase columns button height
|
|
input string IcrClnsBut_Text = ">"; // Increase columns button text
|
|
|
|
// === Collapse/Expand Button ===
|
|
input group " -------- Collapse/Expand Button -------- "
|
|
input color Hid_ButClr = C'255,236,140'; // Background color (light yellow)
|
|
input color Hid_TextClr = C'36,42,56'; // Text color
|
|
input int HidBut_Width = 20; // Width
|
|
input int HidBut_Height = 20; // Height
|
|
input string Hid_CollapseText = "—"; // Text when collapsed
|
|
input string Hid_ExpandText = "+"; // Text when expanded
|
|
|
|
// === Close (Delete Indicator) Button ===
|
|
input group " -------- Close (Delete Indicator) Button -------- "
|
|
input color CloseDelete_ButClr = C'255,138,128'; // Background color (light red)
|
|
input color CloseDelete_TextClr = C'255,255,255'; // Text color (white)
|
|
input int CloseDeleteBut_Width = 20; // Width
|
|
input int CloseDeleteBut_Height= 20; // Height
|
|
input string CloseDeleteBut_Text = "X"; // Text
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Structure to simplify UI state management |
|
|
//+------------------------------------------------------------------+
|
|
struct SymbolState
|
|
{
|
|
bool active; // Symbol active state
|
|
bool is_sell; // Sell or buy direction
|
|
double lot_value; // Lot size
|
|
string symbol_name; // Symbol name
|
|
|
|
SymbolState() : active(false), is_sell(false), lot_value(0.1) {}
|
|
};
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Global positioning constants |
|
|
//+------------------------------------------------------------------+
|
|
const int Cln_Width = 300; // Width of a column (used for X offset positioning)
|
|
const int Row_Height = 30; // Height of a row (used for Y offset positioning)
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Theme switching |
|
|
//+------------------------------------------------------------------+
|
|
enum ThemeType { THEME_DARK = 0, THEME_LIGHT = 1, THEME_CUSTOM = 2 };
|
|
ThemeType g_theme = THEME_CUSTOM; // Default theme is custom
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| UI variables |
|
|
//+------------------------------------------------------------------+
|
|
const string PFX = "Dashboard_"; // Prefix for UI object names
|
|
int g_clnCnt = 1; // Number of columns currently displayed
|
|
bool g_panelExpanded = true; // Dashboard panel expansion flag
|
|
bool g_manualDeletion = false; // Manual indicator deletion flag
|
|
string g_indName; // Indicator name string
|
|
SymbolState g_symSts[]; // Array holding state for each symbol
|
|
int g_ttlSym; // Total number of symbols available
|
|
double g_scl = 1.0; // Current UI scaling factor
|
|
string g_hdrTitle = "EQ"; // Header title string
|
|
string g_loadHistoryLabel = "EQ_LoadHistoryLabel"; // Label for loading history
|
|
|
|
// Auto-calculated symbol button width
|
|
int g_symButW = 100;
|
|
|
|
// Calculation buffers and flags
|
|
double E_buf[]; // Buffer for equity values
|
|
double g_initlPrs[]; // Array of initial prices
|
|
int g_dir[]; // Trade direction: 1=buy, -1=sell
|
|
bool g_startFlag = true; // First run flag
|
|
bool g_startChartFlag = true; // Chart redraw trigger flag
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Initialization function: sets up indicator and UI |
|
|
//+------------------------------------------------------------------+
|
|
int OnInit()
|
|
{
|
|
// Get the name of this indicator program
|
|
g_indName = MQL5InfoString(MQL5_PROGRAM_NAME);
|
|
|
|
// Get total number of symbols available in Market Watch
|
|
g_ttlSym = SymbolsTotal(true);
|
|
|
|
// Resize symbol state array to total symbols count
|
|
ArrayResize(g_symSts, g_ttlSym);
|
|
|
|
// Initialize symbol names in the symbol state array
|
|
InitializeSymbolNames();
|
|
|
|
// Calculate button width for symbols dynamically based on symbol name lengths
|
|
CalcSymbolButWidth();
|
|
|
|
// Load saved states from previous sessions (active symbols, lots, directions)
|
|
LoadStates();
|
|
|
|
// Apply colors according to selected theme
|
|
ApplyThemeColors();
|
|
|
|
// Create the user interface elements (buttons, labels, etc)
|
|
CreateUI();
|
|
|
|
// Set timer event to trigger every 100 milliseconds for UI updates
|
|
EventSetMillisecondTimer(100);
|
|
|
|
// Initialize calculation buffers to hold initial prices and directions
|
|
ArrayResize(g_initlPrs, g_ttlSym);
|
|
ArrayResize(g_dir, g_ttlSym);
|
|
|
|
// Bind the indicator buffer to E_buf for plotting virtual equity line
|
|
SetIndexBuffer(0, E_buf, INDICATOR_DATA);
|
|
|
|
// Set buffer to be indexed as series (time series with index 0 as latest bar)
|
|
ArraySetAsSeries(E_buf, true);
|
|
|
|
// Set number of decimal digits for indicator values
|
|
IndicatorSetInteger(INDICATOR_DIGITS, 2);
|
|
|
|
return(INIT_SUCCEEDED); // Initialization successful
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Deinitialization function: cleans up on indicator removal |
|
|
//+------------------------------------------------------------------+
|
|
void OnDeinit(const int reason)
|
|
{
|
|
// Stop the timer event
|
|
EventKillTimer();
|
|
|
|
// If indicator was not deleted manually, save states and remove UI objects
|
|
if (!g_manualDeletion)
|
|
{
|
|
SaveStates(); // Save current symbol states to persistent storage
|
|
DeleteAllObjects(); // Remove all created UI objects from chart
|
|
}
|
|
|
|
// Remove loading history label if it exists
|
|
if (ObjectFind(0, g_loadHistoryLabel) != -1)
|
|
ObjectDelete(0, g_loadHistoryLabel);
|
|
|
|
// Redraw chart to update display after cleanup
|
|
ChartRedraw();
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Calculation entry point: called on each new tick or bar update |
|
|
//+------------------------------------------------------------------+
|
|
int OnCalculate(const int rates_total, const int prev_calculated, const datetime &time[],
|
|
const double &open[], const double &high[], const double &low[],
|
|
const double &close[], const long &tick_volume[], const long &volume[],
|
|
const int &spread[])
|
|
{
|
|
// Perform main calculation and UI update
|
|
Main();
|
|
|
|
// Return total bars processed to MetaTrader engine
|
|
return(rates_total);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Timer event handler: called every 100 ms to update UI |
|
|
//+------------------------------------------------------------------+
|
|
void OnTimer()
|
|
{
|
|
// Checks for new Market Watch symbols and adds them to the dashboard without resetting settings.
|
|
SyncAndRebuildDashboard();
|
|
// Run main update logic on timer event
|
|
Main();
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Main calculation and update function |
|
|
//+------------------------------------------------------------------+
|
|
void Main()
|
|
{
|
|
// Update the header title text on the dashboard
|
|
UpdateHdrTitle();
|
|
|
|
// Arrays to hold active symbol info: names, directions, and lot sizes
|
|
string actSym[];
|
|
int actDir[];
|
|
double actLot[];
|
|
|
|
// Retrieve currently active symbols and their parameters
|
|
GetActiveSymbols(actSym, actDir, actLot);
|
|
|
|
// Count how many symbols are active
|
|
int actCnt = ArraySize(actSym);
|
|
|
|
// If no active symbols, clear equity buffer and exit
|
|
if(actCnt == 0)
|
|
{
|
|
ArrayInitialize(E_buf, 0.0); // Reset equity buffer to zero
|
|
return;
|
|
}
|
|
|
|
int start = 0; // Starting bar index for calculation
|
|
|
|
// On first run, initialize buffers and read initial prices
|
|
if(g_startFlag)
|
|
{
|
|
ArrayInitialize(E_buf, EMPTY_VALUE); // Mark equity buffer as empty initially
|
|
|
|
// Resize arrays to active symbols count
|
|
ArrayResize(g_initlPrs, actCnt);
|
|
ArrayResize(g_dir, actCnt);
|
|
|
|
// Loop through each active symbol
|
|
for(int i = 0; i < actCnt; i++)
|
|
{
|
|
// Validate symbol availability and history
|
|
if(!CheckSymbol(actSym[i]))
|
|
return; // Exit if symbol data is not ready
|
|
|
|
// Store trade direction for symbol (1 for buy, -1 for sell)
|
|
g_dir[i] = actDir[i];
|
|
|
|
// Store initial opening price at Bars_to_calculate offset for symbol
|
|
g_initlPrs[i] = iOpen(actSym[i], _Period, Bars_to_calculate);
|
|
}
|
|
|
|
// Start calculation from Bars_to_calculate bars ago
|
|
start = Bars_to_calculate;
|
|
|
|
// Clear the start flag after initialization
|
|
g_startFlag = false;
|
|
}
|
|
else
|
|
{
|
|
// On subsequent runs, start from the latest bar (index 0)
|
|
start = 0;
|
|
|
|
// If chart redraw is pending, trigger it once
|
|
if(g_startChartFlag)
|
|
{
|
|
ChartRedraw();
|
|
g_startChartFlag = false;
|
|
}
|
|
}
|
|
|
|
// Loop backwards through bars from start to 0 (latest bar)
|
|
for(int i = start; i >= 0; i--)
|
|
{
|
|
double equity = Initial_balance; // Reset equity to initial balance at each bar
|
|
|
|
// Loop through all active symbols to calculate equity contribution
|
|
for(int j = 0; j < actCnt; j++)
|
|
{
|
|
string symbol = actSym[j]; // Current symbol name
|
|
|
|
// Get close price for symbol at bar i
|
|
double curClose = iClose(symbol, _Period, i);
|
|
|
|
// Skip if close price is zero (invalid data)
|
|
if(curClose == 0)
|
|
continue;
|
|
|
|
// Calculate price change in points from initial price
|
|
double priceChange = (curClose - g_initlPrs[j]) / SymbolInfoDouble(symbol, SYMBOL_POINT);
|
|
|
|
// Calculate point value for symbol (monetary value per point)
|
|
double pointValue = CalculatePointValue(symbol);
|
|
|
|
// Update equity by adding price change * direction * lot size * point value
|
|
equity += priceChange * g_dir[j] * actLot[j] * pointValue;
|
|
}
|
|
|
|
// Store calculated equity value in buffer for plotting
|
|
E_buf[i] = equity;
|
|
|
|
// If first equity value is empty, redraw chart to update display
|
|
if(E_buf[0] == EMPTY_VALUE)
|
|
ChartRedraw();
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Symbol validation: checks if symbol is available and has history|
|
|
//+------------------------------------------------------------------+
|
|
bool CheckSymbol(string symbol)
|
|
{
|
|
// Try to select symbol in Market Watch, returns false if symbol not found
|
|
if(!SymbolSelect(symbol, true))
|
|
{
|
|
Print(symbol + " - error: symbol not found in Market Watch!");
|
|
return false;
|
|
}
|
|
|
|
// Check if close price at Bars_to_calculate is valid (non-zero)
|
|
if(iClose(symbol, PERIOD_CURRENT, Bars_to_calculate) <= 0)
|
|
{
|
|
// Show loading message for symbol history
|
|
Comment("LOADING HISTORY: " + symbol);
|
|
return false;
|
|
}
|
|
|
|
// Symbol is valid and has sufficient history
|
|
return true;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Calculate point value for symbol: monetary value per symbol point|
|
|
//+------------------------------------------------------------------+
|
|
double CalculatePointValue(string symbol)
|
|
{
|
|
// Get tick value in account currency for the symbol
|
|
double tickValue = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_VALUE);
|
|
|
|
// Get tick size (minimum price change) for the symbol
|
|
double tickSize = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_SIZE);
|
|
|
|
// Get point size for the symbol (usually equal to tick size or fraction)
|
|
double point = SymbolInfoDouble(symbol, SYMBOL_POINT);
|
|
|
|
// Calculate and return monetary value of one point move for the symbol
|
|
return tickValue * (point / tickSize);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//+--------------------------------------------------------------------+
|
|
//| ========================= DASHBOARD ============================== |
|
|
//+--------------------------------------------------------------------+
|
|
|
|
color Hdr_BgdClr_work, Hdr_BrdClr_work, Hdr_TitleClr_work;
|
|
color RstSet_ButClr_work, RstSet_TextClr_work;
|
|
color SclPlsBut_Clr_work, SclPlsBut_TextClr_work, SclMnsBut_Clr_work, SclMnsBut_TextClr_work;
|
|
color ClnMng_ButClr_work, ClnMng_TextClr_work;
|
|
color Hid_ButClr_work, Hid_TextClr_work;
|
|
color CloseDelete_ButClr_work, CloseDelete_TextClr_work;
|
|
color Sym_ActiveClr_work, Sym_InactiveClr_work, Sym_TextClr_work;
|
|
color BuySell_BuyClr_work, BuySell_SellClr_work, BuySell_TextClr_work;
|
|
color VolMng_ButClr_work, VolMng_TextClr_work;
|
|
color InputField_BgdClr_work, InputField_TextClr_work;
|
|
color Bgd_Clr_work, Bgd_BrdClr_work;
|
|
color ThemeSwitch_ButClr_work, ThemeSwitch_TextClr_work;
|
|
|
|
int Sht_HdrBg_X = 0;
|
|
int Sht_HdrBg_Y = 0;
|
|
|
|
int Sht_HdrTitle_X = 5;
|
|
int Sht_HdrTitle_Y = 5;
|
|
|
|
int Sht_RstAllBut_X = 117;
|
|
int Sht_RstAllBut_Y = 2;
|
|
|
|
int Sht_ThemeSwitchBut_X = 137;
|
|
int Sht_ThemeSwitchBut_Y = 2;
|
|
|
|
int Sht_SclPlsBut_X = 157;
|
|
int Sht_SclPlsBut_Y = 2;
|
|
|
|
int Sht_SclMnsBut_X = 177;
|
|
int Sht_SclMnsBut_Y = 2;
|
|
|
|
int Sht_DcrClnsBut_X = 197;
|
|
int Sht_DcrClnsBut_Y = 2;
|
|
|
|
int Sht_IcrClnsBut_X = 217;
|
|
int Sht_IcrClnsBut_Y = 2;
|
|
|
|
int Sht_HidBut_X = 237;
|
|
int Sht_HidBut_Y = 2;
|
|
|
|
int Sht_DltIndBut_X = 257;
|
|
int Sht_DltIndBut_Y = 2;
|
|
|
|
int Sht_ClnBgd_X = 0;
|
|
int Sht_ClnBgd_Y = 0;
|
|
|
|
int Sht_SymbolBut_X = 5;
|
|
int Sht_SymbolBut_Y = -5;
|
|
|
|
int Sht_BuySellBut_X = 80;
|
|
int Sht_BuySellBut_Y = 0;
|
|
|
|
int Sht_LotMns01But_X = 130;
|
|
int Sht_LotMns01But_Y = 0;
|
|
|
|
int Sht_LotMns001But_X = 150;
|
|
int Sht_LotMns001But_Y = 0;
|
|
|
|
int Sht_LotInput_X = 175;
|
|
int Sht_LotInput_Y = 0;
|
|
|
|
int Sht_LotPls001But_X = 230;
|
|
int Sht_LotPls001But_Y = 0;
|
|
|
|
int Sht_LotPls01But_X = 250;
|
|
int Sht_LotPls01But_Y = 0;
|
|
|
|
void CalcSymbolButWidth()
|
|
{
|
|
int maxLen = 0;
|
|
for(int i=0; i<g_ttlSym; i++)
|
|
{
|
|
int len = StringLen(g_symSts[i].symbol_name);
|
|
if(len > maxLen)
|
|
maxLen = len;
|
|
}
|
|
g_symButW = 8 * maxLen + 24;
|
|
if(g_symButW < 60) g_symButW = 60;
|
|
if(g_symButW > 200) g_symButW = 200;
|
|
}
|
|
|
|
|
|
void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
|
|
{
|
|
if(id != CHARTEVENT_OBJECT_CLICK && id != CHARTEVENT_OBJECT_ENDEDIT) return;
|
|
|
|
bool needRecalc = false;
|
|
|
|
if(id == CHARTEVENT_OBJECT_CLICK)
|
|
{
|
|
SetButState(sparam, true);
|
|
needRecalc = ProcessClick(sparam);
|
|
SetButState(sparam, false);
|
|
}
|
|
else if(id == CHARTEVENT_OBJECT_ENDEDIT)
|
|
{
|
|
needRecalc = ProcessInputEdit(sparam);
|
|
}
|
|
|
|
if(needRecalc)
|
|
{
|
|
g_startFlag = true;
|
|
Main();
|
|
ChartRedraw();
|
|
}
|
|
}
|
|
|
|
bool ProcessClick(string objName)
|
|
{
|
|
if(objName == PFX + "RstAllBut") { RstAllStates(); return true; }
|
|
if(objName == PFX + "ThemeSwitchBut") { SwitchTheme(); return false; }
|
|
if(objName == PFX + "SclPlsBut") { g_scl += 0.1; if(g_scl > 3.0) g_scl = 3.0; RecreateUI(); return false; }
|
|
if(objName == PFX + "SclMnsBut") { g_scl -= 0.1; if(g_scl < 0.5) g_scl = 0.5; RecreateUI(); return false; }
|
|
if(objName == PFX + "IcrClnsBut") { ChangeClnCount(g_clnCnt + 1); return false; }
|
|
if(objName == PFX + "DcrClnsBut") { ChangeClnCount(MathMax(1, g_clnCnt - 1)); return false; }
|
|
if(objName == PFX + "HidBut") { TogglePanel(); return false; }
|
|
if(objName == PFX + "DltIndBut") { DltInd(); return false; }
|
|
|
|
return ProcessSymbolClick(objName);
|
|
}
|
|
|
|
void RecreateUI()
|
|
{
|
|
DeleteAllObjects();
|
|
CreateUI();
|
|
ChartRedraw();
|
|
}
|
|
|
|
bool ProcessSymbolClick(string objName)
|
|
{
|
|
for(int i = 0; i < g_ttlSym; i++)
|
|
{
|
|
string symName = g_symSts[i].symbol_name;
|
|
|
|
if(objName == PFX + "Symbol_" + symName)
|
|
{
|
|
g_symSts[i].active = !g_symSts[i].active;
|
|
UpdateSymbolBut(i);
|
|
SaveStates();
|
|
return true;
|
|
}
|
|
|
|
if(objName == PFX + "BuySell_" + symName)
|
|
{
|
|
g_symSts[i].is_sell = !g_symSts[i].is_sell;
|
|
UpdateBuySellBut(i);
|
|
SaveStates();
|
|
if (g_symSts[i].active) return true;
|
|
else return false;
|
|
}
|
|
|
|
string lotButs[] = {"Lot1_", "Lot2_", "Lot3_", "Lot4_"};
|
|
double lotChanges[] = {-0.1, -0.01, 0.01, 0.1};
|
|
|
|
for(int j = 0; j < 4; j++)
|
|
{
|
|
if(objName == PFX + lotButs[j] + symName)
|
|
{
|
|
g_symSts[i].lot_value = MathMax(0, g_symSts[i].lot_value + lotChanges[j]);
|
|
UpdateLotInput(i);
|
|
SaveStates();
|
|
if (g_symSts[i].active) return true;
|
|
else return false;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool ProcessInputEdit(string objName)
|
|
{
|
|
for(int i = 0; i < g_ttlSym; i++)
|
|
{
|
|
if(objName == PFX + "LotInput_" + g_symSts[i].symbol_name)
|
|
{
|
|
g_symSts[i].lot_value = StringToDouble(ObjectGetString(0, objName, OBJPROP_TEXT));
|
|
SaveStates();
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void CreateUI()
|
|
{
|
|
CreateHdrPanel();
|
|
CreateTopButs();
|
|
if(g_panelExpanded)
|
|
{
|
|
CreateClnBgds();
|
|
CreateSymbolButs();
|
|
ApplyStates();
|
|
}
|
|
}
|
|
|
|
void CreateHdrPanel()
|
|
{
|
|
CreateBgd(PFX + "HdrBg", Dashboard_Base_X + Sht_HdrBg_X, Dashboard_Base_Y + Sht_HdrBg_Y, Hdr_Width, Hdr_Height, Hdr_BgdClr_work, Hdr_BrdClr_work);
|
|
|
|
string name = PFX + "HdrTitle";
|
|
int relX = Sht_HdrTitle_X;
|
|
int relY = Sht_HdrTitle_Y;
|
|
int sclX = Dashboard_Base_X + int(relX * g_scl);
|
|
int sclY = Dashboard_Base_Y + int(relY * g_scl);
|
|
int sclFntSize = MathMax(8, int(FntSize_HdrAndTopButs * g_scl));
|
|
|
|
if(ObjectCreate(0, name, OBJ_LABEL, 0, 0, 0))
|
|
{
|
|
ObjectSetInteger(0, name, OBJPROP_XDISTANCE, sclX);
|
|
ObjectSetInteger(0, name, OBJPROP_YDISTANCE, sclY);
|
|
ObjectSetInteger(0, name, OBJPROP_FONTSIZE, sclFntSize);
|
|
ObjectSetInteger(0, name, OBJPROP_COLOR, Hdr_TitleClr_work);
|
|
ObjectSetInteger(0, name, OBJPROP_CORNER, 0);
|
|
ObjectSetString(0, name, OBJPROP_TEXT, g_hdrTitle);
|
|
ObjectSetInteger(0, name, OBJPROP_SELECTABLE, false);
|
|
ObjectSetInteger(0, name, OBJPROP_HIDDEN, true);
|
|
ObjectSetInteger(0, name, OBJPROP_ZORDER, 0);
|
|
}
|
|
}
|
|
|
|
void CreateTopButs()
|
|
{
|
|
struct TopBtn { string name, text; int x, y, w, h; color bg, fg; int fontSize; };
|
|
TopBtn buttons[] = {
|
|
{"DcrClnsBut", DcrClnsBut_Text,
|
|
Dashboard_Base_X + Sht_DcrClnsBut_X,
|
|
Dashboard_Base_Y + Sht_DcrClnsBut_Y,
|
|
DcrClnsBut_Width, DcrClnsBut_Height,
|
|
ClnMng_ButClr_work, ClnMng_TextClr_work,
|
|
FntSize_HdrAndTopButs},
|
|
|
|
{"ThemeSwitchBut", ThemeSwitchBut_Text,
|
|
Dashboard_Base_X + Sht_ThemeSwitchBut_X,
|
|
Dashboard_Base_Y + Sht_ThemeSwitchBut_Y,
|
|
ThemeSwitchBut_Width, ThemeSwitchBut_Height,
|
|
ThemeSwitch_ButClr_work, ThemeSwitch_TextClr_work,
|
|
FntSize_HdrAndTopButs},
|
|
|
|
{"IcrClnsBut", IcrClnsBut_Text,
|
|
Dashboard_Base_X + Sht_IcrClnsBut_X,
|
|
Dashboard_Base_Y + Sht_IcrClnsBut_Y,
|
|
IcrClnsBut_Width, IcrClnsBut_Height,
|
|
ClnMng_ButClr_work, ClnMng_TextClr_work,
|
|
FntSize_HdrAndTopButs},
|
|
|
|
{"RstAllBut", RstAllBut_Text,
|
|
Dashboard_Base_X + Sht_RstAllBut_X,
|
|
Dashboard_Base_Y + Sht_RstAllBut_Y,
|
|
RstAllBut_Width, RstAllBut_Height,
|
|
RstSet_ButClr_work, RstSet_TextClr_work,
|
|
FntSize_HdrAndTopButs},
|
|
|
|
// Кнопка "+" масштабирования
|
|
{"SclPlsBut", SclPlsBut_Text,
|
|
Dashboard_Base_X + Sht_SclPlsBut_X,
|
|
Dashboard_Base_Y + Sht_SclPlsBut_Y,
|
|
SclPlsBut_Width, SclPlsBut_Height,
|
|
SclPlsBut_Clr_work, SclPlsBut_TextClr_work,
|
|
FntSize_SclButs},
|
|
|
|
// Кнопка "–" масштабирования
|
|
{"SclMnsBut", SclMnsBut_Text,
|
|
Dashboard_Base_X + Sht_SclMnsBut_X,
|
|
Dashboard_Base_Y + Sht_SclMnsBut_Y,
|
|
SclMnsBut_Width, SclMnsBut_Height,
|
|
SclMnsBut_Clr_work, SclMnsBut_TextClr_work,
|
|
FntSize_SclButs},
|
|
|
|
{"HidBut", g_panelExpanded ? Hid_CollapseText : Hid_ExpandText,
|
|
Dashboard_Base_X + Sht_HidBut_X,
|
|
Dashboard_Base_Y + Sht_HidBut_Y,
|
|
HidBut_Width, HidBut_Height,
|
|
Hid_ButClr_work, Hid_TextClr_work,
|
|
FntSize_HdrAndTopButs},
|
|
|
|
{"DltIndBut", CloseDeleteBut_Text,
|
|
Dashboard_Base_X + Sht_DltIndBut_X,
|
|
Dashboard_Base_Y + Sht_DltIndBut_Y,
|
|
CloseDeleteBut_Width, CloseDeleteBut_Height,
|
|
CloseDelete_ButClr_work, CloseDelete_TextClr_work,
|
|
FntSize_HdrAndTopButs}
|
|
};
|
|
|
|
for(int i = 0; i < ArraySize(buttons); i++)
|
|
{
|
|
CreateBut(PFX + buttons[i].name,
|
|
buttons[i].x, buttons[i].y,
|
|
buttons[i].w, buttons[i].h,
|
|
buttons[i].bg, buttons[i].fg,
|
|
buttons[i].text, buttons[i].fontSize);
|
|
}
|
|
}
|
|
|
|
void CreateSymbolButs()
|
|
{
|
|
for(int i = 0; i < g_ttlSym; i++)
|
|
{
|
|
string symName = g_symSts[i].symbol_name;
|
|
int col = i % g_clnCnt;
|
|
int row = i / g_clnCnt;
|
|
int xShift = col * Cln_Width;
|
|
int yShift = row * Row_Height;
|
|
|
|
int baseX = Dashboard_Base_X + xShift + Sht_SymbolBut_X;
|
|
int baseY = Dashboard_Base_Y + Hdr_Height + 10 + yShift + Sht_SymbolBut_Y;
|
|
|
|
color symbolBg = g_symSts[i].active ? Sym_ActiveClr : Sym_InactiveClr;
|
|
int butW = g_symButW;
|
|
int butH = SymbolBut_Height;
|
|
|
|
CreateBut(PFX + "Symbol_" + symName, baseX, baseY, butW, butH, symbolBg, Sym_TextClr_work, symName, FntSize_SymbolButs);
|
|
|
|
// Кнопка Buy/Sell
|
|
color buySellBg = g_symSts[i].is_sell ? BuySell_SellClr_work : BuySell_BuyClr_work;
|
|
string buySellText = g_symSts[i].is_sell ? BuySell_SellText : BuySell_BuyText;
|
|
CreateBut(PFX + "BuySell_" + symName,
|
|
baseX + Sht_BuySellBut_X, baseY + Sht_BuySellBut_Y,
|
|
BuySellBut_Width, BuySellBut_Height,
|
|
buySellBg, BuySell_TextClr_work, buySellText, FntSize_BuySellButs);
|
|
|
|
CreateBut(PFX + "Lot1_" + symName, baseX + Sht_LotMns01But_X, baseY + Sht_LotMns01But_Y,
|
|
VolMng_ButWidth, VolMng_ButHeight, VolMng_ButClr_work, VolMng_TextClr_work, VolMng_LotMns01Text, FntSize_VolButs);
|
|
CreateBut(PFX + "Lot2_" + symName, baseX + Sht_LotMns001But_X, baseY + Sht_LotMns001But_Y,
|
|
VolMng_ButWidth, VolMng_ButHeight, VolMng_ButClr_work, VolMng_TextClr_work, VolMng_LotMns001Text, FntSize_VolButs);
|
|
|
|
CreateInputField(PFX + "LotInput_" + symName, baseX + Sht_LotInput_X, baseY + Sht_LotInput_Y,
|
|
LotInput_Width, LotInput_Height, InputField_BgdClr_work, InputField_TextClr_work,
|
|
DoubleToString(g_symSts[i].lot_value, 2));
|
|
|
|
CreateBut(PFX + "Lot3_" + symName, baseX + Sht_LotPls001But_X, baseY + Sht_LotPls001But_Y,
|
|
VolMng_ButWidth, VolMng_ButHeight, VolMng_ButClr_work, VolMng_TextClr_work, VolMng_LotPls001Text, FntSize_VolButs);
|
|
CreateBut(PFX + "Lot4_" + symName, baseX + Sht_LotPls01But_X, baseY + Sht_LotPls01But_Y,
|
|
VolMng_ButWidth, VolMng_ButHeight, VolMng_ButClr_work, VolMng_TextClr_work, VolMng_LotPls01Text, FntSize_VolButs);
|
|
}
|
|
}
|
|
|
|
void CreateBut(string name, int x, int y, int w, int h, color bg, color fg, string text, int baseFntSize = 10)
|
|
{
|
|
int relX = x - Dashboard_Base_X;
|
|
int relY = y - Dashboard_Base_Y;
|
|
int sclX = Dashboard_Base_X + int(relX * g_scl);
|
|
int sclY = Dashboard_Base_Y + int(relY * g_scl);
|
|
int sclW = int(w * g_scl);
|
|
int sclH = int(h * g_scl);
|
|
int sclFntSize = MathMax(8, int(baseFntSize * g_scl)); // минимум 8 для читаемости
|
|
|
|
if(ObjectCreate(0, name, OBJ_BUTTON, 0, 0, 0))
|
|
{
|
|
ObjectSetInteger(0, name, OBJPROP_XDISTANCE, sclX);
|
|
ObjectSetInteger(0, name, OBJPROP_YDISTANCE, sclY);
|
|
ObjectSetInteger(0, name, OBJPROP_XSIZE, sclW);
|
|
ObjectSetInteger(0, name, OBJPROP_YSIZE, sclH);
|
|
ObjectSetInteger(0, name, OBJPROP_BGCOLOR, bg);
|
|
ObjectSetInteger(0, name, OBJPROP_COLOR, fg);
|
|
ObjectSetInteger(0, name, OBJPROP_FONTSIZE, sclFntSize);
|
|
ObjectSetInteger(0, name, OBJPROP_STATE, false);
|
|
ObjectSetString(0, name, OBJPROP_TEXT, text);
|
|
}
|
|
}
|
|
|
|
void CreateInputField(string name, int x, int y, int w, int h, color bg, color fg, string text)
|
|
{
|
|
int relX = x - Dashboard_Base_X;
|
|
int relY = y - Dashboard_Base_Y;
|
|
int sclX = Dashboard_Base_X + int(relX * g_scl);
|
|
int sclY = Dashboard_Base_Y + int(relY * g_scl);
|
|
int sclW = int(w * g_scl);
|
|
int sclH = int(h * g_scl);
|
|
int sclFntSize = MathMax(8, int(FntSize_InputField * g_scl));
|
|
|
|
if(ObjectCreate(0, name, OBJ_EDIT, 0, 0, 0))
|
|
{
|
|
ObjectSetInteger(0, name, OBJPROP_XDISTANCE, sclX);
|
|
ObjectSetInteger(0, name, OBJPROP_YDISTANCE, sclY);
|
|
ObjectSetInteger(0, name, OBJPROP_XSIZE, sclW);
|
|
ObjectSetInteger(0, name, OBJPROP_YSIZE, sclH);
|
|
ObjectSetInteger(0, name, OBJPROP_BGCOLOR, bg);
|
|
ObjectSetInteger(0, name, OBJPROP_COLOR, fg);
|
|
ObjectSetInteger(0, name, OBJPROP_FONTSIZE, sclFntSize);
|
|
ObjectSetInteger(0, name, OBJPROP_ALIGN, ALIGN_CENTER);
|
|
ObjectSetString(0, name, OBJPROP_TEXT, text);
|
|
}
|
|
}
|
|
|
|
void CreateBgd(string name, int x, int y, int w, int h, color bgclr, color brdclr)
|
|
{
|
|
int relX = x - Dashboard_Base_X;
|
|
int relY = y - Dashboard_Base_Y;
|
|
int sclX = Dashboard_Base_X + int(relX * g_scl);
|
|
int sclY = Dashboard_Base_Y + int(relY * g_scl);
|
|
int sclW = int(w * g_scl);
|
|
int sclH = int(h * g_scl);
|
|
|
|
if(ObjectCreate(0, name, OBJ_RECTANGLE_LABEL, 0, 0, 0))
|
|
{
|
|
ObjectSetInteger(0, name, OBJPROP_XDISTANCE, sclX);
|
|
ObjectSetInteger(0, name, OBJPROP_YDISTANCE, sclY);
|
|
ObjectSetInteger(0, name, OBJPROP_XSIZE, sclW);
|
|
ObjectSetInteger(0, name, OBJPROP_YSIZE, sclH);
|
|
ObjectSetInteger(0, name, OBJPROP_BGCOLOR, bgclr);
|
|
ObjectSetInteger(0, name, OBJPROP_BORDER_COLOR, brdclr);
|
|
ObjectSetInteger(0, name, OBJPROP_BORDER_TYPE, BORDER_FLAT);
|
|
ObjectSetInteger(0, name, OBJPROP_BACK, false);
|
|
ObjectSetInteger(0, name, OBJPROP_SELECTABLE, false);
|
|
ObjectSetInteger(0, name, OBJPROP_HIDDEN, true);
|
|
ObjectSetInteger(0, name, OBJPROP_ZORDER, -1);
|
|
}
|
|
}
|
|
|
|
void UpdateSymbolBut(int idx)
|
|
{
|
|
string name = PFX + "Symbol_" + g_symSts[idx].symbol_name;
|
|
color bg = g_symSts[idx].active ? Sym_ActiveClr_work : Sym_InactiveClr_work;
|
|
ObjectSetInteger(0, name, OBJPROP_BGCOLOR, bg);
|
|
}
|
|
|
|
void UpdateBuySellBut(int idx)
|
|
{
|
|
string name = PFX + "BuySell_" + g_symSts[idx].symbol_name;
|
|
color bg = g_symSts[idx].is_sell ? BuySell_SellClr_work : BuySell_BuyClr_work;
|
|
string text = g_symSts[idx].is_sell ? BuySell_SellText : BuySell_BuyText;
|
|
ObjectSetInteger(0, name, OBJPROP_BGCOLOR, bg);
|
|
ObjectSetString(0, name, OBJPROP_TEXT, text);
|
|
}
|
|
|
|
void UpdateLotInput(int idx)
|
|
{
|
|
string name = PFX + "LotInput_" + g_symSts[idx].symbol_name;
|
|
ObjectSetString(0, name, OBJPROP_TEXT, DoubleToString(g_symSts[idx].lot_value, 2));
|
|
}
|
|
|
|
void SetButState(string name, bool state)
|
|
{
|
|
ObjectSetInteger(0, name, OBJPROP_STATE, state);
|
|
ChartRedraw();
|
|
}
|
|
|
|
|
|
void InitializeSymbolNames()
|
|
{
|
|
for(int i = 0; i < g_ttlSym; i++)
|
|
{
|
|
g_symSts[i].symbol_name = SymbolName(i, true);
|
|
}
|
|
}
|
|
|
|
void DltInd()
|
|
{
|
|
g_manualDeletion = true;
|
|
SaveStates();
|
|
DeleteAllObjects();
|
|
|
|
int window = ChartWindowFind(0, g_indName);
|
|
if(window != -1)
|
|
ChartIndicatorDelete(0, window, g_indName);
|
|
}
|
|
|
|
void RstAllStates()
|
|
{
|
|
for(int i = 0; i < g_ttlSym; i++)
|
|
{
|
|
g_symSts[i].active = false;
|
|
g_symSts[i].is_sell = false;
|
|
g_symSts[i].lot_value = 0.1;
|
|
}
|
|
ApplyStates();
|
|
SaveStates();
|
|
}
|
|
|
|
void TogglePanel()
|
|
{
|
|
g_panelExpanded = !g_panelExpanded;
|
|
|
|
if(g_panelExpanded)
|
|
{
|
|
CreateClnBgds();
|
|
CreateSymbolButs();
|
|
ApplyStates();
|
|
}
|
|
else
|
|
{
|
|
DeleteSymbolObjects();
|
|
}
|
|
|
|
ObjectSetString(0, PFX + "HidBut", OBJPROP_TEXT,
|
|
g_panelExpanded ? Hid_CollapseText : Hid_ExpandText);
|
|
SaveStates();
|
|
}
|
|
|
|
void ChangeClnCount(int newCount)
|
|
{
|
|
g_clnCnt = newCount;
|
|
DeleteSymbolObjects();
|
|
CreateClnBgds();
|
|
CreateSymbolButs();
|
|
ApplyStates();
|
|
SaveStates();
|
|
}
|
|
|
|
void CreateClnBgds()
|
|
{
|
|
int total = g_ttlSym;
|
|
int cln = g_clnCnt;
|
|
|
|
int minRows = total / cln;
|
|
int extra = total % cln;
|
|
|
|
int gap = Cln_Width - Bgd_Width;
|
|
|
|
for(int col = 0; col < cln; col++)
|
|
{
|
|
int rowsInCln = minRows + (col < extra ? 1 : 0);
|
|
if(rowsInCln <= 0) continue;
|
|
|
|
int x = Dashboard_Base_X + col * Cln_Width - gap * col + Sht_ClnBgd_X;
|
|
int y = Dashboard_Base_Y + Hdr_Height + Sht_ClnBgd_Y;
|
|
int w = Bgd_Width + gap * col;
|
|
int h = rowsInCln * Row_Height + 5;
|
|
|
|
CreateBgd(PFX + "ColBg_" + IntegerToString(col), x, y, w, h, Bgd_Clr_work, Bgd_BrdClr_work);
|
|
}
|
|
}
|
|
|
|
void DeleteSymbolObjects()
|
|
{
|
|
for(int i = ObjectsTotal(0, 0, -1) - 1; i >= 0; i--)
|
|
{
|
|
string name = ObjectName(0, i);
|
|
if(StringFind(name, PFX) == 0 &&
|
|
StringFind(name, "HdrBg") == -1 &&
|
|
StringFind(name, "HdrTitle") == -1 &&
|
|
StringFind(name, "RstAllBut") == -1 &&
|
|
StringFind(name, "ThemeSwitchBut") == -1 &&
|
|
StringFind(name, "SclPlsBut") == -1 &&
|
|
StringFind(name, "SclMnsBut") == -1 &&
|
|
StringFind(name, "HidBut") == -1 &&
|
|
StringFind(name, "IcrClnsBut") == -1 &&
|
|
StringFind(name, "DcrClnsBut") == -1 &&
|
|
StringFind(name, "DltIndBut") == -1)
|
|
{
|
|
ObjectDelete(0, name);
|
|
}
|
|
}
|
|
}
|
|
|
|
void DeleteAllObjects()
|
|
{
|
|
for(int i = ObjectsTotal(0, 0, -1) - 1; i >= 0; i--)
|
|
{
|
|
string name = ObjectName(0, i);
|
|
if(StringFind(name, PFX) == 0)
|
|
ObjectDelete(0, name);
|
|
}
|
|
}
|
|
|
|
void ApplyStates()
|
|
{
|
|
for(int i = 0; i < g_ttlSym; i++)
|
|
{
|
|
UpdateSymbolBut(i);
|
|
UpdateBuySellBut(i);
|
|
UpdateLotInput(i);
|
|
}
|
|
}
|
|
|
|
void SaveStates()
|
|
{
|
|
GlobalVariableSet(PFX + "ClnCount", g_clnCnt);
|
|
GlobalVariableSet(PFX + "PanelExpanded", g_panelExpanded);
|
|
|
|
for(int i = 0; i < g_ttlSym; i++)
|
|
{
|
|
string base = PFX + IntegerToString(i);
|
|
GlobalVariableSet(base + "_Active", g_symSts[i].active);
|
|
GlobalVariableSet(base + "_Sell", g_symSts[i].is_sell);
|
|
GlobalVariableSet(base + "_Lot", g_symSts[i].lot_value);
|
|
}
|
|
}
|
|
|
|
void LoadStates()
|
|
{
|
|
if(GlobalVariableCheck(PFX + "ClnCount"))
|
|
g_clnCnt = (int)GlobalVariableGet(PFX + "ClnCount");
|
|
|
|
if(GlobalVariableCheck(PFX + "PanelExpanded"))
|
|
g_panelExpanded = (bool)GlobalVariableGet(PFX + "PanelExpanded");
|
|
|
|
for(int i = 0; i < g_ttlSym; i++)
|
|
{
|
|
string base = PFX + IntegerToString(i);
|
|
|
|
if(GlobalVariableCheck(base + "_Active"))
|
|
g_symSts[i].active = (bool)GlobalVariableGet(base + "_Active");
|
|
|
|
if(GlobalVariableCheck(base + "_Sell"))
|
|
g_symSts[i].is_sell = (bool)GlobalVariableGet(base + "_Sell");
|
|
|
|
if(GlobalVariableCheck(base + "_Lot"))
|
|
g_symSts[i].lot_value = GlobalVariableGet(base + "_Lot");
|
|
}
|
|
}
|
|
|
|
void GetActiveSymbols(string& sym[], int& directions[], double& lots[])
|
|
{
|
|
int cnt = 0;
|
|
for(int i = 0; i < g_ttlSym; i++)
|
|
{
|
|
if(g_symSts[i].active)
|
|
cnt++;
|
|
}
|
|
|
|
ArrayResize(sym, cnt);
|
|
ArrayResize(directions, cnt);
|
|
ArrayResize(lots, cnt);
|
|
|
|
int idx = 0;
|
|
for(int i = 0; i < g_ttlSym; i++)
|
|
{
|
|
if(g_symSts[i].active)
|
|
{
|
|
sym[idx] = g_symSts[i].symbol_name;
|
|
directions[idx] = g_symSts[i].is_sell ? -1 : 1;
|
|
lots[idx] = g_symSts[i].lot_value;
|
|
idx++;
|
|
}
|
|
}
|
|
}
|
|
|
|
void UpdateHdrTitle()
|
|
{
|
|
bool hasActivePair = false;
|
|
for(int i = 0; i < g_ttlSym; i++)
|
|
{
|
|
if(g_symSts[i].active)
|
|
{
|
|
hasActivePair = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
bool isBufferEmpty = true;
|
|
int bufSize = ArraySize(E_buf);
|
|
if(bufSize > 0)
|
|
{
|
|
if(E_buf[0] != 0 && E_buf[0] != EMPTY_VALUE)
|
|
isBufferEmpty = false;
|
|
else Comment("");
|
|
}
|
|
|
|
string newTitle = "EQ";
|
|
bool needShowLabel = false;
|
|
|
|
if(hasActivePair && isBufferEmpty)
|
|
{
|
|
newTitle = "EQ (Loading...)";
|
|
needShowLabel = true;
|
|
}
|
|
|
|
if(newTitle != g_hdrTitle)
|
|
{
|
|
g_hdrTitle = newTitle;
|
|
string name = PFX + "HdrTitle";
|
|
if(ObjectFind(0, name) != -1)
|
|
{
|
|
ObjectSetString(0, name, OBJPROP_TEXT, g_hdrTitle);
|
|
ChartRedraw();
|
|
}
|
|
}
|
|
|
|
ShowLoadHistoryLabel(needShowLabel);
|
|
}
|
|
|
|
void ShowLoadHistoryLabel(bool show)
|
|
{
|
|
if(!show)
|
|
{
|
|
if(ObjectFind(0, g_loadHistoryLabel) != -1)
|
|
{ObjectDelete(0, g_loadHistoryLabel); ChartRedraw();}
|
|
return;
|
|
}
|
|
|
|
int wnd = ChartWindowFind(0, g_indName);
|
|
if(wnd == -1) wnd = 1;
|
|
|
|
long width = ChartGetInteger(0, CHART_WIDTH_IN_PIXELS, wnd);
|
|
long height = ChartGetInteger(0, CHART_HEIGHT_IN_PIXELS, wnd);
|
|
|
|
long x = width / 2;
|
|
long y = height / 2;
|
|
|
|
if(ObjectFind(0, g_loadHistoryLabel) == -1)
|
|
{
|
|
ObjectCreate(0, g_loadHistoryLabel, OBJ_LABEL, wnd, 0, 0);
|
|
ObjectSetInteger(0, g_loadHistoryLabel, OBJPROP_CORNER, 0);
|
|
ObjectSetInteger(0, g_loadHistoryLabel, OBJPROP_XDISTANCE, x);
|
|
ObjectSetInteger(0, g_loadHistoryLabel, OBJPROP_YDISTANCE, y);
|
|
ObjectSetInteger(0, g_loadHistoryLabel, OBJPROP_FONTSIZE, 24);
|
|
ObjectSetInteger(0, g_loadHistoryLabel, OBJPROP_COLOR, clrOrange);
|
|
ObjectSetInteger(0, g_loadHistoryLabel, OBJPROP_SELECTABLE, false);
|
|
ObjectSetInteger(0, g_loadHistoryLabel, OBJPROP_HIDDEN, false);
|
|
ObjectSetInteger(0, g_loadHistoryLabel, OBJPROP_BACK, false);
|
|
ObjectSetInteger(0, g_loadHistoryLabel, OBJPROP_ALIGN, ALIGN_CENTER);
|
|
ObjectSetString(0, g_loadHistoryLabel, OBJPROP_TEXT, "Loading history...");
|
|
}
|
|
else
|
|
{
|
|
ObjectSetInteger(0, g_loadHistoryLabel, OBJPROP_XDISTANCE, x);
|
|
ObjectSetInteger(0, g_loadHistoryLabel, OBJPROP_YDISTANCE, y);
|
|
}
|
|
}
|
|
|
|
void SyncAndRebuildDashboard()
|
|
{
|
|
int marketCount = SymbolsTotal(true);
|
|
if(marketCount != g_ttlSym)
|
|
{
|
|
RebuildDashboard(marketCount);
|
|
return;
|
|
}
|
|
|
|
for(int i = 0; i < marketCount; i++)
|
|
{
|
|
string marketSym = SymbolName(i, true);
|
|
if(i >= g_ttlSym || g_symSts[i].symbol_name != marketSym)
|
|
{
|
|
RebuildDashboard(marketCount);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void RebuildDashboard(int marketCount)
|
|
{
|
|
g_ttlSym = marketCount;
|
|
ArrayResize(g_symSts, g_ttlSym);
|
|
for(int i = 0; i < g_ttlSym; i++)
|
|
{
|
|
g_symSts[i].symbol_name = SymbolName(i, true);
|
|
g_symSts[i].active = false;
|
|
g_symSts[i].is_sell = false;
|
|
g_symSts[i].lot_value = 0.1;
|
|
}
|
|
|
|
CalcSymbolButWidth();
|
|
|
|
DeleteAllObjects();
|
|
CreateUI();
|
|
ApplyStates();
|
|
|
|
SaveStates();
|
|
ChartRedraw();
|
|
}
|
|
|
|
|
|
|
|
void SwitchTheme()
|
|
{
|
|
g_theme = (ThemeType)((g_theme + 1) % 3);
|
|
ApplyThemeColors();
|
|
RecreateUI();
|
|
}
|
|
void ApplyThemeColors()
|
|
{
|
|
if(g_theme == THEME_DARK)
|
|
{
|
|
Hdr_BgdClr_work = C'38,43,51';
|
|
Hdr_BrdClr_work = C'60,65,75';
|
|
Hdr_TitleClr_work = C'220,230,240';
|
|
|
|
RstSet_ButClr_work = C'48,54,63';
|
|
RstSet_TextClr_work = C'200,90,100';
|
|
|
|
SclPlsBut_Clr_work = C'48,54,63';
|
|
SclPlsBut_TextClr_work = C'100,140,180';
|
|
|
|
SclMnsBut_Clr_work = C'48,54,63';
|
|
SclMnsBut_TextClr_work = C'100,140,180';
|
|
|
|
ClnMng_ButClr_work = C'48,54,63';
|
|
ClnMng_TextClr_work = C'120,90,160';
|
|
|
|
Hid_ButClr_work = C'48,54,63';
|
|
Hid_TextClr_work = C'200,180,60';
|
|
|
|
CloseDelete_ButClr_work = C'48,54,63';
|
|
CloseDelete_TextClr_work = C'255,99,132';
|
|
|
|
Sym_ActiveClr_work = C'0,184,148';
|
|
Sym_InactiveClr_work = C'38,43,51';
|
|
Sym_TextClr_work = C'220,230,240';
|
|
|
|
BuySell_BuyClr_work = C'9,132,227';
|
|
BuySell_SellClr_work = C'255,107,107';
|
|
BuySell_TextClr_work = C'255,255,255';
|
|
|
|
VolMng_ButClr_work = C'48,54,63';
|
|
VolMng_TextClr_work = C'220,230,240';
|
|
|
|
InputField_BgdClr_work = C'60,65,75';
|
|
InputField_TextClr_work = C'220,230,240';
|
|
|
|
Bgd_Clr_work = C'44,49,60';
|
|
Bgd_BrdClr_work = C'60,65,75';
|
|
|
|
ThemeSwitch_ButClr_work = C'48,54,63';
|
|
ThemeSwitch_TextClr_work = C'0,184,148';
|
|
}
|
|
else if(g_theme == THEME_LIGHT)
|
|
{
|
|
Hdr_BgdClr_work = C'200,200,200';
|
|
Hdr_BrdClr_work = C'180,180,180';
|
|
Hdr_TitleClr_work = C'60,60,60';
|
|
|
|
RstSet_ButClr_work = C'200,90,100';
|
|
RstSet_TextClr_work = C'255,255,255';
|
|
|
|
SclPlsBut_Clr_work = C'100,140,180';
|
|
SclPlsBut_TextClr_work = C'255,255,255';
|
|
|
|
SclMnsBut_Clr_work = C'100,140,180';
|
|
SclMnsBut_TextClr_work = C'255,255,255';
|
|
|
|
ClnMng_ButClr_work = C'120,90,160';
|
|
ClnMng_TextClr_work = C'255,255,255';
|
|
|
|
Hid_ButClr_work = C'200,180,60';
|
|
Hid_TextClr_work = C'50,50,50';
|
|
|
|
CloseDelete_ButClr_work = C'180,60,60';
|
|
CloseDelete_TextClr_work = C'255,255,255';
|
|
|
|
Sym_ActiveClr_work = C'0,150,130';
|
|
Sym_InactiveClr_work = C'170,175,180';
|
|
Sym_TextClr_work = C'50,50,50';
|
|
|
|
BuySell_BuyClr_work = C'30,110,170';
|
|
BuySell_SellClr_work = C'180,40,45';
|
|
BuySell_TextClr_work = C'255,255,255';
|
|
|
|
VolMng_ButClr_work = C'170,175,180';
|
|
VolMng_TextClr_work = C'60,60,60';
|
|
|
|
InputField_BgdClr_work = C'220,225,230';
|
|
InputField_TextClr_work = C'50,50,50';
|
|
|
|
Bgd_Clr_work = C'210,215,220';
|
|
Bgd_BrdClr_work = C'160,165,170';
|
|
|
|
ThemeSwitch_ButClr_work = C'70,110,90';
|
|
ThemeSwitch_TextClr_work = C'255,255,255';
|
|
}
|
|
else
|
|
{
|
|
Hdr_BgdClr_work = Hdr_BgdClr;
|
|
Hdr_BrdClr_work = Hdr_BrdClr;
|
|
Hdr_TitleClr_work = Hdr_TitleClr;
|
|
|
|
RstSet_ButClr_work = RstSet_ButClr;
|
|
RstSet_TextClr_work = RstSet_TextClr;
|
|
|
|
SclPlsBut_Clr_work = SclPlsBut_Clr;
|
|
SclPlsBut_TextClr_work = SclPlsBut_TextClr;
|
|
|
|
SclMnsBut_Clr_work = SclMnsBut_Clr;
|
|
SclMnsBut_TextClr_work = SclMnsBut_TextClr;
|
|
|
|
ClnMng_ButClr_work = ClnMng_ButClr;
|
|
ClnMng_TextClr_work = ClnMng_TextClr;
|
|
|
|
Hid_ButClr_work = Hid_ButClr;
|
|
Hid_TextClr_work = Hid_TextClr;
|
|
|
|
CloseDelete_ButClr_work = CloseDelete_ButClr;
|
|
CloseDelete_TextClr_work = CloseDelete_TextClr;
|
|
|
|
Sym_ActiveClr_work = Sym_ActiveClr;
|
|
Sym_InactiveClr_work = Sym_InactiveClr;
|
|
Sym_TextClr_work = Sym_TextClr;
|
|
|
|
BuySell_BuyClr_work = BuySell_BuyClr;
|
|
BuySell_SellClr_work = BuySell_SellClr;
|
|
BuySell_TextClr_work = BuySell_TextClr;
|
|
|
|
VolMng_ButClr_work = VolMng_ButClr;
|
|
VolMng_TextClr_work = VolMng_TextClr;
|
|
|
|
InputField_BgdClr_work = InputField_BgdClr;
|
|
InputField_TextClr_work = InputField_TextClr;
|
|
|
|
Bgd_Clr_work = Bgd_Clr;
|
|
Bgd_BrdClr_work = Bgd_BrdClr;
|
|
|
|
ThemeSwitch_ButClr_work = ThemeSwitch_ButClr;
|
|
ThemeSwitch_TextClr_work = ThemeSwitch_TextClr;
|
|
}
|
|
}
|
|
|