新版仿ok交易所-后端
1
zyy
2025-10-20 d6f1a81f8af23e55bcb2a44909efcfbf61cd34fe
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
package com.yami.trading.huobi.data.job;
 
 
import com.yami.trading.bean.data.domain.Realtime;
import com.yami.trading.bean.item.domain.Item;
import com.yami.trading.common.util.Arith;
import com.yami.trading.huobi.data.AdjustmentValueCache;
import com.yami.trading.huobi.data.DataCache;
import com.yami.trading.huobi.data.internal.DataDBService;
import com.yami.trading.huobi.data.model.AdjustmentValue;
import com.yami.trading.huobi.hobi.HobiDataService;
import com.yami.trading.service.item.ItemService;
import com.yami.trading.service.syspara.SysparaService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
 
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
 
 
public abstract class AbstractGetDataJob implements Runnable {
    public static volatile boolean first = true;
    protected static Logger logger = LoggerFactory.getLogger(StockGetDataJob.class);
    /**
     * 数据接口调用间隔时长(毫秒)
     */
    protected int interval;
    @Autowired
    protected SysparaService sysparaService;
    @Autowired
    protected DataDBService dataDBService;
    @Autowired
    protected HobiDataService hobiDataService;
    @Autowired
    protected ItemService itemService;
 
    public void start() {
        new Thread(this, getName()).start();
    }
 
    public abstract void run();
 
    public abstract String getName();
 
 
    public abstract void realtimeHandle(String symbols);
 
    public void handleRealTimeList(List<Realtime> realtimeList) {
        for (Realtime realtime : realtimeList) {
 
            try {
                String symbol = realtime.getSymbol();
                Integer decimal = itemService.getDecimal(symbol);
                Item item = this.itemService.findBySymbol(symbol);
                BigDecimal currentValue = AdjustmentValueCache.getCurrentValue().get(symbol);
                AdjustmentValue delayValue = AdjustmentValueCache.getDelayValue().get(symbol);
 
                if (delayValue != null) {
                    if (delayValue.getSecond() < 0) {
                        AdjustmentValueCache.getDelayValue().remove(symbol);
                        AdjustmentValueCache.getPreAllocatedAdjustments().remove(symbol);
                        AdjustmentValueCache.getCurrentAdjustmentIndex().remove(symbol);
                        return;
                    }
                    int frequency = (int) Arith.div(Arith.mul(delayValue.getSecond(), 1000.0D), this.interval);
                    List<BigDecimal> adjustments = AdjustmentValueCache.getPreAllocatedAdjustments().get(symbol);
                    Integer currentIndex = AdjustmentValueCache.getCurrentAdjustmentIndex().get(symbol);
 
                    // 首次执行:生成含正负值的调整序列
                    if (adjustments == null || currentIndex == null) {
                        adjustments = generateRandomAdjustments(delayValue.getValue(), frequency, decimal);
                        currentIndex = 0;
                        AdjustmentValueCache.getPreAllocatedAdjustments().put(symbol, adjustments);
                        AdjustmentValueCache.getCurrentAdjustmentIndex().put(symbol, currentIndex);
                    }
 
                    // 分步应用调整值(确保正负交替)
                    if (currentIndex < frequency) {
                        BigDecimal currentAdjust = adjustments.get(currentIndex);
 
                        // 更新当前值(累加正负调整值)
                        if (currentValue == null) {
                            AdjustmentValueCache.getCurrentValue().put(symbol, currentAdjust.setScale(decimal, RoundingMode.HALF_UP));
                        } else {
                            AdjustmentValueCache.getCurrentValue().put(symbol, currentValue.add(currentAdjust).setScale(decimal, RoundingMode.HALF_UP));
                        }
 
                        // 更新延时值(剩余值和时间)
                        delayValue.setValue(delayValue.getValue().subtract(currentAdjust).setScale(decimal, RoundingMode.HALF_UP));
                        delayValue.setSecond(Arith.sub(delayValue.getSecond(), Arith.div(this.interval, 1000.0D)));
                        AdjustmentValueCache.getDelayValue().put(symbol, delayValue);
 
                        // 索引递增,完成后清理缓存
                        int nextIndex = currentIndex + 1;
                        AdjustmentValueCache.getCurrentAdjustmentIndex().put(symbol, nextIndex);
                        if (nextIndex >= frequency) {
                            AdjustmentValueCache.getDelayValue().remove(symbol);
                            AdjustmentValueCache.getPreAllocatedAdjustments().remove(symbol);
                            AdjustmentValueCache.getCurrentAdjustmentIndex().remove(symbol);
                        }
 
                        // 持久化更新
                        BigDecimal newAdjustValue = AdjustmentValueCache.getCurrentValue().get(symbol);
                        if (!item.getAdjustmentValue().equals(newAdjustValue)) {
                            item.setAdjustmentValue(newAdjustValue);
                            itemService.saveOrUpdate(item);
                        }
                    }
                }
 
                currentValue = AdjustmentValueCache.getCurrentValue().get(realtime.getSymbol());
 
                if (currentValue != null && currentValue.compareTo(BigDecimal.ZERO) != 0) {
                    realtime.setClose(realtime.getClose().add(currentValue).setScale(decimal, RoundingMode.HALF_UP));
                    BigDecimal ask = realtime.getAsk();
                    if(ask!=null){
                        realtime.setAsk(ask.add(currentValue).setScale(decimal, RoundingMode.HALF_UP));
                    }
                    BigDecimal bid = realtime.getBid();
                    if(bid!=null){
                        realtime.setBid(bid.add(currentValue).setScale(decimal, RoundingMode.HALF_UP));
                    }
                    // realtime.setVolume(Arith.add(realtime.getVolume(), Arith.mul(Arith.div(currentValue, realtime.getClose()), realtime.getVolume())));
                    // realtime.setAmount(Arith.add(realtime.getAmount(), Arith.mul(Arith.div(currentValue, realtime.getClose()), realtime.getAmount())));
                }
 
                // 缓存中最新一条Realtime数据
                Realtime realtimeLast = DataCache.getRealtime(symbol);
                // 临时处理:正常10秒超过25%也不合理,丢弃.只有虚拟货币才这样执行
                boolean checkRate = getName().contains("虚拟货币");
                double rate = 0;
                if (!checkRate) {
                    saveData(realtime, symbol, item);
                }else{
                    if (realtimeLast != null) {
                        rate = Math.abs(Arith.sub(realtime.getClose().doubleValue(), realtimeLast.getClose().doubleValue()));
                    }
                    if (null == realtimeLast || Arith.div(rate, realtimeLast.getClose().doubleValue()) < 0.25D) {
                        saveData(realtime, symbol, item);
                    } else {
                        logger.error("当前{}价格{},上一次价格为{}过25%也不合理,丢弃Realtime,不入库", realtime.getSymbol(),realtimeLast.getClose(), realtime.getClose());
                    }
                }
 
 
            } catch (Exception e) {
                logger.error("数据采集失败", e);
 
            }
        }
    }
 
