Stock Analyst

This is the main and biggest project of all the application. It contains the UI of the application and is developed with WPF using the MVVM (Model - View - ViewModel pattern), due this paradigm each window will have its own VM. To follow the common WPF guidelines all the UI elements won't have fixed size, only minimums will be set if needed.

All the view model classes inherit from the ViewModelBase, this class provides the default property notification feature but controlling the thread where the notification is send to use always the thread used to create the UI. There is also a property used on most VM called Busy. When the VM is Busy the window should be disabled and with a wait cursor. This behaviour has to be binded in xaml.

To set the margins of every item of the Window the approach found here was tried but it didn't work because sub-panels were not updated. Following this recommendation a default style has been created for all the Controls used here and probably in other WPF applications.

There is also a merged dictionary called StockAnalystTheme.xaml with styles for the controls used on this application. As a control can have only one style all styles on StockAnalystTheme.xaml must be based on the ones at the DefaultTheme.xaml

Options Window

This dialog will let the user to view/edit the settings needed to have realtime data and to connect to the database. To avoid setting fixed sizes the textboxes are 2 times bigger than the labels. This will ensure that they will be consistent in size. To implement this feature a new converter has been created (MultiplierConverter). After trying some things I realized that ActualWidth of the ColumnDefinition is not a dependence property so I switched to the label ActualWidth.

The view model of the window does not nothing but loading / saving the settings, the caller of the dialog must check the return value and a property that lets the caller know if some data has been modified or not to proceed as needed. To allow the viewmodel to close the window a communication is established through an event.

To avoid breaking the MVVM pattern a addon has been created to be able to bind passwords. To encrypt the password a new string extension has been created. The encryption is pretty simple but enought for our needs at this moment.

This is how the screen looks like using different fonts sizes, the screen adapts to what's required without changing its size in run-time:

These are the classes used by the options window:

  • ApplicationOptions: it models the application options. Contains the memory model of the options and methods to compare and clone ApplicationOptions objects.
  • ApplicationOptionsVM: its responsibility is to provide what is needed to the View. Mainly data validation and data change notification.
  • ApplicationOptionsDataSource: its responsibility is to load and save the options from / to the settings persistence layer.
  • OptionsVM: its responsibility is to prepare the data to be shown at the window, to store all the data the view needs to work, to validate the entered data and to execute the actions that the dialog can do. 
  • OptionsDialog: its responsibility is to show the current option values and to allow the enduser to change them.
  • OptionsManager: its responsibility is to create, show and manage the OptionsDialog when it's needed. It shows the OptionsDialog if the settings have not been set on construction time or when requested to do it and notifies the user when a restart is required. It also stores the effective settings that are the ones loaded during application startup. The application should check the settings values always thru this class because the latest values are not the ones being valid.

Current settings available:

  1. Enable Realtime: enable realtime capture. If you enable the realtime capture you must provide a valid username and password for the Interding provider.
  2. User: the Interdin user used to log onto their website
  3. Password: the Interdin password used to log onto their website
  4. Database Server: the name of the server (including instance if it exists) where the information it's going to be stored.
  5. Database Name: the name of the database where the information is going to be stored.

Current window (without Aero):

MainToolBar

The toolbar will allow the user to enter the same commands of the menu and also to set some parameters for these commands.

WIP

StatusBar

The statusbar will show to the end user the status of the application and the internal systems and will let him ensure that everything is working as expected. Usercontrols have to be designed to avoid changing its size during runtime and sizing at their startup to autofit their content, the window will have the responsibility of setting its size.  This is the available information:

  1. Last Scheduler Chek: the last time the Acquisition System checked if the whole system needed a start or a stop.
  2. Last Data Received: the last time the accessor received data from the source.
  3. Data Refreshes: the total amount of times the accessor has received data from the source today (usually a refresh means a page read). This value is reset with each start and stop of the accessor.
  4. Reconnections: the number of times the accessor has done a connection process with the provider. Each day one connection is done when the system starts and then one reconnection is one each time there is an error.
  5. Real Time Capture: shows the status of the realtime acquisistion system.
  6. Engine: shows if the engine is working and thus if the accessor must be connected or not.
  7. Accessor: shows if it is connected to the provider or not.

Current statusbar:

Viewer

