mirror of
https://github.com/DevExpress/netcore-winforms-demos.git
synced 2026-01-04 15:56:04 +00:00
Add Outlook Inspired and Stock Market demos
This commit is contained in:
115
StockMarketTraderApp/ViewModel/BusinessObjectsViewModel.cs
Normal file
115
StockMarketTraderApp/ViewModel/BusinessObjectsViewModel.cs
Normal file
@@ -0,0 +1,115 @@
|
||||
using System;
|
||||
using DevExpress.StockMarketTrader.Model.BusinessObjects;
|
||||
|
||||
namespace DevExpress.StockMarketTrader.ViewModel {
|
||||
public class TradingDataViewModel : ViewModelBase {
|
||||
readonly TradingData tradingData;
|
||||
|
||||
public DateTime Date {
|
||||
get { return TradingData.Date; }
|
||||
set {
|
||||
TradingData.Date = value;
|
||||
OnPropertyChanged("Date");
|
||||
}
|
||||
}
|
||||
public double Price {
|
||||
get { return TradingData.Price; }
|
||||
set {
|
||||
TradingData.Price = value;
|
||||
OnPropertyChanged("Price");
|
||||
}
|
||||
}
|
||||
public double Open {
|
||||
get { return TradingData.Open; }
|
||||
set {
|
||||
TradingData.Open = value;
|
||||
OnPropertyChanged("Open");
|
||||
}
|
||||
}
|
||||
public double Close {
|
||||
get { return TradingData.Close; }
|
||||
set {
|
||||
TradingData.Close = value;
|
||||
OnPropertyChanged("Close");
|
||||
}
|
||||
}
|
||||
public double High {
|
||||
get { return TradingData.High; }
|
||||
set {
|
||||
TradingData.High = value;
|
||||
OnPropertyChanged("High");
|
||||
}
|
||||
}
|
||||
public double Low {
|
||||
get { return TradingData.Low; }
|
||||
set {
|
||||
TradingData.Low = value;
|
||||
OnPropertyChanged("Low");
|
||||
}
|
||||
}
|
||||
public double Volume {
|
||||
get { return TradingData.Volume; }
|
||||
set {
|
||||
TradingData.Volume = value;
|
||||
OnPropertyChanged("Volume");
|
||||
}
|
||||
}
|
||||
public TradingData TradingData { get { return tradingData; } }
|
||||
|
||||
public TradingDataViewModel() {
|
||||
tradingData = new TradingData();
|
||||
}
|
||||
public TradingDataViewModel(TradingData data) : this() {
|
||||
Assign(data);
|
||||
}
|
||||
public TradingDataViewModel(DateTime dateTime) : this() {
|
||||
this.Date = dateTime;
|
||||
}
|
||||
public void Assign(TradingData data) {
|
||||
tradingData.Assign(data);
|
||||
OnPropertyChanged("Price");
|
||||
OnPropertyChanged("Volume");
|
||||
}
|
||||
}
|
||||
|
||||
public class CompanyTradingDataViewModel : TradingDataViewModel {
|
||||
int rise;
|
||||
LockableCollection<TradingDataViewModel> volumeDynamics;
|
||||
|
||||
double totalRise;
|
||||
public double TotalRise {
|
||||
get {
|
||||
return totalRise;
|
||||
}
|
||||
set {
|
||||
totalRise = value;
|
||||
OnPropertyChanged("TotalRise");
|
||||
}
|
||||
}
|
||||
public string CompanyName { get; private set; }
|
||||
public int Rise {
|
||||
get { return rise; }
|
||||
set {
|
||||
rise = value;
|
||||
OnPropertyChanged("Rise");
|
||||
}
|
||||
}
|
||||
public LockableCollection<TradingDataViewModel> VolumeDynamics {
|
||||
get { return volumeDynamics; }
|
||||
set {
|
||||
volumeDynamics = value;
|
||||
OnPropertyChanged("VolumeDynamics");
|
||||
}
|
||||
}
|
||||
|
||||
public CompanyTradingDataViewModel(TradingData data, string companyName, int rise, double totalRise) : base(data) {
|
||||
CompanyName = companyName;
|
||||
TotalRise = totalRise;
|
||||
Rise = rise;
|
||||
}
|
||||
public void Assign(CompanyTradingData ctd) {
|
||||
CompanyName = ctd.CompanyName;
|
||||
base.Assign(ctd);
|
||||
}
|
||||
}
|
||||
}
|
||||
677
StockMarketTraderApp/ViewModel/RealTimeDataViewModel.cs
Normal file
677
StockMarketTraderApp/ViewModel/RealTimeDataViewModel.cs
Normal file
@@ -0,0 +1,677 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Forms;
|
||||
using DevExpress.StockMarketTrader.Model;
|
||||
using DevExpress.StockMarketTrader.Model.BusinessObjects;
|
||||
using DevExpress.StockMarketTrader.StockDataServiceReference;
|
||||
using Application = System.Windows.Forms.Application;
|
||||
|
||||
namespace DevExpress.StockMarketTrader.ViewModel {
|
||||
public class RealTimeDataViewModel : ViewModelBase {
|
||||
public static bool IsReady = false;
|
||||
protected static void InvokeSync(Delegate method) {
|
||||
if (method != null && Application.OpenForms.Count > 0) {
|
||||
for(int i = 0; i < Application.OpenForms.Count; i++) {
|
||||
Form form = Application.OpenForms[i];
|
||||
if(form is StockMarketView)
|
||||
form.Invoke(method, new object[] { });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object sem = new object();
|
||||
string selectedCompanyName = "MSFT";
|
||||
int volumeCount = 15;
|
||||
int countOfWeek = 1;
|
||||
int candlesCount = 72, currentDate = 0, tickCount = 0, offlineTimeInterval = 500, totalTicks = 5;
|
||||
bool isAllBindingDataUpdate = false, canEndUpdate = true, canUpdate = true;
|
||||
double highestPrice = 0, lowestPrice = 0;
|
||||
public RealTimeDataModel model;
|
||||
Dictionary<string, Queue<Delegate>> defferedUpdate = new Dictionary<string, Queue<Delegate>>();
|
||||
List<DateTime> dates;
|
||||
List<string> companies;
|
||||
LockableCollection<TransactionData> transactionGridBindingData;
|
||||
LockableCollection<CompanyTradingDataViewModel> watchLisBindingData;
|
||||
BindingList<CompaniesVolumeData> volumeChartBindingData;
|
||||
BindingList<TradingDataViewModel> stockChartBindingData;
|
||||
CompanyTradingDataViewModel selectedCompany;
|
||||
ObservableCollection<CompanyTradingDataViewModel> oldWatchListData;
|
||||
LiveTileViewModel sparklineTileViewModel = new LiveTileViewModel();
|
||||
List<LiveTileViewModel> topThreeCompanies = new List<LiveTileViewModel>() { new LiveTileViewModel(), new LiveTileViewModel(), new LiveTileViewModel() };
|
||||
|
||||
EventHandler currentPriceIndexChanged;
|
||||
EventHandler watchListChanged;
|
||||
|
||||
public event EventHandler CurrentPriceIndexChanged { add { currentPriceIndexChanged += value; } remove { currentPriceIndexChanged -= value; } }
|
||||
public event EventHandler WatchListChanged { add { watchListChanged += value; } remove { watchListChanged -= value; } }
|
||||
|
||||
|
||||
Timer TimerCore { get; set; }
|
||||
public int CurrentPriceIndex { get; set; }
|
||||
public int Ticks {
|
||||
get { return totalTicks; }
|
||||
set { totalTicks = value; }
|
||||
}
|
||||
public int TickCount {
|
||||
get { return tickCount; }
|
||||
set { tickCount = value; } }
|
||||
public int CandlesCount {
|
||||
get { return candlesCount; }
|
||||
set { candlesCount = value; }
|
||||
}
|
||||
public bool IsSuspendUpdating { get; set; }
|
||||
public bool IsLoading { get; set; }
|
||||
public string NetworkState { get { return model.NetworkState; } }
|
||||
public CompanyTradingDataViewModel SelectedCompany {
|
||||
get { return selectedCompany; }
|
||||
set {
|
||||
if (value != null) {
|
||||
if(selectedCompanyName != value.CompanyName || selectedCompany != value) {
|
||||
List<CompanyTradingDataViewModel> result = watchLisBindingData.Where(e => e.CompanyName == value.CompanyName).Select(e => e).ToList();
|
||||
if (result.Count > 0) {
|
||||
selectedCompanyName = value.CompanyName;
|
||||
selectedCompany = result[0];
|
||||
SetSelectedCompany();
|
||||
}
|
||||
}
|
||||
}
|
||||
OnPropertyChanged("SelectedCompany");
|
||||
}
|
||||
}
|
||||
public LiveTileViewModel SparklineTileViewModel {
|
||||
get { return sparklineTileViewModel; }
|
||||
set { sparklineTileViewModel = value; OnPropertyChanged("SparklineTileViewModel"); }
|
||||
}
|
||||
public List<LiveTileViewModel> TopThreeCompanies {
|
||||
get { return topThreeCompanies; }
|
||||
set { topThreeCompanies = value; OnPropertyChanged("TopThreeCompanies"); }
|
||||
}
|
||||
public LockableCollection<CompanyTradingDataViewModel> WatchListBindingData { get { return watchLisBindingData; } }
|
||||
public BindingList<TradingDataViewModel> StockChartBindingData { get { return stockChartBindingData; } }
|
||||
public LockableCollection<TransactionData> TransactionGridBindingData { get { return transactionGridBindingData; } }
|
||||
public BindingList<CompaniesVolumeData> VolumeChartBindingData { get { return volumeChartBindingData; } }
|
||||
|
||||
public RealTimeDataViewModel(Timer timer) {
|
||||
TimerCore = timer;
|
||||
TimerCore.Interval = offlineTimeInterval;
|
||||
TimerCore.Tick += new EventHandler(UpdateOnTimer);
|
||||
|
||||
model = new RealTimeDataModel();
|
||||
model.UpdateFailed += new EventHandler<RealTimeDataEventArgs>(OnUpdateFailed);
|
||||
model.Initialized += new EventHandler<EventArgs>(OnInitialized);
|
||||
stockChartBindingData = new BindingList<TradingDataViewModel>();
|
||||
watchLisBindingData = new LockableCollection<CompanyTradingDataViewModel>();
|
||||
transactionGridBindingData = new LockableCollection<TransactionData>();
|
||||
volumeChartBindingData = new BindingList<CompaniesVolumeData>();
|
||||
|
||||
IsLoading = true;
|
||||
}
|
||||
void OnInitialized(object sender, EventArgs e) {
|
||||
GetDatesAsync();
|
||||
}
|
||||
void OnUpdateFailed(object sender, RealTimeDataEventArgs e) {
|
||||
}
|
||||
void OnCandlesCountChangedCallBack() {
|
||||
CorrectCurrentDate();
|
||||
tickCount = 0;
|
||||
candlesCount = CandlesCount + 1;
|
||||
StopTimer();
|
||||
UpdateAllBindingData();
|
||||
}
|
||||
void CorrectCurrentDate() {
|
||||
int delta = currentDate;
|
||||
delta = currentDate - (CandlesCount + 1) * Ticks;
|
||||
if (delta > -1)
|
||||
currentDate = delta;
|
||||
else {
|
||||
delta = currentDate - candlesCount * totalTicks;
|
||||
currentDate = delta < 0 ? 0 : delta;
|
||||
}
|
||||
}
|
||||
//void ChangeTimerInterval(int time) {
|
||||
// TimerCore.Interval = time;
|
||||
//}
|
||||
void StartTimer() {
|
||||
InvokeSync(new Action(() => { TimerCore.Start(); }));
|
||||
}
|
||||
void StopTimer() {
|
||||
InvokeSync(new Action(() => { TimerCore.Stop(); }));
|
||||
}
|
||||
void GetDatesAsync() {
|
||||
SetDates(model.Service.GetDates());
|
||||
//Action<DateTime[]> action = new Action<DateTime[]>(SetDates);
|
||||
//AddDefferedDelegate("GetDates", action);
|
||||
//model.BeginGetDates();
|
||||
}
|
||||
void SetDates(DateTime[] dates) {
|
||||
try {
|
||||
if (dates.Length == 0)
|
||||
throw new Exception();
|
||||
this.dates = new List<DateTime>(dates);
|
||||
GetCompaniesAsync();
|
||||
canEndUpdate = true;
|
||||
}
|
||||
catch {
|
||||
canUpdate = false;
|
||||
}
|
||||
}
|
||||
void InitializeChartBindingData() {
|
||||
isAllBindingDataUpdate = true;
|
||||
stockChartBindingData.Clear();
|
||||
}
|
||||
void GetCompaniesAsync() {
|
||||
SetCompanies(model.Service.GetCompaniesName());
|
||||
}
|
||||
void SetCompanies(string[] arrayCompanies) {
|
||||
if(model.IsOnline) {
|
||||
this.companies = new List<string>();
|
||||
for(int i = 0; i < arrayCompanies.Length; i++)
|
||||
this.companies.Add(arrayCompanies[i]);
|
||||
}
|
||||
else
|
||||
this.companies = new List<string>(arrayCompanies);
|
||||
InitializeChartBindingData();
|
||||
GetBindingDataAsync();
|
||||
}
|
||||
void GetVolumeDynamicsDataAsyncCompleted2(StockData[] data) { }
|
||||
void GetBindingDataAsync() {
|
||||
GetWatchListBindingDataAsync();
|
||||
GetCompaniesVolumeAsync();
|
||||
currentDate = 0;
|
||||
|
||||
GetVolumeDynamicsDataAsync();
|
||||
GetStockChartBindingDataAsync();
|
||||
}
|
||||
void GetVolumeDynamicsDataAsync(int current = 0) {
|
||||
if (companies == null) return;
|
||||
int date = current + totalTicks * ((candlesCount - volumeCount) + 1);
|
||||
GetVolumeDynamicsDataAsyncCompleted(model.Service.GetStockDataFromPeriodByCompanyList(date, volumeCount, totalTicks, companies.ToArray()));
|
||||
}
|
||||
void GetVolumeDynamicsDataAsyncCompleted(CompanyStockData[] cd) {
|
||||
foreach (CompanyStockData companyStockData in cd) {
|
||||
CompanyTradingDataViewModel vm = watchLisBindingData.Where(c => c.CompanyName == companyStockData.CompanyName).Select(c => c).FirstOrDefault();
|
||||
vm.VolumeDynamics = CreateVolumeDynamicsBindingData(companyStockData.Data);
|
||||
}
|
||||
TryEndUpdateBindingData();
|
||||
}
|
||||
void GetWatchListBindingDataAsync() {
|
||||
currentDate += candlesCount * totalTicks;
|
||||
UpdateWatchListBindingDataAsyncCompleted(model.Service.GetStockDataByDate(dates[currentDate - 1]));
|
||||
}
|
||||
void GetStockChartBindingDataAsync() {
|
||||
GetStockChartBindingDataAsyncCompleted(model.Service.GetCompanyMultipleDataFromPeriod(currentDate, candlesCount, totalTicks, selectedCompanyName));
|
||||
}
|
||||
void GetStockChartBindingDataAsyncCompleted(CompanyData[] data) {
|
||||
List<CompanyData> newStockChartData = new List<CompanyData>();
|
||||
try {
|
||||
newStockChartData = new List<CompanyData>(data);
|
||||
}
|
||||
catch { }
|
||||
AddChartPoints(newStockChartData);
|
||||
}
|
||||
void AddChartPoints(List<CompanyData> newStockChartData) {
|
||||
CreateChartBindingData(newStockChartData);
|
||||
UpdateSparklineViewModelSource();
|
||||
isAllBindingDataUpdate = false;
|
||||
TryEndUpdateBindingData();
|
||||
}
|
||||
void UpdateSparklineViewModelSource() {
|
||||
SparklineTileViewModel.Source = stockChartBindingData;
|
||||
}
|
||||
void UpdateWatchListBindingDataAsync() {
|
||||
if (dates == null) return;
|
||||
if(currentDate >= 0 && currentDate < dates.Count)
|
||||
UpdateWatchListBindingDataAsyncCompleted(model.Service.GetStockDataByDate(dates[currentDate]));
|
||||
else
|
||||
UpdateWatchListBindingDataAsyncCompleted(model.Service.GetStockDataByDate(dates.FirstOrDefault()));
|
||||
}
|
||||
void UpdateCompaniesVolumeAsync() {
|
||||
if (tickCount == totalTicks || tickCount == 0)
|
||||
GetCompaniesVolumeAsync();
|
||||
}
|
||||
void UpdateWatchListBindingDataAsyncCompleted(StockData[] gridData) {
|
||||
UpdateWatchList(gridData);
|
||||
UpdateSparklineViewModelCompany();
|
||||
UpdateTopThreeCompany();
|
||||
TryEndUpdateBindingData();
|
||||
}
|
||||
void UpdateTopThreeCompany() {
|
||||
var topThree = GetTopThreeVolume();
|
||||
if (topThree.Count < 3) return;
|
||||
var result = new List<LiveTileViewModel>();
|
||||
foreach (CompaniesVolumeData volumeData in topThree) {
|
||||
LiveTileViewModel vm = new LiveTileViewModel();
|
||||
vm.CompanyIndex = volumeData.CompanyName;
|
||||
double delta = 0;
|
||||
double increace = CalcIncrease(volumeData.CompanyName, ref delta);
|
||||
vm.Arrow = increace > 0 ? "▲" : "▼";
|
||||
vm.Persent = Math.Abs(increace) * 100 + "%";
|
||||
vm.PriceIncrease = Math.Abs(Math.Round(delta, 3)).ToString();
|
||||
result.Add(vm);
|
||||
}
|
||||
TopThreeCompanies = result;
|
||||
}
|
||||
void GetCompaniesVolumeAsync() {
|
||||
int endIndex = currentDate - totalTicks;
|
||||
if (dates != null && currentDate < dates.Count && endIndex > 0) {
|
||||
DateTime start = dates[currentDate];
|
||||
DateTime end = dates[endIndex];
|
||||
GetCompaniesVolumeCompleted(model.Service.GetCompaniesVolumeFromPeriod(start, end));
|
||||
}
|
||||
}
|
||||
void GetCompaniesVolumeCompleted(CompaniesVolumeData[] data) {
|
||||
UpdateVolumeChartBindingData(data);
|
||||
}
|
||||
void UpdateVolumeChartBindingData(CompaniesVolumeData[] data) {
|
||||
volumeChartBindingData.Clear();
|
||||
SetVolumeOfSelectedCompany();
|
||||
int index = 1;
|
||||
for (int i = 0; i < data.Length - 1; i++) {
|
||||
if (data[i].CompanyName == selectedCompanyName)
|
||||
continue;
|
||||
if (volumeChartBindingData.Count < data.Length + 1)
|
||||
volumeChartBindingData.Add(data[i]);
|
||||
index++;
|
||||
}
|
||||
ValidateCompaniesVolume();
|
||||
TryEndUpdateBindingData();
|
||||
}
|
||||
void UpdateSparklineViewModelCompany() {
|
||||
SparklineTileViewModel.CompanyIndex = SelectedCompany?.CompanyName;
|
||||
double delta = 0;
|
||||
double increace = CalcIncrease(SelectedCompany?.CompanyName, ref delta);
|
||||
SparklineTileViewModel.Arrow = increace > 0 ? "▲" : "▼";
|
||||
SparklineTileViewModel.Persent = Math.Abs(increace) * 100 + "%";
|
||||
}
|
||||
void ValidateCompaniesVolume() {
|
||||
List<string> volumeCompanies = volumeChartBindingData.Select(c => c.CompanyName).ToList();
|
||||
List<string> exceptCompanies = companies.Except(volumeCompanies).ToList();
|
||||
for (int i = 0; i < volumeChartBindingData.Count; i++) {
|
||||
CompaniesVolumeData volumeData = volumeChartBindingData[i];
|
||||
if (!companies.Contains(volumeData.CompanyName)) {
|
||||
var res = watchLisBindingData.Where(c => exceptCompanies.Contains(c.CompanyName)).ToList();
|
||||
if (res.Count > 0) {
|
||||
double maxVolume = res.Max(c => c.Volume);
|
||||
CompanyTradingDataViewModel vm = watchLisBindingData.Where(c => c.Volume == maxVolume).Select(c => c).FirstOrDefault();
|
||||
exceptCompanies.Remove(vm.CompanyName);
|
||||
volumeChartBindingData[i] = new CompaniesVolumeData() {
|
||||
CompanyName = vm.CompanyName,
|
||||
Volume = (int)maxVolume
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
void SetVolumeOfSelectedCompany() {
|
||||
if (volumeChartBindingData.Count == 0 && SelectedCompany != null) {
|
||||
CompaniesVolumeData cvd = new CompaniesVolumeData();
|
||||
cvd.CompanyName = SelectedCompany.CompanyName;
|
||||
cvd.Volume = (int)SelectedCompany.Volume;
|
||||
volumeChartBindingData.Add(cvd);
|
||||
}
|
||||
else if (SelectedCompany != null) {
|
||||
volumeChartBindingData[0].CompanyName = SelectedCompany.CompanyName;
|
||||
volumeChartBindingData[0].Volume = (int)SelectedCompany.Volume;
|
||||
}
|
||||
}
|
||||
void TryEndUpdateBindingData() {
|
||||
if (canEndUpdate)
|
||||
EndUpdateBindingData();
|
||||
}
|
||||
void EndUpdateBindingData() {
|
||||
if (!TimerCore.Enabled && !isAllBindingDataUpdate)
|
||||
StartTimer();
|
||||
}
|
||||
void UpdateOnTimer(object sender, EventArgs e) {
|
||||
if (!IsSuspendUpdating)
|
||||
UpdateData();
|
||||
}
|
||||
void UpdateAllBindingData(bool needUpdateVolumeDynamics = true) {
|
||||
if (canUpdate) {
|
||||
InitProperties();
|
||||
model.ChangeUserState();
|
||||
defferedUpdate.Clear();
|
||||
tickCount = 0;
|
||||
if (needUpdateVolumeDynamics)
|
||||
GetVolumeDynamicsDataAsync(currentDate);
|
||||
|
||||
UpdateCompaniesVolumeAsync();
|
||||
UpdateWatchListBindingDataAsync();
|
||||
|
||||
InitializeChartBindingData();
|
||||
GetStockChartBindingDataAsync();
|
||||
}
|
||||
}
|
||||
void UpdateData() {
|
||||
lock (sem) {
|
||||
int dateLocal = currentDate;
|
||||
if (dates == null || dateLocal < 0 || dateLocal > dates.Count -1) return;
|
||||
StopTimer();
|
||||
DateTime date = dates[dateLocal];
|
||||
switch (totalTicks) {
|
||||
case 5:
|
||||
RemoveOldCompanyStockChart(date, 1);
|
||||
break;
|
||||
case 10:
|
||||
RemoveOldCompanyStockChart(date, 2);
|
||||
break;
|
||||
case 20:
|
||||
RemoveOldCompanyStockChart(date, 4);
|
||||
break;
|
||||
}
|
||||
UpdateBindingData();
|
||||
}
|
||||
}
|
||||
void RemoveOldCompanyStockChart(DateTime date, int count) {
|
||||
if (date.DayOfWeek == DayOfWeek.Monday && countOfWeek == count) {
|
||||
tickCount = 0;
|
||||
if (stockChartBindingData != null && stockChartBindingData.Count > 1) stockChartBindingData.Remove(stockChartBindingData[0]);
|
||||
foreach (CompanyTradingDataViewModel vm in watchLisBindingData) {
|
||||
if (vm.VolumeDynamics != null && ((IList)vm.VolumeDynamics).Count > 0)
|
||||
((IList)vm.VolumeDynamics).RemoveAt(0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
void UpdateBindingData() {
|
||||
UpdateStockChartBindingDataAsync();
|
||||
UpdateWatchListBindingDataAsync();
|
||||
UpdateCompaniesVolumeAsync();
|
||||
UpdateVolumeDynamicsAsync();
|
||||
UpdateTransactionBindingData();
|
||||
}
|
||||
void UpdateVolumeDynamicsAsync() {
|
||||
if (companies != null)
|
||||
UpdateVolumeDynamicsAsyncCompleted(model.Service.GetStockDataFromDateByCompanyList(dates[currentDate], companies.ToArray()));
|
||||
}
|
||||
void UpdateVolumeDynamicsAsyncCompleted(CompanyStockData[] cd) {
|
||||
foreach (CompanyStockData companynStockData in cd) {
|
||||
try {
|
||||
if (companynStockData.Data.Length == 0) continue;
|
||||
DateTime current = dates[currentDate];
|
||||
CompanyTradingData ctd = GetCompanyTradingData(companynStockData.Data[0], current);
|
||||
CompanyTradingDataViewModel vm = watchLisBindingData.Where(c => c.CompanyName == companynStockData.CompanyName).Select(c => c).FirstOrDefault();
|
||||
if (vm == null) continue;
|
||||
IList<TradingDataViewModel> volDyn = vm.VolumeDynamics as IList<TradingDataViewModel>;
|
||||
|
||||
if (vm.VolumeDynamics == null || ((IList)vm.VolumeDynamics).Count == 0) return;
|
||||
if (tickCount == 2) {
|
||||
ctd.Volume = Math.Round((ctd.Volume / 1000000), 2);
|
||||
volDyn.Add(new TradingDataViewModel(ctd));
|
||||
}
|
||||
if (tickCount != 2) {
|
||||
TradingDataViewModel tdvm = new TradingDataViewModel(volDyn[volDyn.Count - 1].TradingData);
|
||||
tdvm.Volume = Math.Round((ctd.Volume / 1000000), 2);
|
||||
tdvm.Close = ctd.Close;
|
||||
tdvm.Low = lowestPrice;
|
||||
tdvm.High = highestPrice;
|
||||
tdvm.Price = ctd.Price;
|
||||
volDyn[volDyn.Count - 1] = tdvm;
|
||||
}
|
||||
}
|
||||
catch {
|
||||
currentDate++;
|
||||
UpdateStockChartBindingDataAsync();
|
||||
}
|
||||
}
|
||||
TryEndUpdateBindingData();
|
||||
}
|
||||
void UpdateStockChartBindingDataAsync() {
|
||||
UpdateStockChartBindingDataAsyncCompleted(model.Service.GetCompanyStockData(dates[currentDate], selectedCompanyName));
|
||||
}
|
||||
void UpdateStockChartBindingDataAsyncCompleted(StockData[] data) {
|
||||
if (data.Length == 0) {
|
||||
IncrementDateAndUpdateStockChartBindingData();
|
||||
}
|
||||
else {
|
||||
try {
|
||||
UpdateStockChart(data[0]);
|
||||
UpdateSparklineViewModelSource();
|
||||
TryEndUpdateBindingData();
|
||||
}
|
||||
catch {
|
||||
IncrementDateAndUpdateStockChartBindingData();
|
||||
}
|
||||
}
|
||||
}
|
||||
void IncrementDateAndUpdateStockChartBindingData() {
|
||||
currentDate++;
|
||||
UpdateStockChartBindingDataAsync();
|
||||
}
|
||||
void UpdateStockChart(StockData newChartData) {
|
||||
tickCount++;
|
||||
DateTime current = dates[currentDate];
|
||||
CompanyTradingData ctd = GetCompanyTradingData(newChartData, current);
|
||||
switch (totalTicks) {
|
||||
case 5:
|
||||
AddStockChart(current, ctd, 1);
|
||||
break;
|
||||
case 10:
|
||||
AddStockChart(current, ctd, 2);
|
||||
break;
|
||||
default:
|
||||
AddStockChart(current, ctd, 4);
|
||||
break;
|
||||
}
|
||||
currentDate++;
|
||||
}
|
||||
void AddStockChart(DateTime current, CompanyTradingData ctd, int count) {
|
||||
if (current.DayOfWeek == DayOfWeek.Monday && countOfWeek == count) {
|
||||
ctd.Volume = Math.Round((ctd.Volume / 1000000), 2);
|
||||
stockChartBindingData.Add(new TradingDataViewModel(ctd));
|
||||
highestPrice = ctd.High;
|
||||
lowestPrice = ctd.Low;
|
||||
countOfWeek = 1;
|
||||
return;
|
||||
}
|
||||
if (current.DayOfWeek == DayOfWeek.Monday && countOfWeek != count) {
|
||||
SetStockChartBindingData(ctd);
|
||||
countOfWeek++;
|
||||
return;
|
||||
}
|
||||
if (current.DayOfWeek != DayOfWeek.Monday) SetStockChartBindingData(ctd);
|
||||
}
|
||||
void TryResetCurrentDate() {
|
||||
if (dates != null && currentDate + totalTicks > dates.Count - 1) {
|
||||
currentDate = 0;
|
||||
tickCount = 0;
|
||||
}
|
||||
}
|
||||
void CreateChartBindingData(List<CompanyData> newStockChartData) {
|
||||
TryResetCurrentDate();
|
||||
int index = 0;
|
||||
DateTime firstDate = newStockChartData[0].Data.Date;
|
||||
DateTime startDate = new DateTime(firstDate.Year, firstDate.Month, 1);
|
||||
foreach (CompanyData candleData in newStockChartData) {
|
||||
CompanyTradingData ctd = new CompanyTradingData(candleData.Data, "");
|
||||
ctd.Close = candleData.ClosePrice;
|
||||
ctd.Volume = Math.Round(((double)ctd.Volume / 1000000), 2);
|
||||
ctd.Low = lowestPrice = candleData.LowPrice;
|
||||
ctd.High = highestPrice = candleData.HighPrice;
|
||||
TradingDataViewModel viewModel = new TradingDataViewModel(ctd) { Date = startDate };
|
||||
if (stockChartBindingData.Count < candlesCount) {
|
||||
stockChartBindingData.Add(viewModel);
|
||||
}
|
||||
else
|
||||
stockChartBindingData[index] = viewModel;
|
||||
startDate = UpdateDate(startDate, true);
|
||||
index++;
|
||||
}
|
||||
DateTime search = UpdateDate(startDate, false);
|
||||
while (true) {
|
||||
int dateIndex = dates.IndexOf(search);
|
||||
if (dateIndex != -1) {
|
||||
currentDate = dateIndex;
|
||||
break;
|
||||
}
|
||||
search = search.AddDays(-1);
|
||||
}
|
||||
}
|
||||
void UpdateWatchList(StockData[] watchListData) {
|
||||
int count = 0;
|
||||
int isRise = 0;
|
||||
oldWatchListData = new ObservableCollection<CompanyTradingDataViewModel>(watchLisBindingData as IEnumerable<CompanyTradingDataViewModel>);
|
||||
oldWatchListData = new ObservableCollection<CompanyTradingDataViewModel>();
|
||||
foreach (CompanyTradingDataViewModel item in watchLisBindingData) {
|
||||
oldWatchListData.Add(new CompanyTradingDataViewModel(item.TradingData, item.CompanyName, item.Rise, item.TotalRise));
|
||||
}
|
||||
watchLisBindingData.BeginUpdate();
|
||||
foreach (StockData dt in watchListData) {
|
||||
if (companies.Count <= (dt.CompanyID)) continue;
|
||||
CompanyTradingData ctd = new CompanyTradingData(dt, companies[dt.CompanyID]);
|
||||
if (watchLisBindingData.Count < companies.Count)
|
||||
watchLisBindingData.Add(new CompanyTradingDataViewModel(ctd, ctd.CompanyName, isRise, 1));
|
||||
else {
|
||||
SetWatchListBindingData(count, ctd);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
watchLisBindingData.EndUpdate();
|
||||
if (watchListChanged != null)
|
||||
watchListChanged(this, EventArgs.Empty);
|
||||
}
|
||||
void SetWatchListBindingData(int index, CompanyTradingData ctd) {
|
||||
watchLisBindingData[index].Rise = 0;
|
||||
if (ctd.Price > watchLisBindingData[index].Price) {
|
||||
watchLisBindingData[index].TotalRise = Math.Min(0.5 + (1 - watchLisBindingData[index].Price / ctd.Price) * 10, 1.3);
|
||||
watchLisBindingData[index].Rise = 180;
|
||||
}
|
||||
else if (ctd.Price < watchLisBindingData[index].Price) {
|
||||
watchLisBindingData[index].TotalRise = Math.Min(0.5 + (1 - ctd.Price / watchLisBindingData[index].Price) * 10, 1.3);
|
||||
watchLisBindingData[index].Rise = -180;
|
||||
}
|
||||
watchLisBindingData[index].Assign(ctd);
|
||||
}
|
||||
void SetStockChartBindingData(CompanyTradingData ctd)
|
||||
{
|
||||
TradingDataViewModel tdvm = null;
|
||||
if (stockChartBindingData.Count > 0)
|
||||
tdvm = new TradingDataViewModel(stockChartBindingData[stockChartBindingData.Count - 1].TradingData);
|
||||
else
|
||||
tdvm = new TradingDataViewModel();
|
||||
highestPrice = Math.Max(highestPrice, ctd.High);
|
||||
lowestPrice = Math.Min(lowestPrice, ctd.Low);
|
||||
tdvm.Volume = Math.Round((ctd.Volume / 1000000), 2);
|
||||
tdvm.Close = ctd.Close;
|
||||
tdvm.Low = lowestPrice;
|
||||
tdvm.High = highestPrice;
|
||||
tdvm.Price = ctd.Price;
|
||||
if (stockChartBindingData.Count > 0)
|
||||
stockChartBindingData[stockChartBindingData.Count - 1] = tdvm;
|
||||
else
|
||||
stockChartBindingData.Add(tdvm);
|
||||
}
|
||||
void UpdateTransactionBindingData() {
|
||||
TryResetCurrentDate();
|
||||
if (stockChartBindingData.Count < 1) return;
|
||||
List<TransactionData> transactions = model.GetTransactions(stockChartBindingData[stockChartBindingData.Count - 1].Price);
|
||||
SetTransactionGridBindingData(transactions);
|
||||
IsLoading = false;
|
||||
OnPropertyChanged("IsLoading");
|
||||
}
|
||||
void SetTransactionGridBindingData(List<TransactionData> transactions) {
|
||||
transactionGridBindingData.Clear();
|
||||
transactionGridBindingData.BeginUpdate();
|
||||
foreach (TransactionData tdvm in transactions) {
|
||||
transactionGridBindingData.Add(tdvm);
|
||||
}
|
||||
transactionGridBindingData.EndUpdate();
|
||||
CurrentPriceIndex = model.CurrentPriceIndex;
|
||||
RaiseCurrentPriceIndexChanged();
|
||||
}
|
||||
void RaiseCurrentPriceIndexChanged() {
|
||||
if (currentPriceIndexChanged != null)
|
||||
currentPriceIndexChanged(this, EventArgs.Empty);
|
||||
}
|
||||
void SetSelectedCompany() {
|
||||
StopTimer();
|
||||
int delta = currentDate - candlesCount * totalTicks;
|
||||
currentDate = delta < 0 ? 0 : delta;
|
||||
UpdateAllBindingData(true);
|
||||
}
|
||||
void InitProperties() {
|
||||
TryResetCurrentDate();
|
||||
isAllBindingDataUpdate = true;
|
||||
IsLoading = true;
|
||||
model.ClearTransactions();
|
||||
OnPropertyChanged("IsLoading");
|
||||
}
|
||||
double CalcIncrease(string company, ref double delta) {
|
||||
var companyData = watchLisBindingData.Where(c => c.CompanyName == company).Select(c => c).FirstOrDefault();
|
||||
var oldCompanyData = oldWatchListData.Where(c => c.CompanyName == company).Select(c => c).FirstOrDefault();
|
||||
if (companyData != null && oldCompanyData != null) {
|
||||
double newPrice = companyData.Price;
|
||||
double oldPrice = oldCompanyData.Price;
|
||||
delta = newPrice - oldPrice;
|
||||
return Math.Round(delta / newPrice, 3);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
CompanyTradingData GetCompanyTradingData(StockData newData, DateTime current) {
|
||||
CompanyTradingData ctd = new CompanyTradingData(newData, "");
|
||||
return ctd;
|
||||
}
|
||||
DateTime UpdateDate(DateTime startDate, bool add) {
|
||||
DateTime returnDate = new DateTime();
|
||||
switch (totalTicks) {
|
||||
case 1:
|
||||
if (add) startDate = startDate.AddDays(1);
|
||||
if (!add) returnDate = startDate.AddDays(-1);
|
||||
break;
|
||||
case 5:
|
||||
if (add) startDate = startDate.AddDays(7);
|
||||
if (!add) returnDate = startDate.AddDays(-7);
|
||||
break;
|
||||
case 10:
|
||||
if (add) startDate = startDate.AddDays(14);
|
||||
if (!add) returnDate = startDate.AddDays(-14);
|
||||
break;
|
||||
case 20:
|
||||
if (add) startDate = startDate.AddMonths(1);
|
||||
if (!add) returnDate = startDate.AddMonths(-1);
|
||||
break;
|
||||
}
|
||||
if (add) return startDate;
|
||||
return returnDate;
|
||||
}
|
||||
Delegate GetDefferedDelegate(string key) {
|
||||
if (defferedUpdate.ContainsKey(key) && defferedUpdate[key].Count != 0)
|
||||
return defferedUpdate[key].Dequeue();
|
||||
return null;
|
||||
|
||||
}
|
||||
List<CompaniesVolumeData> GetTopThreeVolume() {
|
||||
List<CompaniesVolumeData> result = new List<CompaniesVolumeData>();
|
||||
if (volumeChartBindingData != null && volumeChartBindingData.Count > 0) {
|
||||
for (int i = 0; i < 3; i++)
|
||||
if (volumeChartBindingData.Count >= i + 1)
|
||||
result.Add(volumeChartBindingData[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
LockableCollection<TradingDataViewModel> CreateVolumeDynamicsBindingData(StockData[] data) {
|
||||
LockableCollection<TradingDataViewModel> result = new LockableCollection<TradingDataViewModel>();
|
||||
foreach (StockData currentData in data) {
|
||||
CompanyTradingData ctd = new CompanyTradingData(currentData, "");
|
||||
ctd.Close = double.Parse(currentData.CloseP.ToString());
|
||||
ctd.Volume = Math.Round(((double)ctd.Volume / 1000000), 2);
|
||||
ctd.Low = double.Parse(currentData.LowP.ToString());
|
||||
ctd.High = double.Parse(currentData.HighP.ToString());
|
||||
result.Add(new TradingDataViewModel(ctd));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
public void OnCandlesCountChanged() {
|
||||
OnCandlesCountChangedCallBack();
|
||||
}
|
||||
public void SetTicks(int numberOfTicks) {
|
||||
Ticks = numberOfTicks;
|
||||
countOfWeek = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
47
StockMarketTraderApp/ViewModel/TileViewModels.cs
Normal file
47
StockMarketTraderApp/ViewModel/TileViewModels.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace DevExpress.StockMarketTrader.ViewModel {
|
||||
public class LiveTileViewModel : ViewModelBase {
|
||||
string arrow;
|
||||
string companyIndex;
|
||||
string persent;
|
||||
string priceIncrease;
|
||||
BindingList<TradingDataViewModel> source = new BindingList<TradingDataViewModel>();
|
||||
|
||||
public string Arrow {
|
||||
get { return arrow; }
|
||||
set {
|
||||
arrow = value;
|
||||
OnPropertyChanged("Arrow");
|
||||
}
|
||||
}
|
||||
public string CompanyIndex {
|
||||
get { return companyIndex; }
|
||||
set {
|
||||
companyIndex = value;
|
||||
OnPropertyChanged("CompanyIndex");
|
||||
}
|
||||
}
|
||||
public string Persent {
|
||||
get { return persent; }
|
||||
set {
|
||||
persent = value;
|
||||
OnPropertyChanged("Persent");
|
||||
}
|
||||
}
|
||||
public string PriceIncrease {
|
||||
get { return priceIncrease; }
|
||||
set {
|
||||
priceIncrease = value;
|
||||
OnPropertyChanged("PriceIncrease");
|
||||
}
|
||||
}
|
||||
public BindingList<TradingDataViewModel> Source {
|
||||
get { return source; }
|
||||
set {
|
||||
source = value;
|
||||
OnPropertyChanged("Source");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
92
StockMarketTraderApp/ViewModel/ViewModelBase.cs
Normal file
92
StockMarketTraderApp/ViewModel/ViewModelBase.cs
Normal file
@@ -0,0 +1,92 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Collections.Specialized;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace DevExpress.StockMarketTrader.ViewModel {
|
||||
public class LockableCollection<T> : ObservableCollection<T> {
|
||||
bool isChanged;
|
||||
int updateLockCount;
|
||||
|
||||
public bool IsUpdateLocked { get { return updateLockCount > 0; } }
|
||||
|
||||
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e) {
|
||||
if (IsUpdateLocked)
|
||||
isChanged = true;
|
||||
else
|
||||
base.OnCollectionChanged(e);
|
||||
}
|
||||
protected override void SetItem(int index, T item) {
|
||||
if (!this[index].Equals(item))
|
||||
base.SetItem(index, item);
|
||||
}
|
||||
public void Assign(IList<T> source) {
|
||||
if(Equals(source))
|
||||
return;
|
||||
BeginUpdate();
|
||||
try {
|
||||
Clear();
|
||||
foreach(T item in source)
|
||||
Add(item);
|
||||
} finally {
|
||||
EndUpdate();
|
||||
}
|
||||
}
|
||||
public void BeginUpdate() {
|
||||
if(!IsUpdateLocked)
|
||||
isChanged = false;
|
||||
updateLockCount++;
|
||||
}
|
||||
public void EndUpdate() {
|
||||
if(!IsUpdateLocked)
|
||||
return;
|
||||
updateLockCount--;
|
||||
if(!IsUpdateLocked && isChanged)
|
||||
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
|
||||
}
|
||||
public void ForEach(Action<T> action) {
|
||||
for (int i = 0; i < Count; i++)
|
||||
action(this[i]);
|
||||
}
|
||||
public T Find(Predicate<T> match) {
|
||||
if (match == null)
|
||||
return default(T);
|
||||
int count = Count;
|
||||
for (int i = 0; i < count; i++) {
|
||||
T item = this[i];
|
||||
if (match(item))
|
||||
return item;
|
||||
}
|
||||
return default(T);
|
||||
}
|
||||
public override bool Equals(object obj) {
|
||||
if(obj is IList<T>) {
|
||||
var list = (IList<T>)obj;
|
||||
if(Count != list.Count)
|
||||
return false;
|
||||
else {
|
||||
for(int i = 0; i < Count; i++)
|
||||
if(!this[i].Equals(list[i]))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
} else
|
||||
return base.Equals(obj);
|
||||
}
|
||||
public override int GetHashCode() {
|
||||
return base.GetHashCode();
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class ViewModelBase : INotifyPropertyChanged {
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
protected void OnPropertyChanged(string propertyName) {
|
||||
PropertyChangedEventHandler handler = PropertyChanged;
|
||||
if (handler != null) {
|
||||
handler(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user