428 lines
17 KiB
C#
428 lines
17 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Collections.ObjectModel;
|
|
using System.ComponentModel;
|
|
using System.Linq;
|
|
using System.Threading.Tasks;
|
|
using DynamicData;
|
|
using Eremex.AvaloniaUI.Charts;
|
|
using MarketData.DataAccess;
|
|
using MarketData.Generator;
|
|
using MarketData.MarketDataModel;
|
|
using MarketData.Numerical;
|
|
using MarketData.Utils;
|
|
using PortfolioManager.Cache;
|
|
using PortfolioManager.DataSeriesViewModels;
|
|
using PortfolioManager.Models;
|
|
using PortfolioManager.UIUtils;
|
|
|
|
namespace PortfolioManager.ViewModels
|
|
{
|
|
public partial class BollingerBandViewModel : WorkspaceViewModel
|
|
{
|
|
private bool isBusy = false;
|
|
private List<String> watchListNames;
|
|
private String selectedWatchList;
|
|
private List<Int32> dayCounts = new int[] { 60, 90, 180, 360, 720, 1440, 3600 }.ToList<int>();
|
|
private int selectedDayCount = 90;
|
|
private ObservableCollection<String> symbols = new ObservableCollection<String>();
|
|
private String selectedSymbol = default;
|
|
|
|
private InsiderTransactionSummaries insiderTransactionSummaries = null;
|
|
private Price zeroPrice = null;
|
|
private PortfolioTrades portfolioTrades;
|
|
private PortfolioTrades portfolioTradesLots;
|
|
private StopLimit stopLimit; // This is the stop limit that is looked up in the database and displayed (if there is one)
|
|
private Prices prices = null;
|
|
|
|
private bool syncTradeToBand = true;
|
|
private String companyName = default;
|
|
|
|
|
|
private CompositeDataSource compositeDataSourceZeroPoint = null;
|
|
private CompositeDataSource compositeDataSourceStopLimit = null;
|
|
|
|
private CompositeDataSource compositeDataSourceInsiderTransactionPointDisposedSmall = null;
|
|
private CompositeDataSource compositeDataSourceInsiderTransactionPointDisposedMedium = null;
|
|
private CompositeDataSource compositeDataSourceInsiderTransactionPointDisposedLarge = null;
|
|
private CompositeDataSource compositeDataSourceInsiderTransactionPointAcquiredSmall = null;
|
|
private CompositeDataSource compositeDataSourceInsiderTransactionPointAcquiredMedium = null;
|
|
private CompositeDataSource compositeDataSourceInsiderTransactionPointAcquiredLarge = null;
|
|
|
|
private CompositeDataSource compositeDataSourceK = null;
|
|
private CompositeDataSource compositeDataSourceKL1 = null;
|
|
private CompositeDataSource compositeDataSourceL = null;
|
|
private CompositeDataSource compositeDataSourceLP1 = null;
|
|
private CompositeDataSource compositeDataSourceHigh = null;
|
|
private CompositeDataSource compositeDataSourceLow = null;
|
|
private CompositeDataSource compositeDataSourceClose = null;
|
|
private CompositeDataSource compositeDataSourceSMAN = null;
|
|
private CompositeDataSource compositeDataSourceVolume = null;
|
|
private CompositeDataSource compositeDataSourceLeastSquares = null;
|
|
private CompositeDataSource compositeDataSourceTradePoints = null;
|
|
|
|
private BollingerBands bollingerBands;
|
|
|
|
public BollingerBandViewModel()
|
|
{
|
|
PropertyChanged += OnViewModelPropertyChanged;
|
|
DisplayName = "BollingerBand View";
|
|
Initialize();
|
|
}
|
|
|
|
private void Initialize()
|
|
{
|
|
Task workerTask = Task.Factory.StartNew(() =>
|
|
{
|
|
watchListNames = WatchListDA.GetWatchLists();
|
|
watchListNames.Insert(0, UIConstants.CONST_ALL);
|
|
selectedWatchList = watchListNames.Find(x => x.Equals("Valuations"));
|
|
symbols.AddRange(WatchListDA.GetWatchList(selectedWatchList));
|
|
});
|
|
workerTask.ContinueWith((continuation) =>
|
|
{
|
|
base.OnPropertyChanged("Symbols");
|
|
base.OnPropertyChanged("WatchListNames");
|
|
base.OnPropertyChanged("SelectedWatchList");
|
|
});
|
|
}
|
|
|
|
public bool IsBusy
|
|
{
|
|
get
|
|
{
|
|
return isBusy;
|
|
}
|
|
set
|
|
{
|
|
isBusy = value;
|
|
base.OnPropertyChanged("IsBusy");
|
|
}
|
|
}
|
|
|
|
public override String Title
|
|
{
|
|
get
|
|
{
|
|
return DisplayName;
|
|
}
|
|
}
|
|
|
|
public override String DisplayName
|
|
{
|
|
get
|
|
{
|
|
return "BollingerBand Model";
|
|
// if (null == pathFileName) return "MGSHMomentum Model";
|
|
// String pureFileName = Utility.GetFileNameNoExtension(pathFileName);
|
|
// return "MGSHMomentum Model (" + pureFileName + ")";
|
|
}
|
|
}
|
|
|
|
public ObservableCollection<String> Symbols
|
|
{
|
|
get
|
|
{
|
|
return symbols;
|
|
}
|
|
}
|
|
|
|
public String SelectedSymbol
|
|
{
|
|
get
|
|
{
|
|
return selectedSymbol;
|
|
}
|
|
set
|
|
{
|
|
selectedSymbol = value;
|
|
base.OnPropertyChanged("SelectedSymbol");
|
|
}
|
|
}
|
|
|
|
public int SelectedDayCount
|
|
{
|
|
get
|
|
{
|
|
return selectedDayCount;
|
|
}
|
|
set
|
|
{
|
|
selectedDayCount = value;
|
|
base.OnPropertyChanged("SelectedDayCount");
|
|
}
|
|
}
|
|
|
|
public List<int> DayCounts
|
|
{
|
|
get
|
|
{
|
|
return dayCounts;
|
|
}
|
|
}
|
|
|
|
|
|
// ****************************************************** P R O P E R T I E S ************************************************
|
|
|
|
public List<String> WatchListNames
|
|
{
|
|
get
|
|
{
|
|
return watchListNames;
|
|
}
|
|
}
|
|
|
|
public String SelectedWatchList
|
|
{
|
|
get
|
|
{
|
|
return selectedWatchList;
|
|
}
|
|
set
|
|
{
|
|
selectedWatchList = value;
|
|
base.OnPropertyChanged("SelectedWatchList");
|
|
}
|
|
}
|
|
|
|
// ******************************************************************* P E R S I S T E N C E ***************************************************
|
|
|
|
public override bool CanPersist()
|
|
{
|
|
return false;
|
|
}
|
|
|
|
public override SaveParameters GetSaveParameters()
|
|
{
|
|
return null;
|
|
}
|
|
|
|
public override void SetSaveParameters(SaveParameters saveParameters)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// *************************************************************************************************************************************
|
|
private void OnViewModelPropertyChanged(object sender, PropertyChangedEventArgs eventArgs)
|
|
{
|
|
if (eventArgs.PropertyName.Equals("SelectedSymbol"))
|
|
{
|
|
InitializeDataSources();
|
|
insiderTransactionSummaries = null;
|
|
zeroPrice = null;
|
|
prices = null;
|
|
portfolioTrades = null;
|
|
portfolioTradesLots = null;
|
|
stopLimit = null;
|
|
}
|
|
|
|
if (eventArgs.PropertyName.Equals("SyncTradeToBand")||
|
|
eventArgs.PropertyName.Equals("ShowTradeLabels")||
|
|
eventArgs.PropertyName.Equals("SelectedSymbol")||
|
|
eventArgs.PropertyName.Equals("ShowRiskFree")||
|
|
eventArgs.PropertyName.Equals("LeastSquaresFit")||
|
|
(eventArgs.PropertyName.Equals("SelectedDayCount") && null!=selectedSymbol))
|
|
{
|
|
IsBusy=true;
|
|
Task workerTask=Task.Factory.StartNew(()=>
|
|
{
|
|
base.DisplayName="Bollinger("+selectedSymbol+")";
|
|
base.OnPropertyChanged("DisplayName");
|
|
|
|
// DEBUG
|
|
stopLimit=PortfolioDA.GetStopLimit(selectedSymbol);
|
|
portfolioTrades = PortfolioDA.GetTradesSymbol(selectedSymbol);
|
|
portfolioTradesLots=LotAggregator.CombineLots(portfolioTrades);
|
|
if (null != portfolioTrades && 0 != portfolioTrades.Count)
|
|
{
|
|
DateGenerator dateGenerator = new DateGenerator();
|
|
DateTime earliestTrade = portfolioTrades[0].TradeDate;
|
|
earliestTrade = earliestTrade.AddDays(-30);
|
|
int daysBetween = dateGenerator.DaysBetween(earliestTrade, DateTime.Now);
|
|
if (daysBetween < selectedDayCount || !syncTradeToBand) prices = PricingDA.GetPrices(selectedSymbol, selectedDayCount);
|
|
else prices = PricingDA.GetPrices(selectedSymbol, earliestTrade);
|
|
|
|
DateTime earliestInsiderTransactionDate=dateGenerator.GenerateFutureBusinessDate(prices[prices.Count-1].Date,30);
|
|
insiderTransactionSummaries=InsiderTransactionDA.GetInsiderTransactionSummaries(selectedSymbol,earliestInsiderTransactionDate);
|
|
|
|
// calculate the break even price on the open trades for this symbol
|
|
PortfolioTrades openTrades=portfolioTrades.GetOpenTrades();
|
|
DateTime latestPricingDate = PricingDA.GetLatestDate(selectedSymbol);
|
|
Price latestPrice = PricingDA.GetPrice(selectedSymbol, latestPricingDate);
|
|
zeroPrice=ParityGenerator.GenerateGainLossValue(openTrades,latestPrice);
|
|
|
|
if (!syncTradeToBand)
|
|
{
|
|
DateTime earliestPricingDate = prices[prices.Count - 1].Date;
|
|
earliestPricingDate = earliestPricingDate.AddDays(30);
|
|
IEnumerable<PortfolioTrade> tradesInRange = (from portfolioTrade in portfolioTradesLots where portfolioTrade.TradeDate >= earliestPricingDate select portfolioTrade);
|
|
portfolioTrades = new PortfolioTrades();
|
|
foreach (PortfolioTrade portfolioTrade in tradesInRange) portfolioTrades.Add(portfolioTrade);
|
|
portfolioTradesLots = portfolioTrades;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
prices = PricingDA.GetPrices(selectedSymbol, selectedDayCount);
|
|
if (null != prices && 0 != prices.Count)
|
|
{
|
|
DateGenerator dateGenerator = new DateGenerator();
|
|
DateTime earliestInsiderTransactionDate = dateGenerator.GenerateFutureBusinessDate(prices[prices.Count - 1].Date, 30);
|
|
insiderTransactionSummaries = InsiderTransactionDA.GetInsiderTransactionSummaries(selectedSymbol, earliestInsiderTransactionDate);
|
|
}
|
|
}
|
|
companyName = PricingDA.GetNameForSymbol(selectedSymbol);
|
|
bollingerBands = BollingerBandGenerator.GenerateBollingerBands(prices);
|
|
CreateCompositeDataSources();
|
|
});
|
|
workerTask.ContinueWith((continuation)=>
|
|
{
|
|
IsBusy = false;
|
|
base.OnPropertyChanged("K");
|
|
base.OnPropertyChanged("KL1");
|
|
base.OnPropertyChanged("L");
|
|
base.OnPropertyChanged("LP1");
|
|
base.OnPropertyChanged("High");
|
|
base.OnPropertyChanged("Low");
|
|
base.OnPropertyChanged("Close");
|
|
base.OnPropertyChanged("SMAN");
|
|
base.OnPropertyChanged("Volume");
|
|
base.OnPropertyChanged("LeastSquares");
|
|
base.OnPropertyChanged("Title");
|
|
base.OnPropertyChanged("TradePoints");
|
|
base.OnPropertyChanged("Markers");
|
|
base.OnPropertyChanged("ZeroPoint");
|
|
base.OnPropertyChanged("ZeroPointMarkers");
|
|
base.OnPropertyChanged("StopLimit");
|
|
base.OnPropertyChanged("StopLimitMarkers");
|
|
base.OnPropertyChanged("RiskFreeRatePoint");
|
|
base.OnPropertyChanged("RiskFreeRatePointMarkers");
|
|
|
|
base.OnPropertyChanged("InsiderTransactionPointDisposedSmall");
|
|
base.OnPropertyChanged("InsiderTransactionPointMarkersDisposedSmall");
|
|
base.OnPropertyChanged("InsiderTransactionPointDisposedMedium");
|
|
base.OnPropertyChanged("InsiderTransactionPointMarkersDisposedMedium");
|
|
base.OnPropertyChanged("InsiderTransactionPointDisposedLarge");
|
|
base.OnPropertyChanged("InsiderTransactionPointMarkersDisposedLarge");
|
|
|
|
base.OnPropertyChanged("InsiderTransactionPointAcquiredSmall");
|
|
base.OnPropertyChanged("InsiderTransactionPointMarkersAcquiredSmall");
|
|
base.OnPropertyChanged("InsiderTransactionPointAcquiredMedium");
|
|
base.OnPropertyChanged("InsiderTransactionPointMarkersAcquiredMedium");
|
|
base.OnPropertyChanged("InsiderTransactionPointAcquiredLarge");
|
|
base.OnPropertyChanged("InsiderTransactionPointMarkersAcquiredLarge");
|
|
});
|
|
}
|
|
else if (eventArgs.PropertyName.Equals("SelectedWatchList"))
|
|
{
|
|
IsBusy = true;
|
|
Task workerTask = Task.Factory.StartNew(() =>
|
|
{
|
|
if (selectedWatchList.Equals(Constants.CONST_ALL))
|
|
{
|
|
symbols.Clear();
|
|
symbols.AddRange(SymbolCache.GetInstance().GetSymbols());
|
|
}
|
|
else
|
|
{
|
|
symbols.Clear();
|
|
symbols.AddRange(WatchListDA.GetWatchList(selectedWatchList));
|
|
}
|
|
});
|
|
workerTask.ContinueWith((continuation) =>
|
|
{
|
|
IsBusy = false;
|
|
base.OnPropertyChanged("Symbols");
|
|
});
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
public void CreateCompositeDataSources()
|
|
{
|
|
if(null==prices || 0==prices.Count)return;
|
|
double minClose=(from Price price in prices select price.Close).Min();
|
|
|
|
|
|
// get the maximum date in the bollinger band series
|
|
DateTime maxBollingerDate=(from BollingerBandElement bollingerBandElement in bollingerBands select bollingerBandElement.Date).Max();
|
|
// ensure that the insider transactions are clipped to the bollingerband max date. There are some items in insider transaction summaries (options dated in the future) that will throw the graphic out of proportion
|
|
InsiderTransactionSummaries disposedSummaries=new InsiderTransactionSummaries((from InsiderTransactionSummary insiderTransactionSummary in insiderTransactionSummaries where insiderTransactionSummary.NumberOfSharesAcquiredDisposed<0 && insiderTransactionSummary.TransactionDate.Date<=maxBollingerDate select insiderTransactionSummary).ToList());
|
|
InsiderTransactionSummaries acquiredSummaries=new InsiderTransactionSummaries((from InsiderTransactionSummary insiderTransactionSummary in insiderTransactionSummaries where insiderTransactionSummary.NumberOfSharesAcquiredDisposed>0 && insiderTransactionSummary.TransactionDate.Date<=maxBollingerDate select insiderTransactionSummary).ToList());
|
|
|
|
BinCollection<InsiderTransactionSummary> disposedSummariesBin=BinHelper<InsiderTransactionSummary>.CreateBins(new BinItems<InsiderTransactionSummary>(disposedSummaries),3);
|
|
BinCollection<InsiderTransactionSummary> acquiredSummariesBin=BinHelper<InsiderTransactionSummary>.CreateBins(new BinItems<InsiderTransactionSummary>(acquiredSummaries),3);
|
|
|
|
|
|
// compositeDataSourceZeroPoint = GainLossModel.Price(zeroPrice);
|
|
/*
|
|
if(null!=stopLimits)
|
|
{
|
|
compositeDataSourceStopLimit=StopLimitCompositeModel.CreateCompositeDataSource(stopLimits);
|
|
}
|
|
else if(null!=stopLimit && null!=zeroPrice)
|
|
{
|
|
compositeDataSourceStopLimit=GainLossModel.CreateCompositeDataSource(zeroPrice.Date,stopLimit.StopPrice);
|
|
}
|
|
|
|
compositeDataSourceInsiderTransactionPointDisposedSmall=InsiderTransactionModel.InsiderTransactionSummaries(new InsiderTransactionSummaries(disposedSummariesBin[2]),minClose);
|
|
compositeDataSourceInsiderTransactionPointDisposedMedium=InsiderTransactionModel.InsiderTransactionSummaries(new InsiderTransactionSummaries(disposedSummariesBin[1]),minClose);
|
|
compositeDataSourceInsiderTransactionPointDisposedLarge=InsiderTransactionModel.InsiderTransactionSummaries(new InsiderTransactionSummaries(disposedSummariesBin[0]),minClose);
|
|
compositeDataSourceInsiderTransactionPointAcquiredSmall=InsiderTransactionModel.InsiderTransactionSummaries(new InsiderTransactionSummaries(acquiredSummariesBin[0]),minClose);
|
|
compositeDataSourceInsiderTransactionPointAcquiredMedium=InsiderTransactionModel.InsiderTransactionSummaries(new InsiderTransactionSummaries(acquiredSummariesBin[1]),minClose);
|
|
compositeDataSourceInsiderTransactionPointAcquiredLarge=InsiderTransactionModel.InsiderTransactionSummaries(new InsiderTransactionSummaries(acquiredSummariesBin[2]),minClose);
|
|
|
|
compositeDataSourceK =BollingerBandModel.K(bollingerBands);
|
|
compositeDataSourceKL1 =BollingerBandModel.KL1(bollingerBands);
|
|
compositeDataSourceL =BollingerBandModel.L(bollingerBands);
|
|
compositeDataSourceLP1 =BollingerBandModel.LP1(bollingerBands);
|
|
compositeDataSourceHigh =BollingerBandModel.High(bollingerBands);
|
|
compositeDataSourceLow =BollingerBandModel.Low(bollingerBands);
|
|
compositeDataSourceClose =BollingerBandModel.Close(bollingerBands);
|
|
compositeDataSourceSMAN =BollingerBandModel.SMAN(bollingerBands);
|
|
compositeDataSourceVolume =BollingerBandModel.Volume(bollingerBands);
|
|
|
|
compositeDataSourceLeastSquares = BollingerBandModel.LeastSquares(bollingerBands);
|
|
|
|
compositeDataSourceTradePoints = PortfolioTradeModel.PortfolioTrades(portfolioTradesLots);
|
|
*/
|
|
}
|
|
|
|
private void InitializeDataSources()
|
|
{
|
|
compositeDataSourceStopLimit = Empty();
|
|
compositeDataSourceZeroPoint = Empty();
|
|
|
|
compositeDataSourceInsiderTransactionPointDisposedSmall = Empty();
|
|
compositeDataSourceInsiderTransactionPointDisposedMedium = Empty();
|
|
compositeDataSourceInsiderTransactionPointDisposedLarge = Empty();
|
|
|
|
compositeDataSourceInsiderTransactionPointAcquiredSmall = Empty();
|
|
compositeDataSourceInsiderTransactionPointAcquiredMedium = Empty();
|
|
compositeDataSourceInsiderTransactionPointAcquiredLarge = Empty();
|
|
|
|
compositeDataSourceK = Empty();
|
|
compositeDataSourceKL1 = Empty();
|
|
compositeDataSourceL = Empty();
|
|
compositeDataSourceLP1 = Empty();
|
|
compositeDataSourceHigh = Empty();
|
|
compositeDataSourceLow = Empty();
|
|
compositeDataSourceClose = Empty();
|
|
compositeDataSourceSMAN = Empty();
|
|
compositeDataSourceVolume = Empty();
|
|
compositeDataSourceLeastSquares = Empty();
|
|
compositeDataSourceTradePoints = Empty();
|
|
}
|
|
|
|
private static CompositeDataSource Empty()
|
|
{
|
|
return new CompositeDataSource()
|
|
{
|
|
DataAdapter = new SortedDateTimeDataAdapter()
|
|
};
|
|
}
|
|
}
|
|
}
|