package com.yami.trading.admin.controller.etf; import cn.hutool.core.lang.Tuple; import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.google.common.collect.Lists; import com.yami.trading.admin.controller.service.SysUserOperService; import com.yami.trading.bean.data.domain.Depth; import com.yami.trading.bean.data.domain.Kline; import com.yami.trading.bean.data.domain.Realtime; import com.yami.trading.bean.etf.domain.EtfKLine; 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.EtfSecKLineWrapper; import com.yami.trading.bean.etf.mapstruct.KlineConfigWrapper; import com.yami.trading.bean.etf.query.KlineConfigQuery; import com.yami.trading.bean.item.domain.Item; import com.yami.trading.bean.item.dto.ItemDTO; import com.yami.trading.bean.item.query.ItemQuery; import com.yami.trading.common.domain.Result; import com.yami.trading.common.query.QueryWrapperGenerator; import com.yami.trading.common.util.CopyBeanUtils; import com.yami.trading.common.util.IPHelper; import com.yami.trading.security.common.model.YamiSysUser; import com.yami.trading.security.common.util.SecurityUtils; import com.yami.trading.service.etf.EtfSecKLineService; import com.yami.trading.service.etf.KlineConfigService; import com.yami.trading.service.etf.MarketService; import com.yami.trading.service.item.ItemService; import com.yami.trading.sys.model.SysUser; import com.yami.trading.sys.service.SysUserService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import javax.validation.Valid; import java.math.BigDecimal; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.List; import java.util.Map; import java.util.Objects; /** * etfK线图配置表Controller * * @author lucas * @version 2023-05-03 */ @Api(tags = "债劵ETF_币对管理") @RestController @CrossOrigin @RequestMapping(value = "/etf/klineConfig") public class KlineConfigController { @Autowired private KlineConfigService klineConfigService; @Autowired private KlineConfigWrapper klineConfigWrapper; @Autowired private EtfSecKLineWrapper etfSecKLineWrapper; @Autowired private ItemService itemService; @Autowired MarketService marketService; @Autowired EtfSecKLineService etfSecKLineService; @Autowired SysUserService sysUserService; @Autowired private SysUserOperService sysUserOperService; /** * etfK线图配置表列表数据 */ @ApiOperation(value = "查询etfK线图配置表列表数据") @GetMapping("list") public Result> list(ItemQuery itemQuery, Page page) throws Exception { QueryWrapper queryWrapper = QueryWrapperGenerator.buildQueryCondition(itemQuery, ItemQuery.class); IPage result = itemService.findPage(page, queryWrapper); return Result.ok(result); } /** * 添加交易对 */ @ApiOperation(value = "添加交易对") @PostMapping("addItem") public Result addItem(@Valid @RequestBody Item item) throws Exception { //新增或编辑表单保存 String uuid = item.getUuid(); Item old = null; if (uuid != null) { old = itemService.getById(uuid); String[] propertyNames = CopyBeanUtils.getNullPropertyNames(item); String[] copy = Arrays.copyOf(propertyNames, propertyNames.length + 5); copy[propertyNames.length] = "pips"; copy[propertyNames.length + 1] = "pipsAmount"; copy[propertyNames.length + 2] = "adjustmentValue"; copy[propertyNames.length + 3] = "unitAmount"; copy[propertyNames.length + 4] = "unitFee"; BeanUtils.copyProperties(item, old, copy); itemService.updateById(old); } else { itemService.save(item); } YamiSysUser sysUser = SecurityUtils.getSysUser(); if (sysUser != null) { SysUser secUser = sysUserService.getByUserName(sysUser.getUsername()); if (secUser != null) { if (old != null) { String dec = "修改前数据:{" + "名称=" + old.getName() + ", 代码=" + old.getSymbol() + ", 保留精度=" + old.getDecimals() + ", 交易量倍数=" + old.getMultiple() + ", 借贷利率=" + old.getBorrowingRate() + "}。" + "修改后数据:{" + "名称=" + item.getName() + ", 代码=" + item.getSymbol() + ", 保留精度=" + item.getDecimals() + ", 交易量倍数=" + item.getMultiple() + ", 借贷利率=" + item.getBorrowingRate() + "}"; sysUserOperService.saveLog(secUser, secUser.getUsername(), StrUtil.format("ip:{},行情品种 {}的数据被编辑。{}", IPHelper.getIpAddr(), item.getSymbol(), dec)); } else { sysUserOperService.saveLog(secUser, secUser.getUsername(), StrUtil.format("ip:{},新增行情品种 {}。", IPHelper.getIpAddr(), item.getSymbol())); } } } return Result.ok("添加交易对成功"); } /** * 根据Id获取etfK线图配置表数据 */ @ApiOperation(value = "根据Id获取etfK线图配置表数据") @GetMapping("queryById") public Result queryById(String id) { return Result.ok(klineConfigWrapper.toDTO(klineConfigService.getById(id))); } /** * 根据Id获取etfK线图配置表数据 */ @ApiOperation(value = "查询etfK线图配置列表") @GetMapping("pageList") public Result> pageList(KlineConfigQuery query, Page page) throws Exception { IPage list; if (Objects.isNull(query.getSymbol())) { list = klineConfigService.page(page, new LambdaQueryWrapper().orderBy(true, false, KlineConfig::getOpenTimeTs)).convert(klineConfigWrapper::toDTO); } else { list = klineConfigService.page(page, new LambdaQueryWrapper<>(new KlineConfig()).eq(KlineConfig::getSymbol, query.getSymbol()).orderBy(true, false, KlineConfig::getOpenTimeTs)).convert(klineConfigWrapper::toDTO); } list.getRecords().forEach(r -> { Item bySymbol = itemService.findBySymbol(r.getSymbol()); if (bySymbol != null) { r.setSymbolName(bySymbol.getName()); } }); return Result.ok(list); } /** * 保存etfK线图配置表 */ @ApiOperation(value = "保存etfK线图配置表") @PostMapping("save") public Result save(@RequestBody KlineConfigDTO klineConfigDTO) { Tuple startAndEnd = klineConfigService.getStartAndEnd(klineConfigDTO.getOpenTimeTs()); klineConfigDTO.setOpenTimeTs(startAndEnd.get(0)); klineConfigDTO.setCloseTimeTs(startAndEnd.get(1)); if (etfSecKLineService.count(new LambdaQueryWrapper<>(new EtfSecKLine()).eq(EtfSecKLine::getSymbol, klineConfigDTO.getSymbol()).between(EtfSecKLine::getTs, klineConfigDTO.getOpenTimeTs(), klineConfigDTO.getCloseTimeTs())) > 0) { return Result.failed("今天数据已存在,无法添加"); } //新增或编辑表单保存 KlineConfig klineConfig = klineConfigWrapper.toEntity(klineConfigDTO); klineConfig.setCreateTime(new Date()); List klines = klineConfigService.generateSecKLine(klineConfigDTO); if (klines != null) { List etfSecKLines = etfSecKLineWrapper.toDTO(klines); etfSecKLineService.saveBatch(etfSecKLines, 10000); } klineConfigService.saveOrUpdate(klineConfig); marketService.clear(); return Result.ok("保存etfK线图配置表成功"); } /** * 删除etfK线图配置表 */ @ApiOperation(value = "删除etfK线图配置表") @DeleteMapping("delete") public Result delete(String ids) { List list = Arrays.asList(ids.split(",")); klineConfigService.deleteByRobotModelId(list); return Result.ok("删除etfK线图配置表成功"); } /** * 删除etfK线图配置表 */ @ApiOperation(value = "初始化ETF当天K线图,分钟级别") @PostMapping("init") public Result init(@RequestBody KlineConfigDTO klineConfigDTO) { Item symbol = itemService.findBySymbol(klineConfigDTO.getSymbol()); EtfKLine model = klineConfigService.queryKLine(klineConfigDTO); List klineList = model.getKlineList(); List result = new ArrayList<>(); // 抽象成15分钟图,方便前端显示 List> partition = Lists.partition(klineList, 15); for (List list1Min : partition) { Double high = list1Min.get(0).getHigh(); Double low = list1Min.get(0).getLow(); for (Kline kline : list1Min) { if (high <= kline.getHigh()) { high = kline.getHigh(); } if (low >= kline.getLow()) { low = kline.getLow(); } } int lastIndex = list1Min.size() - 1; Kline kline = new Kline(); kline.setSymbol(klineConfigDTO.getSymbol()); kline.setTs(list1Min.get(lastIndex).getTs()); kline.setSymbol(klineConfigDTO.getSymbol()); kline.setOpen(BigDecimal.valueOf(list1Min.get(0).getOpen()).setScale(symbol.getDecimals(), BigDecimal.ROUND_DOWN).doubleValue()); kline.setHigh(BigDecimal.valueOf(high).setScale(symbol.getDecimals(), BigDecimal.ROUND_DOWN).doubleValue()); kline.setLow(BigDecimal.valueOf(low).setScale(symbol.getDecimals(), BigDecimal.ROUND_DOWN).doubleValue()); kline.setClose(BigDecimal.valueOf(list1Min.get(lastIndex).getClose()).setScale(symbol.getDecimals(), BigDecimal.ROUND_DOWN).doubleValue()); kline.setPeriod(Kline.PERIOD_15MIN); // 格式化小数点位 // klineOneTop.formatPoint(kline); double sumAmount = klineList.stream() .map(Kline::getAmount) .filter(Objects::nonNull) .reduce(0D, Double::sum); double sumVolume = klineList.stream() .map(Kline::getVolume) .filter(Objects::nonNull) .reduce(0D, Double::sum); kline.setAmount(sumAmount); kline.setVolume(sumVolume); result.add(kline); } model.setKlineList(result); return Result.ok(model); } /** * 根据Id获取etfK线图配置表数据 */ @ApiOperation(value = "获取每秒k线图") @GetMapping("secKline") public Result secKline(String symbol) { return Result.ok(marketService.queryRealtime(symbol)); } /** * 根据Id获取etfK线图配置表数据 */ @ApiOperation(value = "获取每秒深度") @GetMapping("secDepth") public Result secDepth(String symbol) { return Result.ok(marketService.queryDepth(symbol)); } /** * 根据Id获取etfK线图配置表数据 */ @ApiOperation(value = "加倍深度") @GetMapping("accelerate") public Result accelerate(@RequestParam(value = "symbol") String symbol, @RequestParam(value = "enlarge") Double enlarge, @RequestParam(value = "enable") Boolean enable) { Map accelerate = marketService.getAccelerate(); if (enable) { accelerate.put(symbol, enlarge); } else { accelerate.remove(symbol); } return Result.succeed(); } }