程序员的量化交易之路(37)--Lean之DataStream数据流5

激光SLAM算法性能对比:在Ubuntu20.04上实测Point-LIO/FAST_LIO2/Faster-LIO的运行效果 本文在Ubuntu 20.04平台上对Point-LIO、FAST-LIO2和Faster-LIO三款激光SLAM算法进行了深度实测与性能对比。通过量化分析绝对轨迹误差、CPU/内存占用及单帧处理延迟等核心指标,结合室内外场景数据,为高精度测绘、服务机器人及自动驾驶等不同应用场景提供了清晰的选型指南和实战调优建议。 阅读详情

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

我们之前说明了数据读者,数据槽。将数据读取到队列中,在算法主线程中需要使用DataFeed线程的数据。这是一个典型的读者-写着问题。

在主线程中和DataFeed打教导的事DataStream。下面我们看它的代码。说明在注释中说明了。

/*
 * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
 * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); 
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at http://www.apache.org /licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/

using System;
using System.Collections.Generic;
using System.Threading;
using System.Diagnostics;
using System.Linq;
using QuantConnect.Data;
using QuantConnect.Lean.Engine.DataFeeds;
using QuantConnect.Logging;

namespace QuantConnect.Lean.Engine
{
    /******************************************************** 
    * QUANTCONNECT NAMESPACES
    *********************************************************/
    /// <summary>
    /// Data stream class takes a datafeed hander and converts it into a synchronized enumerable data format for looping 
    /// 数据流类,拥有数据槽句柄,然后将数据转化为同步可枚举的,用作循环。
    /// in the primary algorithm thread.
    /// </summary>
    public static class DataStream
    {
        /******************************************************** 
        * CLASS VARIABLES
        *********************************************************/
        //Count of bridges and subscriptions.
        //订阅数,就是addSecurity添加的证券数量
        private static int _subscriptions;

        /******************************************************** 
        * CLASS PROPERTIES
        *********************************************************/

        /// <summary>
        /// The frontier time of the data stream
        /// 
        /// </summary>
        public static DateTime AlgorithmTime { get; private set; }

        /******************************************************** 
        * CLASS METHODS
        *********************************************************/
        /// <summary>
        /// Process over the datafeed cross thread bridges to generate an enumerable sorted collection of the data, ready for a consumer
        /// to use and already synchronized in time.
        /// </summary>
        /// <param name="feed">DataFeed object</param>
        /// <param name="frontierOrigin">Starting date for the data feed</param>
        /// <returns></returns>
        public static IEnumerable<Dictionary<int, List<BaseData>>> GetData(IDataFeed feed, DateTime frontierOrigin)
        {
            //Initialize:
            _subscriptions = feed.Subscriptions.Count;//订阅的证券数量
            AlgorithmTime = frontierOrigin;//算法前置时间
            long algorithmTime = AlgorithmTime.Ticks;//获取时间tick
            var frontier = frontierOrigin;
            var nextEmitTime = DateTime.MinValue;
            var periods = feed.Subscriptions.Select(x => x.Resolution.ToTimeSpan()).ToArray();

            //Wait for datafeeds to be ready, wait for first data to arrive:
            while (feed.Bridge.Length != _subscriptions) Thread.Sleep(100);

            // clear data first when in live mode, start with fresh data
            if (Engine.LiveMode)
            {
                feed.PurgeData();
            }

            //Get all data in queues: return as a sorted dictionary:
            //获取队列中的所有数据,以排序好的字典返回
            while (!feed.EndOfBridges)
            {
                //Reset items which are not fill forward:
                long earlyBirdTicks = 0;
                var newData = new Dictionary<int, List<BaseData>>();

                // spin wait until the feed catches up to our frontier
                WaitForDataOrEndOfBridges(feed, frontier);

                for (var i = 0; i < _subscriptions; i++)
                {
                    //If there's data on the bridge, check to see if it's time to pull it off, if it's in the future
                    // we'll record the time as 'earlyBirdTicks' so we can fast forward the frontier time
                    while (!feed.Bridge[i].IsEmpty)//第i个证券中有数据
                    {
                        //Look at first item on list, leave it there until time passes this item.
                        //检查链表中第一个条目
                        List<BaseData> result;
                        if (!feed.Bridge[i].TryPeek(out result))
                        {
                            // if there's no item skip to the next subscription
                            //如果这个证券没有数据,那么就直接跳到下一个证券
                            break;
                        }
                        if (result.Count > 0 && result[0].EndTime > frontier)
                        {
                            // we have at least one item, check to see if its in ahead of the frontier,
                            // if so, keep track of how many ticks in the future it is
                            if (earlyBirdTicks == 0 || earlyBirdTicks > result[0].EndTime.Ticks)
                            {
                                earlyBirdTicks = result[0].EndTime.Ticks;
                            }
                            break;
                        }
                        if (result.Count > 0)
                        {
                            // we have at least one item, check to see if its in ahead of the frontier,
                            // if so, keep track of how many ticks in the future it is
                            if (earlyBirdTicks == 0 || earlyBirdTicks > result[0].EndTime.Ticks)
                            {
                                earlyBirdTicks = result[0].EndTime.Ticks;
                            }
                        }

                        //Pull a grouped time list out of the bridge
                        List<BaseData> dataPoints;
                        if (feed.Bridge[i].TryDequeue(out dataPoints))
                        {
                            // round the time down based on the requested resolution for fill forward data
                            // this is a temporary fix, long term fill forward logic should be moved into this class
                            foreach (var point in dataPoints)
                            {
                                if (algorithmTime < point.EndTime.Ticks)
                                {
                                    // set this to most advanced end point in time, pre rounding
                                    // min  10:02  10:02:01(FF) 10:02:01.01(FF)
                                    // sec  10:02  10:02:01     10:02:01.01(FF)
                                    // tic  10:02  10:02:01     10:02:01.01
                                    // the algorithm time should always be the 'frontier' the furthest
                                    // time within this data slice
                                    algorithmTime = point.EndTime.Ticks;
                                }
                                if (point.IsFillForward)
                                {
                                    point.Time = point.Time.RoundDown(periods[i]);
                                }
                            }
                            // add the list to the collection to be yielded
                            List<BaseData> dp;
                            if (!newData.TryGetValue(i, out dp))
                            {
                                dp = new List<BaseData>();
                                newData[i] = dp;
                            }
                            dp.AddRange(dataPoints);
                        }
                        else
                        {
                            //Should never fail:
                            Log.Error("DataStream.GetData(): Failed to dequeue bridge item");
                        }
                    }
                }

                if (newData.Count > 0)
                {
                    AlgorithmTime = new DateTime(algorithmTime);
                    yield return newData;
                }

                //Update the frontier and start again.
                if (earlyBirdTicks > 0)
                {
                    //Seek forward in time to next data event from stream: there's nothing here for us to do now: why loop over empty seconds
                    frontier = new DateTime(earlyBirdTicks);
                }
                else if (feed.EndOfBridges)
                {
                    // we're out of data or quit
                    break;
                }

                //Allow loop pass through emits every second to allow event handling (liquidate/stop/ect...)
                if (Engine.LiveMode && DateTime.Now > nextEmitTime)
                {
                    AlgorithmTime = DateTime.Now.RoundDown(periods.Min());
                    nextEmitTime = DateTime.Now + TimeSpan.FromSeconds(1);
                    yield return new Dictionary<int, List<BaseData>>();
                }
            }
            Log.Trace("DataStream.GetData(): All Streams Completed.");
        }

        /// <summary>
        /// Waits until the data feed is ready for the data stream to pull data from it.
        /// 等待数据槽准备好了,可以从里面拉取数据
        /// </summary>
        /// <param name="feed">The IDataFeed instance populating the bridges</param>
        /// <param name="dataStreamFrontier">The frontier of the data stream</param>
        private static void WaitForDataOrEndOfBridges(IDataFeed feed, DateTime dataStreamFrontier)
        {
            //Make sure all bridges have data to to peek sync properly.
            var now = Stopwatch.StartNew();

            // timeout to prevent infinite looping here -- 50ms for live and 30sec for non-live
            var loopTimeout = (Engine.LiveMode) ? 50 : 30000;

            if (Engine.LiveMode)
            {
                // give some time to the other threads in live mode
                Thread.Sleep(1);
            }

            //Waiting for data in the bridges:
            while (!AllBridgesHaveData(feed) && now.ElapsedMilliseconds < loopTimeout)
            {
                Thread.Sleep(1);
            }

            //we want to verify that our data stream is never ahead of our data feed.
            //this acts as a virtual lock around the bridge so we can wait for the feed
            //to be ahead of us
            // if we're out of data then the feed will never update (it will stay here forever if there's no more data, so use a timeout!!)
            while (dataStreamFrontier > feed.LoadedDataFrontier && (!feed.EndOfBridges && !feed.LoadingComplete) && now.ElapsedMilliseconds < loopTimeout)
            {
                Thread.Sleep(1);
            }
        }


        /// <summary>
        /// Check if all the bridges have data or are dead before starting the analysis
        /// 
        /// This determines whether or not the data stream can pull data from the data feed.
        /// </summary>
        /// <param name="feed">Feed Interface with concurrent connection between producer and consumer</param>
        /// <returns>Boolean true more data to download</returns>
        private static bool AllBridgesHaveData(IDataFeed feed)
        {
            //Lock on the bridge to scan if it has data:
            for (var i = 0; i < _subscriptions; i++)
            {
                if (feed.EndOfBridge[i]) continue;
                if (feed.Bridge[i].IsEmpty)
                {
                    return false;
                }
            }
            return true;
        }

        /// <summary>
        /// Resets the frontier time to DateTime.MinValue
        /// </summary>
        public static void ResetFrontier()
        {
            AlgorithmTime = new DateTime();
        }
    }
}


