1.首先,我们需要知道波动率是什么?在数学定义上波动率就是标准,标准差就是方差开根号,我们先看一下方差计算公式:
其中x为这组数据的平均数,下面我们需要对方差进行推导:
图 2.
图3.标准差 :
图4.归一化处理:
推导过程:我们先不管前面的1/n,对里面展开:x为平均数,第4步括号1里面为X1到Xn平方的和,我们对后面的式子乘以n再除以n,X1+X2+...+Xn除以n就是平均数所以根据第5步我们得到第6步,因为x是平均数,x等于X1+X2+...+Xn除以n,所以x的平方拆开得到第7步。
不要忘了我们下面还有一个n分只1,才是方差
所以第8步为方差公式,图2的方差公式并不正确,图2的公式是第9步,是对方差乘以n的平方后的公式。但图三的标准差的公式是正确的, 对方差又除以n的平方。所以我们以图2,图3,图4 进行计算。计算完以后进行归一化处理:
测试类:SpringbootApplicationTests.java
package com.zhangdi.springboot; import java.math.BigDecimal;import java.util.ArrayList;import java.util.List;import java.util.concurrent.ConcurrentHashMap; import org.junit.Test;import org.junit.runner.RunWith;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.test.context.SpringBootTest;import org.springframework.test.annotation.Rollback;import org.springframework.test.context.junit4.SpringRunner; import com.zhangdi.springboot.service.UserService;import com.zhangdi.springboot.statistics.MarketDataManager;import com.zhangdi.springboot.statistics.PriceDate;import com.zhangdi.springboot.statistics.PriceProperty;import com.zhangdi.springboot.statistics.PriceStatistics; @RunWith(SpringRunner.class)@SpringBootTestpublic class SpringbootApplicationTests { @Autowired UserService userService; @Test @Rollback(false) public void contextLoads() { } @Test public void test() { //准备测试数据 List<PriceDate> listPriceDate = new ArrayList<PriceDate>(); PriceDate priceDate = new PriceDate(new BigDecimal(2),"bbbb",0.0); PriceDate priceDate1 = new PriceDate(new BigDecimal(4),"bbbb",0.0); PriceDate priceDate2 = new PriceDate(new BigDecimal(6),"bbbb",0.0); PriceDate priceDate3 = new PriceDate(new BigDecimal(4),"bbbb",0.0); PriceDate priceDate4 = new PriceDate(new BigDecimal(6),"bbbb",0.0); PriceDate priceDate5 = new PriceDate(new BigDecimal(2),"bbbb",0.0); listPriceDate.add(priceDate); listPriceDate.add(priceDate1); listPriceDate.add(priceDate2); listPriceDate.add(priceDate3); listPriceDate.add(priceDate4); listPriceDate.add(priceDate5); PriceProperty priceProp = new PriceProperty(); priceProp.setMaxSampleSize(10); //设置样本容量 ConcurrentHashMap<String, PriceProperty> priceProperty = MarketDataManager.getInstance().getPriceProperty(); priceProperty.put("aaa", priceProp); for(PriceDate pd:listPriceDate) { String key = pd.getType(); if (!MarketDataManager.getInstance().getPriceStatistics().containsKey(key)) { MarketDataManager.getInstance().getPriceStatistics().put(key, new PriceStatistics());//根据type求不同类型数据的波动率 } PriceStatistics priceStatistics = MarketDataManager.getInstance().getPriceStatistics().get(key); boolean passAsk = priceStatistics.CalculateStatistics(pd, priceStatistics.askStats); //计算波动率 if(priceStatistics.askStats.get(key)!=null) { priceStatistics.askStats.get(key).getPriceVolatility(); //获取归一化的波动率(测试打印未归一化) } } }}
计算类 PriceStatistics.java
package com.zhangdi.springboot.statistics; import java.util.concurrent.ConcurrentHashMap; public class PriceStatistics { public int max_sample_size; //样本容量,最大多少数据进行波动率计算 // public double error_margin; // public int error_count; public ConcurrentHashMap<String, SingleFeedStatistics> askStats; public PriceStatistics() { askStats = new ConcurrentHashMap<String, SingleFeedStatistics>(); } /** * 根据过滤规则过滤报价信息 * * @author tingting.song * @param fxData * @param stats * @param priceData * @param sideFlag * 0:ask, 1:bid * @return */ public boolean CalculateStatistics(PriceDate priceDate, ConcurrentHashMap<String, SingleFeedStatistics> stats ) { String key = priceDate.getType(); PriceProperty priceProperty = MarketDataManager.getInstance().getPriceProperty().get("aaa"); if (!ObjectUtil.isEmpty(priceProperty)) { max_sample_size = priceProperty.getMaxSampleSize(); //获取样本容量大小 } SingleFeedStatistics singleFeedStatistics; if (stats.containsKey(key)) { singleFeedStatistics = stats.get(key); singleFeedStatistics.getStatsTracker().addValue(priceDate.getPrice().doubleValue()); //计算波动率 先处理数据 } else { stats.put(key, new SingleFeedStatistics( max_sample_size)); //new 一个计算对象 singleFeedStatistics = stats.get(key); singleFeedStatistics.getStatsTracker().addValue(priceDate.getPrice().doubleValue());//计算波动率 先处理数据 } double price = 0; price = priceDate.getPrice().doubleValue(); boolean pass = singleFeedStatistics.calculateAll(price); return pass; } }
计算类 SingleFeedStatistics.java
package com.zhangdi.springboot.statistics; public class SingleFeedStatistics { StatsTracker priceTracker; //每个Tracker都是一个波动率计算,价格的波动率 //StatsTracker tickTracker; //StatsTracker freqTracker; // parameters; public int max_sample_size; //样本容量 // volatility double priceVolatility; public SingleFeedStatistics(int max_sample_size) { this.max_sample_size = max_sample_size; priceTracker = new StatsTracker(max_sample_size); priceVolatility = 0; } public StatsTracker getStatsTracker() { return priceTracker; } /** * 获取价格波动率 * * @return */ public double getPriceVolatility() { return priceVolatility; } /** * 计算波动率 * @param price * @return */ public boolean calculateAll(double price) { calculatePriceStatistics(price); // MOVED adding to statTrackers after both results come in rather than just one. //priceTracker.addValue(price); //计算完对数据处理 return true; } public void calculatePriceStatistics(double price) { priceVolatility = getVolatilityIndex(priceTracker, price); } /**stats.getMovingAverage() 为平均数 * stats.getMovingStandardDev() 为标准差 即波动率 * @param stats * @param value * @return */ protected double getVolatilityIndex(StatsTracker stats, double value) { //对波动率进行归一化处理,这里归一化减去Xn的平均数,公式是减去Xn-1的平均数 double actualDiff = Math.abs(value - stats.getMovingAverage()); double numStdDevDiff = Math.abs(actualDiff / stats.getMovingStandardDev()); System.out.println(stats.getMovingAverage()+"..."+stats.getMovingStandardDev()); // double vol = numStdDevDiff * 11 / error_margin; // double vol = numStdDevDiff * 11 / 4; //vol = vol + 1; return numStdDevDiff; } }
数据处理类 StatsTracker.java
package com.zhangdi.springboot.statistics; import java.math.BigDecimal; public class StatsTracker { public long totalSampleSize; long count; double s1; //tracking moving sum (s1 = s1+val) double s2; //traving moving square sum(s2 + (val*val)) double movingAverage; double movingStandardDev; public StatsTracker() { super(); } public StatsTracker(int totalSampleSize) { this.totalSampleSize = totalSampleSize; count = 0; s1 = 0; s2 = 0; movingAverage = 0; movingStandardDev = 0; } public long getCount() { return count; } public double getMovingAverage() { return movingAverage; } public double getMovingStandardDev() { return movingStandardDev; } public boolean addValue(double value) { if(value <= 0) { return false; } if(count>=totalSampleSize) { //当到达样本容量时 这里减去的是平均数 不是第一个数 count --; s1 = s1 - movingAverage; s2 = s2 - (movingAverage*movingAverage); } count++; s1 = s1+value; //s1 是所有数的和 s2 = s2 + (value*value); //s2 是所有数的平方和 movingAverage = (s1)/count; double mVar = Math.abs(((count*s2)-(s1*s1))); /** * right now, this is calculating population standard deviation. * we need to get it to calculate standard deviation. * The difference is, for standard deviation, we need to divide by n-1 * whereas in population standard deviation, we need to divide by n * so in order to not screw up my count, i need to create a custom divisor. */ movingStandardDev = ((Math.sqrt(mVar))/count); movingAverage = CalculateUtil.truncate(new BigDecimal(movingAverage), 6).doubleValue(); if(!(movingStandardDev==0)){ movingStandardDev = CalculateUtil.truncate(new BigDecimal(movingStandardDev), 6).doubleValue(); } return true; } }
价格实体类 PriceDate.java
package com.zhangdi.springboot.statistics; import java.math.BigDecimal; public class PriceDate { private BigDecimal price; private String type; private double volatility; public PriceDate(BigDecimal price,String type, Double volatility){ this.price=price; this.type=type; this.volatility=volatility; } public BigDecimal getPrice() { return price; } public void setPrice(BigDecimal price) { this.price = price; } public String getType() { return type; } public void setType(String type) { this.type = type; } public double getVolatility() { return volatility; } public void setVolatility(double volatility) { this.volatility = volatility; } }
属性实体类 PriceProperty.java
package com.zhangdi.springboot.statistics; public class PriceProperty {private int maxSampleSize; public int getMaxSampleSize() { return maxSampleSize;}public void setMaxSampleSize(int maxSampleSize) { this.maxSampleSize = maxSampleSize;} }
计算工具类 CalculateUtil.java
package com.zhangdi.springboot.statistics; import java.math.BigDecimal;import java.math.RoundingMode; public class CalculateUtil { /** * BigDecimal加法运算 * @author tingting.song * @param v1 * @param v2 * @return */ public static BigDecimal add(String v1, String v2) { if (ObjectUtil.isEmpty(v1) || ObjectUtil.isEmpty(v2)) { return null; } BigDecimal b1 = new BigDecimal(v1); BigDecimal b2 = new BigDecimal(v2); return b1.add(b2); } /** * BigDecimal减法运算 * @author tingting.song * @param v1 * @param v2 * @return */ public static BigDecimal sub(String v1, String v2) { if (ObjectUtil.isEmpty(v1) || ObjectUtil.isEmpty(v2)) { return null; } BigDecimal b1 = new BigDecimal(v1); BigDecimal b2 = new BigDecimal(v2); return b1.subtract(b2); } /** * BigDecimal乘法运算 * @author tingting.song * @param v1 * @param v2 * @return */ public static BigDecimal multi(String v1, String v2) { if (ObjectUtil.isEmpty(v1) || ObjectUtil.isEmpty(v2)) { return null; } BigDecimal b1 = new BigDecimal(v1); BigDecimal b2 = new BigDecimal(v2); return b1.multiply(b2); } /** * BigDecimal除法运算 * @author tingting.song * @param v1 * @param v2 * @return */ public static BigDecimal div(String v1, String v2) { if (ObjectUtil.isEmpty(v1) || ObjectUtil.isEmpty(v2)) { return null; } BigDecimal b1 = new BigDecimal(v1); BigDecimal b2 = new BigDecimal(v2); return b1.divide(b2); } /** * BigDecimal除法运算 * @author tingting.song * @param v1 * @param v2 * @param scale 保留几位小数 * @param round 是否要四舍五入(BigDecimal.ROUND_HALF_UP) * @return */ public static BigDecimal div(String v1, String v2, int scale, int round) { if (ObjectUtil.isEmpty(v1) || ObjectUtil.isEmpty(v2)) { return null; } BigDecimal b1 = new BigDecimal(v1); BigDecimal b2 = new BigDecimal(v2); return b1.divide(b2, scale, round); } /** * 按精度,四舍五入 * @author tingting.song * @param value * @param places * @return */ public static BigDecimal round(BigDecimal value, int places) { if(value.equals(BigDecimal.ZERO)) { return value; } if (places < 0) throw new IllegalArgumentException(); value = value.setScale(places, RoundingMode.HALF_UP); return value; } /** * 根据截取的精度,得到一定精度的数值(不四舍五入) * @author tingting.song * @param value * @param places * @return */ public static BigDecimal truncate(BigDecimal value, int places) { if (value.equals(BigDecimal.ZERO) || value == null) { return value; } if (places < 0) { throw new IllegalArgumentException(); } String decimalPlace = ""; for (int i = 0; i < places; i++) { decimalPlace += 0; } java.text.DecimalFormat df = new java.text.DecimalFormat("#." + decimalPlace); df.setRoundingMode(RoundingMode.FLOOR); return new BigDecimal(df.format(value)); }}
辅助工具类 ObjectUtil.java
package com.zhangdi.springboot.statistics; import java.lang.reflect.Array;import java.util.Collection;import java.util.Map; public class ObjectUtil { /** * 判断该对象是否为null * @author tingting.song * @param o * @return */ public static boolean isNull(Object o) { return (o == null); } /** * 判断该对象是否不为null * @author tingting.song * @param o * @return */ public static boolean notNull(Object o) { return (!(isNull(o))); } /** * 判断该对象是否为空 * @author tingting.song * @param o * @return */ @SuppressWarnings("rawtypes") public static boolean isEmpty(Object o) { if (isNull(o)) { return true; } if (o instanceof String) { return "".equals(o.toString()); } if (o instanceof Collection) { return ((Collection)o).isEmpty(); } if (o instanceof Map) { return ((Map)o).isEmpty(); } if (o.getClass().isArray()) { return (Array.getLength(o) == 0); } return false; } /** * 判断该对象是否不为空 * @author tingting.song * @param o * @return */ public static boolean notEmpty(Object o) { return (!(isEmpty(o))); } /** * 防止空指针异常 * @author tingting.song * @param actual * @param safe * @return */ public static <T> T nullSafe(T actual, T safe) { return ((actual == null) ? safe : actual); }}
有些童鞋说少了一个类,我就从新复制了一下代码,写出来了,万幸,跑出来结果还是一样的。
package com.hxjf.equipment.zhangdi; import java.util.concurrent.ConcurrentHashMap; public class MarketDataManager { private static final MarketDataManager instance = new MarketDataManager(); public MarketDataManager() { super(); } public static MarketDataManager getInstance() { return instance; } private ConcurrentHashMap<String,PriceStatistics> priceStatistics = new ConcurrentHashMap<String,PriceStatistics>(); public ConcurrentHashMap<String,PriceStatistics> getPriceStatistics() { return priceStatistics; } private ConcurrentHashMap<String,PriceProperty> priceProperty = new ConcurrentHashMap<String,PriceProperty>(); public ConcurrentHashMap<String,PriceProperty> getPriceProperty() { return priceProperty; }}
计算结果:...左边是平均数,...右边是标准差(波动率),具体计算过程可以根据实际情况自行修改。
原网址: 访问
创建于: 2022-12-16 10:50:49
目录: default
标签: 无
未标明原创文章均为采集,版权归作者所有,转载无需和我联系,请注明原出处,南摩阿彌陀佛,知识,不只知道,要得到
最新评论