程序员的量化交易之路(36)--Lean之数据读取SubscriptionDataReader4

用QuantConnect Lean打造算法交易的利器 摘要: LEAN是由QuantConnect团队开发的专业算法交易平台,支持Python和C#,提供模块化设计和事件驱动架构,适用于量化策略开发、回测及实时交易。安装需通过LEAN CLI命令(如pip install lean),支持本地Docker环境运行与云混合开发。平台兼容Windows(Visual Studio)、macOS(VS Code)和Linux(dotnet SDK),并集成Python支持。同类工具包括Backtrader、Zipline等,满足多样化交易需求。 阅读详情

转载需注明出处:http://blog.youkuaiyun.com/minimicall?viewmode=contents,http://cloudtrade.top

数据读取需要定义一个读者。直接见下面代码:

namespace QuantConnect.Lean.Engine.DataFeeds
{
    /******************************************************** 
    * CLASS DEFINITIONS
    *********************************************************/
    /// <summary>
    /// Subscription data reader is a wrapper on the stream reader class to download, unpack and iterate over a data file.
    /// 订阅数据的读者是对数据流读取类的一个封装,负责下载、解压、遍历数据
    /// </summary>
    /// <remarks>The class accepts any subscription configuration and automatically makes it availble to enumerate</remarks>
    public class SubscriptionDataReader : IEnumerator<BaseData>
    {
        /******************************************************** 
        * CLASS PRIVATE VARIABLES
        *********************************************************/
        /// Source string to create memory stream:
        private string _source = "";

        ///Default true to fillforward for this subscription, take the previous result and continue returning it till the next time barrier.
        private bool _isFillForward = true;

        ///Date of this source file.
        private DateTime _date = new DateTime();

        ///End of stream from the reader
        private bool _endOfStream = false;

        /// Internal stream reader for processing data line by line:
        private IStreamReader _reader = null;

        /// All streams done async via web protocols:
        private WebClient _web = new WebClient();

        /// Configuration of the data-reader:订阅数据的配置
        private SubscriptionDataConfig _config;

        /// Subscription Securities Access证券
        private Security _security;

        /// true if we can find a scale factor file for the security of the form: ..\Lean\Data\equity\factor_files\{SYMBOL}.csv
        private bool _hasScaleFactors = false;

        // Subscription is for a QC type:
        private bool _isDynamicallyLoadedData = false;

        //Symbol Mapping:
        private string _mappedSymbol = "";

        /// Location of the datafeed - the type of this data. 数据类型
        private readonly DataFeedEndpoint _feedEndpoint;

        /// Object Activator - Fast create new instance of "Type":
        private readonly Func<object[], object> _objectActivator;

        ///Create a single instance to invoke all Type Methods:
        private readonly BaseData _dataFactory;

        /// Remember edge conditions as market enters/leaves open-closed.这是什么鬼
        private BaseData _lastBarOfStream = null;
        private BaseData _lastBarOutsideMarketHours = null;

        //Start finish times of the backtest:
        private readonly DateTime _periodStart;
        private readonly DateTime _periodFinish;

        private readonly FactorFile _factorFile;
        private readonly MapFile _mapFile;

        // we set the price factor ratio when we encounter a dividend in the factor file
        // and on the next trading day we use this data to produce the dividend instance
        private decimal? _priceFactorRatio;

        // we set the split factor when we encounter a split in the factor file
        // and on the next trading day we use this data to produce the split instance
        private decimal? _splitFactor;

        /******************************************************** 
        * CLASS PUBLIC VARIABLES
        *********************************************************/
        /// <summary>
        /// Last read BaseData object from this type and source
        /// 最近一个读取出来的数据
        /// </summary>
        public BaseData Current
        {
            get;
            private set;
        }

        /// <summary>
        /// Explicit Interface Implementation for Current
        /// </summary>
        object IEnumerator.Current
        {
            get { return Current; }
        }

        /// <summary>
        /// Provides a means of exposing extra data related to this subscription.
        /// For now we expose dividend data for equities through here
        /// 额外数据:提供证券订阅数据额外相关的数据的存储,这里指股息
        /// </summary>
        /// <remarks>
        /// It is currently assumed that whomever is pumping data into here is handling the
        /// time syncing issues. Dividends do this through the RefreshSource method
        /// </remarks>
        public Queue<BaseData> AuxiliaryData { get; private set; }

        /// <summary>
        /// Save an instance of the previous basedata we generated
        /// 上一个数据(比Current更前)
        /// </summary>
        public BaseData Previous
        {
            get;
            private set;
        }

        /// <summary>
        /// Source has been completed, load up next stream or stop asking for data.
        /// </summary>
        public bool EndOfStream
        {
            get 
            {
                return _endOfStream || _reader == null;
            }
            set
            {
                _endOfStream = value;
            }
        }

