using System; using System.Diagnostics; using System.ComponentModel; using System.Collections.ObjectModel; using System.Collections.Specialized; using System.Collections.Generic; using System.Windows.Threading; using System.Threading.Tasks; using System.Threading; using System.Windows; using System.Linq; using System.Text; using System.Windows.Data; using MarketData.MarketDataModel; using MarketData.DataAccess; using MarketData.Utils; using MarketData.Integration; using MarketData; using TradeBlotter.Command; using TradeBlotter.ViewModels; using TradeBlotter.Model; using TradeBlotter.DataAccess; using TradeBlotter.Cache; using TradeBlotter.UIUtils; using System.Windows.Media; using Forms=System.Windows.Forms; using MarketData.Numerical; using System.Windows.Controls; using Ticker.Animation; using Ticker.Views; using Ticker.Models; using TradeBlotter.Views; using System.Windows.Input; using System.Configuration; namespace TradeBlotter.ViewModels { public class FloatingWindowViewModel : WorkspaceViewModel { private static int FLOATING_WINDOW_FEED_INTERVAL_MINUTES=1; // This is the amount of time between feed pulls private readonly FeedManager manager = null; private Ticker ticker=null; private Panel mainPanel=null; private bool isPaused=false; private int itemCount=0; private RelayCommand togglePlayPausedCommand; private DateTime lastEarningsAnnouncementBroadcast; private DateTime lastAnalystRatingsBroadcast; private DateTime lastPremarketBroadcast; public FloatingWindowViewModel(Panel panel) { manager=new FeedManager(); manager.FeedIntervalMinutes=FLOATING_WINDOW_FEED_INTERVAL_MINUTES; mainPanel=panel; ticker = new Ticker(mainPanel); ticker.ItemDisplayed += ticker_ItemDisplayed; manager.FeedSourceEventHandler+=GetFeedItemsEventHandler; manager.NewFeedItem+= (o,e)=>AddItem(e.Item); base.OnPropertyChanged("IsPaused"); PropertyChanged += OnFloatingViewModelPropertyChanged; manager.Start(); ticker.Start(); } public override SaveParameters GetSaveParameters() { return null; } private void OnFloatingViewModelPropertyChanged(object sender, PropertyChangedEventArgs eventArgs) { if (eventArgs.PropertyName.Equals("IsPaused")) { if(IsPaused && ticker.IsRunning) { ticker.Stop(); } else if(!IsPaused && !ticker.IsRunning) { ticker.Start(); } } } // The feed does not persist contents between successive runs. It uses feed cache to filter previously displayed items for the day public override void SetSaveParameters(SaveParameters saveParameters) { } public override bool CanPersist() { return false; } //***************************************************************************************************************************************************************************** private void AddItem(FeedItem item) { Application.Current.Dispatcher.Invoke((Forms.MethodInvoker)delegate() { ticker.Items.Enqueue(new TickerItemView(item)); }); } public String ItemCount { get{return itemCount.ToString();} set{itemCount=int.Parse(value);base.OnPropertyChanged("ItemCount");} } public bool IsPaused { get{return isPaused;} set{isPaused=value;base.OnPropertyChanged("IsPaused");} } public ICommand TogglePlayPauseCommand { get { if (togglePlayPausedCommand == null) { togglePlayPausedCommand = new RelayCommand(action => {IsPaused=!IsPaused;},action => { return true; }); } return togglePlayPausedCommand; } } private void ticker_ItemDisplayed(object sender, ItemEventArgs e) { manager.MarkFeedAsRead(e.Item.FeedItem); itemCount=manager.GetFeedItemCount(); base.OnPropertyChanged("ItemCount"); } public List GetFeedItemsEventHandler() { bool itemsAdded=false; List feedItems=new List(); List openSymbols=new List(); List holidayStatusFeedItems=HolidayStatusToFeedItems(); if(null!=holidayStatusFeedItems){feedItems.AddRange(holidayStatusFeedItems);itemsAdded=holidayStatusFeedItems.Count>0?true:itemsAdded;} List networkStatusFeedItems=NetworkStatusToFeedItems(); if(null!=networkStatusFeedItems){feedItems.AddRange(networkStatusFeedItems);itemsAdded=networkStatusFeedItems.Count>0?true:itemsAdded;} if((Utility.IsEpoch(lastPremarketBroadcast)||DateTime.Now-lastPremarketBroadcast>new TimeSpan(0,5,0))) // earnings broadcast every 5 minutes { lastPremarketBroadcast=DateTime.Now; List premarketFeedItems=PremarketToFeedItems(); if(null!=premarketFeedItems) { feedItems.AddRange(premarketFeedItems); itemsAdded=premarketFeedItems.Count>0?true:itemsAdded; } } List headlineFeedItems=HeadlinesToFeedItems(); if(null!=headlineFeedItems){feedItems.AddRange(headlineFeedItems);itemsAdded=headlineFeedItems.Count>0?true:itemsAdded;} try{openSymbols=PortfolioDA.GetOpenSymbols();}catch(Exception){;} List openPricesFeedItems=OpenPricesToFeedItems(openSymbols); if(null!=openPricesFeedItems){feedItems.AddRange(openPricesFeedItems);itemsAdded=openPricesFeedItems.Count>0?true:itemsAdded;} if(Utility.IsEpoch(lastAnalystRatingsBroadcast)||DateTime.Now-lastAnalystRatingsBroadcast>new TimeSpan(0,20,0)) // analyst ratings broadcast every 20 minutes { lastAnalystRatingsBroadcast=DateTime.Now; List analystRatingsFeedItems=AnalystRatingsToFeedItems(openSymbols); if(null!=analystRatingsFeedItems){feedItems.AddRange(analystRatingsFeedItems);itemsAdded=analystRatingsFeedItems.Count>0?true:itemsAdded;} } if(Utility.IsEpoch(lastEarningsAnnouncementBroadcast)||DateTime.Now-lastEarningsAnnouncementBroadcast>new TimeSpan(0,20,0)) // earnings broadcast every 20 minutes { lastEarningsAnnouncementBroadcast=DateTime.Now; List earningsAnnouncementFeedItems=EarningsAnnouncementsToFeedItems(openSymbols); if(null!=earningsAnnouncementFeedItems){feedItems.AddRange(earningsAnnouncementFeedItems);itemsAdded=earningsAnnouncementFeedItems.Count>0?true:itemsAdded;} } return feedItems; } // *************************************************************************************************************************************************** // ************************************************************************ F E E D C O N V E R T E R S ******************************************** // *************************************************************************************************************************************************** private List NetworkStatusToFeedItems() { List feedItems=new List(); try { //if(NetworkStatus.IsNetworkAvailable())return null; if(NetworkStatus.IsInternetConnected())return null; FeedItem feedItem=new FeedItem(); feedItem.Description="Network is unavailable"; feedItem.Title=String.Format("Network is unavailable"); feedItem.Link="http://192.168.1.1/"; feedItem.Source="Network"; feedItem.PubDate=DateTime.Now.ToShortDateString()+" "+Utility.DateTimeToStringHHMMSS(DateTime.Now); feedItem.Guid="Network"+feedItem.PubDate; feedItem.BrushAssigment=FeedBrushes.BrushColor.Red; feedItems.Add(feedItem); return feedItems; } catch(Exception exception) { MDTrace.WriteLine(LogLevel.DEBUG,exception.ToString()); return null; } } private List HolidayStatusToFeedItems() { List feedItems=new List(); try { DateTime today=DateTime.Now.Date; DateGenerator dateGenerator = new DateGenerator(); if(!dateGenerator.IsHoliday(today.Date))return feedItems; String holidayDescription = HolidayDA.GetHolidayDescription(today); FeedItem feedItem=new FeedItem(); feedItem.Description="Market is closed today - "+holidayDescription+"."; feedItem.Title=String.Format("Market is closed today for "+holidayDescription+"."); feedItem.Link="http://192.168.1.1/"; feedItem.Source="Holiday"; feedItem.PubDate=DateTime.Now.ToShortDateString()+" "+Utility.DateTimeToStringHHMMSS(DateTime.Now); feedItem.Guid="Holiday"+feedItem.PubDate; feedItem.BrushAssigment=FeedBrushes.BrushColor.Red; feedItems.Add(feedItem); return feedItems; } catch(Exception exception) { MDTrace.WriteLine(LogLevel.DEBUG,exception.ToString()); return null; } } private List PremarketToFeedItems() { List feedItems=new List(); try { String tickerPremarketFeedIdleAfter=ConfigurationManager.AppSettings["TickerPremarketFeedIdleAfter"]; if(null==tickerPremarketFeedIdleAfter)tickerPremarketFeedIdleAfter="09:30:00"; TimeSpan cutoff=TimeSpan.Parse(tickerPremarketFeedIdleAfter); if(DateTime.Now.TimeOfDay>cutoff)return feedItems; PremarketElements premarketElements=PremarketDA.GetLatestPremarketData(); if(null==premarketElements||0==premarketElements.Count)return feedItems; foreach(PremarketElement premarketElement in premarketElements) { FeedItem feedItem=new FeedItem(); feedItem.Description=premarketElement.Market; feedItem.Title=String.Format("{0} {1}({2})",premarketElement.Market,Utility.FormatNumber(premarketElement.ChangeValue,2),Utility.FormatPercent(premarketElement.ChangePercent/100.00)); feedItem.Link="https://money.cnn.com/data/premarket//"; feedItem.Source="CNN"; feedItem.PubDate=premarketElement.Timestamp.ToShortDateString()+" "+Utility.DateTimeToStringHHMMSS(premarketElement.Timestamp); feedItem.Guid=premarketElement.Market+feedItem.PubDate; if(premarketElement.ChangePercent<0)feedItem.BrushAssigment=FeedBrushes.BrushColor.Red; else feedItem.BrushAssigment=FeedBrushes.BrushColor.Green; feedItems.Add(feedItem); } return feedItems; } catch(Exception exception) { MDTrace.WriteLine(LogLevel.DEBUG,exception.ToString()); return null; } } private List EarningsAnnouncementsToFeedItems(List openSymbols) { List feedItems=new List(); int maxDaysFromToday=2; try { DateTime today=DateTime.Now; String tickerEarningsAnnouncementMaxDays=ConfigurationManager.AppSettings["TickerEarningsAnnouncementMaxDays"]; if(null!=tickerEarningsAnnouncementMaxDays)int.TryParse(tickerEarningsAnnouncementMaxDays,out maxDaysFromToday); List earningsAnnouncementModels = new List(); List symbols = WatchListDA.GetWatchList("valuations"); foreach (String symbol in symbols) { EarningsAnnouncementModel earningsAnnouncementModel=CompositeDA.GetEarningsAnnouncement(symbol); if(null==earningsAnnouncementModel)continue; if (earningsAnnouncementModel.DaysFromToday > maxDaysFromToday || earningsAnnouncementModel.DaysFromToday<0) continue; earningsAnnouncementModels.Add(earningsAnnouncementModel); } earningsAnnouncementModels.Sort(); foreach(EarningsAnnouncementModel earningsAnnouncementModel in earningsAnnouncementModels) { int days=Math.Abs(earningsAnnouncementModel.DaysFromToday); FeedItem feedItem=new FeedItem(); feedItem.Description=earningsAnnouncementModel.Symbol; if(0==days)feedItem.Title=String.Format("Earnings Annoucement for {0} due today",earningsAnnouncementModel.Symbol); else feedItem.Title=String.Format("Earnings Annoucement for {0} due in {1} {2} ",earningsAnnouncementModel.Symbol,days,days>1?"days":"day");; feedItem.Link="https://www.zacks.com/stock/research/"+earningsAnnouncementModel.Symbol+"/earnings-announcements"; feedItem.Source="Earnings Announcements"; feedItem.PubDate=today.ToShortDateString()+" "+Utility.DateTimeToStringHHMMSS(DateTime.Now); feedItem.Guid="Earnings Announcement "+earningsAnnouncementModel.Symbol+" "+today+" "+Utility.DateTimeToStringHHMMSS(DateTime.Now); if(openSymbols.Any(x=>x.Equals(earningsAnnouncementModel.Symbol)))feedItem.BrushAssigment=FeedBrushes.BrushColor.Red; feedItems.Add(feedItem); } return feedItems; } catch(Exception exception) { MDTrace.WriteLine(LogLevel.DEBUG,exception.ToString()); return feedItems; } } private List AnalystRatingsToFeedItems(List openSymbols) { List feedItems=new List(); List watchListSymbols = WatchListDA.GetWatchList("valuations"); if(null==watchListSymbols)watchListSymbols=new List(); if(null==openSymbols)openSymbols=new List(); try { DateTime today=DateTime.Now; AnalystRatings analystRatings=AnalystRatingsDA.GetAnalystRatings(today); foreach(AnalystRating analystRating in analystRatings) { if(!openSymbols.Any(x=>x.Equals(analystRating.Symbol)) && !watchListSymbols.Any(x=>x.Equals(analystRating.Symbol)))continue; StringBuilder sb=new StringBuilder(); FeedItem feedItem=new FeedItem(); sb.Append(analystRating.Symbol).Append("(").Append(analystRating.Type).Append(")").Append(":").Append(analystRating.RatingsChange); if(0.00!=analystRating.PriceTarget)sb.Append(":").Append(Utility.FormatCurrency(analystRating.PriceTarget)); String lineData=sb.ToString(); feedItem.Description=analystRating.Symbol; feedItem.Title=lineData; feedItem.Link="https://www.google.com/search?q="+Uri.EscapeDataString(analystRating.Symbol)+"/"; feedItem.Source="Analyst Ratings"; feedItem.PubDate=today.ToShortDateString()+" "+Utility.DateTimeToStringHHMMSS(DateTime.Now); feedItem.Guid="Analyst Ratings"+analystRating.Symbol+" "+today+" "+Utility.DateTimeToStringHHMMSS(DateTime.Now);; if(openSymbols.Any(x=>x.Equals(analystRating.Symbol)&&analystRating.Type.Equals("Downgrades")))feedItem.BrushAssigment=FeedBrushes.BrushColor.Red; else if(openSymbols.Any(x=>x.Equals(analystRating.Symbol)&&analystRating.Type.Equals("Upgrades"))) feedItem.BrushAssigment=FeedBrushes.BrushColor.Green; feedItems.Add(feedItem); } return feedItems; } catch(Exception exception) { MDTrace.WriteLine(LogLevel.DEBUG,exception.ToString()); return feedItems; } } private List OpenPricesToFeedItems(List openSymbols) { List feedItems=new List(); try { DateTime pricingDate=DateTime.Now; DateGenerator dateGenerator=new DateGenerator(); foreach(String symbol in openSymbols) { Price todaysPrice=PricingDA.GetPrice(symbol); if(null==todaysPrice)continue; DateTime prevDate=dateGenerator.FindPrevBusinessDay(todaysPrice.Date); Price prevPrice=PricingDA.GetPrice(symbol,prevDate); if(null==prevPrice)continue; double change=(todaysPrice.Close-prevPrice.Close)/prevPrice.Close; String strPercentChange=Utility.FormatPercent(change); FeedItem feedItem=new FeedItem(); feedItem.Description=symbol; feedItem.Title=symbol+":"+strPercentChange; feedItem.Link="https://www.google.com/search?q="+Uri.EscapeDataString(symbol)+"/"; feedItem.Source="Price Feed"; feedItem.PubDate=todaysPrice.Date.ToShortDateString()+" "+Utility.DateTimeToStringHHMMSS(DateTime.Now); feedItem.Guid=symbol+todaysPrice.Date.ToShortDateString()+":"+strPercentChange; if(change<0)feedItem.BrushAssigment=FeedBrushes.BrushColor.Red; else if(change>0)feedItem.BrushAssigment=FeedBrushes.BrushColor.Green; else feedItem.BrushAssigment=FeedBrushes.BrushColor.Normal; feedItems.Add(feedItem); } return feedItems; } catch(Exception exception) { MDTrace.WriteLine(LogLevel.DEBUG,exception.ToString()); return feedItems; } } private List HeadlinesToFeedItems() { List feedItems=new List(); try { DateTime today=DateTime.Now; MarketData.MarketDataModel.Headlines headlines=HeadlinesDA.GetHeadlines(today); for(int index=0;index