The viewer is the control in charge of showing the stock information in a textual way. As the stock analyzer is focused on day trading the viewer shows information regarding the evolution of a stock over a day. The viewer has to be designed to support realtime information as well as historical data as we will use the same control on both modes.

How the data flows to the viewer

These are the workflows of the data from the generator to the viewer:

This is how a section of the viewer currently looks (there is no space to put a full size image):

These are the classes used by the viewer:

  • GridViewer: it is the user control in charge of showing to the end user the information of all the available stocks in a precise moment.  It has a column for each available field (if visible). Each cell can be configured to show a flash when the value changes, some to show an arrow showing the tendency (on certain cells this does not makes sense) and some to color its value from red (bad value) to green (good value). Users will be able to change the order of the columns just dragging them.
    • Note: the xaml code has lots of repeated code just changing binding variables. I'm not happy at all with the code and I will probably refactor it sooner or latter but as inheriting UserControls inhibits you from using XAML I'm looking for an alternative solution.
    • Note 2: to make the control autosize as we want to we need to select a column that has the header text bigger than the content, load the stuff and find the relation of the other columns agains the selected one. We need the header bigger because if not its size will change in runtime and this is what we want to avoid.
    • Note 3: to increase performance the rows will be shown only when they're all loaded. Only the GroupInitializer knows when all the stocks are loaded so we will check the status of the AcquisitionEngine and show the rows when the status change to Enabled.
  • GridVM: the main goal of ViewModel of the viewer is to create the ViewModel of all the stocks in the form of RowVM. It's a kind of Stock -> RowVM converter. It does the job attaching to the different events that notify about changes on the collections containing Groups and Stocks. It also track changes on the DisplayIndex of the columns (as they can be modified dragging them) to save the options on change. It is very important the order in which things are done because items should be added to collections after they are tracked by the GridVM. 
    • Note: initially, as the viewer had to work with realtime and historical data there was a DateTime? property to set the day the GridVM had to show. Then I realized that the viewers always have only one day loaded so we only need to find the day with data to load it and we can remove this property.
    • Note 2: to show the data in a ordered way even when working with parallel enabled we sort the list of rows each time one is inserted. As the algorithm does nothing with the already sortered rows there is only a small performance penalty.
    • Note 3: to improve performance and allow a good sizing of the columns a placeholder (an empty row) is shown when no data is available. There is a method called ChangePlaceHolderVisibility that shows or hides the placeholder to avoid showing the grid changing its data as witht eh current DataGrid this reduces a lot the performance.
    • Note 4: as there are a lot of stocks on the viewer a filter by name has been created. The method ApplyFilter sets a filter on the rows viewed.
  • RowVM: the view model of a row contains all the data that a row contains in the form of several cell viewmodels. A row represents daily information data of a stock so its model it's a QuotationDailyInfo object. As all the values of a row change at the same time if they do it the row viewmodel is the one in charge of creating the timer used into the cells to reset the datachanged property which animates the cell background on value change. At the beginning we had a timer created on each cell but that represented some overhead and this is why this solution was taken.
  • CellVM: its the base class of all the cells of the grid. Represents the intersection of a row with a column. Contains the properties to detect when a value changes (used by the UI to show a flash if configured to do so) and to know when it is the first change or not.
  • CellIntegerVM: represents a cell containing an integer value and provides a property to check whenever the value is going up or down.
  • CellDecimalVM: represents a cell containing a decimal value and provides a property to check whenever the value is going up or down.
  • CellTimeSpanVM: represents a cell containing a TimeSpan value and provides a property to check whenever the value is going up or down.
  • CellDateTimeSpanVM: represents a cell containing a DateTime value.
  • CellStringVM: represents a cell containing a string value.

The whole model of the viewer is represented on the following diagram:

Column Options

The viewer can be configured to modify their columns. The things you can configure are:

  1. Visibility: you can view or hide all the columns but the Group and Name ones.
  2. Display Index: you can sort the columns in whatever order you want. You can change the order with the options dialog or dragging the columns on the grid.
  3. View Change: you can choose to display a flash on each cell every time its value changes.
  4. View Arrow: on the columns with values that can go up or down you can select to view an arrow showing the last tendence.
  5. Color Value: on the columns with a fixed range (currently the percentage columns) you can choose to color the cell's value between red and green (passing thru grey). The value for red is -Limit, for grey is 0 and for Green is +Limit
  6. Limit: the lower and higher limit of the color value specified for option 5.