        /******************************************************** 
        * CLASS CONSTRUCTOR
        *********************************************************/
        /// <summary>
        /// Subscription data reader takes a subscription request, loads the type, accepts the data source and enumerate on the results.
        /// </summary>
        /// <param name="config">Subscription configuration object 订阅配置</param>
        /// <param name="security">Security asset 证券</param>
        /// <param name="feed">Feed type enum 类型</param>
        /// <param name="periodStart">Start date for the data request/backtest 开始时间</param>
        /// <param name="periodFinish">Finish date for the data request/backtest 结束时间</param>
        public SubscriptionDataReader(SubscriptionDataConfig config, Security security, DataFeedEndpoint feed, DateTime periodStart, DateTime periodFinish)
        {
            Console.WriteLine("SubscriptionDataReader,SubscriptionDataConfig:<symbol:{0},resolution:{1}>" ,config.Symbol,config.Resolution);

            //Save configuration of data-subscription:
            _config = config;//配置

            AuxiliaryData = new Queue<BaseData>();//额外数据队列

            //Save access to fill foward flag:是否向前填充
            _isFillForward = config.FillDataForward;

            //Save Start and End Dates:起止时间
            _periodStart = periodStart;
            _periodFinish = periodFinish;

            //Save access to securities
            _security = security;//证券
            _isDynamicallyLoadedData = security.IsDynamicallyLoadedData;//是否动态加载数据

            // do we have factor tables?
            _hasScaleFactors = FactorFile.HasScalingFactors(config.Symbol);//变换因子

            //Save the type of data we'll be getting from the source.数据类型
            _feedEndpoint = feed;

            //Create the dynamic type-activators:提供一种创建给定类型对象的方法
            _objectActivator = ObjectActivator.GetActivator(config.Type);

            if (_objectActivator == null) 
            {//创建失败
                Engine.ResultHandler.ErrorMessage("Custom data type '" + config.Type.Name + "' missing parameterless constructor E.g. public " + config.Type.Name + "() { }");
                _endOfStream = true;
                return;
            }

            //Create an instance of the "Type":
            var userObj = _objectActivator.Invoke(new object[] { });
            _dataFactory = userObj as BaseData;

            //If its quandl set the access token in data factory:
            var quandl = _dataFactory as Quandl;
            if (quandl != null)
            {
                if (!Quandl.IsAuthCodeSet)
                {
                    Quandl.SetAuthCode(Config.Get("quandl-auth-token"));   
                }
            }

            //Load the entire factor and symbol mapping tables into memory, we'll start with some defaults
            Console.WriteLine("load the entire factor and symbol mapping tables into memory");
            _factorFile = new FactorFile(config.Symbol, new List<FactorFileRow>());
            _mapFile = new MapFile(config.Symbol, new List<MapFileRow>());
            try 
            {
                if (_hasScaleFactors)
                {
                    _factorFile = FactorFile.Read(config.Symbol);
                    _mapFile = MapFile.Read(config.Symbol);
                }
            } 
            catch (Exception err) 
            {
                Log.Error("SubscriptionDataReader(): Fetching Price/Map Factors: " + err.Message);
           }
        }

