using System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Windows.Input; using System.IO; using System.Linq; using System.Net; using System.Text; using System.Windows.Forms; using System.Xml; using System.Drawing; using LumenWorks.Framework.IO.Csv; using TradeIdeas.MiscSupport; using TradeIdeas.ServerConnection; using TradeIdeas.TIProData; using TradeIdeas.TIProGUI; using TradeIdeas.XML; using TradeIdeas.TIProGUI.Charting; using TradeIdeas.TIProData.Configuration; using TradeIdeas.TIProData.Interfaces; using MarketExplorer.Menu; using static TradeIdeas.TIProData.ListManager; using TradeIdeas.TIProGUI.AI; using System.Data.Common; namespace MarketExplorer { public partial class MarketExplorer : Form, ISaveLayout, IFont, IContextMenuStrip, ISymbolLinkingChannel, ITreemapSource { /// /// This is the xml that was used to restore this form. If this form wasn't layout-restored then this will be null. /// public XmlNode RestoredLayout { get; set; } /// /// This gets called before any other code in the SaveLayout function. Currently this is aimed at the Scottrade addin but anything can set this code. /// public Action
PreSaveLayoutCode { get; set; } /// /// This gets called after SaveBase and it passes the XmlNode that the form is being saved to. This allows extensions to add properties to the layout. Access the layout XmlNode /// from a form using RestoredLayout. /// public Action SaveLayoutCode { get; set; } /// /// Actions for this form. /// private readonly Actions _actions; public bool Pinned { get; set; } private readonly IConnectionMaster _connectionMaster; private List _allColumns = new List(); private readonly Dictionary> _currentColumns = new Dictionary>(); private readonly Dictionary _columnToGridColumn = new Dictionary(); private readonly Dictionary _dataGridViewColumns = new Dictionary(); // configuration options /// /// Intraday or daily /// private bool _intraday; private int _minutesPerCandle = 1; private CandleSize _candleSize = CandleSize.None; private int _preMarketMinutes = 120; private int _postMarketMinutes = 120; private bool _firstCandleShorter; private bool _sendingRunOnceRequest = false; private int _lastIdUsed = -1; private bool _onlyLastBar = true; private bool _onlyLastDay; private bool _onlyLastBars; private int _lastBars; private bool _onlyBetweenDates; private DateTime? _startTime; private DateTime? _endTime; private bool _returnAllRecords; private bool _useMonoliticReplace; private List _symbols = new List(); private bool _usingInitialCount = true; private int _initialCount = 10; private bool _usingInitialTime; private DateTime? _initialTime; private bool _removeBlanks = true; private int _maxCount = 50; private bool _isTopPanelHidden = true; private bool _isHelpInstructionsVisible = true; /// /// Assigns the ordering type of the server descending or not /// private bool _serverSortDescending = true; private string _filterColumn = ""; /// /// The SERVER sort column /// private string _sortColumn = ""; /// /// The LOCAL sort by column /// private ColumnInfo _sortByColumn; /// /// The LOCAL sort type /// private SortType _sortType = SortType.Descending; /// /// Is local sorting enabled or not /// private bool _localSortEnabled; /// /// Used to keep track of the sort column that was specified in a layout. /// private string _importSortBy = ""; private bool _repeatEnabled; private int _repeatInterval = 60; private string _windowName = "My Market Explorer Strategy"; private bool _showStatusLine; private DateTime _windowStartTime = ServerFormats.Now; private DateTime? _requestSent; private DateTime? _responseReceived; private bool _receivedResults; private int _resultSymbols; private int _resultRows; private int _responsesReceived; /// /// The server assigned ID from the persist_window command /// private string _serverId = ""; private bool _loadingFromServer; /// /// Controls whether advanced column editing and Run Now options are available in the menus /// private readonly bool _adminMode; private bool _restoringLayout = false; private readonly BindingList _rowDatas = new BindingList(); private readonly Timer _statusTimer = new Timer(); // new variable to track symbol linking channel - RVH20210923 private string _linkChannel = SymbolLinkChannels.DefaultLinkChannel; public static readonly WindowIconCache WINDOW_ICON_CACHE = new WindowIconCache(FORM_TYPE); WindowIconCache ISaveLayout.WindowIconCache => WINDOW_ICON_CACHE; private readonly TiqColumnLibraryManager _columnManager; //treemap control. private const int TREEMAP_MAX_ROW_COUNT = 17; private int _treemapMaxRowNumber = TREEMAP_MAX_ROW_COUNT; private ChromiumTreemapControl _chromiumTreemapControl; private bool _useBrowserInterface = false; /// /// Exposes the right click menu for wrappers to access. /// public ContextMenuStrip MyContextMenuStrip => dataGridView1.ContextMenuStrip; //Send To Option private makeSendToContextMenu _sendToContextMenu; ISendManager _sendManager; private List _sendTo; /// /// Multi-symbol Send To Symbol List support /// private List _selectedRowsList = new List(); /// /// The link to be display along with the main message /// private string _linkSource = string.Empty; private BindingList _boundList = new BindingList(); public BindingList BoundList { get => _boundList; } public MarketExplorer() { InitializeComponent(); dataGridView1.DoubleBufferedDatagrid(true); GuiEnvironment.QuoteFeedManager.QuoteFeedDataReceived += QuoteFeedManager_QuoteFeedDataReceived; // check to see if auto-size columns is set - RVH20211112 if (GuiEnvironment.autosizeColumns) dataGridView1.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill; // Add browser treemap control. _chromiumTreemapControl = new ChromiumTreemapControl(this) { Location = new Point(0, 0), Dock = DockStyle.Fill, Visible = false }; tableLayoutPanel1.Controls.Add(_chromiumTreemapControl, 0, 1); SetWelcomeMessage(); AddDefaultSymbols(); _actions = new Actions(this); _connectionMaster = GuiEnvironment.FindConnectionMaster(""); _columnManager = TiqColumnLibraryManager.Instance(); _columnManager.ColumnLibraryReceived += _columnManager_ColumnLibraryReceived; _columnManager.LoadIndicatorLibrary(); AddDefaultColumns(); RowDataHelper.SetGridDefaults(dataGridView1); dataGridView1.MultiSelect = true; ChooseRowSelect(); SetTitle(); // Admin mode only available in the development build and with the settings in the Custom4.xml file. if (GuiEnvironment.DevelopmentMode) _adminMode = GuiEnvironment.XmlConfig.Node("MARKET_EXPLORER").Node("ADMIN_MODE").Property("ENABLED", "NO") == "YES"; _showStatusLine = _adminMode; SetStatusLine(); StartStatusTimer(); WINDOW_ICON_CACHE.SetIcon(this); selectTheFont(); SetSnapToGrid(GuiEnvironment.SnapToGrid); contextMenuStrip1.Opening += ContextMenuStrip1_Opening; RequestAvailableWindows(); _sendManager = _connectionMaster.SendManager; _sendTo = GuiEnvironment.XmlConfig.Node("TOPLIST_WINDOW").Node("PHRASES"); _useMonoliticReplace = GuiEnvironment.GlobalSettings.Node("MARKET_EXPLORER").Node("USE_MONOLITIC_REPLACE").Property("VALUE", false); _treemapMaxRowNumber = GuiEnvironment.GlobalSettings.Node("MARKET_EXPLORER").Node("TREEMAP_MAX_ROW_COUNT").Property("VALUE", TREEMAP_MAX_ROW_COUNT); } void QuoteFeedManager_QuoteFeedDataReceived(string symbol, RowData data) { this.BeginInvokeIfRequired(delegate () { UpdateBoundList(symbol); }); } /// /// Updates the value of the Change from Close column when the data for the symbol is received /// /// private void UpdateBoundList(string symbol) { if (_boundList.Any(row => row.GetSymbol() == symbol)) { RowData currentValues = GuiEnvironment.QuoteFeedManager.GetCurrentValues(symbol); if (null != currentValues) { var cFCP = currentValues.GetAsDouble("c_FCP", 0.00); foreach (var item in _boundList.Where(row => row.GetSymbol() == symbol).ToList()) { if (item.Data.ContainsKey("c_FCP")) item.Data["c_FCP"] = cFCP; } } if (_useBrowserInterface) { // Update treemap chart. _chromiumTreemapControl.UpdateChart(); } } } /// /// Load the default welcome message /// private void SetWelcomeMessage() => SetMainMessageText("Market Explorer is one of the latest tools to be \noffered by Trade-Ideas.\n\nTo learn more about how to use this window\nand all of the other features in TI Pro, visit", "\nMarket Explorer User Guide", GuiEnvironment.MarketExploreLink); /// /// Customize the main message /// /// The text of the main message /// The label of the link (optional) /// The link attached to the link label (optional) private void SetMainMessageText(string newMessage, string newLinkLabel = null, string newLinkSource = null) { this.BeginInvokeIfRequired(delegate { labelMessage.Text = newMessage; linkLabel.Text = newLinkLabel; _linkSource = newLinkSource; //Hide the link label control if no link is provided. linkLabel.Visible = !string.IsNullOrEmpty(newLinkSource); ShowHelpInstructions(); RepositionHelpInstruction(); }); } /// /// Sends request for available windows from the server. /// private void RequestAvailableWindows() { var message = new object[] { "command", MARKET_EXPLORER_USER_COMMAND, "subcommand", "me_get_windows" }; var messageToSend = TalkWithServer.CreateMessage(message); _connectionMaster.SendManager.SendMessage(messageToSend, AvailableWindowsMenuGeneratorResponse); } private readonly List _allWindows = new List(); private void AvailableWindowsResponse(byte[] body, object clientId) { if (null == body) RequestAvailableWindows(); else { XmlNode message = XmlHelper.Get(body).Node(0); string type = message.Property("type"); if (type == "windows") { _allWindows.Clear(); int count = message.Property("cnt", 0); for (int i = 1; i <= count; i++) { string name = message.Property("NAME" + i); string layout = message.Property("LAYOUT" + i); int id = message.Property("ID" + i, 0); var window = new MarketExplorerWindow(name, id, layout); _allWindows.Add(window); } } this.BeginInvokeIfRequired(AddWindowsToMenu); } } private void AddWindowsToMenu() { chooseWindowToolStripMenuItem.DropDownItems.Clear(); foreach (var window in _allWindows) { var toolStripMenuItem = new ToolStripMenuItem { Text = window.Name, Tag = window }; toolStripMenuItem.Click += SelectWindowMenuItemClick; chooseWindowToolStripMenuItem.DropDownItems.Add(toolStripMenuItem); } } private List AllMenuItems = new List(); private void AvailableWindowsMenuGeneratorResponse(byte[] body, object clientId) { if (null == body) RequestAvailableWindows(); var menuGeneratorCommand = new MarketExplorerMenuTreeGeneratorCommand(body); AllMenuItems = menuGeneratorCommand.Execute(); this.BeginInvokeIfRequired(AddWindowsFromMenuGeneratorToMenu); } private void AddWindowsFromMenuGeneratorToMenu() { chooseWindowToolStripMenuItem.DropDownItems.Clear(); foreach (var window in AllMenuItems) { var toolStripMenuItem = new ToolStripMenuItem { Text = window.Name, Tag = window }; var shouldHandleChildWindows = (window.Children != null && window.Children.Count > 0); if (shouldHandleChildWindows) { AddChildrenWindowsFromMenuGeneratorToMenu(toolStripMenuItem, window.Children); } else { toolStripMenuItem.Click += SelectWindowMenuItemFromMenuGeneratorClick; } chooseWindowToolStripMenuItem.DropDownItems.Add(toolStripMenuItem); } } private void AddChildrenWindowsFromMenuGeneratorToMenu(ToolStripMenuItem parentMenu, List children) { if (parentMenu == null || children.Count == 0) { return; } foreach (var window in children) { var toolStripMenuItem = new ToolStripMenuItem { Text = window.Name, Tag = window }; toolStripMenuItem.Click += SelectWindowMenuItemFromMenuGeneratorClick; parentMenu.DropDownItems.Add(toolStripMenuItem); if (window.Children != null && window.Children.Count > 0) { AddChildrenWindowsFromMenuGeneratorToMenu(toolStripMenuItem, window.Children); } } } private void SelectWindowMenuItemFromMenuGeneratorClick(object sender, EventArgs e) { if (!(sender is ToolStripMenuItem menuItem) || !(menuItem.Tag is Menu.Models.MenuItem)) return; if (!(menuItem.Tag is Menu.Models.MenuItem window)) return; HideHelpInstructions(); _windowName = window.Name; if (!_adminMode) DisableAdminFunctions(); _sendingRunOnceRequest = false; SetTitle(); LoadFromLayout(window.Id.ToString(), window.Layout); _lastIdUsed = window.Id; } private void SelectWindowMenuItemClick(object sender, EventArgs e) { if (!(sender is ToolStripMenuItem menuItem) || !(menuItem.Tag is MarketExplorerWindow)) return; if (!(menuItem.Tag is MarketExplorerWindow window)) return; HideHelpInstructions(); _windowName = window.Name; if (!_adminMode) DisableAdminFunctions(); SetTitle(); LoadFromLayout(window.Id.ToString(), window.Layout); } private void HideHelpInstructions() { // Hide Market Explorer instruction row tableLayoutPanel1.RowStyles[1].Height = 100; // percent values tableLayoutPanel1.RowStyles[2].Height = 0; // percent values _isHelpInstructionsVisible = false; } /// /// Display the Help Instructions section /// private void ShowHelpInstructions() { // Show Market Explorer instruction row tableLayoutPanel1.RowStyles[1].Height = 0; // percent values tableLayoutPanel1.RowStyles[2].Height = 100; // percent values _isHelpInstructionsVisible = true; } private class MarketExplorerWindow { public string Name { get; } public int Id { get; } public string Layout { get; } public MarketExplorerWindow(string name, int id, string layout) { Name = name; Id = id; Layout = layout; } } private RowData _currentRowData; private RowData _mostRecentRowData; private void ContextMenuStrip1_Opening(object sender, CancelEventArgs e) { if (null != GuiEnvironment.RobotStrategyMenuCode) { string symbol = ""; if (null != _currentRowData && dataGridView1.SelectedRows.Count < 2) symbol = _currentRowData.GetSymbol(); GuiEnvironment.RobotStrategyMenuCode(contextMenuStrip1, symbol, "ME", _currentRowData); } if (!_adminMode) DisableAdminFunctions(); restarttoolStripMenuItem.Visible = _adminMode && _sendingRunOnceRequest; restarttoolStripMenuItem.Enabled = _adminMode && _sendingRunOnceRequest; // add symbol linking channels to menu - RVH20210927 symbolLinkingToolStripMenuItem.DropDown.Items.Clear(); //Detect if the current window is in floating mode var floatingMode = string.IsNullOrEmpty(GuiEnvironment.GetDockWindowID(this)); foreach (KeyValuePair channel in SymbolLinkChannels.Channels) { if (channel.Key == SymbolLinkChannels.DockWindowChannel && floatingMode) continue; ToolStripMenuItem menuItem = new ToolStripMenuItem(channel.Key, null, delegate { SetLinkChannel(channel.Key); }); menuItem.BackColor = channel.Value; Color foreColor = GradientInfo.AltColor(channel.Value); menuItem.ForeColor = foreColor; menuItem.Checked = _linkChannel == channel.Key; symbolLinkingToolStripMenuItem.DropDown.Items.Add(menuItem); } SetSendToMenuItem(); showTreemapSortOptionsMenuItem.Visible = !_isHelpInstructionsVisible && showTreemapToolStripMenuItem.Checked; } /// /// Prepares the Send To menu item for display: /// determines the options, translations and visibility conditions. /// private void SetSendToMenuItem() { //Extract the selected rowDatas from the dataGridView _selectedRowsList = new List(); if (dataGridView1.SelectedCells.Count > 1) { var selectedRows = dataGridView1.SelectedCells.Cast() .Select(cell => cell.OwningRow) .Distinct(); _selectedRowsList.AddRange(_rowDatas .Where(i => selectedRows .Any(r => r.Index == _rowDatas.IndexOf(i)))); } //Populate the label and determine the visibility of the Send To option if (null != _mostRecentRowData) { var sendToText = _sendTo.Node("SEND_SYMBOL_TO").PropertyForCulture("TEXT", "***"); var displaySymbol = _selectedRowsList.Count > 1 ? "" : _mostRecentRowData.GetSymbol(); sendSymbolToToolStripMenuItem.Visible = sendToText != "---"; sendToText = sendToText.Replace("{symbol}", displaySymbol); sendSymbolToToolStripMenuItem.Text = sendToText; } else sendSymbolToToolStripMenuItem.Visible = false; } /// /// Set the symbol link channel from symbol linking /// /// The link channel void ISymbolLinkingChannel.SetLinkChannel(string linkChannel) { SetLinkChannel(linkChannel); } /// /// Set the symbol link channel /// /// The link channel private void SetLinkChannel(string linkChannel) { _linkChannel = linkChannel; // change window icon SymbolLinkingChannelsHelper.SetFormIcon(this, "E", linkChannel); } /// /// Get the symbol link channel /// /// string ISymbolLinkingChannel.GetLinkChannel() { return _linkChannel; } /// /// Disabled admin functions in context menu. /// private void DisableAdminFunctions() { runToolStripMenuItem.Visible = false; runToolStripMenuItem.Enabled = false; configureToolStripMenuItem.Visible = false; configureToolStripMenuItem.Enabled = false; addNewColumnToolStripMenuItem.Visible = false; addNewColumnToolStripMenuItem.Enabled = false; toolStripSeparatorAdminFunctions.Visible = false; toolStripMenuItemQueueBackoffice.Visible = false; toolStripMenuItemQueueBackoffice.Enabled = false; getLayoutToolStripMenuItem.Visible = false; getLayoutToolStripMenuItem.Enabled = false; getPrototypeToolStripMenuItem.Visible = false; getPrototypeToolStripMenuItem.Enabled = false; modifyColumnParametersToolStripMenuItem.Visible = false; modifyColumnParametersToolStripMenuItem.Enabled = false; } private void _columnManager_ColumnLibraryReceived() { AddColumns(); } public const string FORM_TYPE = "MARKET_EXPLORER_FORM"; public static void RegisterLayout() { // change parameters to accommodate dock panel changes - RVH20210402 //LayoutManager.Instance().AddRestoreRule(FORM_TYPE, delegate (XmlNode description, bool ignorePosition, bool cascadePosition) LayoutManager.Instance().AddRestoreRule(FORM_TYPE, delegate (XmlNode description, bool ignorePosition, bool cascadePosition, bool dockPanelMode, string mainDockPanelName, string mainDockPanelTitle, string dockPanelId) { var connectionMaster = GuiEnvironment.FindConnectionMaster(description.Property("CONNECTION")); if (null == connectionMaster) { // We could report an error here, but it's simpler just to do nothing. Any error message we tried to // report would probably be confusing at best to the user. } else { //CheckForOtherLimitAlertsFormInstance(); var form = new MarketExplorer(); // change parameters to accommodate dock panel changes - RVH20210402 //form.Restore(description, ignorePosition, cascadePosition); form.Restore(description, ignorePosition, cascadePosition, dockPanelMode, mainDockPanelName, mainDockPanelTitle, dockPanelId); form.RestoredLayout = description; } }); } public void SetSnapToGrid(bool enabled) { formSnapper1.Enabled = enabled; if (GuiEnvironment.RunningWin10 && enabled) { formSnapper1.Win10HeightAdjustment = GuiEnvironment.HEIGHT_INCREASE; formSnapper1.Win10WidthAdjustment = GuiEnvironment.WIDTH_INCREASE; } } // change parameters to accommodate dock panel changes - RVH20210402 //public void Restore(XmlNode description, bool ignorePosition, bool cascadePosition) public void Restore(XmlNode description, bool ignorePosition, bool cascadePosition, bool dockPanelMode = false, string mainDockPanelName = "", string mainDockPanelTitle = "", string dockPanelId = "") { _restoringLayout = true; try { _allColumns.Clear(); _columnToGridColumn.Clear(); _currentColumns.Clear(); _dataGridViewColumns.Clear(); dataGridView1.Columns.Clear(); _rowDatas.Clear(); AddDefaultColumns(); // change parameters to accommodate dock panel changes - RVH20210402 // LayoutManager.RestoreBase(description, this, ignorePosition, cascadePosition); LayoutManager.RestoreBase(description, this, ignorePosition, cascadePosition, null, false, dockPanelMode, mainDockPanelName, mainDockPanelTitle, dockPanelId); // if in dock panel mode - readjust the size and force a resize of the parent window - RVH20210625 if (this.ParentForm is WindowDocumentDock windowDocumentDock) { this.Left = 0; this.Top = 0; windowDocumentDock.ForceResize(); } //restore column order.. foreach (XmlNode columnNode in description.Node("COLUMNS").ChildNodes) { var column = new TiqColumn(); int width = columnNode.Property("WIDTH", 0); bool visible = columnNode.Property("IS_VISIBLE", true); column.Restore(columnNode); AddColumnToStrategy(column, width, visible); } _actions.Load(description); Pinned = description.Property("PINNED", false); pinnedToolStripMenuItem.Checked = Pinned; _windowName = description.Property("WINDOW_NAME"); _intraday = description.Property("USE_INTRADAY", false); _candleSize = description.PropertyEnum("CANDLE_SIZE", CandleSize.None); _dateFieldDescription = description.Property("DATE_FIELD_DESCRIPTION", "Start"); SetDateFieldProperties(); _showStatusLine = description.Property("SHOW_STATUS", true); SetStatusLineDisplayStatus(); _repeatEnabled = description.Property("REPEAT_ENABLED", false); _repeatInterval = description.Property("REPEAT_INTERVAL", 60); _preMarketMinutes = description.Property("PRE_MARKET_MINUTES", 120); _postMarketMinutes = description.Property("POST_MARKET_MINUTES", 120); _minutesPerCandle = description.Property("MINUTES_PER_CANDLE", 1); _firstCandleShorter = description.Property("FIRST_CANDLE_SHORTER", false); _onlyLastBar = description.Property("ONLY_LAST_BAR", false); _onlyLastBars = description.Property("ONLY_LAST_BARS", false); _lastBars = description.Property("LAST_BARS", 0); _onlyLastDay = description.Property("ONLY_LAST_DAY", false); _onlyBetweenDates = description.Property("ONLY_BETWEEN_DATES", false); _returnAllRecords = !_onlyLastBar && !_onlyLastDay && !_onlyBetweenDates && !_onlyLastBars; if (description.Property("START_TIME", 0.0) != 0.0) _startTime = ServerFormats.FromTimeT((long)description.Property("START_TIME", 0.0)); if (description.Property("END_TIME", 0.0) != 0.0) _endTime = ServerFormats.FromTimeT((long)description.Property("END_TIME", 0.0)); string rawSymbols = description.Property("SYMBOLS"); _symbols = rawSymbols.Split(',').ToList(); _usingInitialCount = description.Property("USING_INITIAL_COUNT", false); _initialCount = description.Property("INITIAL_COUNT", 10); _usingInitialTime = description.Property("USING_INITIAL_TIME", false); double initialTimeT = description.Property("INITIAL_TIME", 0.0); if (initialTimeT != 0.0) _initialTime = ServerFormats.FromTimeT((long)initialTimeT); _removeBlanks = description.Property("REMOVE_BLANKS", true); _maxCount = description.Property("MAX_COUNT", 10); _serverSortDescending = description.Property("LARGEST_ON_TOP", true); _filterColumn = description.Property("FILTER_COLUMN"); _sortColumn = description.Property("SORT_COLUMN"); _localSortEnabled = description.Property("LOCALSORTENABLED", false); _sortType = description.PropertyEnum("LOCALSORTTYPE", SortType.Descending); _importSortBy = description.Property("LOCALSORTCODE"); if (_importSortBy != "") { foreach (var c in GetAllColumns().ToList()) { if (c.InternalCode == _importSortBy) { _sortByColumn = c; break; } } } SetTitle(); string windowId = description.Property("SERVER_ID"); if (windowId != "" && !_loadingFromServer) { SendSubscribeMessage(windowId); if (int.TryParse(windowId, out int id)) _lastIdUsed = id; HideHelpInstructions(); } SetHeaderCellsText(); // Restore treemap chart settings. _useBrowserInterface = description.Property("SHOW_TREEMAP_CHART", _useBrowserInterface); _isTopPanelHidden = description.Property("IS_TOP_PANEL_HIDDEN", true); showTreemapSortOptionsMenuItem.Checked = description.Property("SHOW_TREEMAP_SORT_OPTIONS", false); showTreemapToolStripMenuItem.Checked = _useBrowserInterface; if (_useBrowserInterface) ShowHideBrowserControl(); loadSortOptions(); UpdateTreemapSortOptions(); } finally { _restoringLayout = false; } } private void SaveColumns(XmlNode columnsNode) { foreach (var column in dataGridView1.Columns.OfType().OrderBy(x => x.DisplayIndex)) { if (!(column is Column gridColumn)) continue; if (!(gridColumn.ClientObject is TiqColumn marketExplorerColumn)) continue; XmlNode columnNode = columnsNode.NewNode("COLUMN"); marketExplorerColumn.SaveLayout(columnNode); columnNode.SetProperty("WIDTH", gridColumn.Width); columnNode.SetProperty("IS_VISIBLE", gridColumn.Visible); } } public void SaveLayout(XmlNode parent) { PreSaveLayoutCode?.Invoke(this); var description = LayoutManager.SaveBase(parent, this, FORM_TYPE); SaveLayoutCode?.Invoke(this, description); _actions.Save(description); //save Column Order... SaveColumns(description.NewNode("COLUMNS")); description.SetProperty("PINNED", Pinned); description.SetProperty("WINDOW_NAME", _windowName); description.SetProperty("DATE_FIELD_DESCRIPTION", _dateFieldDescription); description.SetProperty("WINDOW_NAME", _windowName); // filtering description.SetProperty("SHOW_STATUS", _showStatusLine); description.SetProperty("REPEAT_ENABLED", _repeatEnabled); description.SetProperty("REPEAT_INTERVAL", _repeatInterval); description.SetProperty("USE_INTRADAY", _intraday); description.SetProperty("CANDLE_SIZE", _candleSize); description.SetProperty("PRE_MARKET_MINUTES", _preMarketMinutes); description.SetProperty("POST_MARKET_MINUTES", _postMarketMinutes); description.SetProperty("MINUTES_PER_CANDLE", _minutesPerCandle); description.SetProperty("FIRST_CANDLE_SHORTER", _firstCandleShorter); description.SetProperty("ONLY_LAST_BAR", _onlyLastBar); description.SetProperty("ONLY_LAST_BARS", _onlyLastBars); description.SetProperty("LAST_BARS", _lastBars); description.SetProperty("ONLY_LAST_DAY", _onlyLastDay); description.SetProperty("ONLY_BETWEEN_DATES", _onlyBetweenDates); if (_startTime.HasValue) description.SetProperty("START_TIME", ServerFormats.ToTimeT(_startTime.Value)); if (_endTime.HasValue) description.SetProperty("END_TIME", ServerFormats.ToTimeT(_endTime.Value)); description.SetProperty("SYMBOLS", String.Join(",", _symbols)); description.SetProperty("USING_INITIAL_COUNT", _usingInitialCount); description.SetProperty("INITIAL_COUNT", _initialCount); description.SetProperty("USING_INITIAL_TIME", _usingInitialTime); if (_initialTime.HasValue) description.SetProperty("INITIAL_TIME", ServerFormats.ToTimeT(_initialTime.Value)); description.SetProperty("REMOVE_BLANKS", _removeBlanks); description.SetProperty("MAX_COUNT", _maxCount); description.SetProperty("LARGEST_ON_TOP", _serverSortDescending); description.SetProperty("FILTER_COLUMN", _filterColumn); description.SetProperty("SORT_COLUMN", _sortColumn); description.SetProperty("LOCALSORTENABLED", _localSortEnabled); if (null != _sortByColumn) description.SetProperty("LOCALSORTCODE", _importSortBy); description.SetProperty("LOCALSORTTYPE", _sortType); description.SetProperty("SERVER_ID", _serverId); // Save the treemap chart settings. description.SetProperty("SHOW_TREEMAP_CHART", _useBrowserInterface); description.SetProperty("IS_TOP_PANEL_HIDDEN", _isTopPanelHidden); description.SetProperty("SHOW_TREEMAP_SORT_OPTIONS", showTreemapSortOptionsMenuItem.Checked); } /// /// Loads from layout normally from the get_layout server call response. /// /// The identifier. /// The layout - string that can be read as XML. internal void LoadFromLayout(string id, string layout) { try { var xmlDocument = new XmlDocument(); xmlDocument.LoadXml(layout); XmlNode description = xmlDocument.Node(0); if (_linkChannel != "") { var nodebase = description.Node("BASE"); nodebase.SetProperty("LinkChannel", _linkChannel); } _loadingFromServer = true; Restore(description, true, false); SendSubscribeMessage(id); if (int.TryParse(id, out int usedid)) _lastIdUsed = usedid; _loadingFromServer = false; } catch (Exception e) { string unused = e.StackTrace; } } internal void Duplicate() { var connectionMaster = GuiEnvironment.FindConnectionMaster(""); if (null != connectionMaster) { GuiEnvironment.RecordUseCase("LimitAlerts.RightClick.Duplicate", connectionMaster.SendManager); LayoutManager.Instance().Duplicate(this); } } private void StartStatusTimer() { _statusTimer.Interval = 1000; _statusTimer.Tick += StatusTimer_Tick; _statusTimer.Start(); } private void StatusTimer_Tick(object sender, EventArgs e) { this.BeginInvokeIfRequired(SetStatusLine); } private string _todayTimeFormat = "hh:mm:ss tt"; private string _yesterdayTimeFormat = "MM-dd hh:mm:ss tt"; private string GetTimeFormat(DateTime dateTime) { if (ServerFormats.Now.ToString("yyyy-MM-dd") == dateTime.ToString("yyyy-MM-dd")) return _todayTimeFormat; else return _yesterdayTimeFormat; } private void SetStatusLine() { string status = ""; if (!_receivedResults && !_requestSent.HasValue) { status += "Window started at " + _windowStartTime.ToString(GetTimeFormat(_windowStartTime)) + " (" + DataCell.GetRelativeTime(_windowStartTime) + ")"; labelStatus.Text = status; } else if (_receivedResults && _responseReceived.HasValue && _responsesReceived > 0) { string rows = "rows"; if (_resultRows == 1) rows = "row"; string symbols = "symbols"; if (_resultSymbols == 1) symbols = "symbol"; if (null != _responseReceived && null != _requestSent) { if (_sendingRunOnceRequest) { var requestTimeTooked = _responseReceived.Value - _requestSent.Value; status = $"Received {_resultRows} {rows} from {_resultSymbols} {symbols} at {_responseReceived.Value.ToString(GetTimeFormat(_responseReceived.Value))} ({DataCell.GetRelativeTime(_responseReceived.Value)} and took {requestTimeTooked.Minutes.ToString("00")}:{requestTimeTooked.Seconds.ToString("00")}). Received {_responsesReceived} responses."; SendUnsubscribe(); } else status = $"Received {_resultRows} {rows} from {_resultSymbols} {symbols} at {_responseReceived.Value.ToString(GetTimeFormat(_responseReceived.Value))} ({DataCell.GetRelativeTime(_responseReceived.Value)}). Received {_responsesReceived} responses."; } labelStatus.Text = status; } else if (_requestSent.HasValue && !_responseReceived.HasValue) { // ReSharper disable once PossibleInvalidOperationException status += "Request sent at " + _requestSent.Value.ToString(GetTimeFormat(_requestSent.Value)) + " (" + DataCell.GetRelativeTime(_requestSent.Value) + ")..."; labelStatus.Text = status; } else { status += "None"; labelStatus.Text = status; } } private void SetTitle() { string title = _windowName; if (_repeatEnabled) title = "↻ " + _windowName; Text = title; // change Text of parent form if running in dock panel mode - RVH20210329 var parent = (Form)this.Parent; if (parent != null && parent is WindowDocumentDock) parent.Text = this.Text; } public void ChooseRowSelect() { dataGridView1.SelectionMode = GuiEnvironment.HighlightGridRow ? DataGridViewSelectionMode.FullRowSelect : DataGridViewSelectionMode.CellSelect; } private void AddDefaultSymbols() { _symbols.Add("SPY"); _symbols.Add("QQQ"); _symbols.Add("DIA"); } private void AddColumns() { this.BeginInvokeIfRequired(delegate { _allColumns.Clear(); addNewColumnToolStripMenuItem.DropDownItems.Clear(); if (_columnManager.IsIndicatorAdmin()) { var addNewMenuItem = new TiqColumnMenuItem(null) { Text = "Add New Column..." }; addNewMenuItem.Click += MenuItem_Click; addNewColumnToolStripMenuItem.DropDownItems.Add(addNewMenuItem); } _allColumns = _columnManager.GetIndicatorLibrary(false); foreach (var column in _allColumns) { var menuItem = new TiqColumnMenuItem(column); menuItem.Click += MenuItem_Click; menuItem.Text = column.DisplayName; var menuItemParent = addNewColumnToolStripMenuItem; string[] categoryPath = column.Category.Split(new[] { "|" }, StringSplitOptions.RemoveEmptyEntries); if (categoryPath.Length > 0) { foreach (var categoryName in categoryPath) { if (categoryName == "") continue; if (_categoryMenuItems.ContainsKey(categoryName)) menuItemParent = _categoryMenuItems[categoryName]; else { var toolStripMenuItem = new ToolStripMenuItem(categoryName); menuItemParent.DropDownItems.Add(toolStripMenuItem); menuItemParent = toolStripMenuItem; _categoryMenuItems.Add(categoryName, toolStripMenuItem); } } } menuItemParent.DropDownItems.Add(menuItem); } }); } private readonly Dictionary _categoryMenuItems = new Dictionary(); private void MenuItem_Click(object sender, EventArgs e) { if (!(sender is TiqColumnMenuItem columnMenuItem)) return; var indicator = columnMenuItem.Indicator; if (null != indicator) { indicator = indicator.DeepCopy(); _columnManager.LinkChildIndicators(indicator); } if (_columnManager.IsIndicatorAdmin()) { var modifyIndicatorForm = new ModifyIndicator(indicator); var result = modifyIndicatorForm.ShowDialog(); if (result == DialogResult.OK) AddColumnToStrategy(modifyIndicatorForm.ChartIndicator); } else { var modifyParameters = new ModifyParameters(_allColumns.ToList(), indicator); var result = modifyParameters.ShowDialog(); if (result != DialogResult.OK) return; foreach (var toRemove in modifyParameters.IndicatorsToRemove.Where(toRemove => _currentColumns.ContainsKey(toRemove))) { _currentColumns.Remove(toRemove); // TODO fully remove column } if (null != modifyParameters.IndicatorToAdd) AddColumnToStrategy(modifyParameters.IndicatorToAdd); } } private List GetAllColumns() { var toReturn = new List(); foreach (DataGridViewColumn dataGridViewColumn in dataGridView1.Columns) { if (!(dataGridViewColumn is Column column)) continue; toReturn.Add(column.ColumnInfo); } return toReturn; } /// /// "Start" is the default but this can be changed /// private string _dateFieldDescription = "Start"; private List AddDefaultColumns() { var toReturn = new List(); var symbolColumnInfo = new ColumnInfo { TextHeader = true, WireName = "symbol", InternalCode = "symbol", Description = "Symbol", SizeHint = "SymbolXX", Format = "" }; DataGridViewColumn gridColumnSymbol = DataCell.GetColumn(symbolColumnInfo, _connectionMaster, this, null, false, this.CreateGraphics(), Font); RowDataHelper.SetHeaderCellDefaults(gridColumnSymbol.HeaderCell); dataGridView1.Columns.Add(gridColumnSymbol); toReturn.Add(symbolColumnInfo); _dateGridColumnInfo = new ColumnInfo { TextHeader = true, WireName = "start_time", InternalCode = "start_time", Description = _dateFieldDescription, SizeHint = "YYYY-MM-DD HH:MM:SS TT", Format = GetDateFieldFormat() }; _dateGridColumn = DataCell.GetColumn(_dateGridColumnInfo, _connectionMaster, this, null, false, this.CreateGraphics(), Font); RowDataHelper.SetHeaderCellDefaults(_dateGridColumn.HeaderCell); dataGridView1.Columns.Add(_dateGridColumn); toReturn.Add(_dateGridColumnInfo); return toReturn; } private string GetDateFieldFormat() { return _intraday ? "t" : "shortdate"; } private ColumnInfo _dateGridColumnInfo; private Column _dateGridColumn; private void SetDateFieldProperties() { _dateGridColumn.ColumnInfo.Format = GetDateFieldFormat(); _dateGridColumn.HeaderText = _dateFieldDescription; _dateGridColumn.RefreshDataCell(); } private void AddColumnToStrategy(TiqColumn column, int width = -1, bool visible = true) { var columnInfo = new ColumnInfo { WireName = column.ResolvedReferenceName(), InternalCode = column.ResolvedReferenceName(), Description = column.DisplayName, Format = column.Format, SizeHint = column.DisplayName, TextHeader = true, GradientInfo = column.GetGradientInfo() }; var gridColumn = DataCell.GetColumn(columnInfo, _connectionMaster, this, null, false, this.CreateGraphics(), Font); gridColumn.ClientObject = column; if (width > 0) gridColumn.Width = width; StoreColumnFormula(column, gridColumn); var menu = new ContextMenuStrip(); var strategyColumn = new StrategyColumn(column, gridColumn); if (_adminMode) { gridColumn.HeaderCell.ContextMenuStrip = BuildColumnContextMenu(strategyColumn, menu); gridColumn.HeaderCell.ContextMenuStrip.Opening += ContextMenuStrip_Opening; } gridColumn.Visible = visible; RowDataHelper.SetHeaderCellDefaults(gridColumn.HeaderCell); _dataGridViewColumns.Add(columnInfo, gridColumn); if (_currentColumns.ContainsKey(column)) _currentColumns[column].Add(gridColumn); else { var gridColumns = new List { gridColumn }; _currentColumns.Add(column, gridColumns); } _columnToGridColumn[column] = gridColumn; dataGridView1.Columns.Add(gridColumn); foreach (var subColumn in column.ChildIndicators) { AddColumnToStrategy(subColumn); } } private void StoreColumnFormula(TiqColumn column, Column gridColumn) { gridColumn.ClientData = column.Code; } private void ContextMenuStrip_Opening(object sender, CancelEventArgs e) { var menu = sender as ContextMenuStrip; if (!(menu?.Tag is StrategyColumn strategyColumn)) return; BuildColumnContextMenu(strategyColumn, menu); } private void sendSymbolToToolStripMenuItem_MouseEnter(object sender, EventArgs e) { if (sendSymbolToToolStripMenuItem.DropDownItems.Count == 1) /*We have the "dummy" item there just to make it look like the "send to" item has children*/ { sendSymbolToToolStripMenuItem.DropDownItems.Clear(); _sendToContextMenu = new makeSendToContextMenu(this, this, sendSymbolToToolStripMenuItem, _mostRecentRowData, _sendManager, "MARKET_EXPLORER", _connectionMaster); } if (_selectedRowsList.Count > 1) _sendToContextMenu.setRowDataList(_selectedRowsList); else _sendToContextMenu.setRowData(_mostRecentRowData, "", _mostRecentRowData.GetSymbol(), _mostRecentRowData.GetExchange(), _connectionMaster); } private ContextMenuStrip BuildColumnContextMenu(StrategyColumn column, ContextMenuStrip menu) { UnsubscribeContextmenu(menu); menu.Items.Clear(); menu.Tag = column; var editFormulaMenuItem = new ToolStripMenuItem { Text = "Edit Formula", Tag = column }; editFormulaMenuItem.Click += EditFormulaMenuItem_Click; menu.Items.Add(editFormulaMenuItem); var filterMenuItem = new ToolStripMenuItem { Text = "Use " + column.MarketExplorerColumn.DisplayName + " as Filter", Tag = column, CheckOnClick = true, Checked = _filterColumn == column.MarketExplorerColumn.ResolvedReferenceName() }; filterMenuItem.Click += filterMenuItem_Click; menu.Items.Add(filterMenuItem); var sortAscendingMenuItem = new ToolStripMenuItem { Text = "Server Sort by " + column.MarketExplorerColumn.DisplayName + " Ascending", Tag = column, CheckOnClick = true, Checked = _sortColumn == column.MarketExplorerColumn.ResolvedReferenceName() && !_serverSortDescending }; sortAscendingMenuItem.Click += SortAscendingMenuItem_Click; menu.Items.Add(sortAscendingMenuItem); var sortDescendingMenuItem = new ToolStripMenuItem { Text = "Server Sort by " + column.MarketExplorerColumn.DisplayName + " Descending", Tag = column, CheckOnClick = true, Checked = _sortColumn == column.MarketExplorerColumn.ResolvedReferenceName() && _serverSortDescending }; sortDescendingMenuItem.Click += SortDescendingMenuItem_Click; menu.Items.Add(sortDescendingMenuItem); return menu; } private void UnsubscribeContextmenu(ContextMenuStrip menu) { if (menu?.Items == null) return; foreach (var menuItem in menu.Items) { if (menuItem is ToolStripMenuItem toolStripMenuItem) { if (toolStripMenuItem.Text.Contains("Edit Formula")) toolStripMenuItem.Click -= EditFormulaMenuItem_Click; else if (toolStripMenuItem.Text.Contains("as Filter")) toolStripMenuItem.Click -= filterMenuItem_Click; else if (toolStripMenuItem.Text.Contains("Server Sort by")) { if (toolStripMenuItem.Text.Contains("Ascending")) toolStripMenuItem.Click -= SortAscendingMenuItem_Click; else if (toolStripMenuItem.Text.Contains("Descending")) toolStripMenuItem.Click -= SortDescendingMenuItem_Click; } } } } private void RemoveColumn(TiqColumn indicator) { if (_currentColumns.ContainsKey(indicator)) _currentColumns.Remove(indicator); } private void EditFormulaMenuItem_Click(object sender, EventArgs e) { var menuItem = sender as ToolStripMenuItem; if (!(menuItem?.Tag is StrategyColumn strategyColumn)) return; var column = strategyColumn.MarketExplorerColumn; var modifyIndicatorForm = new ModifyIndicator(column); var result = modifyIndicatorForm.ShowDialog(); if (result != DialogResult.OK) return; if (modifyIndicatorForm.DeleteIndicator) RemoveColumn(column); else RefreshColumnDefinition(strategyColumn.Column, column); } /// /// Refreshes the column definition. Usually called after a column has been edited in some way. /// /// The column. /// private void RefreshColumnDefinition(Column column, TiqColumn tiqColumn) { this.BeginInvokeIfRequired(delegate { column.HeaderText = tiqColumn.DisplayName; column.ColumnInfo.Format = tiqColumn.Format; column.ColumnInfo.WireName = tiqColumn.ResolvedReferenceName(); column.ColumnInfo.InternalCode = tiqColumn.ResolvedReferenceName(); column.ColumnInfo.GradientInfo = tiqColumn.GetGradientInfo(); column.RefreshDataCell(); }); } private void SortAscendingMenuItem_Click(object sender, EventArgs e) { if (!(sender is ToolStripMenuItem menuItem)) return; if (!(menuItem.Tag is StrategyColumn strategyColumn)) return; var column = strategyColumn.MarketExplorerColumn; string referenceName = column.ResolvedReferenceName(); if (referenceName == _sortColumn && !_serverSortDescending) _sortColumn = ""; else _sortColumn = referenceName; _serverSortDescending = false; if (!_currentColumns.ContainsKey(column)) return; foreach (var gridColumn in _currentColumns[column]) { SetHeaderCellText(column, gridColumn); } } private void SortDescendingMenuItem_Click(object sender, EventArgs e) { if (!(sender is ToolStripMenuItem menuItem)) return; if (!(menuItem.Tag is StrategyColumn strategyColumn)) return; var column = strategyColumn.MarketExplorerColumn; string referenceName = column.ResolvedReferenceName(); if (referenceName == _sortColumn && !_serverSortDescending) _sortColumn = ""; else _sortColumn = column.ResolvedReferenceName(); _serverSortDescending = true; if (!_currentColumns.ContainsKey(column)) return; foreach (var gridColumn in _currentColumns[column]) { SetHeaderCellText(column, gridColumn); } } /// /// Inverts the marks for sorting and filtering on the text of the headers where appropriate. /// private void SetHeaderCellsText() { foreach (var column in _currentColumns.Keys) { var gridColumns = _currentColumns[column]; foreach (var gridColumn in gridColumns) SetHeaderCellText(column, gridColumn); } } private void SetHeaderCellText(TiqColumn column, DataGridViewColumn gridColumn) { string text = column.ResolvedAbbreviatedName(); if (_filterColumn == column.ResolvedReferenceName()) text += " ↯"; if (_sortColumn == column.ResolvedReferenceName()) { if (_serverSortDescending) text += " ▾"; else text += " ▴"; } gridColumn.HeaderCell.Value = text; } private void filterMenuItem_Click(object sender, EventArgs e) { if (!(sender is ToolStripMenuItem menuItem)) return; if (!(menuItem.Tag is StrategyColumn strategyColumn)) return; var column = strategyColumn.MarketExplorerColumn; _filterColumn = _filterColumn == column.ResolvedReferenceName() ? "" : column.ResolvedReferenceName(); SetHeaderCellsText(); } private void RunToolStripMenuItem_Click(object sender, EventArgs e) { // by default no merging should occur for the Run Once workflow which only admins have access to if (GuiEnvironment.XmlConfig.Node("MARKET_EXPLORER").Node("CLEAR_RESULTS").Property("ENABLED", "YES") == "YES") _rowDatas.Clear(); _sendingRunOnceRequest = true; //SendUnsubscribe(); SendRequest(); HideHelpInstructions(); } /// /// Command for user market explorer windows. Different from MARKET_EXPLORER_ADMIN_COMMAND so we have flexibility to /// segment these functions on the server side. /// private const string MARKET_EXPLORER_USER_COMMAND = "market_explorer"; /// /// Command for admin market explorer windows.Different from MARKET_EXPLORER_USER_COMMAND so we have flexibility to /// segment these functions on the server side. /// private const string MARKET_EXPLORER_ADMIN_COMMAND = "market_explorer_admin"; private void SendUnsubscribe() { var message = new object[] { "command", MARKET_EXPLORER_USER_COMMAND, "subcommand", "unsubscribe_window", "id", _serverId }; var messageToSend = TalkWithServer.CreateMessage(message); _connectionMaster.SendManager.SendMessage(messageToSend); CancelToken(); } /// /// Cancel the token. This is important when we get disconnected from the server. /// private void CancelToken() { if (null != _deliveriesCancelToken) { _connectionMaster.SendManager.CancelMessage(_deliveriesCancelToken); _deliveriesCancelToken = null; } } /// /// Gets details of the window in a format suitable for sending to the server for results. /// /// private object[] GetWindowDetails(bool adminFormat) { string prototype = GetPrototype(adminFormat); string columns = GetColumns(); string symbols = string.Join(" ", _symbols); var details = new object[] { "prototype", prototype, "symbols", symbols, "row_num", null, "row_date", null, "columns", columns, "sort_by", GetSortBy(), "sort_dir", _serverSortDescending ? '+' : '-', "use_last_bar", _onlyLastBar ? '1' : '0', "use_last_bars", _onlyLastBars ? '1' : '0', "last_bars", _lastBars, "use_last_day", _onlyLastDay ? '1' : '0', "start_time", (_startTime.HasValue && _onlyBetweenDates) ? ServerFormats.ToTimeT(_startTime).ToString() : "0", "end_time", (_endTime.HasValue && _onlyBetweenDates) ? ServerFormats.ToTimeT(_endTime).ToString() : "0", "max_count", _maxCount, "name", _windowName, "filter_col", GetFilter() }; return details; } private void SendRequest() { string subCommand = "me_top_list"; var details = GetWindowDetails(false); var message = new object[] { "command", MARKET_EXPLORER_ADMIN_COMMAND, "subcommand", subCommand }; message = message.Concat(details).ToArray(); _lastMessage = TalkWithServer.CreateMessage(message); SendMessage(); _requestSent = ServerFormats.Now; _responseReceived = null; } private Dictionary _lastMessage; private object _messageId; private void SendMessage() { _messageId = new object(); _connectionMaster.SendManager.SendMessage(_lastMessage, GetDataResponse, clientId: _messageId); } private TalkWithServer.CancelToken _deliveriesCancelToken; private void SendSubscribeMessage(string windowId) { if (string.IsNullOrEmpty(_serverId) || _serverId == windowId) CancelToken(); else SendUnsubscribe(); _requestSent = ServerFormats.Now; var message = new object[] { "command", MARKET_EXPLORER_USER_COMMAND, "subcommand", "me_subscribe_window", "id", windowId }; var messageToSend = TalkWithServer.CreateMessage(message); _deliveriesCancelToken = new TalkWithServer.CancelToken(); _serverId = windowId; _connectionMaster.SendManager.SendMessage(messageToSend, GetDeliveries, true, cancelToken: _deliveriesCancelToken); } private void GetDeliveries(byte[] body, object clientId) { if (null == body) { if (!_sendingRunOnceRequest) SendSubscribeMessage(_serverId); } else { XmlNode message = XmlHelper.Get(body).Node(0); string type = message.Property("type"); if (type == "unauthorized" && null != _deliveriesCancelToken) { _deliveriesCancelToken.Cancel(); SetMainMessageText(message.Property("error_msg"), "\nClick here to learn more.", message.Property("url")); } else if (type == "window_subscribed") { _serverId = message.Property("ID"); } else { this.InvokeIfRequired(delegate { ResponseInThread(body); }); } } } private void GetDataResponse(byte[] body, object clientId) { if (null == body) SendMessage(); else { this.InvokeIfRequired(delegate { ResponseInThread(body); }); } } /// /// Update the values in the target row with the values in the source row if necessary /// /// /// private void UpdateRow(RowData source, RowData target) { var dictionaryList = source.Data.ToList(); dictionaryList.ForEach(dl => { if (dl.Key.ToString() != "symbol" && dl.Key.ToString() != "start_time") { object value = null; if (target.Data.TryGetValue(dl.Key, out value)) { if (dl.Value.ToString() != value.ToString()) { target.Data[dl.Key] = dl.Value; } } } }); } private void ResponseInThread(byte[] body) { _responseReceived = ServerFormats.Now; _receivedResults = true; _responsesReceived++; var savedSelection = dataGridView1.SelectedCells; // saved selection is mostly useless after calling _boundList.Clear(); int[] selectedRows = new int[savedSelection.Count]; int[] selectedCols = new int[savedSelection.Count]; for (int i = 0; i < savedSelection.Count; i++) { selectedRows[i] = savedSelection[i].RowIndex; selectedCols[i] = savedSelection[i].ColumnIndex; } int horizontalScrollPosition = dataGridView1.HorizontalScrollingOffset; int firstCol = dataGridView1.FirstDisplayedScrollingColumnIndex; int firstRow = dataGridView1.FirstDisplayedScrollingRowIndex; string csv = Encoding.UTF8.GetString(body); TextReader textReader = new StringReader(csv); var csvReader = new CsvReader(textReader, true) { MissingFieldAction = MissingFieldAction.ReplaceByEmpty }; dataGridView1.SuspendLayout(); var receivedRowDatas = new List(); var resultsBySymbol = new Dictionary(); while (csvReader.ReadNextRecord()) { var rowData = GetRowData(csvReader); string symbol = rowData.GetSymbol(); if (!resultsBySymbol.ContainsKey(symbol)) resultsBySymbol.Add(symbol, 1); else resultsBySymbol[symbol]++; receivedRowDatas.Add(rowData); } if (_rowDatas.Count == 0) { receivedRowDatas.ForEach(rrd => _rowDatas.Add(rrd)); dataGridView1.DataSource = _rowDatas; } else if (_useMonoliticReplace) { dataGridView1.DataSource = null; _rowDatas.Clear(); receivedRowDatas.ForEach(received => _rowDatas.Add(received)); dataGridView1.DataSource = _rowDatas; } else { var removedRows = _rowDatas.Where(rd => !receivedRowDatas.Any(rrd => rrd.GetSymbol() == rd.GetSymbol())) .ToList(); removedRows.ForEach(rd => _rowDatas.Remove(rd)); var newRowsDataReceived = new List(); foreach (var receivedRowData in receivedRowDatas) { var existentRowData = _rowDatas.FirstOrDefault(rd => rd != null && rd.GetSymbol() == receivedRowData.GetSymbol() && rd.GetAsString("start_time") == receivedRowData.GetAsString("start_time")); if (existentRowData == null) newRowsDataReceived.Add(receivedRowData); } newRowsDataReceived.ForEach(newRow => _rowDatas.Add(newRow)); var visibleRowsCount = dataGridView1.DisplayedRowCount(true); var firstDisplayedRowIndex = dataGridView1.FirstDisplayedCell is null ? 0 : dataGridView1.FirstDisplayedCell.RowIndex; var lastVisibleRowIndex = (firstDisplayedRowIndex + visibleRowsCount) - 1; for (int rowIndex = firstDisplayedRowIndex; rowIndex <= lastVisibleRowIndex; rowIndex++) { var row = dataGridView1.Rows[rowIndex].DataBoundItem as RowData; var receivedRowData = receivedRowDatas.FirstOrDefault(rrd => row != null && rrd.GetSymbol() == row.GetSymbol() && rrd.GetAsString("start_time") == row.GetAsString("start_time")); if (receivedRowData != null) UpdateRow(receivedRowData, row); receivedRowDatas.FirstOrDefault(rrd => row != null && rrd.GetSymbol() == row.GetSymbol() && rrd.GetAsString("start_time") == row.GetAsString("start_time")); } } dataGridView1.ClearSelection(); bool markedCurrentCell = false; for (int i = 0; i < selectedRows.Length; i++) { int row = selectedRows[i]; int col = selectedCols[i]; if ((row < dataGridView1.RowCount) && (col <= dataGridView1.ColumnCount)) { // Need to set both selected rows and current cell to keep the cell/row focus insync. if (!markedCurrentCell) { dataGridView1.CurrentCell = dataGridView1.Rows[row].Cells[col]; markedCurrentCell = true; } dataGridView1.Rows[row].Cells[col].Selected = true; } } dataGridView1.ResumeLayout(); try { dataGridView1.FirstDisplayedScrollingColumnIndex = firstCol; if (firstRow >= 0) dataGridView1.FirstDisplayedScrollingRowIndex = firstRow; dataGridView1.HorizontalScrollingOffset = horizontalScrollPosition; } catch { } _resultSymbols = resultsBySymbol.Keys.Count; _resultRows = _rowDatas.Count; DoSorting(); SetRepeatTimer(); } /// /// Updates the list with the data used in the Treemap. /// private void UpdateBoundList() { var treemaprows = _rowDatas.Take(_treemapMaxRowNumber).Select(row => row.GetSymbol()).ToList(); var toRemove = _boundList.Where(existing => !treemaprows.Any(symbol => symbol == existing.GetSymbol())).ToList(); var toAdd = treemaprows.Where(symbol => !_boundList.Any(row => symbol == row.GetSymbol())).ToList(); foreach (var item in toRemove) _boundList.Remove(item); foreach (var item in toAdd) { var rowData = new RowData(); rowData.Data.Add("c_D_Symbol", item); rowData.Data.Add("c_FCP", 0); _boundList.Add(rowData); GuiEnvironment.QuoteFeedManager.AddQuoteFeed(item); } if (_useBrowserInterface) _chromiumTreemapControl.UpdateChart(); } private readonly Timer _repeatTimer = new Timer(); private void SetRepeatTimer() { if (!_repeatEnabled || _repeatTimer.Enabled) return; int seconds = Math.Max(_repeatInterval, 10); _repeatTimer.Tick -= RepeatTimer_Tick; _repeatTimer.Tick += RepeatTimer_Tick; _repeatTimer.Interval = seconds * 1000; _repeatTimer.Start(); } private void RepeatTimer_Tick(object sender, EventArgs e) { _repeatTimer.Stop(); SendRequest(); } private RowData GetRowData(CsvReader csvReader) { var rowData = new RowData(); foreach (string header in csvReader.GetFieldHeaders()) { string value = csvReader[header]; rowData.Data.Add(header, value); } return rowData; } /// /// Gets all column definitions in TCL format. /// /// private string GetColumns() { var columns = new StringBuilder(); foreach (var column in dataGridView1.Columns) { var gridColumn = column as Column; if (gridColumn?.ClientObject is TiqColumn marketExplorerColumn) columns.LAppend(marketExplorerColumn.ResolvedReferenceName()); } return columns.ToString(); } private string GetSortBy() { return _sortColumn; } private string GetFilter() { return _filterColumn; } /// /// Gets prototype for window in TCL format. The adminFormat parameter control whether newlines are removed which /// is currently required to avoid a bug in TclList.cs /// /// /// private string GetPrototype(bool adminFormat) { string allIndicatorCode = ""; string space = ""; foreach (var column in dataGridView1.Columns.OfType().OrderBy(x => x.DisplayIndex)) { var gridColumn = column as Column; if (!(gridColumn?.ClientObject is TiqColumn marketExplorerColumn)) continue; string indicatorCode = _columnManager.GetIndicatorCode(marketExplorerColumn); if (adminFormat) indicatorCode = indicatorCode.Replace(Environment.NewLine, " "); allIndicatorCode += space + indicatorCode; space = " "; } var result = new StringBuilder(); result.LAppend(_intraday ? "intraday" : "daily"); result.LAppend(allIndicatorCode); var options = new StringBuilder(); if (_usingInitialCount) { options.LAppend("row_count"); options.LAppend(_initialCount.ToString()); } if (_usingInitialTime) { options.LAppend("at_time"); options.LAppend(ServerFormats.ToTimeT(_initialTime).ToString()); } options.LAppend("pack"); options.LAppend(_removeBlanks ? "1" : "0"); if (_intraday) { options.LAppend("minutes_per_candle"); options.LAppend(_minutesPerCandle.ToString()); options.LAppend("start_offset"); options.LAppend(_preMarketMinutes.ToString()); options.LAppend("end_offset"); options.LAppend(_postMarketMinutes.ToString()); options.LAppend("first_candle_size"); options.LAppend(_firstCandleShorter ? "0" : _minutesPerCandle.ToString()); } else if (_candleSize == CandleSize.Week) { options.LAppend("candle_size"); options.LAppend("week"); } else if (_candleSize == CandleSize.Month) { options.LAppend("candle_size"); options.LAppend("month"); } result.LAppend(options.ToString()); return result.ToString(); } private void ConfigureToolStripMenuItem_Click(object sender, EventArgs e) { var editOptions = new EditOptions { UseIntraday = _intraday, CandleSize = _candleSize, MinutesPerCandle = _minutesPerCandle, PreMarketMinutes = _preMarketMinutes, PostMarketMinutes = _postMarketMinutes, RemoveBlanks = _removeBlanks, MaximumResults = _maxCount, FirstCandleShorter = _firstCandleShorter, Symbols = _symbols, RepeatEnabled = _repeatEnabled, RepeatInterval = _repeatInterval, WindowName = _windowName, DateFieldDescription = _dateFieldDescription, InitialBarCount = _initialCount, OnlyLastBar = _onlyLastBar, OnlyLastDay = _onlyLastDay, OnlyLastBars = _onlyLastBars, LastBars = _lastBars, BetweenDates = _onlyBetweenDates, Font = Font }; if (_startTime.HasValue) editOptions.StartTime = _startTime.Value; if (_endTime.HasValue) editOptions.EndTime = _endTime.Value; editOptions.ReturnAllRecords = _returnAllRecords; var result = editOptions.ShowDialog(); if (result != DialogResult.OK) return; _intraday = editOptions.UseIntraday; _candleSize = editOptions.CandleSize; _minutesPerCandle = editOptions.MinutesPerCandle; _preMarketMinutes = editOptions.PreMarketMinutes; _postMarketMinutes = editOptions.PostMarketMinutes; _maxCount = editOptions.MaximumResults; _firstCandleShorter = editOptions.FirstCandleShorter; _symbols = editOptions.Symbols; _repeatEnabled = editOptions.RepeatEnabled; _repeatInterval = editOptions.RepeatInterval; _windowName = editOptions.WindowName; _dateFieldDescription = editOptions.DateFieldDescription; _removeBlanks = editOptions.RemoveBlanks; _initialCount = editOptions.InitialBarCount; _startTime = editOptions.StartTime; _endTime = editOptions.EndTime; _onlyLastBar = editOptions.OnlyLastBar; _onlyLastBars = editOptions.OnlyLastBars; _lastBars = editOptions.LastBars; _onlyLastDay = editOptions.OnlyLastDay; _onlyBetweenDates = editOptions.BetweenDates; _returnAllRecords = editOptions.ReturnAllRecords; SetDateFieldProperties(); SetTitle(); } private class StrategyColumn { public TiqColumn MarketExplorerColumn { get; } public Column Column { get; } public StrategyColumn(TiqColumn marketExplorerColumn, Column column) { MarketExplorerColumn = marketExplorerColumn; Column = column; } } private void showStatusLineToolStripMenuItem_Click(object sender, EventArgs e) { _showStatusLine = showStatusLineToolStripMenuItem.Checked; SetStatusLineDisplayStatus(); } private void SetStatusLineDisplayStatus() { flowLayoutPanelStatus.Visible = _showStatusLine && !showTreemapToolStripMenuItem.Checked; } private void DataGridView1_CellClick(object sender, DataGridViewCellEventArgs e) { if (e.RowIndex != -1 && GuiEnvironment.IntegrationSupportSingleClick) SendToExternalLinking(e.RowIndex); } private void SortRows(ColumnInfo columnInfo) { // Set sortType to descending by default when we pick a new column to sort. if ((_sortByColumn == null) || (_sortByColumn != columnInfo)) _localSortEnabled = false; _sortByColumn = columnInfo; _importSortBy = _sortByColumn.InternalCode; if (!_localSortEnabled) _sortType = SortType.Descending; else if (!_restoringLayout) _sortType = _sortType == SortType.Ascending ? SortType.Descending : SortType.Ascending; _localSortEnabled = true; DoSorting(); } private void dataGridView1_CellDoubleClick(object sender, DataGridViewCellEventArgs e) { if (e.RowIndex != -1 && !GuiEnvironment.IntegrationSupportSingleClick) SendToExternalLinking(e.RowIndex); else if (e.RowIndex == -1) { var column = (Column)dataGridView1.Columns[e.ColumnIndex]; if (null == column || null == column.ColumnInfo) return; GuiEnvironment.RecordUseCase("MarketExplorer.Sort." + column.ColumnInfo.InternalCode, _connectionMaster.SendManager); SortRows(column.ColumnInfo); } } private void DoSorting() { RowDataHelper.DoSorting(dataGridView1, _rowDatas, _sortByColumn, _sortType, _sortColumn, _serverSortDescending); RowDataHelper.FixCellHeaders(dataGridView1, GetAllColumns(), _sortByColumn); UpdateTreemapSortOptions(); UpdateBoundList(); } /// /// Updates the information with the description of the ordering that is currently being used /// private void UpdateTreemapSortOptions() { sortDirectionLabel.Text = _sortType == SortType.Ascending ? "Ascending" :"Descending"; // Avoid exception when loading TreeMap. if (_sortByColumn != null) comboSortOptions.SelectedIndex = comboSortOptions.Items.IndexOf(_sortByColumn.Description); } private void SendToExternalLinking(int index) { var rowData = _rowDatas[index]; if (null == rowData) return; string symbol = rowData.GetSymbol(); if (symbol == "") return; var linkRowData = new RowData(); linkRowData.Data.Add("SYMBOL", symbol); AppendAvwapDynamicRowDataIfExists(rowData, linkRowData); AppendGoLevelRowDataIfExists(rowData, linkRowData); RecordExternalLinkUseCase(linkRowData); string exchange = _connectionMaster.SymbolDetailsCacheManager.Request(symbol).Exchange ?? ""; // add symbol linking channels here GuiEnvironment.sendSymbolToExternalConnector(symbol, exchange, "", null, linkRowData, linkChannel: _linkChannel, dockWindowID: GuiEnvironment.GetDockWindowID(this)); //GuiEnvironment.sendSymbolToExternalConnector(symbol, exchange, "", null, linkRowData); } private void AppendAvwapDynamicRowDataIfExists(RowData marketExplorerCurrentRowData, RowData symbolLinkingRowDataToSet) { var foundAvwapColumnMaps = new FindAvwapDynamicDateTimesForRowCommand().Go(marketExplorerCurrentRowData); if (foundAvwapColumnMaps.DoesNotHaveAny()) return; var avwapValidDates = FindAvwapDynamicDateTimesForRowCommand.GetValidAvwapDateTimes(foundAvwapColumnMaps); symbolLinkingRowDataToSet.Data.Add("Chart_AvwapIndicatorDatesToAdd", avwapValidDates); } private void AppendGoLevelRowDataIfExists(RowData marketExplorerCurrentRowData, RowData symbolLinkingRowDataToSet) { var goLevelExists = new GoLevelColumnExistsCommand().Go(marketExplorerCurrentRowData); if (goLevelExists) { symbolLinkingRowDataToSet.Data.Add("Chart_AddGoNoGoIndicator", true); } } private void RecordExternalLinkUseCase(RowData rowData) { GuiEnvironment.RecordExternalLinkingUseCase(rowData, "ME", _connectionMaster.SendManager); } private void DuplicateToolStripMenuItem_Click(object sender, EventArgs e) { Duplicate(); } private void ModifyColumnParametersToolStripMenuItem_Click(object sender, EventArgs e) { var modifyParameters = new ModifyParameters(_currentColumns.Keys.ToList(), null); var result = modifyParameters.ShowDialog(); if (result != DialogResult.OK) return; foreach (var column in modifyParameters.IndicatorsToRemove) { RemoveColumn(column); } foreach (var column in modifyParameters.Indicators) { if (_columnToGridColumn.ContainsKey(column) && null != _columnToGridColumn[column]) { var gridColumn = _columnToGridColumn[column]; RefreshColumnDefinition(gridColumn, column); } } } private void MarketExplorer_FormClosing(object sender, FormClosingEventArgs e) { SendUnsubscribe(); _columnManager.ColumnLibraryReceived -= _columnManager_ColumnLibraryReceived; contextMenuStrip1.Opening -= ContextMenuStrip1_Opening; if (MyContextMenuStrip != null) MyContextMenuStrip.Opening -= LayoutManager.Instance().contextMenuStrip_Opening; GuiEnvironment.QuoteFeedManager.QuoteFeedDataReceived -= QuoteFeedManager_QuoteFeedDataReceived; _sendToContextMenu = null; _mostRecentRowData = null; if (null != _statusTimer) { _statusTimer.Stop(); _statusTimer.Tick -= StatusTimer_Tick; } if (null != _repeatTimer) { _repeatTimer.Stop(); _repeatTimer.Tick -= RepeatTimer_Tick; } foreach (var menuItem in chooseWindowToolStripMenuItem.DropDownItems) { if (menuItem is ToolStripMenuItem toolStripMenuItem) toolStripMenuItem.Click -= SelectWindowMenuItemClick; } foreach (var menuItem in addNewColumnToolStripMenuItem.DropDownItems) { if (menuItem is TiqColumnMenuItem tiqColumnMenuItem) tiqColumnMenuItem.Click -= MenuItem_Click; } if (_adminMode) { // M. Nauss was getting "The given key was not present in the dictionary" exception. // I was unable to reproduce. I'm adding key checks and adding a try and catch. try { foreach (TiqColumn column in _currentColumns.Keys) { if (_currentColumns.ContainsKey(column)) { List gridColumns = _currentColumns[column]; foreach (DataGridViewColumn gridColumn in gridColumns) { if (null != gridColumn && null != gridColumn.HeaderCell && null != gridColumn.HeaderCell.ContextMenuStrip) { UnsubscribeContextmenu(gridColumn.HeaderCell.ContextMenuStrip); gridColumn.HeaderCell.ContextMenuStrip.Opening -= ContextMenuStrip_Opening; } } } } foreach (ColumnInfo columnInfo in _dataGridViewColumns.Keys) { if (_dataGridViewColumns.ContainsKey(columnInfo)) { DataGridViewColumn gridColumn = _dataGridViewColumns[columnInfo]; if (null != gridColumn && null != gridColumn.HeaderCell && null != gridColumn.HeaderCell.ContextMenuStrip) { UnsubscribeContextmenu(gridColumn.HeaderCell.ContextMenuStrip); gridColumn.HeaderCell.ContextMenuStrip.Opening -= ContextMenuStrip_Opening; } } } foreach (Column column in dataGridView1.Columns) { if (null != column && null != column.HeaderCell && null != column.HeaderCell.ContextMenuStrip) { UnsubscribeContextmenu(column.HeaderCell.ContextMenuStrip); column.HeaderCell.ContextMenuStrip.Opening -= ContextMenuStrip_Opening; } } } catch (Exception ex) { string unused = ex.StackTrace; } } // Chart cleanup. _chromiumTreemapControl.Cleanup(); } private void saveToCloudToolStripMenuItem_Click(object sender, EventArgs e) { SaveToCloud.DoIt(_connectionMaster.SendManager, this); } private string GetLayout() { var xmlDocument = new XmlDocument(); xmlDocument.LoadXml(""); XmlNode layout = xmlDocument.Node(0); SaveLayout(layout); string layoutString = layout.Node("WINDOW").OuterXml; return layoutString; } private void DataGridView1_CellMouseEnter(object sender, DataGridViewCellEventArgs e) { int selectedRow = e.RowIndex; if (selectedRow != -1 && !contextMenuStrip1.Visible) _mostRecentRowData = _currentRowData = _rowDatas[selectedRow]; } private void DataGridView1_CellMouseLeave(object sender, DataGridViewCellEventArgs e) { _currentRowData = null; } /// /// Returns a list of all columns that are currently visible. /// /// private List GetVisibleColumns() { var toReturn = new List(); foreach (var pair in _dataGridViewColumns) { if (pair.Value.Visible) toReturn.Add(pair.Key); } return toReturn; } private void ColumnsToolStripMenuItem_Click(object sender, EventArgs e) { ConfigWindowWrapper configWindowWrapper = new TraditionalConfigWindowWrapper(ConfigurationType.CustomColumns, _connectionMaster) { VisibleCustomColumns = GetVisibleColumns(), AllCustomColumns = GetAllColumns() }; configWindowWrapper.ShowIt(); if (configWindowWrapper.CanceledAIColumnConfig) return; // this is the new list that the user has chosen to be visible var visibles = configWindowWrapper.VisibleCustomColumns; var temp = new Dictionary(_dataGridViewColumns); if (null == visibles || visibles.Count == 0)//We don't want all columns hidden. So if user makes all hidden get the defaults.. visibles = AddDefaultColumns(); foreach (var visibleColumn in visibles) { if (temp.ContainsKey(visibleColumn)) { (temp[visibleColumn]).Visible = true; temp.Remove(visibleColumn); } } // now what items(columns) are left in the temp dictionary will become hidden foreach (var pair in temp) { (pair.Value).Visible = false; } loadSortOptions(); UpdateTreemapSortOptions(); } private string _fileNameSaved = ""; private void SaveAsToolStripMenuItem_Click(object sender, EventArgs e) { GuiEnvironment.RecordUseCase("ME.RightClick.SaveAs", _connectionMaster.SendManager); var layoutManager = LayoutManager.Instance(); var dialog = new SaveFileDialog(); if (null != layoutManager.Directory) dialog.InitialDirectory = layoutManager.Directory; dialog.Filter = GuiEnvironment.XmlConfig.Node("ALERT_WINDOW").Node("PHRASES").Node("WINDOW_FILTER").PropertyForCulture("TEXT", "***"); dialog.DefaultExt = "WTI"; string fileName = _fileNameSaved; if (fileName == "") fileName = "ME - " + _windowName; dialog.FileName = FileNameMethod.QuoteFileName(fileName); if (dialog.ShowDialog() == DialogResult.OK) { layoutManager.SaveOne(this, dialog.FileName); _fileNameSaved = Path.GetFileName(dialog.FileName); } dialog.Dispose(); } private void DataGridView1_ColumnDisplayIndexChanged(object sender, DataGridViewColumnEventArgs e) { } private void DataGridView1_RowEnter(object sender, DataGridViewCellEventArgs e) { int rowIndex = e.RowIndex; if (rowIndex == -1) return; _mostRecentRowData = _rowDatas[rowIndex]; // Require datagrid focus so we can ignore up/down key pressed outside of our application if (GuiEnvironment.IntegrationSupportUpDownKeys && dataGridView1.Focused && (Keyboard.IsKeyDown(Key.Down) || Keyboard.IsKeyDown(Key.Up))) SendToExternalLinking(rowIndex); } private void DataGridView1_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e) { if ((ModifierKeys & Keys.Control) == Keys.Control && e.KeyCode == Keys.C) { if ((ModifierKeys & Keys.Shift) == Keys.Shift) { // skip this behavior if shift key is down } else { // override the default behavior by including the header row Clipboard.SetText(GetCsvFromGrid()); e.SuppressKeyPress = true; } } } private string GetCsvFromGrid(string fieldSeparator = "\t") { string asString = ""; string separator = ""; foreach (DataGridViewColumn column in dataGridView1.Columns) { asString += separator + column.HeaderText; separator = fieldSeparator; } asString += Environment.NewLine; foreach (DataGridViewRow row in dataGridView1.Rows) { separator = ""; foreach (DataGridViewColumn column in dataGridView1.Columns) { var formattedValue = row.Cells[column.Index].FormattedValue; if (formattedValue != null) asString += separator + formattedValue; separator = fieldSeparator; } asString += Environment.NewLine; } return asString; } private void GetLayoutToolStripMenuItem_Click(object sender, EventArgs e) { string layout = GetLayout(); MessageBox.Show("Setting layout to clipboard:" + Environment.NewLine + layout, "Layout"); Clipboard.SetText(layout); } private string GetPrototype() { var details = GetWindowDetails(true); string formattedDetails = ""; string space = ""; for (int i = 0; i < details.Length; i += 2) { string name = (string)details[i]; object value = details[i + 1]; if ((name == null) || (value == null)) continue; string asString = value.ToString(); if (value is DateTime time) { long asTimeT = ServerFormats.ToTimeT(time); asString = asTimeT.ToString(); } else if (value is double asDouble) asString = ServerFormats.ToString(asDouble); else if (value is bool asBool) asString = asBool ? "1" : "0"; formattedDetails += space + name + " {" + asString + "}"; space = " "; } return formattedDetails; } private void GetPrototypeToolStripMenuItem_Click(object sender, EventArgs e) { string formattedDetails = GetPrototype(); MessageBox.Show("Setting prototype to clipboard:" + Environment.NewLine + formattedDetails, "Prototype"); Clipboard.SetText(formattedDetails); } public void selectTheFont() { Font = GuiEnvironment.FontSettings; if (_useBrowserInterface) _chromiumTreemapControl.SetChartSize(); if (_isTopPanelHidden) { hideTopPanel(); } else if (!_isTopPanelHidden && showTreemapSortOptionsMenuItem.Checked && showTreemapToolStripMenuItem.Checked) { comboSortOptions.Font = Font; sortFielLabel.Font = Font; sortDirectionLabel.Font = Font; tableLayoutPanel2.Height = comboSortOptions.Height + 3; tableLayoutPanel2.Visible = true; } else { tableLayoutPanel2.Visible = false; } dataGridView1.ContextMenuStrip.Font = Font; _chromiumTreemapControl.SetChartSize(); RepositionHelpInstruction(); } private void MarketExplorer_TextChanged(object sender, EventArgs e) { // change Text of parent form if running in dock panel mode - RVH20210329 var parent = (Form)this.Parent; if (parent != null && parent is WindowDocumentDock) parent.Text = this.Text; } private void pinnedToolStripMenuItem_Click(object sender, EventArgs e) { Pinned = pinnedToolStripMenuItem.Checked; } private void toolStripMenuItemQueueBackoffice_Click(object sender, EventArgs e) { string url = "https://secure.trade-ideas.com/will-stats/MarketExplorer.php?name=" + WebUtility.UrlEncode(_windowName) + "&layout=" + WebUtility.UrlEncode(GetLayout()) + "&prototype=" + WebUtility.UrlEncode(GetPrototype()); Process.Start(url); } private void SaveResultsAsCSVToolStripMenuItem_Click(object sender, EventArgs e) { var dialog = new SaveFileDialog(); if (null != LayoutManager.Instance().Directory) dialog.InitialDirectory = LayoutManager.Instance().Directory; dialog.Filter = "CSV Files (*.csv)|*.csv"; dialog.DefaultExt = "csv"; string fileName = ""; fileName = dialog.FileName; dialog.FileName = FileNameMethod.QuoteFileName(fileName); if (dialog.ShowDialog() == DialogResult.OK) File.WriteAllText(dialog.FileName, GetCsvFromGrid(",")); dialog.Dispose(); } private void linkLabelHelp_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) => Process.Start(_linkSource); private void MarketExplorer_Resize(object sender, EventArgs e) { RepositionHelpInstruction(); } private void RepositionHelpInstruction() { // Center Help Instructions within the tableLayoutPanel1 while with in the panelHelp. labelMessage.Left = (panelHelp.Width - labelMessage.Width) / 2; var top = (tableLayoutPanel1.Height - labelMessage.Height - linkLabel.Height) / 2; if (top < dataGridView1.Height) labelMessage.Top = (panelHelp.Height - labelMessage.Height - linkLabel.Height) / 2; else labelMessage.Top = top - dataGridView1.Height; linkLabel.Left = (panelHelp.Width - linkLabel.Width) / 2; linkLabel.Top = labelMessage.Top + labelMessage.Height; } private void launchRealTimeStockRaceToolStripMenuItem_Click(object sender, EventArgs e) { int listID = CreateSymbolList(); string config = CreateTopListConfig(listID); GuiEnvironment.OpenRealTimeStockRace(true, false, false, config, TopListSortType.DeltaValue, null, null, this); } /// /// Create a symbol list from the rows. /// /// Symbol list ID private int CreateSymbolList() { SymbolListsCacheManager symbolListsCacheManager = GuiEnvironment.GetSymbolListsCacheManager(_connectionMaster); string listName = "RTSR - " + _windowName; int listID = symbolListsCacheManager.CreateList(listName); listName += " - " + listID.ToString(); symbolListsCacheManager.RenameList(listID, listName); foreach (RowData row in _rowDatas) { symbolListsCacheManager.AddSymbol(listID, row.GetSymbol()); if (symbolListsCacheManager.GetSymbols(listID).Count >= 20) // Only add 20 symbols to list. break; } return listID; } /// /// Create top list config string. /// /// Symbol list ID /// config string private string CreateTopListConfig(int listID) { return $"form=1&sort=MaxFCP&count=100&X_NYSE=on&X_ARCA=on&X_AMEX=on&XN=on&SL_0_{listID}=on&WN=Biggest+Gainers+(%25)&show0=D_Symbol&show1=Price&show2=FCD&show3=FCP&show4=TV&show5=RD&show6=&col_ver=1&count=100"; } /// /// Converts a Market Explorer RowData UnixTime (TimeT) to a DateTime?. This handles if the UnixTime has decimals places coming from Market Explorer as well. /// /// /// public static DateTime? ConvertUnixTimeColumnToNullableDateTime(string unixTimeColumnValue) { //Note: I almost put this method in the RowData class, but I put it in the MarketExplorer class since it's really Market Explorer specific since it needs to handle a UnixTime column that can have decimal places // Convert UnixTime (TimeT) string to a double first since UnixTime in Market Explorer will have decimal places by default unless the column is formatted double columnValue_AsDouble; if (double.TryParse(unixTimeColumnValue, out columnValue_AsDouble)) { var columnValue_AsLong = Convert.ToInt64(columnValue_AsDouble); var columnValue_AsNullableDateTime = ServerFormats.FromTimeT(columnValue_AsLong); return columnValue_AsNullableDateTime; } return null; } private void restarttoolStripMenuItem_Click(object sender, EventArgs e) { _sendingRunOnceRequest = false; if (_lastIdUsed != -1) { SendSubscribeMessage(_lastIdUsed.ToString()); SendRequest(); } } private void showChromeDevToolsToolToolStripMenuItem_Click(object sender, EventArgs e) { _chromiumTreemapControl.ShowDevTools(); } /// /// Show/Hide the positions browser control. /// private void ShowHideBrowserControl() { if (_useBrowserInterface) { dataGridView1.Visible = false; showStatusLineToolStripMenuItem.Visible = false; toolStripSeparator2.Visible = false; _chromiumTreemapControl.Visible = true; _chromiumTreemapControl.BringToFront(); } else { showStatusLineToolStripMenuItem.Visible = true; toolStripSeparator2.Visible = true; dataGridView1.Visible = true; _chromiumTreemapControl.Visible = false; _chromiumTreemapControl.SendToBack(); } ShowTheTopPanel(showTreemapSortOptionsMenuItem.Checked); selectTheFont(); SetStatusLineDisplayStatus(); } /// /// Show the controls context menu. /// public void ShowContextMenu() { this.InvokeIfRequired(delegate () { contextMenuStrip1.Show(System.Windows.Forms.Cursor.Position); }); } public Form GetAsForm() => this; /// /// Make Show Chrome Dev Tools menu item visible if in Development mode. /// public void EnableShowChromeDevToolsMenuItem() { this.InvokeIfRequired(delegate () { if (GuiEnvironment.DevelopmentMode) showChromeDevToolsToolStripMenuItem.Visible = true; }); } private void showTreemapToolStripMenuItem_Click(object sender, EventArgs e) { _useBrowserInterface = !_useBrowserInterface; ShowHideBrowserControl(); contextMenuStrip1.Hide(); } private void tableLayoutPanel1_VisibleChanged(object sender, EventArgs e) { if (_useBrowserInterface) { _chromiumTreemapControl.SetChartSize(true); } } private void hideTopPanel() { _isTopPanelHidden = true; tableLayoutPanel2.Height = 2; tableLayoutPanel2.Visible = false; showTreemapSortOptionsMenuItem.Checked = false; } private void picBoxHide_Click(object sender, EventArgs e) { hideTopPanel(); } private void showTreemapSortOptionsMenuItem_Click(object sender, EventArgs e) { ShowTheTopPanel(!showTreemapSortOptionsMenuItem.Checked); selectTheFont(); } private void ShowTheTopPanel(bool showSortOptions) { showTreemapSortOptionsMenuItem.Checked = showSortOptions; if (!showSortOptions) hideTopPanel(); else if (showSortOptions && showTreemapToolStripMenuItem.Checked) { tableLayoutPanel2.Visible = true; _isTopPanelHidden = false; } else if (showSortOptions && !showTreemapToolStripMenuItem.Checked) tableLayoutPanel2.Visible = false; } //Stores the list of columns to filter private List _visibleGridColumnsList; /// /// Load the sorting options from the visible columns of the grid /// private void loadSortOptions() { _visibleGridColumnsList = dataGridView1.Columns.Cast().Where(item => item.Visible).Select(item => item.ColumnInfo).ToList(); comboSortOptions.Items.Clear(); foreach (var column in _visibleGridColumnsList) { comboSortOptions.Items.Add(column.Description); } } private void comboSortOptions_SelectedIndexChanged(object sender, EventArgs e) { var index = comboSortOptions.SelectedIndex; if (index > -1) { var filterColumn = _visibleGridColumnsList[index]; SortRows(filterColumn); } } } public class FindAvwapDynamicDateTimesForRowCommand { // Note: AVWAP_DYNAMIC is a macro used in column calculations in Market Explorer, it can be found in macros.tcl: // https://github.com/TI-Pro/cpp_alert_server/blob/master/source/tikiller/macros.tcl private string AvwapDynamicMacroName = "AVWAP_DYNAMIC"; /// /// At a high level, this command class finds AVWAP Dynamic anchor dates in the selected /// Market Explorer Row, so it can be linked and drawn on a Chart with an AVWAP Indicator. /// The logic loops through the Market Explorer columns and looks for AVWAP Dynamic /// columns. If it finds them, it then looks for the AVWAP Dynamic anchor column parameter - /// like "IpoDate". It will then find the UnixTime value of that parameter column and /// returns it in an AvwapColumnMap that also includes the full Market Explorer macro call /// and the Avway Dynamic paremeter column name. /// /// The currnelty selected Market Explorer row the user clicked on /// public List Go(RowData marketExplorerSelectedRowData) { var foundAvwapDynamicColumnMaps = new List(); foreach (KeyValuePair keyValuePair in marketExplorerSelectedRowData.Data) { var avwapDynamicColumnFound = keyValuePair.Key.ToString().Contains(AvwapDynamicMacroName); if (avwapDynamicColumnFound) { var fullAvwapDynamicMacroCallWithParameter = keyValuePair.Key.ToString(); var avwapDynamicTimeColumnName = GetTimeParameterColumnName(fullAvwapDynamicMacroCallWithParameter); if (avwapDynamicTimeColumnName.DoesNotHaveValue()) continue; var avwapDynamicDateTimeValue = FindTimeParameterColumnAndGetValue(marketExplorerSelectedRowData, avwapDynamicTimeColumnName); var foundAvwapDynamicColumnMap = new AvwapColumnMap { FullAvwapDynamicMacroCall = fullAvwapDynamicMacroCallWithParameter, AvwapDateParemterColumnName = avwapDynamicTimeColumnName, AvwapDate = avwapDynamicDateTimeValue, }; foundAvwapDynamicColumnMaps.Add(foundAvwapDynamicColumnMap); } } return foundAvwapDynamicColumnMaps; } private string GetTimeParameterColumnName(string fullAvwapDynamicMacroCall) { var avwapDynamicTimeColumnSplits = fullAvwapDynamicMacroCall.Split(' '); if (!avwapDynamicTimeColumnSplits.Any() || avwapDynamicTimeColumnSplits.Length != 2) return null; var avwapDynamicTimeColumnName = avwapDynamicTimeColumnSplits[1]; return avwapDynamicTimeColumnName; } private DateTime? FindTimeParameterColumnAndGetValue(RowData currentRowData, string avwapDynamicTimeColumnName) { // Note: START is a Market Explorer Macro variable, but the column in Market Explorer is start_time if (avwapDynamicTimeColumnName.Trim().ToUpper() == "START") { avwapDynamicTimeColumnName = "start_time"; } foreach (KeyValuePair keyValuePair in currentRowData.Data) { if (keyValuePair.Key.ToString().ToUpper().Trim() == avwapDynamicTimeColumnName.ToUpper().Trim()) { var avwapDynamicTimeParemeterValue = keyValuePair.Value.ToString(); if (avwapDynamicTimeParemeterValue.DoesNotHaveValue()) return null; return MarketExplorer.ConvertUnixTimeColumnToNullableDateTime(avwapDynamicTimeParemeterValue); } } return null; } public static List GetValidAvwapDateTimes(List avwapColumnMaps) { if (avwapColumnMaps.DoesNotHaveAny()) return new List(); var foundAvwapValidDates = avwapColumnMaps.Where(x => x.AvwapDate.HasValue).Select(x => x.AvwapDate.Value).ToList(); return foundAvwapValidDates; } } public class AvwapColumnMap { public string FullAvwapDynamicMacroCall { get; set; } public string AvwapDateParemterColumnName { get; set; } public DateTime? AvwapDate { get; set; } } public class GoLevelColumnExistsCommand { // Note: GO_LEVEL is a macro used in column calculations in Market Explorer, it can be found in macros.tcl: // https://github.com/TI-Pro/cpp_alert_server/blob/master/source/tikiller/macros.tcl private string goLevelMacroName = "GO_LEVEL"; /// /// This command finds the GO_LEVEL column if it exists, so the indicator can be added to the chart /// /// public bool Go(RowData marketExplorerSelectedRowData) { foreach (KeyValuePair keyValuePair in marketExplorerSelectedRowData.Data) { var goLevelColumnFound = keyValuePair.Key.ToString().Contains(goLevelMacroName); if (goLevelColumnFound) { return true; } } return false; } } }