When an option does not makes sense on a particular column that option will not appear on the options dialog but the setting will exist, this way the datasources won't need to handle exceptions on the way of Loading / Saving settings.

The application options window approach has been used with this window again but this one is more complex because the options are complex type with sub-objects. The following schema defines the class design:

Because the validation is called directly on the ColumnOptionsVM while the validation can only be done on the AllColumnsOptionsVM (the valid values of one column depends on the values of the others) an event is raised requesting validation captured by the AllColumnsOptionsVM and returning the validation result thru the EventArtgs.

The first approach was to allow the user to view the changes done on the options dialog while the changes were done (sharing the AllColumnsOptionsVM object between both classes (OptionsDialogVM and GridVM) but the way that WPF handles the changes on the DisplayIndex (while changing the values will be times where repeated values exists until the edition finishes) makes the DisplayIndex edition weird, values change by theirselves.

Instead of using this approach only the options will be shared between the GridVM and the OptionsDialogVM). As the options do not notify about property changes (they are model objects) an event will be raised by the OptionsManager when the option values change that will be handled by the GridVM. The GridVM will call a method on the AllColumnsOptions that will raise a PropertyChange on all its own properties.

This is how the window currently looks:

These are the classes used by the options window:

  • ColumnOptions: this class represents the options a single column can have. Implements the PropertyChange event to synchronize the data between the columns and the options. The options have a property that specify the column name. This is a trick to be able to process all the columns on the AllColumnsOptions classes with loops and avoid having to process them one by one.
  • ColumnOptionsDataSource: its duty is to load and save a ColumnOptions object to its repository (currently project settings).
  • ColumnOptionsVM: it is the ViewModel of the ColumnOptions class. It implements the VM validation. As it cannot validate its data by itself it raises an event that its handled by the AllColumnsOptionsVM class.
  • AllColumnsOptions: this class represents all the columns with their own options.
  • AllColumnsOptionsDataSource: its responsibility is to load and save all the column's options from the repository (calling ColumnOptionsDataSource).
  • AllColumnsOptionsVM: it is the ViewModel of the AllColumnsOptions class. It implements the validation system. It is also used by the viewer to store the effective options of the columns and to allow the change of the display index by dragging the columns on the viewer. There should be a new class to model the grid columns to follow the SOLID principle (because the validation is not needed in this case) but as the system is already complex (for such a small feature) the class will be reused.
  • OptionsDialogVM: it contains the view model of the dialog and has the VM commands and an AllColumnOptionsVM object. 
  • OptionsDialog: it is the dialog that let the user to change the settings.
  • OptionsManager: the options manager is in charge of showing the OptionsDialog to the end user and saving the options to the repository if it's needed.

MainWindow

The application main window consists on a layer of some viewmodels and usercontrols to show its data as can be seen on the following picture:

  • MainToolBarVM: it contains the data viewed / setted at the toolbar. As some commands are repeated between the application menu and the toolbar a new class (ApplicationCommandsVM) has been created to store all the application commands so they can be reference from anywhere. Regarding the data, as most of them is not shared by the menu as the menu can only (almost) contain commands, has been stored into the MainToolbarVM but it is reference sometimes from the MainWindow as it has to change its behavior depending on what has been selected at the toolbar.
  • ApplicationCommandsVM: contains all the commands the application can execute. This way the viewmodels of the mainwindow do not contain commands as they are all grouped together in this class.
  • RealtimeGridVM: it is the viewmodel of the realtime viewer and contains its data. 
  • HistoricalGridVM: it is the viewmodel of the historical viewer and contains its data. 
  • MainStatusbarVM: it is the viewmodel of the statusbar of the application. It contains the status of the main elements of the application like the engines and the accessors. 

Other classes

  • ApplicationInitializer: its main responsibility is to execute the required steps to initialize the application main objects. It initialize the objects required by all the application but not the view models. The viewmodels are always created from the MainWindowVM as they belong to it.
  • ApplicationCloser; its main responsibility is to shutdown everything before exiting the application.

Last edited Feb 18, 2013 at 9:04 AM by somos, version 57

Comments

No comments yet.