        /******************************************************** 
        * CLASS METHODS
        *********************************************************/
        /// <summary>
        /// Try and create a new instance of the object and return it using the MoveNext enumeration pattern ("Current" public variable).
        /// 试图创建一个实例,付给Current
        /// </summary>
        /// <remarks>This is a highly called method and should be kept lean as possible.</remarks>
        /// <returns>Boolean true on successful move next. Set Current public property.</returns>
        public bool MoveNext() {
            Console.WriteLine("MoveNext()");
            // yield the aux data first附加数据优先
            if (AuxiliaryData.Count != 0)
            {
                Previous = Current;//将现在这个付给Previous
                Current = AuxiliaryData.Dequeue();//将这个 附属数据弹出付给Current
                Console.WriteLine("AuxiliaryData:symbol:"+Current.Symbol+",price:"+Current.Price);
                return true;
            }

            BaseData instance = null;
            var instanceMarketOpen = false;
            Log.Debug("SubscriptionDataReader.MoveNext(): Starting MoveNext...");

            try
            {
                //Calls this when no file, first "moveNext()" in refresh source.
                if (_endOfStream || _reader == null || _reader.EndOfStream)
                {
                    if (_reader == null)
                    {
                        //Handle the 1% of time:: getReader failed e.g. missing day so skip day:
                        Current = null;
                    }
                    else
                    {
                        //This is a MoveNext() after reading the last line of file:
                        _lastBarOfStream = Current;
                    }
                    _endOfStream = true;
                    return false;
                }

                //Log.Debug("SubscriptionDataReader.MoveNext(): Launching While-InstanceNotNull && not EOS: " + reader.EndOfStream);
                //Keep looking until output's an instance:
                while (instance == null && !_reader.EndOfStream)
                {
                    //Get the next string line from file, create instance of BaseData:读取一行
                    var line = _reader.ReadLine();//这个_reader里面其实会调用系统的输入流的readLine()
                    try
                    {
                        instance = _dataFactory.Reader(_config, line, _date, _feedEndpoint);//将字符行变成对象
                    }
                    catch (Exception err)
                    {
                        //Log.Debug("SubscriptionDataReader.MoveNext(): Error invoking instance: " + err.Message);
                        Engine.ResultHandler.RuntimeError("Error invoking " + _config.Symbol + " data reader. Line: " + line + " Error: " + err.Message, err.StackTrace);
                        _endOfStream = true;
                        continue;
                    }

                    if (instance != null)
                    {
                        // we care if the market was open at any time over the bar判断是否在开市时间段内
                        instanceMarketOpen = Exchange.IsOpenDuringBar(instance.Time, instance.EndTime, false);
                        
                        //Apply custom user data filters:
                        try
                        {
                            if (!_security.DataFilter.Filter(_security, instance))
                            {
                                instance = null;
                                continue;
                            }
                        }
                        catch (Exception err)
                        {
                            Log.Error("SubscriptionDataReader.MoveNext(): Error applying filter: " + err.Message);
                            Engine.ResultHandler.RuntimeError("Runtime error applying data filter. Assuming filter pass: " + err.Message, err.StackTrace);
                        }

                        if (instance == null)
                        {
                            // REVIEW -- Is this condition heuristically possible?
                            Log.Trace("SubscriptionDataReader.MoveNext(): Instance null, continuing...");
                            continue;
                        }


                        //Check if we're in date range of the data request
                        if (instance.Time < _periodStart)//取出的数据不在订阅的数据范围内
                        {
                            _lastBarOutsideMarketHours = instance;
                            instance = null;
                            continue;
                        }
                        if (instance.Time > _periodFinish)//取出的数据比订阅的数据晚
                        {
                            // we're done with data from this subscription, finalize the reader
                            Current = null;
                            _endOfStream = true;
                            return false;
                        }

                        //Save bar for extended market hours (fill forward).
                        if (!instanceMarketOpen)
                        {
                            _lastBarOutsideMarketHours = instance;
                        }

                        //However, if we only want market hours data, don't return yet: Discard and continue looping.
                        if (!_config.ExtendedMarketHours && !instanceMarketOpen)
                        {
                            instance = null;
                        }
                    }
                }

                //Handle edge conditions: First Bar Read: 
                // -> Use previous bar from yesterday if available
                if (Current == null)
                {
                    //Handle first loop where not set yet:
                    if (_lastBarOfStream == null)
                    {
                        //For first bar, fill forward from premarket data where possible
                        _lastBarOfStream = _lastBarOutsideMarketHours ?? instance;
                    }
                    //If current not set yet, set Previous to yesterday/last bar read. 
                    Previous = _lastBarOfStream;
                }
                else
                {
                    Previous = Current;
                }

                Current = instance;

                //End of Stream: rewind reader to last
                if (_reader.EndOfStream && instance == null)
                {
                    //Log.Debug("SubscriptionDataReader.MoveNext(): Reader EOS.");
                    _endOfStream = true;

                    if (_isFillForward && Previous != null)
                    {
                        //If instance == null, current is null, so clone previous to record the final sample:
                        Current = Previous.Clone(true);
                        //When market closes fastforward current bar to the last bar fill forwarded to close time.
                        Current.Time = _security.Exchange.TimeOfDayClosed(Previous.Time);
                        // Save the previous bar as last bar before next stream (for fill forwrd).
                        _lastBarOfStream = Previous;
                    }
                    return false;
                }
                return true;
            }
            catch (Exception err)
            {
                Log.Error("SubscriptionDataReader.MoveNext(): " + err.Message);
                return false;
            }
        }

        /// <summary>
        /// For backwards adjusted data the price is adjusted by a scale factor which is a combination of splits and dividends. 
        /// This backwards adjusted price is used by default and fed as the current price.
        /// </summary>
        /// <param name="date">Current date of the backtest.</param>
        private void UpdateScaleFactors(DateTime date)
        {
            switch (_config.DataNormalizationMode)
            {
                case DataNormalizationMode.Raw:
                case DataNormalizationMode.TotalReturn:
                    return;
                
                case DataNormalizationMode.SplitAdjusted:
                    _config.PriceScaleFactor = _factorFile.GetSplitFactor(date);
                    break;

                case DataNormalizationMode.Adjusted:
                    _config.PriceScaleFactor = _factorFile.GetPriceScaleFactor(date);
                    break;
                
                default:
                    throw new ArgumentOutOfRangeException();
            }
        }

