TB3流通市值过滤问题,无法获得流通市值并做上下限过滤

//------------------------------------------------------------------------ // 简称: StockPick_IndustryLeader // 名称: 选股-行业龙头 // 类别: 策略应用 // 类型: 内建应用 // 修改: 增加流通市值绝对值过滤(小于100亿、大于500亿,可分别启用) //------------------------------------------------------------------------ /* 行业龙头,30天成交额前10%,流通市值前10%,主营收入前30%,盈利,取120日涨跌幅前5% */ Params enum<String> IndustrytypeID(["F101022","F101021","F101026","F101003"]); //F101022:申万2级分类 F101021:申万1级分类F101026:ZJH分类 F101003:TB分类 String IndustryLeader ("行业龙头"); //推送到行情报价的三级板块名 Numeric MarkNumber(2); //标记的号码 Array<Numeric> TurnoverPCT([30,10]); //n天成交金额排名前m,n=TurnoverPCT[0],m=TurnoverPCT[1] Numeric MarketCapPCT(10); //流通市值前10% Numeric RevenuePCT(30); //营业收入前30% Array<Numeric> zdfPCT([120,5]); //满足前面所有条件的按n日涨跌幅排序取前面m,n=zdfPCT[0],m=zdfPCT[1] Numeric CrossDate(20260515); //选股的截面日期 Numeric writelog(0); //1写log,否则不写log // ==== 新增参数:流通市值绝对值过滤 ==== Bool EnableMinMarketCap(True); // 是否启用最小市值过滤(True:启用, False:禁用) Numeric MinMarketCap(100); // 最小流通市值(亿元),小于此值将被过滤 Bool EnableMaxMarketCap(True); // 是否启用最大市值过滤(True:启用, False:禁用) Numeric MaxMarketCap(500); // 最大流通市值(亿元),大于此值将被过滤 Vars //基础数据定义 Dic<Array<Numeric>> tbCapital("TB_CAPITAL_CIRCULATIONSHARES"); //数据中心》基础数据》股本结构》流通股份 Dic<Array<Numeric>> tbRevenue("TB_INCOME_REVENUE"); //数据中心》基础数据》利润分配表》营业收入 Dic<Array<Numeric>> tbprofit("TB_INCOME_PROFIT"); //数据中心》基础数据》利润分配表》利润汇总 //循环订阅所有板块,不需要重置 Global Numeric IdyNum(0); //当前板块在板块数组IdyNamearr的序号 Global Array<String> IdyNamearr; //板块数组 Global Integer i(0); //需要重置区域 //推送选股和标记专用 Global String tmpSyms; //自定义合约的股票 Global String tmpIds; Global String tmpDesps; //其它变量 Global Array<Numeric> mv; //流通市值(亿元) Global Array<Numeric> zdf120; //涨跌幅 Global Array<Numeric> turnover30; //成交金额 Global Array<Numeric> revenue; //营业收入 Global Array<Numeric> profit; //净利润 Global Array<Numeric> flag; //选股标识 Global Array<Integer> BarStatus2Flag(0); //数据源到最后一根的标识 Global Integer BarStatus2FlagCount(0);//数据源满足最后一根的个数 Defs //写日志,方便代码调试 Integer msgbox(StringRef msg) { if(writelog==1) FileAppend(".\\log\\"+FormulaName, "[" + DateTimeToString(SystemDateTime) + "] " + msg); Return 0; } //从基础数据读取行业板块名称,依据板块名称从基础数据读取板块内品种名称,订阅品种bar数据 Bool SubscribeData() { //清空数组,准备新的板块选股 ArrayClear(mv); ArrayClear(zdf120); ArrayClear(turnover30); ArrayClear(revenue); ArrayClear(profit); ArrayClear(flag); ArrayClear(BarStatus2Flag);//清空标识 BarStatus2FlagCount=0; //获取当前是第几个板块 if(IdyNum==0) { if(IndustrytypeID=="F101003") IdyNum=1;//F101003第0个值的板块为全部,所以从1开始是行业板块 GetDicValue("TB_INDUSTRY",IndustrytypeID,CrossDate,IdyNamearr); } //写日志 msgbox("idnum="+Text(IdyNum)+"/"+Text(GetArraySize(IdyNamearr)-1)); //获取A股所有板块 //订阅数据,追加的数据源 Array<String> subSymbols; //板块节点(科创板) 如果为空则不再添加数据 String IdyName=IdyNamearr[IdyNum]; PushStatusMsg("正在执行["+IdyName+"],"+Text(IdyNum)+"/"+Text(GetArraySize(IdyNamearr)-1)); if(IdyName<>"") { GetDicValue("TB_INDUSTRY",IdyName,SystemDateTime(),subSymbols); } msgbox(TextArray(subSymbols)); for i=0 to GetArraySize(subSymbols)-1 { msgbox("起始日期"+text(DateAdd(CrossDate,-180))); SubscribeBar(subSymbols[i],"1d",DateAdd(CrossDate,-180),CrossDate); //msgbox("订阅"+subSymbols[i]+"成功"); //Else //msgbox("订阅"+subSymbols[i]+"失败"); } Range[0:DataCount-1] { AddDataFlag(Enum_Data_RolloverBackWard());//设置后复权 } Return True; } //1、检查订阅数据的完整性,对于空数据的品种进行退订。2、设置后复权 Bool CheckData() { Integer datanum; Array<Integer> BarCountarr; //统计下各数据源的bar数 Range[i=0:DataCount-1] { BarCountarr[i]=BarCount; } msgbox(TextArray(BarCountarr)); msgbox("检查前数据源数量="+text(DataCount)); //倒序剔除无数据的数据源 datanum=DataCount; for i=0 to DataCount-1 { if(BarCountarr[datanum-1-i]==0 or BarCountarr[datanum-1-i]==InvalidInteger) { //msgbox("删除数据,因为bar数目="+Text(BarCountarr[datanum-1-i])); UnsubscribeBar(datanum-1-i); } } msgbox("检查后数据源数量="+text(DataCount)); if(DataCount==0) { IdyNum=IdyNum+1; //选过的板块数量加1 if(IdyNum<GetArraySize(IdyNamearr)) { ReStart(false); //重启订阅下一个板块 }Else { PushStatusMsg("选股完成"); AddStrategyFlag(Enum_Strategy_Finished);//正常停止策略运行 } } Return True; } //计算指标 //计算指标 Bool countIndicators() { Range[i=0:DataCount-1] { // 无条件执行序列函数(每根Bar都会调用,避免警告) Numeric tempTurnover30 = Summation(TurnOver, TurnoverPCT[0]); if(((BarCount==1 && barstatus==0) ||barstatus==2) && BarStatus2Flag[i]==0) { if(close==InvalidNumeric) { mv[i]=-1; zdf120[i]=-1; turnover30[i]=-1; } Else { zdf120[i]=close/close[zdfPCT[0]]; mv[i]=close/Rollover*tbCapital[0][1]*0.0001*0.0001; turnover30[i] = tempTurnover30; // 只在最后一根Bar记录 } revenue[i]=tbRevenue[0][1]; profit[i]=tbprofit[0][11]; BarStatus2Flag[i]=1; BarStatus2FlagCount=BarStatus2FlagCount+1; msgbox(TextArray(BarStatus2Flag)); } } Return True; } //指标排序 Bool SortIndicators() { //站在data0上对所有品种进行排序,最后结果存为一个数组 msgbox("开始排序!"); msgbox(TextArray(BarStatus2Flag)); msgbox(TextArray(zdf120)); //确认数值都获取到 msgbox(TextArray(mv)); msgbox(TextArray(turnover30)); msgbox(TextArray(revenue)); msgbox(TextArray(profit)); // 1. 流通市值排名前MarketCapPCT% Array<Integer> id1; Array<Integer> id2; for i=0 to DataCount-1 //下标数组的初始化赋值 { id1[i]=i; id2[i]=i; } SortIds(mv,id1,id2,0,DataCount-1,False);//对流通市值进行倒序排序 Array<Numeric> flagmv; for i=0 to DataCount-1 { if(id2[i]<DataCount*MarketCapPCT*0.01) //选择排名考前的标识为1 flagmv[i]=1; Else flagmv[i]=0; } // 2. 新增:流通市值绝对值过滤(小于MinMarketCap或大于MaxMarketCap) Array<Numeric> flagMarketCapAbs; for i=0 to DataCount-1 { flagMarketCapAbs[i] = 1; // 默认通过 if(EnableMinMarketCap and mv[i] < MinMarketCap) flagMarketCapAbs[i] = 0; if(EnableMaxMarketCap and mv[i] > MaxMarketCap) flagMarketCapAbs[i] = 0; } // 日志输出市值过滤情况 if(EnableMinMarketCap or EnableMaxMarketCap) { Integer passCount = 0; for i=0 to DataCount-1 if(flagMarketCapAbs[i]==1) passCount = passCount + 1; msgbox("市值绝对值过滤:启用最小"+IIFString(EnableMinMarketCap,Text(MinMarketCap)+"亿","否")+ ",启用最大"+IIFString(EnableMaxMarketCap,Text(MaxMarketCap)+"亿","否")+ ",通过数量="+Text(passCount)+"/"+Text(DataCount)); } // 3. 30天成交额排名前TurnoverPCT[1]% ArrayClear(id1); ArrayClear(id2); for i=0 to DataCount-1 { id1[i]=i; id2[i]=i; } SortIds(turnover30,id1,id2,0,DataCount-1,False); Array<Numeric> flagturnover30; for i=0 to DataCount-1 { if(id2[i]<DataCount*TurnoverPCT[1]*0.01) flagturnover30[i]=1; Else flagturnover30[i]=0; } // 4. 营业收入排名前RevenuePCT% ArrayClear(id1); ArrayClear(id2); for i=0 to DataCount-1 { id1[i]=i; id2[i]=i; } SortIds(revenue,id1,id2,0,DataCount-1,False); Array<Numeric> flagrevenue; for i=0 to DataCount-1 { if(id2[i]<DataCount*RevenuePCT*0.01) flagrevenue[i]=1; Else flagrevenue[i]=0; } // 5. 盈利过滤(净利润>0) Array<Numeric> flagprofit; for i=0 to DataCount-1 { if(profit[i]>0) flagprofit[i]=1; Else flagprofit[i]=0; } // 日志输出各条件计数 msgbox(TextArray(flagmv)); msgbox(TextArray(flagturnover30)); msgbox(TextArray(flagrevenue)); msgbox(TextArray(flagprofit)); // 6. 汇总所有条件(原4项 + 新增市值绝对值过滤) Array<Numeric> flag1; for i=0 to DataCount-1 { flag1[i]=flagmv[i]*flagturnover30[i]*flagrevenue[i]*flagprofit[i]*flagMarketCapAbs[i]; } // 7. 按涨跌幅排序,取前zdfPCT[1]% ArrayClear(id1); ArrayClear(id2); for i=0 to DataCount-1 { id1[i]=i; id2[i]=i; } SortIds(zdf120,id1,id2,0,DataCount-1,False); Numeric k=0; Numeric targetCount = RoundUp(zdfPCT[1]*0.01*DataCount,0); for i=0 to DataCount-1 //循环选取股票,当达到数量上限则停止选股 { if(flag1[id1[i]]==1 and k<targetCount) { flag[id1[i]]=1; k=k+1; } Else flag[id1[i]]=0; } msgbox("最终入选股票数量="+Text(k)); Return True; } //选股并推送到板块 Bool PickStock_Send() { if(GetArraySize(flag)>0) { msgbox(TextArray(flag)); } Range[i=0:DataCount-1] { if(flag[i]==1) { tmpSyms = tmpSyms+Symbol+","; tmpIds=tmpIds+Text(MarkNumber)+","; //写标记 tmpDesps=tmpDesps+Text(SystemDateTime,9)+","; } } Map<String,String> context; //写标记用 Map<String,String> mySyms; //推送自定义合约的MAP mySyms["合约集合"]=tmpSyms;//选股合约 mySyms["板块名称"]="策略选择_"+IndustryLeader ;//自定义行情设置,格式是:一级板块_二级板块 If(IdyNum==1) mySyms["添加方式"]="override";//更新方式:override,append Else mySyms["添加方式"]="append"; context["合约集合"]=tmpSyms;//选股合约 context["标记编号集合"]=tmpIds;//合约标记ID【1-10】 context["标记内容集合"]=tmpDesps;//标记内容 if(tmpSyms<>"") { PublishEvent("系统-选股事件",mySyms,"行情报价");//发送选股事件到行情报价 PublishEvent("系统-标记事件",context,"行情报价"); //写标记 } tmpSyms=""; tmpIds=""; tmpDesps=""; IdyNum=IdyNum+1; //选过的板块数量加1 if(IdyNum<GetArraySize(IdyNamearr)) { ReStart(false); //重启订阅下一个板块 }Else { PushStatusMsg("选股完成"); AddStrategyFlag(Enum_Strategy_Finished);//正常停止策略运行 } Return True; } Events OnInit() { //订阅数据 SubscribeData(); } OnReady() { //检查数据 CheckData(); } OnBar(ArrayRef<Integer> indexs) { //计算指标 countIndicators(); //指标排序 //所有数据源都结束再选股 if(BarStatus2FlagCount==DataCount) { SortIndicators(); //选股并推送到板块 PickStock_Send(); } } //------------------------------------------------------------------------ // 编译版本 GS2010.12.08 // 版权所有 TradeBlazer Software 2003-2045 // 更改声明 TradeBlazer Software保留对TradeBlazer平 // 台每一版本的TradeBlazer公式修改和重写的权利 //------------------------------------------------------------------------TB3流通市值过滤问题,无法获得流通市值并做上下限过滤,比如过滤掉流通市值小于100亿,大于500亿的股票。麻烦老师指点一下,谢谢!

