示例#1
0
        /// <summary>
        /// Calculate MACD, as described here:
        /// <see href="https://en.wikipedia.org/wiki/MACD"/>
        /// </summary>
        /// <param name="series">input time series</param>
        /// <param name="fast">fast EMA period</param>
        /// <param name="slow">slow EMA period</param>
        /// <param name="signal">signal line period</param>
        /// <param name="parentId">caller cache id, optional</param>
        /// <param name="memberName">caller's member name, optional</param>
        /// <param name="lineNumber">caller line number, optional</param>
        /// <returns></returns>
        public static _MACD MACD(this ITimeSeries <double> series, int fast = 12, int slow     = 26, int signal = 9,
                                 CacheId parentId = null, [CallerMemberName] string memberName = "", [CallerLineNumber] int lineNumber = 0)
        {
            var cacheId = new CacheId(parentId, memberName, lineNumber,
                                      series.GetHashCode(), fast, slow, signal);

            var container = Cache <_MACD> .GetData(
                cacheId,
                () => new _MACD());

            container.Fast       = series.EMA(fast, cacheId);
            container.Slow       = series.EMA(slow, cacheId);
            container.MACD       = container.Fast.Subtract(container.Slow, cacheId);
            container.Signal     = container.MACD.EMA(signal, cacheId);
            container.Divergence = container.MACD.Subtract(container.Signal, cacheId);

            return(container);
        }
示例#2
0
        /// <summary>
        /// Calculate Double Exponential Moving Average, as described here:
        /// <see href="https://en.wikipedia.org/wiki/Double_exponential_moving_average"/>
        /// </summary>
        /// <param name="series">input time series</param>
        /// <param name="n">averaging length</param>
        /// <param name="parentId">caller cache id, optional</param>
        /// <param name="memberName">caller's member name, optional</param>
        /// <param name="lineNumber">caller line number, optional</param>
        /// <returns>DEMA time series</returns>
        public static ITimeSeries <double> DEMA(this ITimeSeries <double> series, int n,
                                                CacheId parentId = null, [CallerMemberName] string memberName = "", [CallerLineNumber] int lineNumber = 0)
        {
            var cacheId = new CacheId(parentId, memberName, lineNumber,
                                      series.GetHashCode(), n);

            return(series
                   .Multiply(2.0, cacheId)
                   .EMA(n, cacheId)
                   .Subtract(
                       series
                       .EMA(n, cacheId)
                       .EMA(n, cacheId),
                       cacheId));
        }
示例#3
0
        override public void Run()
        {
            //---------- initialization

            // set simulation time frame
            StartTime = DateTime.Parse("01/01/2015");
            EndTime   = DateTime.Parse("12/31/2016");

            // add instruments
            AddDataSource(_instrumentNick);

            //---------- simulation

            foreach (DateTime simTime in SimTimes)
            {
                // find our instrument. if we have only one instrument,
                // we could also just use Instruments.Values.First()
                Instrument instrument = FindInstrument(_instrumentNick);

                // calculate simple indicators
                // the output of an indicator is a time series
                ITimeSeries <double> ema26 = instrument.Close.EMA(26);
                ITimeSeries <double> ema12 = instrument.Close.EMA(12);

                // therefore, indicators can be calculated on top of indicators
                ITimeSeries <double> macd   = ema12.Subtract(ema26);
                ITimeSeries <double> signal = macd.EMA(9);

                // plot our data
                _plotter.SelectChart("indicators vs time", "date");
                _plotter.SetX(simTime.Date);
                _plotter.Plot(instrument.Symbol, instrument.Close[0] + _offsetPrice);
                _plotter.Plot("ema26", ema26[0] + _offsetPrice);
                _plotter.Plot("ema12", ema12[0] + _offsetPrice);
                _plotter.Plot("macd", macd[0]);
                _plotter.Plot("signal", signal[0]);
            }
        }
示例#4
0
        /// <summary>
        /// Calculate True Strength Index of input time series, as described here:
        /// <see href="https://en.wikipedia.org/wiki/True_strength_index"/>
        /// </summary>
        /// <param name="series">input time series</param>
        /// <param name="r">smoothing period for momentum</param>
        /// <param name="s">smoothing period for smoothed momentum</param>
        /// <param name="parentId">caller cache id, optional</param>
        /// <param name="memberName">caller's member name, optional</param>
        /// <param name="lineNumber">caller line number, optional</param>
        /// <returns>TSI time series</returns>
        public static ITimeSeries <double> TSI(this ITimeSeries <double> series, int r = 25, int s           = 13,
                                               CacheId parentId = null, [CallerMemberName] string memberName = "", [CallerLineNumber] int lineNumber = 0)
        {
            var cacheId = new CacheId(parentId, memberName, lineNumber,
                                      series.GetHashCode(), r, s);

            ITimeSeries <double> momentum = series
                                            .Return(cacheId);

            double numerator = momentum
                               .EMA(r, cacheId)
                               .EMA(s, cacheId)[0];

            double denominator = momentum
                                 .AbsValue(cacheId)
                                 .EMA(r, cacheId)
                                 .EMA(s, cacheId)[0];

            return(IndicatorsBasic.BufferedLambda(
                       v => 100.0 * numerator / Math.Max(1e-10, denominator),
                       0.5,
                       cacheId));
        }
示例#5
0
 /// <summary>
 /// Normalize time series over number of bars; 1.0 being the average.
 /// </summary>
 /// <param name="series">input time series</param>
 /// <param name="n">normalizing period</param>
 /// <returns>normalized time series</returns>
 public static ITimeSeries <double> Normalize(this ITimeSeries <double> series, int n)
 {
     return(series.Divide(series.EMA(n)));
 }