        /// <summary>
        /// Check if this time is open for this subscription.
        /// </summary>
        /// <param name="time">Date and time we're checking to see if the market is open</param>
        /// <returns>Boolean true on market open</returns>
        public bool IsMarketOpen(DateTime time) 
        {
            return _security.Exchange.DateTimeIsOpen(time);
        }

        /// <summary>
        /// Gets the associated exchange for this data reader/security
        /// </summary>
        public SecurityExchange Exchange
        {
            get { return _security.Exchange; }
        }

        /// <summary>
        /// Check if we're still in the extended market hours
        /// </summary>
        /// <param name="time">Time to scan</param>
        /// <returns>True on extended market hours</returns>
        public bool IsExtendedMarketOpen(DateTime time) 
        {
            return _security.Exchange.DateTimeIsExtendedOpen(time);
        }

        /// <summary>
        /// Reset the IEnumeration
        /// </summary>
        /// <remarks>Not used</remarks>
        public void Reset() 
        {
            throw new NotImplementedException("Reset method not implemented. Assumes loop will only be used once.");
        }


        /// <summary>
        /// Fetch and set the location of the data from the user's BaseData factory:
        /// </summary>
        /// <param name="date">Date of the source file.</param>
        /// <returns>Boolean true on successfully retrieving the data</returns>
        public bool RefreshSource(DateTime date)
        {
            //Update the source from the getSource method:
            _date = date;
            Log.Trace("RefreshSource:"+date);
            // if the map file is an empty instance this will always return true
            if (!_mapFile.HasData(date))
            {
                // don't even bother checking the disk if the map files state we don't have ze dataz
                return false;
            }

            // check for dividends and split for this security
            CheckForDividend(date);
            CheckForSplit(date);

            var newSource = "";

            //If we can find scale factor files on disk, use them. LiveTrading will aways use 1 by definition
            if (_hasScaleFactors)
            {
                // check to see if the symbol was remapped
                _mappedSymbol = _mapFile.GetMappedSymbol(date);
                _config.MappedSymbol = _mappedSymbol;

                // update our price scaling factors in light of the normalization mode
                UpdateScaleFactors(date);
            }

            //Make sure this particular security is trading today:
            if (!_security.Exchange.DateIsOpen(date))
            {
                _endOfStream = true;
                return false;
            }

            //Choose the new source file, hide the QC source file locations
            newSource = GetSource(date);

            //When stream over stop looping on this data.
            if (newSource == "") 
            {
                _endOfStream = true;
                return false;
            }

            Log.Debug("SubscriptionDataReader.MoveNext(): Source Refresh: " + newSource,1);
            if (_source != newSource && newSource != "")
            {
                //If a new file, reset the EOS flag:
                _endOfStream = false;
                //Set the new source.
                _source = newSource;
                //Close out the last source file.
                Dispose();

                //Load the source:
                try 
                {
                    Log.Trace("SubscriptionDataReader.RefreshSource(): Created new reader for source: " + _source);
                    _reader = GetReader(_source);
                } 
                catch (Exception err) 
                {
                    Log.Error("SubscriptionDataReader.RefreshSource(): Failed to get reader: " + err.Message);
                    //Engine.ResultHandler.DebugMessage("Failed to get a reader for the data source. There may be an error in your custom data source reader. Skipping date (" + date.ToShortDateString() + "). Err: " + err.Message);
                    return false;
                }

                if (_reader == null)
                {
                    Log.Error("Failed to get StreamReader for data source(" + _source + "), symbol(" + _mappedSymbol + "). Skipping date(" + date.ToShortDateString() + "). Reader is null.");
                    //Engine.ResultHandler.DebugMessage("We could not find the requested data. This may be an invalid data request, failed download of custom data, or a public holiday. Skipping date (" + date.ToShortDateString() + ").");
                    if (_isDynamicallyLoadedData)
                    {
                        Engine.ResultHandler.ErrorMessage("We could not fetch the requested data. This may not be valid data, or a failed download of custom data. Skipping source (" + _source + ").");
                    }
                    return false;
                }

                //Reset the public properties so we can explicitly set them with lastBar data.
                Current = null;
                Previous = null;

                //99% of time, populate the first "Current". 1% of of time no source file (getReader fails), so
                // method sets the Subscription properties as if no data.
                try
                {
                    MoveNext();
                }
                catch (Exception err) 
                {
                    throw  new Exception("SubscriptionDataReader.RefreshSource(): Could not MoveNext to init stream: " + _source + " " + err.Message + " >> " + err.StackTrace);
                }
            }

            //Success:
            return true;
        }

        /// <summary>
        /// Check for dividends and emit them into the aux data queue
        /// </summary>
        private void CheckForSplit(DateTime date)
        {
            if (_splitFactor != null)
            {
                var close = GetRawClose();
                var split = new Split(_config.Symbol, date, close, _splitFactor.Value);
                AuxiliaryData.Enqueue(split);
                _splitFactor = null;
            }

            decimal splitFactor;
            if (_factorFile.HasSplitEventOnNextTradingDay(date, out splitFactor))
            {
                _splitFactor = splitFactor;
            }
        }