回复:QS这类属于一级键名、实时更新数据吧?麻烦老师看下以下代码加载有Jigou(提示敏感词,拼音代替)的股票为什么无法获取数据,是否使用方法不对,是否需要单独订阅相关数据。Vars Array<Numeric> arrInstNum; // 用于接收数合计数据 Numeric totalInst; // 存储最终的总数Events{ OnInit() { // 在 OnInit 中订阅基础数据 SubscribeDic("TB_QS_033", Symbol); } OnBar(ArrayRef<Integer> indexs) { Range[0:DataSourceSize()-1] { // 使用数组接收数据(正确用法) If(GetDicValue("TB_QS_033", Symbol, Date, arrInstNum) And GetArraySize(arrInstNum) > 0) { totalInst = arrInstNum[0]; // 总数通常在索引0 Commentary(Symbol + " 总数: " + Text(totalInst)); } Else { Commentary(Symbol + " 未能读取数据"); } } }}

回复:Vars    Array<Numeric> arrInstNum;   // 用于接收数合计数据    Numeric totalInst;           // 存储最终的总数 Events    OnInit()    {        // 在 OnInit 中订阅基础数据        SubscribeDic("TB_QS_033", Symbol);    }        OnBar(ArrayRef<Integer> indexs)    {        Range[0:DataSourceSize()-1]        {            // 使用数组接收数据(正确用法)            If(GetDicValue("TB_QS_033", Symbol, Date, arrInstNum) And GetArraySize(arrInstNum) > 0)            {                totalInst = arrInstNum[0];  // 总数通常在索引0                Commentary(Symbol + " 总数: " + Text(totalInst));            }            Else            {                Commentary(Symbol + " 未能读取数据");            }        }    }  更正一下上面代码

有没有函数可以直接查询流值和PE?

是不能用了吗?有没有其他替代的过滤方法?