手把手教你学Simulink——基于Simulink的无感FOC(滑模观测器+PLL)实战 本文详细介绍了基于Simulink的无感FOC(滑模观测器+PLL)实现方法。主要内容包括:1)SMO+PLL原理精讲,阐述滑模观测器核心思想和PLL的作用;2)系统架构全景图展示;3)Simulink建模全流程,从基础FOC框架到SMO和PLL模块的实现;4)关键参数整定指南和工程实践要点;5)仿真结果分析及常见问题解决方案。该方法可有效替代机械传感器,降低成本并提高可靠性,适用于空调压缩机、电动汽车水泵等工业场景。文章还提供了详细的调试建议和动手实践指导。 阅读详情

相关推荐

QT播放器插件内嵌浏览器配合流媒体实现国标摄像头网页端播放

基本原理在浏览器⽹页中的指定播放窗口的位置和⼤⼩,实现⼀个内嵌到⽹页中显⽰的播放窗⼝,前端还必须可对这个内嵌播放窗⼝进⾏控制,⽽且播放窗⼝必须跟随浏览器窗⼝的移动和缩放、⽹页滚动、标签页切换、关闭等操作进⾏⾃动联动。播放器可以通过QT实现。这个播放窗⼝同时提供Web Socket的服务端和JSON打包命令的解析执⾏模块,前端就可以通过Web Socket连接后发送JSON打包的控制命令实现控制播放窗⼝。