        /// <summary>
        /// Check for dividends and emit them into the aux data queue
        /// 检查股息,并将它写到附加数据队列中
        /// </summary>
        private void CheckForDividend(DateTime date)
        {
            if (_priceFactorRatio != null)
            {
                var close = GetRawClose();
                var dividend = new Dividend(_config.Symbol, date, close, _priceFactorRatio.Value);
                // let the config know about it for normalization
                _config.SumOfDividends += dividend.Distribution;
                AuxiliaryData.Enqueue(dividend);
                _priceFactorRatio = null;
            }

            // check the factor file to see if we have a dividend event tomorrow
            decimal priceFactorRatio;
            if (_factorFile.HasDividendEventOnNextTradingDay(date, out priceFactorRatio))
            {
                _priceFactorRatio = priceFactorRatio;
            }
        }

        /// <summary>
        /// Un-normalizes the Previous.Value标准化什么鬼值
        /// </summary>
        private decimal GetRawClose()
        {
            if (Previous == null) return 0m;

            var close = Previous.Value;

            switch (_config.DataNormalizationMode)
            {
                case DataNormalizationMode.Raw:
                    break;
                
                case DataNormalizationMode.SplitAdjusted:
                case DataNormalizationMode.Adjusted:
                    // we need to 'unscale' the price
                    close = close/_config.PriceScaleFactor;
                    break;
                
                case DataNormalizationMode.TotalReturn:
                    // we need to remove the dividends since we've been accumulating them in the price
                    close -= _config.SumOfDividends;
                    break;
                
                default:
                    throw new ArgumentOutOfRangeException();
            }
            return close;
        }


        /// <summary>
        /// Using this source URL, download it to our cache and open a local reader.
        /// </summary>
        /// <param name="source">Source URL for the data:</param>
        /// <returns>StreamReader for the data source</returns>
        private IStreamReader GetReader(string source)
        {
            IStreamReader reader = null;

            if (_feedEndpoint == DataFeedEndpoint.LiveTrading)
            {
                // live trading currently always gets a rest endpoint,如果是实时交易,则只能用Rest读取
                return new RestSubscriptionStreamReader(source);
            }

            // determine if we're hitting the file system/backtest
            if (_feedEndpoint == DataFeedEndpoint.FileSystem || _feedEndpoint == DataFeedEndpoint.Backtesting)
            {
                // construct a uri to determine if we have a local or remote file
                var uri = new Uri(source, UriKind.RelativeOrAbsolute);

                if (uri.IsAbsoluteUri && !uri.IsLoopback)
                {//绝对地址切uri的IP不是环回地址,即远端
                    reader = HandleRemoteSourceFile(source);
                }
                else
                {//本地
                    reader = HandleLocalFileSource(source);
                }
            }

            // if the reader is already at end of stream, just set to null so we don't try to get data for today
            if (reader != null && reader.EndOfStream)
            {
                reader = null;
            }

            return reader;
        }


        /// <summary>
        /// Dispose of the Stream Reader and close out the source stream and file connections.
        /// 废弃该流
        /// </summary>
        public void Dispose() 
        { 
            if (_reader != null) 
            {
                _reader.Close();
                _reader.Dispose();
            }

            if (_web != null) 
            {
                _web.Dispose();
            }
        }

        /// <summary>
        /// Get the source URL string for this datetime from the users GetSource() method in BaseData.
        /// 获取这个时间对应的文件URL
        /// </summary>
        /// <param name="date">DateTime we're requesting.</param>
        /// <returns>URL string of the source file</returns>
        public string GetSource(DateTime date)
        {
            var newSource = "";
            //Invoke our instance of this method.
            if (_dataFactory != null) 
            {
                try
                {
                    newSource = _dataFactory.GetSource(_config, date, _feedEndpoint);
                }
                catch (Exception err) 
                {
                    Log.Error("SubscriptionDataReader.GetSource(): " + err.Message);
                    Engine.ResultHandler.ErrorMessage("Error getting string source location for custom data source: " + err.Message, err.StackTrace);
                }
            }
            //Return the freshly calculated source URL.
            return newSource;
        }

        /// <summary>
        /// Opens up an IStreamReader for a local file source
        /// 打开一个本地文件数据流
        /// </summary>
        private IStreamReader HandleLocalFileSource(string source)
        {
            if (!File.Exists(source))
            {
                // the local uri doesn't exist, write an error and return null so we we don't try to get data for today
                Log.Trace("SubscriptionDataReader.GetReader(): Could not find QC Data, skipped: " + source);
                Engine.ResultHandler.SamplePerformance(_date.Date, 0);
                return null;
            }

            // handles zip or text files压缩文件或者文本文件都可以读取
            return new LocalFileSubscriptionStreamReader(source);
        }

