package com.yami.trading.service.etf;
|
|
import cn.hutool.core.collection.CollectionUtil;
|
import cn.hutool.core.lang.Tuple;
|
import cn.hutool.core.util.NumberUtil;
|
import com.alibaba.fastjson.JSON;
|
import com.alibaba.fastjson.JSONArray;
|
import com.alibaba.fastjson.JSONObject;
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.yami.trading.bean.data.domain.Kline;
|
import com.yami.trading.bean.data.domain.RobotModel;
|
import com.yami.trading.bean.etf.domain.EtfKLine;
|
import com.yami.trading.bean.etf.domain.EtfMinuteKLine;
|
import com.yami.trading.bean.etf.domain.EtfSecKLine;
|
import com.yami.trading.bean.etf.domain.KlineConfig;
|
import com.yami.trading.bean.etf.dto.KlineConfigDTO;
|
import com.yami.trading.bean.etf.mapstruct.EtfMinuteKLineWrapper;
|
import com.yami.trading.bean.etf.mapstruct.EtfSecKLineWrapper;
|
import com.yami.trading.bean.item.domain.Item;
|
import com.yami.trading.bean.robot.domain.RobotOrder;
|
import com.yami.trading.common.exception.YamiShopBindException;
|
import com.yami.trading.common.util.Arith;
|
import com.yami.trading.dao.data.RobotModelMapper;
|
import com.yami.trading.dao.etf.mapper.KlineConfigMapper;
|
import com.yami.trading.service.item.ItemService;
|
import com.yami.trading.service.robot.RobotOrderService;
|
import org.jetbrains.annotations.NotNull;
|
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.context.annotation.Lazy;
|
import org.springframework.stereotype.Service;
|
import org.springframework.transaction.annotation.Transactional;
|
|
import java.math.BigDecimal;
|
import java.math.RoundingMode;
|
import java.text.ParseException;
|
import java.text.SimpleDateFormat;
|
import java.time.Instant;
|
import java.time.ZoneId;
|
import java.time.ZonedDateTime;
|
import java.util.*;
|
|
/**
|
* etfK线图配置表Service
|
*
|
* @author lucas
|
* @version 2023-05-03
|
*/
|
@Service
|
@Transactional
|
public class KlineConfigService extends ServiceImpl<KlineConfigMapper, KlineConfig> {
|
|
@Autowired
|
private RobotModelMapper robotModelMapper;
|
|
@Autowired
|
private ItemService itemService;
|
|
@Autowired
|
EtfSecKLineService etfSecKLineService;
|
|
@Autowired
|
EtfSecKLineWrapper etfSecKLineWrapper;
|
|
|
@Autowired
|
RobotOrderService robotOrderService;
|
|
@Autowired
|
EtfMinuteKLineService etfMinuteKLineService;
|
|
@Autowired
|
EtfMinuteKLineWrapper etfMinuteKLineWrapper;
|
|
@Lazy
|
@Autowired
|
MarketService marketService;
|
|
|
@Transactional(rollbackFor = Exception.class)
|
public void deleteByRobotModelId(List<String> ids) {
|
long currentTimeMillis = System.currentTimeMillis();
|
for (String id : ids) {
|
KlineConfig config = this.getBaseMapper().selectById(id);
|
if (config != null) {
|
if (config.getOpenTimeTs() <= currentTimeMillis && config.getCloseTimeTs() >= currentTimeMillis) {
|
throw new YamiShopBindException("当前为开市时间,不能删除");
|
}
|
removeById(id);
|
|
etfSecKLineService.remove(new QueryWrapper<EtfSecKLine>().eq("symbol", config.getSymbol()).between("ts", config.getOpenTimeTs(), config.getCloseTimeTs()));
|
|
//etfMinuteKLineService 根据config的开市时间,结束时间,symbol去删除
|
etfMinuteKLineService.remove(new QueryWrapper<EtfMinuteKLine>().eq("symbol", config.getSymbol()).between("ts", config.getOpenTimeTs(), config.getCloseTimeTs()));
|
|
marketService.getCacheKline().put(config.getSymbol(), new LinkedHashMap<>());
|
}
|
}
|
}
|
|
public EtfKLine queryKLine(KlineConfigDTO klineConfigDTO) {
|
BigDecimal divide = BigDecimal.valueOf((klineConfigDTO.getClosePrice() - klineConfigDTO.getOpenPrice()) / klineConfigDTO.getOpenPrice() * 100);
|
// BigDecimal divide = klineConfigDTO.getClosePrice().subtract(klineConfigDTO.getOpenPrice()).divide(klineConfigDTO.getOpenPrice(), 2, BigDecimal.ROUND_HALF_UP).multiply(BigDecimal.valueOf(100));
|
|
List<RobotModel> robotModels = new LambdaQueryChainWrapper<>(robotModelMapper).between(RobotModel::getPercent, divide.subtract(new BigDecimal(0.5)), divide.add(new BigDecimal(0.5))).list();
|
|
if (CollectionUtil.isEmpty(robotModels)) {
|
throw new YamiShopBindException("没有满足条件的趋势图");
|
}
|
|
|
// 解析数据库满足条件涨幅的k线图数据
|
// 随机获取一个,获取完整一天的分钟k线图
|
RobotModel robotModel = robotModels.get(new Random().nextInt(robotModels.size()));
|
List<Kline> randomKLine = parseHistoryKLine(robotModel);
|
|
// 获取完整一天的k线图
|
randomKLine.sort(Comparator.comparing(Kline::getTs));
|
|
// 生成分钟图返回
|
List<Kline> klines = accrodingSecOrign(klineConfigDTO, robotModel, randomKLine, 60);
|
|
// printResult(klines);
|
|
return new EtfKLine(robotModel.getUuid(),klines);
|
|
}
|
|
public List<Kline> generateSecKLine(KlineConfigDTO klineConfigDTO) {
|
|
|
RobotModel robotModel = robotModelMapper.selectById(klineConfigDTO.getRobot_model_uuid());
|
|
// 假图的分钟图
|
List<Kline> klines = parseHistoryKLine(robotModel);
|
|
// 生成分钟图
|
List<Kline> minute = accrodingSecOrign(klineConfigDTO, robotModel, klines, 60);
|
|
etfMinuteKLineService.saveBatch(etfMinuteKLineWrapper.toDTO(minute),500);
|
|
saveRobotOrder(klineConfigDTO, minute);
|
|
// 生成的秒图
|
return getRecentWholwSecKline(klineConfigDTO.getSymbol(), minute);
|
}
|
|
private void saveRobotOrder(KlineConfigDTO klineConfigDTO, List<Kline> minute) {
|
Random random = new Random();
|
Item item = itemService.findBySymbol(klineConfigDTO.getSymbol());
|
|
List<RobotOrder> robotOrders = new ArrayList<>(minute.size());
|
for (Kline kline : minute) {
|
RobotOrder robotOrder = new RobotOrder();
|
robotOrder.setSymbol(klineConfigDTO.getSymbol());
|
robotOrder.setPrice(NumberUtil.roundDown(randomDouble(kline.getHigh(), kline.getLow(),random),item.getDecimals()).doubleValue());
|
// 设置订单状态挂单中
|
robotOrder.setStatus(1);
|
robotOrder.setOrderType(random.nextInt(2) + 1);
|
robotOrder.setDirection(random.nextInt(2) + 1);
|
robotOrder.setOrderQuantity(NumberUtil.roundDown(randomDouble(kline.getVolume(), kline.getVolume() * 0.8, random), item.getDecimals()).doubleValue());
|
robotOrder.setTurnover(0d);
|
robotOrder.setTs(kline.getTs());
|
robotOrder.setUuid(UUID.randomUUID().toString().replaceAll("-", ""));
|
robotOrder.setUid(UUID.randomUUID().toString().replaceAll("-", ""));
|
robotOrders.add(robotOrder);
|
}
|
robotOrderService.saveBatch(robotOrders);
|
}
|
|
// 生成秒级的假图
|
private List<Kline> accrodingSecOrign(KlineConfigDTO klineConfigDTO,RobotModel robotModel, List<Kline> originalSecKline, int sec) {
|
|
Item item = itemService.findBySymbol(klineConfigDTO.getSymbol());
|
|
double todayVolume = randomDouble(klineConfigDTO.getTurnoverHigh(), klineConfigDTO.getTurnoverLow(), new Random());
|
// BigDecimal todayAmount = todayVolume.divide(klineConfigDTO.getOpenPrice().add(klineConfigDTO.getClosePrice()).divide(BigDecimal.valueOf(2)), item.getDecimals(), BigDecimal.ROUND_HALF_UP);
|
double todayAmount = Arith.div(todayVolume,(klineConfigDTO.getOpenPrice() + klineConfigDTO.getClosePrice()) / 2, item.getDecimals());
|
double totalVolume = originalSecKline.stream()
|
.mapToDouble(klien -> klien.getVolume())
|
.sum();
|
Tuple startAndEnd = getStartAndEnd(klineConfigDTO.getOpenTimeTs());
|
|
klineConfigDTO.setOpenTimeTs(startAndEnd.get(0));
|
klineConfigDTO.setCloseTimeTs(startAndEnd.get(1));
|
|
Kline finalSecondKline;
|
double open = klineConfigDTO.getOpenPrice();
|
double secHigh;
|
double secLow;
|
double secVolume;
|
double secAmount;
|
boolean isOver = false;
|
List<Kline> finalResult = new ArrayList<>(originalSecKline.size());
|
Random random = new Random();
|
for (int i = 0; i < originalSecKline.size(); i++) {
|
Kline kline = originalSecKline.get(i);
|
finalSecondKline = new Kline();
|
finalSecondKline.setTs(klineConfigDTO.getOpenTimeTs() + i * sec * 1000);
|
finalSecondKline.setSymbol(item.getSymbol());
|
|
// 设置开仓价
|
finalSecondKline.setOpen(open);
|
|
// 分钟级最高价 model.high / model.open * 分钟的open
|
secHigh = NumberUtil.roundDown((kline.getHigh() / kline.getOpen()) * finalSecondKline.getOpen(), item.getDecimals()).doubleValue();
|
// secHigh = NumberUtil.roundDown(Arith.div(kline.getHigh(), kline.getOpen()) * finalSecondKline.getOpen(), item.getDecimals()).doubleValue();
|
// secHigh = kline.getHigh().divide(kline.getOpen(), 10, BigDecimal.ROUND_HALF_UP).multiply(finalSecondKline.getOpen()).setScale(item.getDecimals(), BigDecimal.ROUND_HALF_UP);
|
finalSecondKline.setHigh(secHigh);
|
|
// 分钟级最低价
|
secLow = NumberUtil.roundDown((kline.getLow() / kline.getOpen()) * finalSecondKline.getOpen(), item.getDecimals()).doubleValue();
|
// secLow = kline.getLow().divide(kline.getOpen(), 10, BigDecimal.ROUND_HALF_UP).multiply(finalSecondKline.getOpen()).setScale(item.getDecimals(), BigDecimal.ROUND_HALF_UP);
|
finalSecondKline.setLow(secLow);
|
|
// 分钟级成交量
|
if (kline.getVolume() == 0) {
|
secVolume = 0;
|
} else {
|
secVolume = NumberUtil.roundDown((kline.getVolume() / totalVolume) * todayVolume, item.getDecimals()).doubleValue();
|
// secVolume = kline.getVolume().divide(BigDecimal.valueOf(totalVolume),10, BigDecimal.ROUND_HALF_UP).multiply(todayVolume).setScale(item.getDecimals(), BigDecimal.ROUND_HALF_UP);
|
}
|
finalSecondKline.setVolume(secVolume);
|
|
if (kline.getAmount() == 0) {
|
secAmount = 0;
|
} else {
|
// 分钟级成交手数
|
secAmount = NumberUtil.roundDown((kline.getAmount() / robotModel.getAmount()) * todayAmount, item.getDecimals()).doubleValue();
|
// secAmount = kline.getAmount().divide(BigDecimal.valueOf(robotModel.getAmount()),10, BigDecimal.ROUND_HALF_UP).multiply(todayAmount).setScale(item.getDecimals(), BigDecimal.ROUND_HALF_UP);
|
}
|
|
finalSecondKline.setAmount(secAmount);
|
|
|
// 收盘价
|
if (finalSecondKline.getTs() > klineConfigDTO.getCloseTimeTs() || i == originalSecKline.size() - 1) {
|
finalSecondKline.setClose(BigDecimal.valueOf(klineConfigDTO.getClosePrice()).setScale(item.getDecimals(), BigDecimal.ROUND_HALF_UP).doubleValue());
|
isOver = true;
|
} else {
|
double close = randomDouble(secHigh, secLow, random);
|
finalSecondKline.setClose(BigDecimal.valueOf(close).setScale(item.getDecimals(), BigDecimal.ROUND_HALF_UP).doubleValue());
|
}
|
|
|
open = finalSecondKline.getClose();
|
finalResult.add(finalSecondKline);
|
if (isOver) {
|
break;
|
}
|
}
|
return finalResult;
|
}
|
|
@NotNull
|
private List<Kline> getRecentWholwSecKline(String symbol, List<Kline> collect) {
|
Item bySymbol = itemService.findBySymbol(symbol);
|
|
List<Kline> originalSecKline = new ArrayList<>(collect.size());
|
Kline originalSecondKline = null;
|
Random random = new Random();
|
for (Kline kline : collect) {
|
|
// 将这一分钟成交量拆分成60份
|
List<Double> volumes = splitData(kline.getVolume(), 60, 30);
|
List<Double> amounts = splitData(kline.getAmount(), 60, 30);
|
|
double open = originalSecondKline == null ? kline.getOpen() : originalSecondKline.getClose();
|
|
for (int i = 0; i < 60; i++) {
|
originalSecondKline = new Kline();
|
originalSecondKline.setSymbol(symbol);
|
originalSecondKline.setTs(kline.getTs() + i * 1000);
|
|
originalSecondKline.setOpen(BigDecimal.valueOf(open).setScale(bySymbol.getDecimals(), BigDecimal.ROUND_HALF_UP).doubleValue());
|
double close = 0;
|
if (i == 59) {
|
originalSecondKline.setClose(BigDecimal.valueOf(kline.getClose()).setScale(bySymbol.getDecimals(), BigDecimal.ROUND_HALF_UP).doubleValue());
|
} else {
|
close = randomDouble(kline.getOpen(), kline.getClose(), random);
|
originalSecondKline.setClose(BigDecimal.valueOf(close).setScale(bySymbol.getDecimals(), BigDecimal.ROUND_HALF_UP).doubleValue());
|
}
|
double high = randomDouble(kline.getLow(), kline.getHigh(), random);
|
originalSecondKline.setHigh(BigDecimal.valueOf(high).setScale(bySymbol.getDecimals(), BigDecimal.ROUND_HALF_UP).doubleValue());
|
double low = randomDouble(kline.getLow(), originalSecondKline.getClose(), random);
|
originalSecondKline.setLow(BigDecimal.valueOf(low).min(BigDecimal.valueOf(originalSecondKline.getOpen())).setScale(bySymbol.getDecimals(), BigDecimal.ROUND_HALF_UP).doubleValue());
|
originalSecondKline.setVolume(BigDecimal.valueOf(volumes.get(i)).setScale(bySymbol.getDecimals(), BigDecimal.ROUND_HALF_UP).doubleValue());
|
originalSecondKline.setAmount(BigDecimal.valueOf(amounts.get(i)).setScale(bySymbol.getDecimals(), BigDecimal.ROUND_HALF_UP).doubleValue());
|
|
// 重新调整K线图数据
|
adjustKline(originalSecondKline);
|
|
// 重新打散
|
while (originalSecondKline.getHigh() == originalSecondKline.getLow()) {
|
// 收盘价在最高和最低之间 当最高价最低价相同时, close = random ( high * random(1,1.01) , low * random(1,1.01) )
|
|
// 随机最高价 为当前分钟最高价的1.005倍
|
// BigDecimal tempHigh = kline.getHigh().multiply(getRandomBigDecimal(1));
|
double tempHigh = kline.getHigh() * getRandomBigDecimal(1).doubleValue();
|
// 随机最低价 为当前分钟最低价的0.995倍
|
// double tempLow = kline.getLow().multiply(getRandomBigDecimal(-1));
|
double tempLow = kline.getLow() * getRandomBigDecimal(-1).doubleValue();
|
|
originalSecondKline.setClose(BigDecimal.valueOf(randomDouble(tempHigh,tempLow, random)).setScale(bySymbol.getDecimals(), BigDecimal.ROUND_HALF_UP).doubleValue());
|
|
// 最高价在收盘价和这一分钟的最高价之间
|
originalSecondKline.setHigh(BigDecimal.valueOf(randomDouble(originalSecondKline.getClose(), kline.getHigh(), random)).setScale(bySymbol.getDecimals(), BigDecimal.ROUND_HALF_UP).doubleValue());
|
|
// 最低价在收盘价和这一分钟的最低价之间
|
originalSecondKline.setLow(BigDecimal.valueOf(randomDouble(kline.getLow(), originalSecondKline.getClose(), random)).setScale(bySymbol.getDecimals(), BigDecimal.ROUND_HALF_UP).doubleValue());
|
|
adjustKline(originalSecondKline);
|
}
|
|
open = originalSecondKline.getClose();
|
originalSecKline.add(originalSecondKline);
|
}
|
}
|
return originalSecKline;
|
}
|
|
|
public static Kline adjustKline(Kline kline) {
|
double[] values = {kline.getHigh(), kline.getOpen(), kline.getClose(), kline.getLow()};
|
Arrays.sort(values);
|
kline.setHigh(values[3]);
|
kline.setLow(values[0]);
|
return kline;
|
}
|
|
|
public static BigDecimal getRandomBigDecimal(int input) {
|
BigDecimal lowerBound;
|
BigDecimal upperBound;
|
|
if (input == 1) {
|
lowerBound = BigDecimal.ONE;
|
upperBound = new BigDecimal("1.005");
|
} else if (input == -1) {
|
lowerBound = new BigDecimal("0.995");
|
upperBound = BigDecimal.ONE;
|
} else {
|
throw new IllegalArgumentException("Invalid input value. Expected 1 or -1.");
|
}
|
|
BigDecimal range = upperBound.subtract(lowerBound);
|
BigDecimal randomValue = range.multiply(BigDecimal.valueOf(Math.random())).add(lowerBound);
|
return randomValue.setScale(3, RoundingMode.HALF_UP);
|
}
|
|
private void printResult(List<Kline> originalSecKline) {
|
// 输出到echarts
|
List<List<Object>> result = new ArrayList<>();
|
List<String> time = new ArrayList<>();
|
// 格式化时间
|
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("HH:mm:ss");
|
|
for (Kline kline : originalSecKline) {
|
List<Object> tmp = new ArrayList<>();
|
time.add(simpleDateFormat.format(new Date(kline.getTs())));
|
tmp.add(BigDecimal.valueOf(kline.getOpen()).setScale(5, BigDecimal.ROUND_HALF_UP));
|
tmp.add(BigDecimal.valueOf(kline.getClose()).setScale(5, BigDecimal.ROUND_HALF_UP));
|
tmp.add(BigDecimal.valueOf(kline.getLow()).setScale(5, BigDecimal.ROUND_HALF_UP));
|
tmp.add(BigDecimal.valueOf(kline.getHigh()).setScale(5, BigDecimal.ROUND_HALF_UP));
|
// tmp.add(kline.getVolume().setScale(5, BigDecimal.ROUND_HALF_UP));
|
result.add(tmp);
|
}
|
System.err.println(JSON.toJSONString(time));
|
System.err.println(JSON.toJSONString(result));
|
}
|
|
/**
|
* 传入时间字符串获取当天第一个时间戳
|
*/
|
private Long getTodayFirstTimestamp(String time) {
|
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
|
Date date = null;
|
try {
|
date = dateFormat.parse(time);
|
} catch (ParseException e) {
|
e.printStackTrace();
|
}
|
Calendar calendar = Calendar.getInstance();
|
calendar.setTime(date);
|
calendar.set(Calendar.HOUR_OF_DAY, 0);
|
calendar.set(Calendar.MINUTE, 0);
|
calendar.set(Calendar.SECOND, 0);
|
return calendar.getTimeInMillis();
|
}
|
|
/**
|
* 传入时间字符串获取当天最后一个时间戳
|
*/
|
private Long getTodayLastTimestamp(String time) {
|
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
|
Date date = null;
|
try {
|
date = dateFormat.parse(time);
|
} catch (ParseException e) {
|
e.printStackTrace();
|
}
|
Calendar calendar = Calendar.getInstance();
|
calendar.setTime(date);
|
calendar.set(Calendar.HOUR_OF_DAY, 23);
|
calendar.set(Calendar.MINUTE, 59);
|
calendar.set(Calendar.SECOND, 59);
|
return calendar.getTimeInMillis();
|
}
|
|
@NotNull
|
private List<Kline> parseHistoryKLine(RobotModel robotModel) {
|
JSONArray jsonArray = JSON.parseArray(robotModel.getKLineData());
|
List<Kline> klines = new ArrayList<>(jsonArray.size());
|
for (int i = 0; i < jsonArray.size(); i++) {
|
JSONObject item = jsonArray.getJSONObject(i);
|
Kline kline = new Kline();
|
kline.setTs(item.getLong("ts"));
|
kline.setVolume(item.getDouble("volume"));
|
kline.setAmount(item.getDouble("amount"));
|
kline.setOpen(item.getDouble("open"));
|
kline.setHigh(item.getDouble("high"));
|
kline.setLow(item.getDouble("low"));
|
kline.setClose(item.getDouble("close"));
|
klines.add(kline);
|
}
|
return klines;
|
}
|
|
public static double randomDouble(double a, double b, Random random) {
|
double diff = b - a;
|
double randNum = diff * random.nextDouble();
|
return a + randNum;
|
}
|
|
public static List<Double> splitData(double data, int n, double maxDeviationPercent) {
|
// 计算每份的理论平均值
|
double avg = data / n;
|
// 计算允许的最大偏差
|
double maxDeviation = avg * maxDeviationPercent / 100;
|
|
// 创建一个存储每份数据的列表
|
List<Double> splits = new ArrayList<>();
|
|
Random random = new Random();
|
double remainingData = data;
|
|
// 按照N-1份进行随机拆分
|
for (int i = 0; i < n - 1; i++) {
|
// 生成一个随机数,表示当前份数据的比例(0到1之间)
|
double ratio = random.nextDouble();
|
// 计算当前份数据的大小
|
double currentSplit = avg + (ratio - 0.5) * 2 * maxDeviation;
|
// 将当前份数据加入列表
|
splits.add(currentSplit);
|
// 更新剩余数据量
|
remainingData -= currentSplit;
|
}
|
|
// 最后一份数据即为剩余数据量
|
splits.add(remainingData);
|
|
// 打乱列表中数据的顺序
|
Collections.shuffle(splits);
|
return splits;
|
}
|
|
private static BigDecimal getRandomBigDecimal(BigDecimal min, BigDecimal max, Random random) {
|
double range = max.doubleValue() - (min.doubleValue());
|
double randomValue = range * random.nextDouble();
|
return BigDecimal.valueOf(min.doubleValue() + randomValue).setScale(min.scale(), BigDecimal.ROUND_HALF_UP);
|
}
|
|
/**
|
* 查询秒级K线图
|
*
|
* @param symbol
|
* @return
|
*/
|
public List<Kline> querySecKlineBySymbol(String symbol) {
|
|
Tuple startAndEnd = getStartAndEnd();
|
|
List<EtfSecKLine> list = etfSecKLineService.list(new QueryWrapper<EtfSecKLine>().eq("symbol", symbol).between("ts", startAndEnd.get(0), startAndEnd.get(1)).orderByAsc("ts"));
|
|
return etfSecKLineWrapper.toEntity(list);
|
}
|
|
public Tuple getStartAndEnd() {
|
// 获取当前时间的时间戳(毫秒级)
|
long currentTimestamp = System.currentTimeMillis();
|
|
// 转换为ZonedDateTime对象,使用系统默认时区
|
ZonedDateTime currentDateTime = Instant.ofEpochMilli(currentTimestamp)
|
.atZone(ZoneId.systemDefault());
|
|
// 获取当天的21:30时间点
|
ZonedDateTime targetDateTime;
|
if (currentDateTime.getHour() >= 4 && currentDateTime.getHour() <= 23) {
|
// 当前时间在4点到21点之间,获取当天的21:30时间点
|
targetDateTime = currentDateTime.withHour(23).withMinute(59).withSecond(59).withNano(0);
|
} else {
|
// 当前时间在0点到4点之间,获取前一天的21:30时间点
|
targetDateTime = currentDateTime.minusDays(1).withHour(21).withMinute(30).withSecond(0).withNano(0);
|
}
|
|
|
// 获取第二天凌晨4点时间点
|
ZonedDateTime nextDayDateTime = targetDateTime.plusDays(1).withHour(4).withMinute(0);
|
// 转换为毫秒时间戳
|
long start = targetDateTime.toInstant().toEpochMilli();
|
long end = nextDayDateTime.toInstant().toEpochMilli();
|
return new Tuple(start, end);
|
}
|
|
|
public Tuple getStartAndEnd(long ts) {
|
// 转换为ZonedDateTime对象,使用系统默认时区
|
ZonedDateTime inputDateTime = Instant.ofEpochMilli(ts)
|
.atZone(ZoneId.systemDefault());
|
|
// 获取当天的21:30时间点
|
ZonedDateTime targetDateTime = inputDateTime.withHour(21).withMinute(30).withSecond(0).withNano(0);
|
|
// 获取第二天的4:00时间点
|
ZonedDateTime nextDayDateTime = targetDateTime.plusDays(1).withHour(4).withMinute(0);
|
|
// 转换为毫秒时间戳
|
long start = targetDateTime.toInstant().toEpochMilli();
|
long end = nextDayDateTime.toInstant().toEpochMilli();
|
|
return new Tuple(start, end);
|
}
|
|
|
|
/**
|
* 查询所有秒级K线图
|
*
|
* @param symbol
|
* @return
|
*/
|
public List<Kline> querySecKlineBySymbolAllData(String symbol) {
|
List<EtfSecKLine> list = etfSecKLineService.list(new QueryWrapper<EtfSecKLine>().eq("symbol", symbol).orderBy(true, true, "ts"));
|
return etfSecKLineWrapper.toEntity(list);
|
}
|
}
|