package com.yami.trading.huobi.data.job;
|
|
import java.math.BigDecimal;
|
import java.math.RoundingMode;
|
import java.util.List;
|
import java.util.Map;
|
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.Executors;
|
import java.util.concurrent.ScheduledExecutorService;
|
import java.util.concurrent.ScheduledFuture;
|
import java.util.concurrent.TimeUnit;
|
|
import com.alibaba.fastjson.JSONObject;
|
import com.google.common.collect.Lists;
|
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.websocket.model.market.MarketTicker;
|
import com.yami.trading.service.item.ItemService;
|
import org.slf4j.Logger;
|
import org.slf4j.LoggerFactory;
|
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.stereotype.Component;
|
|
@Component
|
public class AdjustmentTaskScheduler {
|
private static final Logger log = LoggerFactory.getLogger(AdjustmentTaskScheduler.class);
|
|
private static final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(10);
|
private static final Map<String, ScheduledFuture<?>> scheduledTasks = new ConcurrentHashMap<>();
|
|
@Autowired
|
private ItemService itemService;
|
|
@Autowired
|
protected DataDBService dataDBService;
|
|
/**
|
* 安排调控任务
|
*/
|
public void scheduleAdjustment(String symbol, AdjustmentValue delayValue, long interval, Integer decimal) {
|
// 取消已有的任务(如果有)
|
cancelExistingTask(symbol);
|
|
// 计算需要执行多少次(每秒执行一次,总共执行 delayValue.getSecond() 次)
|
int totalExecutions = (int) delayValue.getSecond();
|
|
// 计算每次调整的值
|
double valuePerExecution = delayValue.getValue() / totalExecutions;
|
|
// 创建任务
|
Runnable adjustmentTask = createAdjustmentTask(symbol, valuePerExecution, totalExecutions, decimal);
|
|
// 安排任务执行(每秒执行一次)
|
ScheduledFuture<?> future = scheduler.scheduleAtFixedRate(
|
adjustmentTask, 0, 1000, TimeUnit.MILLISECONDS); // 固定每秒执行一次
|
|
// 保存任务引用以便后续取消
|
scheduledTasks.put(symbol, future);
|
|
log.info("Scheduled adjustment for symbol: {}, total value: {}, duration: {}s, executions: {}",
|
symbol, delayValue.getValue(), delayValue.getSecond(), totalExecutions);
|
}
|
|
/**
|
* 创建调控任务
|
*/
|
private Runnable createAdjustmentTask(String symbol, double valuePerExecution, int totalExecutions, Integer decimal) {
|
return new Runnable() {
|
private int executions = 0;
|
|
@Override
|
public void run() {
|
try {
|
// 获取当前值和延迟值
|
Double currentValue = AdjustmentValueCache.getCurrentValue().get(symbol);
|
AdjustmentValue delayValue = AdjustmentValueCache.getDelayValue().get(symbol);
|
|
if (delayValue == null) {
|
// 如果延迟值已被移除,取消任务
|
cancelExistingTask(symbol);
|
return;
|
}
|
|
// 更新当前值
|
if (currentValue == null) {
|
AdjustmentValueCache.getCurrentValue().put(symbol, valuePerExecution);
|
} else {
|
AdjustmentValueCache.getCurrentValue().put(symbol, currentValue + valuePerExecution);
|
}
|
|
// 更新延迟值
|
delayValue.setValue(delayValue.getValue() - valuePerExecution);
|
delayValue.setSecond(delayValue.getSecond() - 1); // 每次减少一秒
|
|
// 更新数据库
|
Item item = itemService.findBySymbol(symbol);
|
if (item != null && item.getAdjustmentValue() != AdjustmentValueCache.getCurrentValue().get(symbol)) {
|
item.setAdjustmentValue(AdjustmentValueCache.getCurrentValue().get(symbol));
|
itemService.saveOrUpdate(item);
|
}
|
|
// 记录执行日志
|
log.info("Adjustment executed for symbol: {}, execution: {}/{}, value added: {}, total value: {}",
|
symbol, executions + 1, totalExecutions, valuePerExecution,
|
AdjustmentValueCache.getCurrentValue().get(symbol));
|
|
// 检查是否完成
|
executions++;
|
if (executions >= totalExecutions) {
|
log.info("Adjustment completed for symbol: {}, total value: {}",
|
symbol, AdjustmentValueCache.getCurrentValue().get(symbol));
|
// 在调整值应用后,立即更新 realtime 数据
|
// Realtime realtime = establish(symbol);
|
// handleRealTimeList(Lists.newArrayList(realtime));
|
cancelExistingTask(symbol);
|
|
// 清除延迟值缓存
|
AdjustmentValueCache.getDelayValue().remove(symbol);
|
}
|
} catch (Exception e) {
|
log.error("Adjustment task error for symbol: {}", symbol, e);
|
cancelExistingTask(symbol);
|
}
|
}
|
};
|
}
|
|
public Realtime establish(String symbol){
|
// 2. 从缓存获取最新的 realtime 数据
|
Realtime currentRealtime = DataCache.getRealtime(symbol);
|
if (currentRealtime == null) {
|
// 如果缓存中没有,从数据库获取最新的一条
|
currentRealtime = dataDBService.get(symbol);
|
log.info("----------------symbol--------------:"+symbol);
|
log.info("----------------Realtime--------------"+currentRealtime.toString());
|
}
|
// 3. 创建新的 realtime 对象(避免修改原始对象)
|
return cloneRealtime(currentRealtime);
|
}
|
|
|
public void handleRealTimeList(List<Realtime> realtimeList) {
|
for (Realtime realtime : realtimeList) {
|
try {
|
String symbol = realtime.getSymbol();
|
symbol = itemService.getSymbolByRemarks(symbol);
|
Item item = this.itemService.findBySymbol(symbol);
|
//更新行情中的symbol [要不然后续取不到缓存]
|
realtime.setSymbol(item.getSymbol());
|
|
try {
|
// 缓存中最新一条Realtime数据
|
Realtime realtimeLast = DataCache.getRealtime(symbol);
|
// 临时处理:正常10秒超过25%也不合理,丢弃.只有虚拟货币才这样执行
|
boolean checkRate = Item.cryptos.equals(Item.cryptos);
|
if (!checkRate) {
|
saveData(realtime, symbol, item);
|
} else {
|
if (null == realtimeLast) {
|
log.error("缓存里面没有realtimeLast数据, 注意观察");
|
saveData(realtime, symbol, item);
|
return;
|
}
|
if (realtimeLast.getClose() == 0) {
|
saveData(realtime, symbol, item);
|
}
|
saveData(realtime, symbol, item);
|
}
|
} catch (Exception e) {
|
log.error("---> AbstractGetDataJob.handleRealTimeList debug 位置4, realtime -> symbol:{}, error: ", realtime.getSymbol(), e);
|
throw e;
|
}
|
} catch (Exception e) {
|
e.printStackTrace();
|
log.error("数据采集失败 {}:[]", realtime.getSymbol(), JSONObject.toJSON(realtime), e);
|
}
|
}
|
}
|
|
private void saveData(Realtime realtime, String symbol, Item item) {
|
Double high = DataCache.getRealtimeHigh(symbol);
|
Double low = DataCache.getRealtimeLow(symbol);
|
if (realtime.getTs().toString().length() <= 10) {
|
realtime.setTs(Long.valueOf(realtime.getTs() + "000"));
|
}
|
realtime.setName(item.getName());
|
if (high == null || realtime.getHigh() > high) {
|
// 刷新内存中的 high
|
DataCache.putRealtimeHigh(symbol, realtime.getHigh());
|
}
|
if ((low == null || realtime.getLow() < low) && realtime.getLow() > 0) {
|
// 刷新内存中的 low,并且只使用值大于 0 的 low
|
DataCache.putRealtimeLow(symbol, realtime.getLow());
|
}
|
this.dataDBService.saveAsyn(realtime);
|
}
|
|
private Realtime cloneRealtime(Realtime original) {
|
Realtime clone = new Realtime();
|
clone.setSymbol(original.getSymbol());
|
clone.setName(original.getName());
|
clone.setTs(original.getTs());
|
clone.setOpen(original.getOpen());
|
clone.setClose(original.getClose());
|
clone.setHigh(original.getHigh());
|
clone.setLow(original.getLow());
|
clone.setAsk(original.getAsk());
|
clone.setBid(original.getBid());
|
clone.setVolume(original.getVolume());
|
//获取24h开盘价
|
MarketTicker marketTicker = DataCache.getMarketTicker(original.getSymbol());
|
BigDecimal open = marketTicker.getOpen();
|
BigDecimal close = new BigDecimal(original.getClose());
|
//计算涨跌幅
|
BigDecimal changeRatio = close.subtract(open).divide(open, 10, RoundingMode.HALF_UP)
|
.multiply(new BigDecimal(100)).setScale(2, RoundingMode.DOWN);
|
BigDecimal netChange = close.multiply(changeRatio).divide(new BigDecimal(100), 10, RoundingMode.HALF_UP);
|
netChange = netChange.setScale(4, RoundingMode.DOWN);
|
clone.setNetChange(netChange.doubleValue());
|
clone.setChangeRatio(changeRatio.doubleValue());
|
return clone;
|
}
|
|
/**
|
* 取消现有任务
|
*/
|
public void cancelExistingTask(String symbol) {
|
ScheduledFuture<?> existingFuture = scheduledTasks.get(symbol);
|
if (existingFuture != null) {
|
existingFuture.cancel(false);
|
scheduledTasks.remove(symbol);
|
log.info("Cancelled adjustment task for symbol: {}", symbol);
|
}
|
}
|
|
/**
|
* 取消所有任务
|
*/
|
public void cancelAllTasks() {
|
for (String symbol : scheduledTasks.keySet()) {
|
cancelExistingTask(symbol);
|
}
|
}
|
}
|