        /// <summary>
        /// Opens up an IStreamReader for a remote file source
        /// 打开远端文件数据源
        /// </summary>
        private IStreamReader HandleRemoteSourceFile(string source)
        {
            // clean old files out of the cache
            if (!Directory.Exists(Constants.Cache)) Directory.CreateDirectory(Constants.Cache);
            foreach (var file in Directory.EnumerateFiles(Constants.Cache))
            {
                if (File.GetCreationTime(file) < DateTime.Now.AddHours(-24)) File.Delete(file);//一天前的文件都删除掉
            }

            try
            {
                // this will fire up a web client in order to download the 'source' file to the cache
                return new RemoteFileSubscriptionStreamReader(source, Constants.Cache);//创建一个远端文件读取流(先下载,后调用本地的读取流)
            }
            catch (Exception err)
            {
                Engine.ResultHandler.ErrorMessage("Error downloading custom data source file, skipped: " + source + " Err: " + err.Message, err.StackTrace);
                Engine.ResultHandler.SamplePerformance(_date.Date, 0);
                return null;
            }
        }
    }
}


基于QuantConnect开源引擎Lean本地实现Fama-French五因子Python策略 5.目录\ToolBox\CoarseUniverseGenerator\CoarseUniverseGeneratorProgram.cs下语句修改成var hasFundamentalData = true;目录\Common\Data\UniverseSelection\CoarseFundamentalDataProvider.cs下语句修改成return coarse.HasFundamentalData; 阅读详情

相关推荐

Tutorials:QuantConnect网站上的Jupyter笔记本教程,适用于Python,Finance和LEAN

QuantConnect LEAN教程 | | | 该存储库是WordPress和Jupyter笔记本教程的集合,这些教程针对LEAN展示了财务概念和LEAN。 教程分为每个类别和教程系列的文件夹。 Jupyter笔记本和关联HTML网页必须使用匹配的文件名。 HTML是使用wordpress生成并显示的。 精益引擎是一个开放源代码的完全托管的C#算法交易引擎,专为桌面和云使用而构建。 它是在Mono中设计的,可在Windows,Linux和Mac平台上运行。 有关LEAN算法交易引擎的更多信息,请参见引擎存储库。 新教程要求和编辑 请将新的教程请求作为问题提交给存储库。 在提交问题之前,请阅读其他内容以确保它不是重复的。 热烈欢迎进行编辑和修复以使内容更加清晰! 邮件列表 该项目的邮件列表可以在找到 贡献者和请求请求 我们非常欢迎您提供稿件,但请您阅读现有代码,以了解其格式,注释和确保

【亲测免费】 探索QuantConnect的开放源代码算法交易引擎——Lean

