最近公司的产品系统要重构,但是时间又比较紧迫,所以底层的结构如mongo mq的连接操作就直接用之前的jar包了,目前系统采用的maven多module模块模式,最可耻的是webframework是用的play,而且大家也觉得替换spring在短时间内不好实现。所以只好去把paly服务作为module集成到maven中了,这块任务交到我这里那就做吧,相关资料少之又少,通过git源码及联系原作者,终于用maven play plugin的方式将play集成到maven中去了。下一步我的开发任务便是业务指标的梳理,整体上包括三部分:取数据的dateOperation层、algorithm层及指标计算层:即指标计算层调用其它两层从而计算出指标。
dataOperation层: 1)简单的mongo的crud操作,写成工具类的形式;2)策略模式实现不同的取数及计算规则,返回指标计算想要的中间值。
algor层:仅仅的指标计算的算法,其实就是公式了。没有多余的取数及逻辑
index计算层:在指标计算过程中,用不同的策略计算中间值,然后调用相关算法来计算指标。
以上三层均定义接口及抽象类,java的多态还是蛮有用的。
然后最近在梳理业务,因为有些指标计算不仅是简单的入参然后输出一个指标。譬如:
基金公司的某组合id 一段时间范围内所有的持仓数据
1)根据持仓计算个券的指标
2)将所有的持仓根据type(股票、期货、债券等等)分类,然后计算每一层的指标(sum(权重*个券) )。
3)股票层还要根据行业分类标准分成不同的行业层,每一层计算指标(sum(权重*个券))
呵呵,然后用了二天半时间,不断地推翻重建,终于形成了一套初步的方式。这里分享下,源码如下:
clientParam.setCollection("bond_position");
Set<String> keySet = new HashSet<>();
keySet.add("combination_id");
keySet.add("date");
keySet.add("type");
keySet.add("code");
keySet.add("name");
keySet.add("value");
keySet.add("hq_close_price");
clientParam.setKey(keySet);
List<Map<String, Object>> totalBondList = (List<Map<String, Object>>) context.handle(params, clientParam);
//预处理 dimension的industryNames 及 map<code, level1_name>
clientParam.clearQueryParameters();
clientParam.setCollection("stock_category");
clientParam.setParam("industry_name_cd", "SW");
params.setParam("keyName", "ticker");
params.setParam("valName", "level1_name");
// map<code, level1_name>
Map<String, String> code_industry = (Map<String, String>) context.handle(params, clientParam);
//dimension的industryNames
clientParam.setGroup("$level1_name");
Stragtegy stragtegy2 = strategy.get("AggregateDataHandleStra");
context.setStrategy(stragtegy2);
List<String> industrayList = (List<String>) context.handle(params, clientParam);
//第一步 根据入参date及type及dimension将结构搭好
//date结构里放入type结构
DateModel dateModel = new DateModel();
for(int type : new ArrayList<Integer>()) {
TypeModel typemodel = new TypeModel(type, "typeName");
dateModel.setTypeModel(type, typemodel);
}
//type为股票的放入行业结构
TypeModel typeModel = dateModel.getTypeMap().get(1);
for(String industryName : industrayList) {
IndustryModel industryModel = new IndustryModel(industryName);
typeModel.setIndustryModel(industryName, industryModel);
}
//组合层次放入日期结构,此时用到了之前构建好的dateModel结构。
CombIdModel combIdModel = new CombIdModel(119);
for(Date date :new ArrayList<Date>()) {
combIdModel.setDateModel(date, dateModel);
}
//第二步 将范围内个券转换成singleBond对象,并将个体对象放到已搭建好的结构combIdModel合适位置
for(Map<String, Object> single1 : totalBondList) {
SingleBondModel single = new SingleBondModel();
//type date用来分类
int type = Integer.parseInt(single1.get("type").toString());
Date date = DateUtil.stringToDateGL(single1.get("date").toString());
String code = single1.get("code").toString();
//基本信息直接copy
single.setType(type);
single.setCode(code);
single.setDate(date);
//需要计算的指标计算完毕再set进对象,指标计算走之前的设计逻辑
Double initWeight = 0.001;
single.setInitWeight(initWeight);
single.setIdx(123.0);
//开始往combIdModel结构中放入 个券放入过程中在相应的层级累加initweight
if(1== type) {
combIdModel.getDateModel(date).addInitWeight(initWeight).getTypeModel(type).addInitWeight(initWeight).getIndustryModel(code_industry.get(code)).addInitWeight(initWeight).addSingle(single);
} else {
combIdModel.getDateModel(date).addInitWeight(initWeight).getTypeModel(type).addInitWeight(initWeight).addSingle(single);
}
}
//第三步 开始计算各维度的idx
combIdModel.calIdx();
一头雾水对吧,其实思想层次是这样:
先根据date type industry 把存放数据的结构建好,就好比你要把一群乞丐放进收容所,你得先把收容所根据性别、年龄等建好男女宿舍、厕所等。
ok,存放数据的结构建好了,下一步就是把数据库取出来的数据封装成SingleBondModel对象并放入合适的位置,这里在循环遍历每一条数据的时候做了两件事:
1、计算个券的指标idx,计算其权重initWeight。连同重要数据一并放入对象中
2、放到它本来应该在的位置,那就根据该单个对象的date、type、industry依次查找直至合适它的位置,在寻找过程中,将包括它的相应层级的initWeight加之
//开始往combIdModel结构中放入 个券放入过程中在相应的层级累加initweight
if(1== type) {
combIdModel.getDateModel(date).addInitWeight(initWeight).getTypeModel(type).addInitWeight(initWeight).getIndustryModel(code_industry.get(code)).addInitWeight(initWeight).addSingle(single);
} else {
combIdModel.getDateModel(date).addInitWeight(initWeight).getTypeModel(type).addInitWeight(initWeight).addSingle(single);
}
最后计算每一层的指标,这里看似只调用了
//第三步 开始计算各维度的idx
combIdModel.calIdx();
但内部实现原理是这样的:
首先combIdModel不同的层级包含了对应的对象,当调用combIdModel.calIdx()时,首先是计算每一日期的指标,每一日期的指标计算方法中会触发下一级别层次的指标计算,直至找到最底层的SingleBondModel并计算之。
CombIdModel:
//触发该组合下每一个DateModel的指标计算
@Override
public void calIdx() {
for(Date date : dateMap.keySet())
dateMap.get(date).calIdx();
}
DateModel:
//计算该DateModel的指标,由CombIdModel层触发
@Override
public void calIdx() {
Double initSum = 0.0D;
for(int type : typeMap.keySet()) {
TypeModel typeModel = typeMap.get(type);
initSum += typeModel.calAndGetIdx() * typeModel.getInitWeight();
}
idx = initSum / initWeight;
TypeModel:
//在DateModel层调用calAndGetIdx()触发
@Override
public void calIdx() {
if(null!=industryMap)
calIndustryMap();
else
calSingleList();
}
public void calIndustryMap() {
Double initSum = 0.0D;
for(String industryName : industryMap.keySet()) {
IndustryModel industryModel = industryMap.get(industryName);
initSum += industryModel.calAndGetIdx() * industryModel.getInitWeight();
}
idx = initSum / initWeight;
}
public void calSingleList() {
Double initSum = 0.0D;
for(SingleBondModel single : singleList) {
initSum += single.getIdx() * single.getInitWeight();
}
idx = initSum / initWeight;
}
IndustryModel:
//在TypeModel层调用calAndIdx方法触发
@Override
public void calIdx() {
Double initSum = 0.0D;
for(SingleBondModel single : singleList) {
initSum += single.getIdx() * single.getInitWeight();
}
idx = initSum / initWeight;
}
这些model均实现了抽象类
/**
* model抽象层
* @author fujian
*
*/
public abstract class AbstrateModel implements Model {
Double idx;
@Override
public Double calAndGetIdx() {
calIdx(); //当前层级下触发计算指标动作
return idx; //返回指标
}
public abstract void calIdx();
}
ok,好久不更博,总结mark下
然后被老板嫌弃 弃用了…………….