Overall Statistics
namespace QuantConnect 
{   
    /// <summary>
    /// QCU: Derivative Tradeable Securities
    ///
    /// This algorithm shows how to define a security that derives from tradebar data
    /// 
    /// </summary>
    public class DerivedSecurityAlgorithm : QCAlgorithm
    {
        public override void Initialize()
        {
            SetStartDate(2013, 10, 07);
            SetEndDate(2013, 11, 07);

            // add our custom data
            AddData<PutOption>("SPY.PUT", Resolution.Minute);
            
            // we need to set the exchange hours properly
            Securities["SPY.PUT"].Exchange = new EquityExchange();
        }

        public override void OnData(Slice slice)
        {
            if (Transactions.OrdersCount == 0)
            {
                // we can order our custom data like any other
                SetHoldings("SPY.PUT", 0.1);
            }
        }
    }
}
namespace QuantConnect {
    /// <summary>
    /// This is our custom derived security type. It produces a security whose value
    /// is equal to:
    /// 
    /// Value = underlying.Close + Math.Abs((C - O) * (H - L))
    /// </summary>
    public class PutOption : BaseData
    {
        // define derived properties
        public decimal DerivedProperty1 { get; set; }
        public decimal DerivedProperty2 { get; set; }

        // override so we can properly set it from the tradebar
        public override DateTime EndTime { get; set; }

        /// <summary>
        /// Reader converts each line of the data source into BaseData objects. Each data type creates its own factory method, and returns a new instance of the object 
        /// each time it is called. 
        /// </summary>
        /// <param name="config">Subscription data config setup object</param>
        /// <param name="line">Line of the source document</param>
        /// <param name="date">Date of the requested data</param>
        /// <param name="isLiveMode">true if we're in live mode, false for backtesting mode</param>
        /// <returns>Instance of the T:BaseData object generated by this line of the CSV</returns>
        public override BaseData Reader(SubscriptionDataConfig config, string line, DateTime date, bool isLiveMode)
        {
            try
            {
                config = HackSubscriptionDataConfig(config);

                // use the tradebar reader implementation to read QC csv files
                var tradebar = (TradeBar)new TradeBar().Reader(config, line, date, isLiveMode);

                // now that we have the tradebar for our underlying, we can do some math
                // here I just did something random to show the possibilities.
                return new PutOption
                {
                    // symbol, time, and endtime are required values. the end time is used for time syncing the data
                    Symbol = config.Symbol + ".PUT",
                    Time = tradebar.Time,
                    EndTime = tradebar.EndTime,
                    // we can compute derived properties from the tradebar
                    DerivedProperty1 = tradebar.High - tradebar.Low,
                    DerivedProperty2 = tradebar.Close - tradebar.Open,
                    // value must resolve to greater than zero to be 'tradeable' in QC backtests
                    Value = tradebar.Close + (tradebar.Close - tradebar.Open) * (tradebar.High - tradebar.Low),
                };
            }
            catch
            {
                return null;
            }
        }

        /// <summary>
        /// Return the URL string source of the file. This will be converted to a stream 
        /// </summary>
        /// <param name="config">Configuration object</param>
        /// <param name="date">Date of this source file</param>
        /// <param name="isLiveMode">true if we're in live mode, false for backtesting mode</param>
        /// <returns>String URL of source file.</returns>
        public override SubscriptionDataSource GetSource(SubscriptionDataConfig config, DateTime date, bool isLiveMode)
        {
            // the source of our data is the same as normal trade bar data
            config = HackSubscriptionDataConfig(config);
            return new TradeBar().GetSource(config, date, isLiveMode);
        }

        /// <summary>
        /// Reroutes the configuration to an equity trade bar
        /// </summary>
        private static SubscriptionDataConfig HackSubscriptionDataConfig(SubscriptionDataConfig config)
        {
            // we need to override the configuration produced by the AddData method so it will get the
            // data from the same place we get equity tradebar equity data
            config = new SubscriptionDataConfig(typeof(TradeBar), SecurityType.Equity,
                // we replace the .PUT from the symbol. 
                config.Symbol.Value.Replace(".PUT", string.Empty),
                // reuse all the other options so we get the right data
                config.Resolution, config.Market, config.TimeZone, config.FillDataForward,
                config.ExtendedMarketHours, config.IsInternalFeed, config.IsCustomData
                );
            return config;
        }
    }
}