![QuantConnect Lean Logo](https://cdn.quantconnect.com/web/i/20180601-1615-lean-logo-small.png) --- ## 项目简介 QuantConnect的Lean引擎是一个强大的开放源代码算法交易平台,专为策略研究、回测和实时交易设计。它无缝支持C#和Python两种编程语言,并能在Linux、Mac和W...

gitblog_00063的博客 1854

基于STM32的便携式心率血氧监测系统 | 保姆式教程 开源可复刻

本项目基于STM32F103C8T6核心控制器,完整实现了便携式心率血氧监测系统的全功能开发,覆盖MAX30102光电传感器驱动、PPG信号处理、心率血氧解算算法、人机交互、数据存储、报警保护、低功耗管理等核心功能,全程采用无跳步保姆式教学,从硬件选型、接线、CubeMX配置、代码开发、调试优化全流程拆解,跟着步骤一步步操作,就能顺利完成项目复刻

ZhongWeiXiang9的博客 768

量化交易平台——QuantConnect Lean CLI

量化交易平台——QuantConnect Lean CLI lean-cliCLI for running the LEAN engine locally and in the cloud项目地址:https://gitcode.com/gh_mirrors/le/lean-cli QuantConnect的Lean CLI是一个跨平台的命令行工具,专为简化本地和云端LEAN引擎开发而设计。通...

gitblog_00046的博客 5068

CVE-2017-7921漏洞深度解析:海康设备明文密码泄露原理与七层防御

网络摄像头安全本质上是嵌入式Web服务安全,其核心在于身份认证机制是否健全。CVE-2017-7921并非传统远程执行漏洞,而是因信任错位导致的未授权API暴露——`/Security/users/1`接口绕过Session校验,直接返回admin明文密码。该问题根植于安防设备早期‘物理隔离+前端可控’的设计假设,在P2P、云平台等新场景下全面失效。技术价值在于揭示了轻量级HTTP服务中路径级访问控制缺失的普遍风险;典型应用场景包括ONVIF协议接管、Telnet后门登录及NVR侧横向移动。本文基于DS-2

weixin_33324197的博客 403

计算机考研408复试题汇总

TCP连接是全双工的,两端都可以先挥手 其中一端完成数据发送任务后,发送一个FIN包来终止,另一端针对这个FIN包回复确认包, 直到另一端也发送请求终止数据包FIN,另一端作出确认应答,并且还要发送一个ACK=1表示确认号有效,如果没有收到这个就可以进行重传.

ca1m4n的博客 1万+

【亲测免费】 QuantConnect Lean 项目教程

QuantConnect Lean 是一个开源的算法交易引擎,支持多种资产类别和市场。以下是其主要目录结构的介绍: - **.`/Algorithm.CSharp`**: 包含用C#编写的示例算法。 - **`/Algorithm.Python`**: 包含用Python编写的示例算法。 - **`/Brokerages`**: 包含与不同经纪商接口的实现。 - **`/Common`**: 包...

gitblog_00345的博客 1155

STM32CubeMX之DAC产成正弦波

“在之前的文章中曾经介绍过用TIM产生PWM做DAC用,STM32定时器输出PWM做DAC。部分型号的STM32单片机内部有专用的DAC,本篇文章将介绍如何用内部DAC+DMA产生正弦波...

zhang062061的专栏 1513

Windows环境联合开发:Docker Desktop QuantConnect Lean后端 & Panoptes GUI前端

以QuantConnect的开源框架Lean为核心量化回测、交易框架后端(使用Docker Desktop部署,免去开发环境、运行环境复杂配置); Panoptes为量化回测、交易框架前端(基于Avalonia,跨Windows、Linux等平台); 证券基础数据、基本面数据可随机生成(假数据,日常测试用),或者国信iQuant等第三方平台免费获取数据到本地再转换导入(真实数据,验证策略);

gregmankiw的博客 1072

9、储备池学习:从学习到学习的新范式

本文探讨了基于学习到学习(L2L)框架的储备池计算新范式,提出通过在外循环中优化储备池的超参数(如递归连接权重、输入权重和读出初始化),以提升其在多种任务中的内循环学习性能。研究展示了两种主要实验设置:一是优化储备池用于回归二阶Volterra滤波器任务,显著优于随机基线;二是实现无需调整读出权重、仅依赖内部动态学习非线性函数的能力,表明储备池可快速构建目标函数的内部模型并安装任务先验知识。结合流程图与表格,文章系统呈现了L2L的训练流程、技术细节及实验结果,并讨论了性能提升、泛化能力等开放问题,指出了未来

ujm56789012的博客 504

SAP Joule 经过了超过 2.5 亿行 ABAP 代码的训练之后......

披露的统计数据,Joule 提供的这种全新系统交互方式,可将事务性任务执行速度提高 90%,访问 SAP Help Portal 内容的速度提高 95%。在 ABAP 应用开发领域,SAP 官网数据显示,Joule 经过超过 2.5 亿行 ABAP 代码的训练,有信心成为这一领域行业领先的代码助手。刚刚过去的 SAP 蓝宝石大会上,SAP 提到,从2023年第四季度以来,SAP 已经交付了 50 项基于人工智能的创新。让其生成 SAP 应用能够识别的结构化应用数据,业务用户全程无需离开 SAP 应用程序。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 798

程序员的量化交易之路(33)--QuantConnect之案例1

转载需注明:http://blog.youkuaiyun.com/minimicall,http://cloudtrade.top/ 分析Cointrader有一定层度了,发现它毕竟不是一个产品,没有得到验证。在架构、编码等方面都非常的不规范。 想编写一个云交易平台,任道而重远。我们需要参照一些成熟的架构。 Quantopian的zipline不行,因为我就是看...

weixin_34364135的博客 4493

【Docker安装】Ubuntu 24.04.2 LTS系统下安装Docker环境——指定APT源安装方式

【Docker安装】Ubuntu 24.04.2 LTS系统下安装Docker环境——指定APT源安装方式

jks212454的博客 625

你应该知道的21大Python量化交易工具

技术可用性的快速增长使个人交易者也能够进行系统和算法交易。下面为大家分享2022年 Python 量化交易使用最广泛的21大交易平台和框架、经纪自营商、数据提供商和其他有用的交易库等,这些交易库适用于搭建个人完整的量化分析和交易系统。一、云交易平台 对于大多数人来说,开始进行算法交易的最佳方式是使用在线交易平台。这些平台提供了自动化交易所需要的基础...

Python金融量化 1万+

QT使用libssh2库通过密匙实现sftp协议上传文件

qt下使用libssh2通过密匙连接sftp服务器端

小米的修行之路 945

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

【亲测免费】 QuantConnect LEAN CLI 使用教程

QuantConnect LEAN CLI 是一个跨平台的命令行工具,旨在简化 LEAN 引擎的本地和云端开发。LEAN 引擎是 QuantConnect 提供的一个开源算法交易平台,支持回测、优化和实时交易。LEAN CLI 提供了丰富的功能,包括本地和云端的回测、优化、实时交易以及 Jupyter 研究环境等。 ## 2. 项目快速启动 ### 安装 LEAN CLI 首先,确保你已经安...

gitblog_01121的博客 1450

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

QuantConnect Lean:开源量化交易引擎的完整开发指南

QuantConnect Lean是一个功能强大的开源算法交易引擎,为量化投资者和开发者提供从策略研究到实盘部署的一站式解决方案。作为全球领先的量化交易平台QuantConnect的核心引擎,Lean支持多资产类别交易、高性能回测和实时交易执行,帮助开发者快速构建和部署专业的量化策略。 ## 1. 项目定位与核心价值 ### 1.1 为什么选择Lean引擎? Lean引擎凭借三大核心优势在量

gitblog_00803的博客 746

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

掌握专业量化交易:QuantConnect Lean引擎完全指南

在当今快速发展的金融市场中,算法交易正成为投资者获取超额收益的重要工具。QuantConnect Lean引擎作为一款功能强大的开源算法交易平台,为量化交易爱好者提供了从策略研究到实盘交易的全流程解决方案。无论你是初学者还是专业交易员,Lean都能帮助你构建、测试和部署高效的交易策略。 ## 为什么选择Lean量化交易平台 Lean引擎采用事件驱动的架构设计,支持C#和Python两种主流编程

gitblog_00107的博客 519

QuantConnect/Lean 项目推荐

QuantConnect/Lean 是一个专业的算法交易引擎,由 QuantConnect 公司开发。该项目支持 Python 和 C# 两种编程语言,旨在为量化交易者提供一个高效、灵活且易于扩展的平台。Lean 的设计理念是模块化和可插拔,使得开发者可以根据需要定制和扩展其功能。 ## 2. 项目的核心功能 Lean 的核心功能包括: - **事件驱动交易引擎**:支持实时和历史数据的事件...

gitblog_00596的博客 851

Lean与QuantConnect云平台:本地策略迁移指南

### 1.1 环境配置检查清单 | 环境要求 | 本地环境 | 云平台环境 | 配置方法 | |---------|---------|-----------|---------| | .NET SDK | 6.0+ | 自动配置 | [官方安装指南](https://dotnet.microsoft.com/download) | | Python | 3.8-3.10 | 3.10 | `...

gitblog_00221的博客 647

程序员的量化交易(34)--QuantConnect_Lean如何定义Indicator指标2

转载需注明出处:http://blog.youkuaiyun.com/minimicall,http://cloudtrade.top/ 指标(Indicator)由三大关键组件组成: 1. 实现你指标的类 2. 在ACAlgorithm基类中的Helper方法,用于简化对你指标实现的调用。 3. 测试方法用于测试指标的表现。 为了实现一个指标,上述所有组件需要...

weixin_34032792的博客 829

QuantConnect Lean算法交易引擎架构重构解析

QuantConnect Lean是一个开源的算法交易引擎,支持多种编程语言和金融工具。本文深入分析其架构设计,并提出模块化重构方案,帮助开发者构建更清晰、高效的交易系统。 ## 核心架构现状分析 Lean引擎当前采用分层架构设计,主要模块包括算法执行、数据处理、经纪商接口和性能分析等。从项目结构可以看出,系统已经实现了较好的模块分离,但在某些方面仍存在优化空间。 [![系统详细架构图](h

gitblog_00412的博客 374

QuantConnect开源框架Lean后端与Panoptes前端交互的一个测试案例

【代码】QuantConnect开源框架Lean后端与Panoptes前端交互的一个测试案例。

gregmankiw的博客 918

QuantConnect Lean CLI:量化交易工具的全栈开发与部署解决方案

QuantConnect Lean CLI 是一套功能完备的量化交易工具,专为算法交易开发打造的本地回测系统。该工具链基于 Python 构建,通过 Docker 容器化技术实现跨平台一致性,提供从策略编码、本地回测到云端部署的全流程支持。本文将详细介绍如何利用这套系统构建稳定高效的量化交易基础设施,实现多环境策略同步与性能优化。 ## 1. 核心优势解析 ### 1.1 技术架构概览 架构

gitblog_00423的博客 1211

Lean — 优秀好用的开源量化交易平台

Lean 是 QuantConnect 开源的一款非常强大的开源量化交易平台,可以回测或运行Python或者C#写的策略,并在代码仓库中内置了上百个C#和Python的策略算法。这个开源的...

Oner.wv的专栏 5919
上一篇: 程序员的量化交易之路(35)--Lean之DataFeed数据槽3
下一篇: 程序员的量化交易之路(37)--Lean之DataStream数据流5
minimicall
博客等级 码龄18年 407粉丝 174原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值