none
F# find different market open time RRS feed

  • Question

  • Hello:

    I need a function to tell me at now (DateTime.Now), if a specific market is open, if open return True, if not, return False.

    There are 3 different markets, market A runs in 2 time slots: first time slot, from 9:00AM to 11:00AM; the second time slot, from 13:00PM to 15:00PM.

    Market B runs in 3 time slots: first time slot, from 9:00AM to 10:30AM; the second time slot, from 11:00AM to 13:00PM; the third time slot from 14:00PM to 15:00PM.

    Market C runs in 4 time slots: first time slot, from 9:00AM to 10:15AM; the second time slot, from 10:30AM to 13:00PM; the third time slot from 12:00PM to 13:00PM; the last time slot from 14:00PM to 15:00PM.

    I can do this in imperative way, but not easy to figure out how to do this in functional way.

    By the way, I also want to have some kind of improvement: in stead of checking every second or every minute if the current time (DateTime.Now), one market is open or not, I want to set up some kind of timer, so my program will check only when the timer events happen.

    For example: if the current time now is: 9:30AM, then all the 3 markets are open, so the next time, my program to check will be at least 10:15AM, when market C will close. So my program will not check for 45 minutes starting from 9:30AM, or my program will not check fro 75 minutes starting from 9:00AM.

    However, I can’t figure out a good way to do so.

    Please advice.

    Thanks,

    Monday, November 6, 2017 9:14 AM

All replies

  • Share some code to show your approach and I'm sure the community will guide you in the right direction. 

    Regards Vallarasu S. BreakingDotNet.blogspot.com

    Tuesday, January 30, 2018 6:09 AM
  • I enjoy F# but sadly get few opportunities to leverage it at work, so I can solve your problem with C# much more quickly. In fact your question is more design than language specific because you're seeking an overall approach it seems.

    Fiddling around with Timers and so on might be best done in C# anyway and have the F# simply leverage the code as an external assembly.

    However those with > F# than me may have have some good ideas and I'd like to see this in F#, here's a complete working console app that I think delivers what you're asking (I got immersed in this yet never intended to!).


    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;
    
    namespace ConsoleApp8
    {
        class Program
        {
            static void Main(string[] args)
            {
                Market marketA = Market.Create("Market_A").AddTimeWindow("09:00:00", "11:00:00").AddTimeWindow("13:00:00", "15:00:00");
                Market marketB = Market.Create("Market_B").AddTimeWindow("09:00:00", "10:30:00").AddTimeWindow("11:00:00", "13:00:00").AddTimeWindow("14:00:00","15:00:00");
                Market marketC = Market.Create("Market_C").AddTimeWindow("09:00:00", "10:15:00").AddTimeWindow("10:30:00", "11:00:00").AddTimeWindow("12:00:00","13:00:00").AddTimeWindow("14:00:00","15:00:00");
    
                MarketNotifier notifier = MarketNotifier.Create().AddMarket(marketA).AddMarket(marketB).AddMarket(marketC);
    
                notifier.OnMarketChange += Handler;
    
                notifier.Start();
    
                Thread.Sleep(-1);
            }
    
            private static void Handler (object State, EventArgs Args)
            {
                MarketChangeEventArgs args = (MarketChangeEventArgs)(Args);
            }
        }
    
        public class MarketNotifier
        {
            public event EventHandler OnMarketChange = delegate { };
            public List<Market> Markets { get; private set; }
            private Dictionary<Market,Timer> timers { get; set; }
            public static MarketNotifier Create()
            {
                return new MarketNotifier();
            }
            private MarketNotifier()
            {
                Markets = new List<Market>();
                timers = new Dictionary<Market, Timer>();
            }
    
            public MarketNotifier AddMarket (Market Market)
            {
                if (Market == null)
                    throw new ArgumentNullException(nameof(Market));
    
                if (Markets.Where(m => m.MarketName == Market.MarketName).Any())
                    throw new ArgumentException($"A market with the name '{Market.MarketName}' has already been added.");
    
                Markets.Add(Market);
                timers.Add(Market, new Timer(Handler, Market, -1, -1));
    
                return this;
            }
    
            public void Start()
            {
                TimeSpan now = DateTime.Now.TimeOfDay; // get this once so it never fluctuates as we loop.
    
                foreach (var market in Markets)
                {
                    SetNextEventForMarket(market, now);
                }
            }
    
            private void Handler (object State)
            {
                Market schedule = (Market)(State);
    
                MarketEvent type = schedule.NextEvent; // save this because the next set operation will alter it.
    
                SetNextEventForMarket(schedule, DateTime.Now.TimeOfDay);
    
                // Invoke event
    
                MarketChangeEventArgs args = new MarketChangeEventArgs(type, schedule.MarketName);
                OnMarketChange(this, args);
            }
    
            private void SetNextEventForMarket(Market Market, TimeSpan Now)
            {
                foreach (var window in Market.Times)
                {
                    if (Now > window.Item1 && Now < window.Item2)
                    {
                        // This market is currently open, so next event must be a close.
                        timers[Market].Change((int)(window.Item2.TotalMilliseconds - Now.TotalMilliseconds), -1);
                        Market.SetNextEvent(MarketEvent.Close);
                        break;
                    }
    
                    if (Now < window.Item1)
                    {
                        // This market is currently closed, so next event must be an open.
                        timers[Market].Change((int)(window.Item1.TotalMilliseconds - Now.TotalMilliseconds), -1);
                        Market.SetNextEvent(MarketEvent.Open);
                        break;
                    }
                }
    
            }
        }
        public class MarketChangeEventArgs : EventArgs
        {
            public MarketEvent Type { get; private set; }
            public string Name { get; private set; }
    
            public MarketChangeEventArgs (MarketEvent Type, string Name)
            {
                this.Type = Type;
                this.Name = Name;
            }
        }
        public class Market
        {
            private MarketEvent nextEvent;
            public MarketEvent NextEvent { get { return nextEvent; } }
            public string MarketName { get; private set; }
            public List<Tuple<TimeSpan, TimeSpan>> Times { get; private set; }
    
            public void SetNextEvent (MarketEvent MarketEvent)
            {
                nextEvent = MarketEvent;
            }
            public static Market Create(string MarketName)
            {
                return new Market(MarketName);
            }
            private Market(string MarketName)
            {
                this.MarketName = MarketName;
                this.Times = new List<Tuple<TimeSpan, TimeSpan>>();
            }
    
            public Market AddTimeWindow(string Open, string Close)
            {
                return AddTimeWindow(TimeSpan.Parse(Open), TimeSpan.Parse(Close));
            }
    
            public Market AddTimeWindow (TimeSpan Open, TimeSpan Close)
            {
                if (Close <= Open)
                    throw new ArgumentException("Open time must be earlier than Close time.");
    
                if (Times.Where(t => Open >= t.Item1 && Open <= t.Item2 || Close >= t.Item1 && Close <= t.Item2).Any())
                    throw new ArgumentException("The time window must not overlap an existing time window.");
    
                Times.Add(new Tuple<TimeSpan, TimeSpan>(Open, Close));
    
                // Maintain order with earliest window first
    
                Times = Times.OrderBy(t => t.Item1).ToList();
    
                return this;
            }
        }
        public enum MarketEvent
        {
            Open,
            Close
        }
    }



    Sunday, May 6, 2018 4:05 PM