    private void saveData(Realtime realtime, String symbol, Item item) {
        Double high = DataCache.getRealtimeHigh().get(symbol);
        Double low = DataCache.getRealtimeLow().get(symbol);
        if (realtime.getTs().toString().length() <= 10) {
            realtime.setTs(Long.valueOf(realtime.getTs() + "000"));
        }
        realtime.setName(item.getName());
        if (high == null || realtime.getHigh().doubleValue() > high) {
            DataCache.getRealtimeHigh().put(symbol, realtime.getHigh().doubleValue());
        }
        if ((low == null || realtime.getLow().doubleValue() < low) && realtime.getLow().doubleValue() > 0) {
            DataCache.getRealtimeLow().put(symbol, realtime.getLow().doubleValue());
        }
        this.dataDBService.saveAsyn(realtime);
    }
 
 
    private List<BigDecimal> generateRandomAdjustments(BigDecimal totalValue, int count, int decimal) {
        List<BigDecimal> adjustments = new ArrayList<>(count);
        BigDecimal sum = BigDecimal.ZERO; // 整体累积和
        boolean isOverallUp = totalValue.signum() > 0; // 整体大趋势
 
        // 1. 大幅扩大基础波动幅度(比之前再提高30%+,确保单次波动更剧烈)
        BigDecimal baseFluct = totalValue.abs().multiply(new BigDecimal(isOverallUp ? 0.25 : 0.22)) // 上涨时25%,下跌时22%
                .max(new BigDecimal("0.001")); // 最小波动阈值提高到0.001,避免微小波动
 
        // 2. 极大放宽累积范围(允许更大中途偏离,给子周期正负波动留空间)
        BigDecimal minPreSum = totalValue.multiply(new BigDecimal("0.5")); // 整体最低允许50%
        BigDecimal maxPreSum = totalValue.multiply(new BigDecimal("1.5")); // 整体最高允许150%
 
        // 3. 几乎取消“不动”状态(概率1%,突出剧烈波动)
        double flatProbability = 0.01;
 
        // 4. 子周期配置:每20次为一个子周期,每个子周期随机生成正负趋势
        int subCycleLength = 20; // 子周期长度
        Boolean currentSubCycleUp = null; // 当前子周期的趋势(null表示未初始化)
        BigDecimal subSum = BigDecimal.ZERO; // 当前子周期的累积和
 
        for (int i = 0; i < count - 1; i++) {
            // 每进入新的子周期(i为0或20的倍数),随机初始化子周期趋势(50%正,50%负)
            if (i % subCycleLength == 0) {
                currentSubCycleUp = Math.random() < 0.5; // 子周期趋势随机正负
                subSum = BigDecimal.ZERO; // 重置子周期累积和
            }
 
            // 计算当前允许的累积总和范围(动态适配剩余步数)
            BigDecimal remainingCount = new BigDecimal(count - 1 - i);
            BigDecimal minCurrentSum = sum.add(minPreSum.subtract(sum).divide(remainingCount, decimal + 4, RoundingMode.HALF_UP));
            BigDecimal maxCurrentSum = sum.add(maxPreSum.subtract(sum).divide(remainingCount, decimal + 4, RoundingMode.HALF_UP));
 
            // 极低概率“不动”
            boolean isFlat = Math.random() < flatProbability;
            if (isFlat) {
                BigDecimal adjustment = BigDecimal.ZERO.setScale(decimal, RoundingMode.HALF_UP);
                adjustments.add(adjustment);
                sum = sum.add(adjustment);
                subSum = subSum.add(adjustment); // 累加子周期和
                continue;
            }
 
            // 5. 动态调整涨跌概率:优先满足“子周期正负交替”,再适配整体趋势
            double upProbability;
            // 子周期内:若子周期趋势为正,80%概率涨;为负,80%概率跌(确保子周期总和有明确正负)
            if (currentSubCycleUp) {
                upProbability = 0.8;
            } else {
                upProbability = 0.2;
            }
            // 二次修正:若子周期累积和已偏离目标(如子周期应为正但当前为负),进一步提高对应概率
            if (currentSubCycleUp && subSum.compareTo(BigDecimal.ZERO) < 0) {
                upProbability = Math.min(0.98, upProbability + 0.2); // 子周期需正但当前负,大幅提高涨概率
            } else if (!currentSubCycleUp && subSum.compareTo(BigDecimal.ZERO) > 0) {
                upProbability = Math.max(0.02, upProbability - 0.2); // 子周期需负但当前正,大幅提高跌概率
            }
            // 三次修正:确保整体累积和不偏离太远(弱于子周期优先级)
            if (sum.compareTo(minPreSum) < 0) {
                upProbability = Math.min(0.98, upProbability + 0.1);
            } else if (sum.compareTo(maxPreSum) > 0) {
                upProbability = Math.max(0.02, upProbability - 0.1);
            }
            boolean isCurrentUp = Math.random() < upProbability;
 
            // 6. 生成超大随机幅度(0.6~1.2倍baseFluct,跳过中小幅度,直接用大波动)
            double randomRate = 0.6 + Math.random() * 0.6; // 范围:0.6~1.2(确保单次波动至少是baseFluct的60%)
            BigDecimal fluct = baseFluct.multiply(new BigDecimal(randomRate))
                    .setScale(decimal + 4, RoundingMode.HALF_UP);
 
            // 7. 生成当前调整值(允许接近上限的剧烈波动)
            BigDecimal adjustment;
            if (isCurrentUp) {
                adjustment = fluct.setScale(decimal, RoundingMode.HALF_UP);
                // 超上限时仅截断到上限(不额外缩小,保留大涨幅)
                if (sum.add(adjustment).compareTo(maxCurrentSum) > 0) {
                    adjustment = maxCurrentSum.subtract(sum).setScale(decimal, RoundingMode.HALF_UP);
                }
            } else {
                adjustment = fluct.negate().setScale(decimal, RoundingMode.HALF_UP);
                // 低于下限时仅截断到下限(保留大跌幅)
                if (sum.add(adjustment).compareTo(minCurrentSum) < 0) {
                    adjustment = minCurrentSum.subtract(sum).setScale(decimal, RoundingMode.HALF_UP);
                }
            }
 
            adjustments.add(adjustment);
            sum = sum.add(adjustment);
            subSum = subSum.add(adjustment); // 累加子周期和
        }
 
        // 8. 最后一个值:允许极大补平幅度(不超过baseFluct的8倍,适配剧烈波动后的差额)
        BigDecimal lastAdjustment = totalValue.subtract(sum)
                .setScale(decimal, RoundingMode.HALF_UP);
        BigDecimal maxLastAdjust = baseFluct.multiply(new BigDecimal(8)); // 从5倍提高到8倍
        if (lastAdjustment.abs().compareTo(maxLastAdjust) > 0) {
            lastAdjustment = maxLastAdjust.multiply(lastAdjustment.signum() == 1 ? BigDecimal.ONE : BigDecimal.ONE.negate());
            // 微调前一个值分担差额(确保总和准确)
            BigDecimal prevAdjust = adjustments.get(adjustments.size() - 1);
            adjustments.set(adjustments.size() - 1, prevAdjust.add(totalValue.subtract(sum).subtract(lastAdjustment)));
        }
        adjustments.add(lastAdjustment);
 
        return adjustments;
    }
 
    public static void main(String[] args) {
        AbstractGetDataJob abstractGetDataJob = new CryptosGetDataJob();
        List<BigDecimal> list = abstractGetDataJob.generateRandomAdjustments(new BigDecimal(0.002), 300, 8);
        BigDecimal sum = BigDecimal.ZERO;
        int num = 0;
        int dmt = 1;
        BigDecimal numd = BigDecimal.ZERO;
        for (int i = 0; i < list.size(); i++) {
            sum = sum.add(list.get(i));
            System.out.println((i+1) + "~                      " + list.get(i));
            System.out.println(sum);
 
            numd = numd.add(list.get(i));
            num++;
            if (num == 20) {
                System.out.println(dmt+"ddd" + numd);
                dmt++;
                num=0;
                numd=BigDecimal.ZERO;
            }
        }
    }
 
}