cameravision的博客 562

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

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

Oner.wv的专栏 5919

《Linux运维总结:etcd 3.5.15集群数据备份与恢复》

《Linux运维总结:etcd 3.5.15集群数据备份与恢复》

东城绝神 1080

量化交易平台——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

DDR5内存命令真值表详解:如何正确解析JESD79-5标准中的关键指令

本文深度解析JESD79-5标准中的DDR5内存命令真值表,将其视为动态通信协议进行拆解。详细阐述了1-Cycle与2-Cycle命令的区别、Bank Group寻址机制以及模式寄存器(MR)操作流程,为硬件与固件工程师提供了从信号解析到系统调试的完整实战指南,是理解和优化高性能计算平台内存子系统的核心。

numpy6sculptor的博客 548

STM32测测速---编码电机读取速度的计算

速度计算:轮胎每转一圈的脉冲数取决于编码器的分辨率,可由下面公式进行计算:PPR是电机的线数最后可以计算轮胎每转一圈的脉冲数为:轮胎每转一圈的脉冲数 = 9.6 × 11 × 4 = 422.4最后的速度公式简化为:速度 = (0.01 秒内产生的脉冲数 ∗ 0.055 ∗ π )/(0.01 ∗422.4​。

weixin_69414084的博客 3811

引用:Lean方法旨在通过减少浪费和增加价值来提高生产效率

流程改进,指在原有工作流程的基础上,通过识别、分析、评估、优化和重构等方法,对流程进行改进,以达到提高工作质量、效率、降低成本、优化资源利用、保障产品安全生产等目的的过程。流程改进旨在发现和消除流程中的瓶颈、缺陷和浪费,优化和重构流程以提高工作效率、提高产品的品质、增强组织的竞争力。引用:增长黑客的方法与精益创业不同,它侧重于在验证产品的需求和解决方案后,通过快速试验和迭代来实现用户增长、激活和留存,并在此过程中寻找新的增长点。Lean方法是一种优化生产流程的方法,它通过减少浪费和优化价值流来提高效率。

[Blog][Domain] programb.blog.youkuaiyun.com 1112

NEU-DET 冷轧钢缺陷检测:基于 YOLOv8 的目标检测与可视化 UI 实现

冷轧钢的生产过程中,由于设备故障、工艺问题或者人为因素,钢板表面可能会出现多种缺陷,如划痕、裂纹、孔洞等,这些缺陷会严重影响钢材的质量。它比之前的版本(如 YOLOv5、YOLOv4)在速度和精度上都有显著提升,并且对硬件要求较低,适合进行工业界面和嵌入式系统的应用。这些版本相较于更大型的模型(如 YOLOv8x)具有更快的推理速度和较低的资源占用,适合工业生产线中的实时应用。通过将训练好的模型部署到工业生产线摄像头中,我们可以实现实时的缺陷检测,极大地提升生产效率和产品质量。

YOLO 737

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

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

weixin_34032792的博客 829

【第1章>第5节】SOM自组织映射网络的理论学习与MATLAB仿真

自组织映射网络(Self-Organizing Map,SOM)是一种无监督学习的人工神经网络,由芬兰学者Teuvo Kohonen于1981年提出,也被称为Kohonen网络。它的主要功能是将高维输入数据映射到低维(通常是二维)的离散网格上,同时保持输入数据的拓扑结构,即相邻的输入数据在映射后的网格上也相邻。

FPGA/MATLAB学习教程/源码/项目合作开发 403

从数据库到数据仓库:数据仓库导论

本文为数据仓库导论,旨在介绍数据仓库的基本理念和应用场景,帮助读者理解数据仓库的重要性及其在企业中的实际应用。

探索大数据世界 - 深入解析数据存储、分布式计算与人工智能 2784

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

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

gitblog_00107的博客 519

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

量化交易平台Lean引擎深度解析与实战指南

在当今数字化金融时代,QuantConnect Lean引擎作为一款功能强大的开源算法交易平台,为投资者提供了从策略研究到实盘交易的全流程解决方案。无论你是量化交易新手还是经验丰富的开发者,Lean都能帮助你构建、测试和部署高效的交易策略,在竞争激烈的市场中获取稳定收益。 ## 平台核心特性深度剖析 Lean采用事件驱动架构设计,支持C#和Python双语言开发,兼容多种操作系统,为量化交易提供

gitblog_01083的博客 938

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

Lean数据类型详解:TradeBar、Tick与Quote数据处理

在量化交易(Quantitative Trading)系统中,市场数据是策略决策的基础。Lean算法交易引擎(Algorithmic Trading Engine)作为QuantConnect推出的开源框架,支持多种市场数据类型的处理,其中**TradeBar**、**Tick**与**Quote**是最核心的三种数据结构。本文将深入剖析这三种数据类型的定义、应用场景及处理方法,帮助开发者构建更精...

gitblog_00727的博客 660

如何通过Lean实现专业量化交易?4个维度全面解析

在金融市场竞争日益激烈的今天,量化交易已成为获取稳定收益的核心手段。然而,从零构建交易系统面临开发门槛高、数据整合难、实盘部署复杂等痛点。QuantConnect Lean引擎作为开源量化交易平台的佼佼者,通过事件驱动架构与模块化设计,为开发者提供从策略研发到实盘交易的全流程解决方案,支持C#与Python双语言开发,让量化策略落地效率提升60%。 ## 定位量化交易价值:解锁Lean引擎的核心

gitblog_01130的博客 740

如何用Lean引擎实现量化交易自动化?从入门到实盘的完整指南

在金融市场的数字化转型浪潮中,量化交易已成为普通投资者与专业机构同台竞技的重要工具。然而传统交易方式面临三大核心痛点:人工操作效率低下、策略验证周期漫长、实盘执行风险难控。QuantConnect Lean引擎作为开源量化交易领域的标杆解决方案,通过模块化设计与跨语言支持,为交易者提供了从策略研发到实盘部署的全流程自动化工具链。本文将以"核心价值-场景应用-实践指南-深度拓展"为框架,帮助不同技术

gitblog_00209的博客 887

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

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

gregmankiw的博客 1072

八大优秀开源量化交易系统

QuantConnect是一个基于云的算法交易平台,包含了backtester、研究环境、实时交易等多种量化工具。- 一款基于C#的算法交易开源框架。- 一个为机器学习驱动的算法交易策略而设计的开源平台,整合了TensorFlow和诸多经典算法交易库。- 一款用Python编写的功能库,专注于帮助开发者进行回测和交易策略设计,特色是框架易用性高。- 一个由Enigma开发的Python开源量化交易框架,有良好的文档和社区支持。- 一个用Python编写的事件驱动的算法交易库,包含了回测和实时交易模块。

宋志辉的博客 8073

探索量化交易的未来:QuantConnect深度解读

探索量化交易的未来:QuantConnect深度解读 DocumentationQuantConnect Wiki Style Documentation Behind QuantConnect项目地址:https://gitcode.com/gh_mirrors/documentation11/Documentation 在金融技术的浩瀚宇宙中,QuantConnect犹如一颗璀璨的新星,以...

gitblog_00046的博客 4661

Lean量化交易平台完整使用指南:从零构建智能交易系统

在当今金融科技快速发展的时代,如何快速构建专业的量化交易策略?QuantConnect的Lean开源算法交易引擎为你提供了完美的解决方案。这个强大的平台支持C#和Python双语言开发,能够进行策略研究、历史回测和实时交易,是量化金融领域的终极工具。 ## 平台核心架构解析 Lean量化交易平台采用模块化设计,整体架构清晰高效: [![量化交易平台架构图](https://raw.gitco

gitblog_00006的博客 825

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

转载需注明出处:http://blog.youkuaiyun.com/minimicall?viewmode=contents,http://cloudtrade.top 数据读取需要定义一个读者。直接见下面代码: namespace QuantConnect.Lean.Engine.DataFeeds { /**********************...

weixin_34277853的博客 420

微软开源!世界首个AI量化投资平台 Qlib 基本使用教程

量化往期推荐Easytrader 超简单的股市自动交易神器Lean — 优秀好用的开源量化交易平台30分钟教你搭建普罗监控系统—股票人气榜实时变化!可转债交易薅羊毛策略 — Python ...

Python实用宝典网 6577

Lean量化交易引擎完整指南:从零构建专业级算法交易系统

Lean量化交易引擎是QuantConnect开发的开源算法交易平台,支持Python和C#双语言开发,提供从数据获取、策略编写到回测分析的全流程解决方案。无论你是量化交易新手还是有经验的开发者,都能通过本文快速掌握这一强大工具的核心功能与应用方法,从零构建专业级交易系统。 ## 为什么选择Lean量化引擎? 在众多量化交易框架中,**Lean量化交易引擎**凭借其独特优势脱颖而出。作为一款开

gitblog_00279的博客 762

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

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

gitblog_01121的博客 1450

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

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

gitblog_00423的博客 1211
上一篇: 程序员的量化交易之路(36)--Lean之数据读取SubscriptionDataReader4
下一篇: 程序员的量化交易之路(38)--Lean之实时事件处理接口IRealTimeHandler和RealTimeEvent6
minimicall
博客等级 码龄18年 407粉丝 174原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值