java 实现移动 波动率 的设计与实现_心如花木,向阳而生的博客-CSDN博客

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
标签: 无

请先后发表评论
  • 最新评论
  • 总共0条评论