示例#6
0
        override public void Run()
        {
            //---------- initialization

            // set simulation time frame
            StartTime = DateTime.Parse("01/01/2017", CultureInfo.InvariantCulture);
            EndTime   = DateTime.Parse("08/01/2018", CultureInfo.InvariantCulture);

            // set account value
            Deposit(_initialCash);
            CommissionPerShare = 0.01;

            // add instruments
            // the underlying must be added explicitly,
            // as the simulation engine requires it
            AddDataSource(_underlyingNickname);
            AddDataSource(_optionsNickname);

            //---------- simulation

            // loop through all bars
            foreach (DateTime simTime in SimTimes)
            {
                // find the underlying instrument
                // we could also find the underlying from the option chain
                _underlyingInstrument = _underlyingInstrument ?? FindInstrument(_underlyingNickname);

                // retrieve the underlying spot price
                double underlyingPrice = _underlyingInstrument.Close[0];
                _initialUnderlyingPrice = _initialUnderlyingPrice ?? underlyingPrice;

                // calculate volatility
                ITimeSeries <double> volatilitySeries = _underlyingInstrument.Close
                                                        .Volatility(10)
                                                        .Multiply(Math.Sqrt(252.0));
                double volatility = Math.Max(
                    volatilitySeries.EMA(21)[0],
                    volatilitySeries.Highest(5)[0]);

                // find all expiry dates on the 3rd Friday of the month
                List <DateTime> expiryDates = OptionChain(_optionsNickname)
                                              .Where(o => o.OptionExpiry.DayOfWeek == DayOfWeek.Friday && o.OptionExpiry.Day >= 15 && o.OptionExpiry.Day <= 21 ||
                                                     o.OptionExpiry.DayOfWeek == DayOfWeek.Saturday && o.OptionExpiry.Day >= 16 && o.OptionExpiry.Day <= 22)
                                              .Select(o => o.OptionExpiry)
                                              .Distinct()
                                              .ToList();

                // select expiry 3 to 4 weeks out
                DateTime expiryDate = expiryDates
                                      .Where(d => (d - simTime).TotalDays >= 21 &&
                                             (d - simTime).TotalDays <= 28)
                                      .FirstOrDefault();

                // retrieve option chain for this expiry
                List <Instrument> optionChain = OptionChain(_optionsNickname)
                                                .Where(o => o.OptionIsPut &&
                                                       o.OptionExpiry == expiryDate)
                                                .ToList();

                // if we are currently flat, attempt to open a position
                if (Positions.Count == 0)
                {
                    // determine strike price: far away from spot price
                    double strikePrice = _underlyingInstrument.Close[0]
                                         / Math.Exp(1.75 * Math.Sqrt((expiryDate - simTime).TotalDays / 365.25) * volatility);

                    // find contract closest to our desired strike
                    Instrument shortPut = optionChain
                                          .OrderBy(o => Math.Abs(o.OptionStrike - strikePrice))
                                          .FirstOrDefault();

                    // enter short put position
                    if (shortPut != null)
                    {
                        // Interactive Brokers margin requirements for short naked puts:
                        // Put Price + Maximum((15 % * Underlying Price - Out of the Money Amount),
                        //                     (10 % * Strike Price))
                        double margin = Math.Max(0.15 * underlyingPrice - Math.Max(0.0, underlyingPrice - shortPut.OptionStrike),
                                                 0.10 * underlyingPrice);
                        int contracts = (int)Math.Floor(Math.Max(0.0, _regTMarginToUse * Cash / (100.0 * margin)));

                        shortPut.Trade(-contracts, OrderType.closeThisBar)
                        .Comment = "open";
                    }
                }

                // monitor and maintain existing positions
                else // if (Postions.Count != 0)
                {
                    // find our currently open position
                    // we might need fancier code, in case we have more than
                    // one position open
                    Instrument shortPut = Positions.Keys.First();

                    // re-evaluate the likely trading range
                    double expectedLowestPrice = _underlyingInstrument.Close[0]
                                                 / Math.Exp(0.60 * Math.Sqrt((shortPut.OptionExpiry - simTime).Days / 365.25) * volatility);

                    // exit, when the risk of ending in the money is too high
                    // and, the contract is actively traded
                    if (expectedLowestPrice < shortPut.OptionStrike &&
                        shortPut.BidVolume[0] > 0 &&
                        shortPut.Ask[0] < 2 * shortPut.Bid[0])
                    {
                        shortPut.Trade(-Positions[shortPut], OrderType.closeThisBar)
                        .Comment = "exit early";
                    }
                }

                // plot the underlying against our strategy results, plus volatility
                _plotter.SelectChart("nav vs time", "time"); // this will go to Sheet1
                _plotter.SetX(simTime);
                _plotter.Plot(_underlyingInstrument.Symbol, underlyingPrice / (double)_initialUnderlyingPrice);
                _plotter.Plot("volatility", volatilitySeries[0]);
                _plotter.Plot("net asset value", NetAssetValue[0] / _initialCash);
            }

            //---------- post-processing

            // create a list of trades on Sheet2
            _plotter.SelectChart("trades", "time");
            foreach (LogEntry entry in Log)
            {
                _plotter.SetX(entry.BarOfExecution.Time);
                _plotter.Plot("action", entry.Action);
                _plotter.Plot("instr", entry.Symbol);
                _plotter.Plot("qty", entry.OrderTicket.Quantity);
                _plotter.Plot("fill", entry.FillPrice);
                _plotter.Plot("comment", entry.OrderTicket.Comment ?? "");
            }

            FitnessValue = NetAssetValue[0];
        }