package com.yami.trading.api.controller; import cn.hutool.core.util.StrUtil; import com.yami.trading.bean.contract.domain.ContractOrder; import com.yami.trading.bean.data.domain.Realtime; import com.yami.trading.bean.item.domain.Item; import com.yami.trading.common.domain.Result; import com.yami.trading.common.exception.YamiShopBindException; import com.yami.trading.common.lang.LangUtils; import com.yami.trading.common.util.DateTimeTools; import com.yami.trading.common.util.StringUtils; import com.yami.trading.common.util.ThreadUtils; import com.yami.trading.security.common.util.SecurityUtils; import com.yami.trading.service.contract.ContractLockService; import com.yami.trading.service.contract.ContractOrderService; import com.yami.trading.service.data.DataService; import com.yami.trading.service.item.ItemService; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.ObjectUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletRequest; import java.io.IOException; import java.math.BigDecimal; import java.util.*; /** * 永续合约持仓单 */ @RestController @CrossOrigin @Slf4j public class ApiContractOrderController { @Autowired private ContractOrderService contractOrderService; @Autowired private DataService dataService; @Autowired private ItemService itemService; @Autowired private ContractLockService contractLockService; private final String action = "/api/contractOrder!"; /** * 止盈止损 * order_no 订单号 * stop_price_profit 止盈触发价格 * stop_price_loss 止损触发价格 */ @RequestMapping(action + "stopLossAndProfit.action") public Result stopLossAndProfit(HttpServletRequest request) { String order_no = request.getParameter("order_no"); String stop_price_profit = request.getParameter("stop_price_profit"); String stop_price_loss = request.getParameter("stop_price_loss"); try { ContractOrder order = contractOrderService.findByOrderNo(order_no); if(StringUtils.isNotEmpty(stop_price_profit)) { order.setStopPriceProfit(new BigDecimal(stop_price_profit)); }if(StringUtils.isNotEmpty(stop_price_loss)) { order.setStopPriceLoss(new BigDecimal(stop_price_loss)); } contractOrderService.stopLossAndProfit(order); } catch (Exception t) { log.error("操作失败", t); return Result.failed("操作失败"); } return Result.succeed("操作成功"); } /** * 平仓 * order_no 订单号 */ @RequestMapping(action + "close.action") public Result close(@RequestParam String order_no) { try { // 建议使用线程池 TODO CloseDelayThread lockDelayThread = new CloseDelayThread(SecurityUtils.getCurrentUserId(), order_no, this.contractOrderService, false); Thread t = new Thread(lockDelayThread); t.start(); } catch (Exception e) { log.error("平仓失败", e); return Result.failed("平仓失败"); } return Result.succeed("平仓成功"); } /** * 一键平仓 */ @RequestMapping(action + "closeAll.action") public Result closeAll() { try { CloseDelayThread lockDelayThread = new CloseDelayThread(SecurityUtils.getCurrentUserId(), "", this.contractOrderService, true); Thread t = new Thread(lockDelayThread); t.start(); } catch (Exception e) { log.error("一键平仓失败", e); return Result.failed("一键平仓失败"); } return Result.succeed("一键平仓成功"); } /** * 订单列表 * page_no 页码 * symbol 币种 * type 查询类型:orders 当前持仓单;hisorders 历史持仓单; */ @RequestMapping(action + "list.action") public Result>> list(@RequestParam(required = false, defaultValue = "1") Integer page_no , @RequestParam(required = false) String type, @RequestParam(required = false) String symbol, @RequestParam(required = false) String startTime, @RequestParam(required = false) String endTime, @RequestParam(required = false) String symbolType) { List> data = new ArrayList<>(); String partyId = SecurityUtils.getCurrentUserId(); if ("orders".equals(type)) { // 此处返回的 closeTime 是时间戳类型 data = this.contractOrderService.findSubmittedRedis(partyId, symbol, startTime, endTime, symbolType); } else if ("hisorders".equals(type)) { // 此处返回的 closeTime 是时间戳类型 data = this.contractOrderService.getPaged(page_no, 10, partyId, symbol, type, startTime, endTime, symbolType); } String symbolsStr = ""; Set symbols = new HashSet<>(); for (int i = 0; i < data.size(); i++) { Map oneRow = data.get(i); String sym = oneRow.get("symbol").toString(); if (!symbols.contains(sym)) { symbols.add(sym); if (i != 0) { symbolsStr = symbolsStr + "," + sym; } else { symbolsStr = sym; } } if (ObjectUtils.isEmpty(oneRow.get("profit"))) { oneRow.put("profit", 0); } if (oneRow.get("create_time_ts") != null && StrUtil.isNotBlank(oneRow.get("create_time_ts").toString()) && !Objects.equals(oneRow.get("create_time_ts").toString(), "0")) { String oneValue = oneRow.get("create_time_ts").toString(); Long timestamp = Long.parseLong(oneValue); long showTimestamp = DateTimeTools.transferShowTimeToClientTime(timestamp); oneRow.put("create_time_ts", String.valueOf(showTimestamp)); } if (oneRow.get("close_time") != null && StrUtil.isNotBlank(oneRow.get("close_time").toString()) && !Objects.equals(oneRow.get("close_time").toString(), "0")) { String oneValue = oneRow.get("close_time").toString(); if (oneValue.contains("-")) { continue; } Long timestamp = Long.parseLong(oneValue); long showTimestamp = DateTimeTools.transferShowTimeToClientTime(timestamp); oneRow.put("close_time", String.valueOf(showTimestamp)); } } List realtime_all = this.dataService.realtime(symbolsStr); if (realtime_all.size() <= 0) { realtime_all = new ArrayList<>(); } Map realtimeMap = new HashMap(); for (int i = 0; i < realtime_all.size(); i++) { realtimeMap.put(realtime_all.get(i).getSymbol(), realtime_all.get(i)); } for (int i = 0; i < data.size(); i++) { Map map = data.get(i); // 标记价格 Realtime realtime = realtimeMap.get(map.get("symbol")); if (null == realtime) { map.put("mark_price", 0); } else { String thisSymbol = realtime.getSymbol(); Item bySymbol = itemService.findBySymbol(thisSymbol); if(LangUtils.isEnItem()){ map.put("name", bySymbol.getName()); } map.put("mark_price", realtime.getClose()); } if (ObjectUtils.isEmpty(data.get(i).get("close_avg_price"))) { data.get(i).put("close_avg_price", data.get(i).get("mark_price")); } } return Result.ok(data); } /** * 订单详情 * order_no 订单号 */ @RequestMapping(action + "get.action") public Result> get(@RequestParam String order_no) { ContractOrder order = this.contractOrderService.findByOrderNo(order_no); if (null == order) { log.info("contractOrder!get order_no:" + order_no + ", order null"); throw new YamiShopBindException("订单不存在"); } Map retData = this.contractOrderService.bulidOne(order); for (Map.Entry oneEntry : retData.entrySet()) { String key = oneEntry.getKey(); Object value = oneEntry.getValue(); if (Objects.equals(key, "create_time_ts") || Objects.equals(key, "close_time") || Objects.equals(key, "close_time_ts")) { if (value == null || StrUtil.isBlank(value.toString()) || Objects.equals(value.toString(), "0")) { continue; } if (value.toString().contains("-")) { continue; } Long timestamp = Long.parseLong(value.toString()); long showTimestamp = DateTimeTools.transferShowTimeToClientTime(timestamp); retData.put(key, String.valueOf(showTimestamp)); } } return Result.ok(retData); } /** * 订单列表 *

* page_no 页码 * symbol 币种 * type 查询类型:orders 当前持仓单;hisorders 历史持仓单; */ @RequestMapping(action + "assets.action") public Result> assets(HttpServletRequest request) { String page_no = request.getParameter("page_no"); String symbol = request.getParameter("symbol"); String type = request.getParameter("type"); String symbolType = request.getParameter("symbolType"); if(StringUtils.isEmptyString(symbolType)){ symbolType = Item.forex; } String startTime = request.getParameter("startTime"); String endTime = request.getParameter("endTime"); String page_size = request.getParameter("page_size"); List> data = new ArrayList>(); if (StringUtils.isNullOrEmpty(page_no)) { page_no = "1"; } if (StringUtils.isNullOrEmpty(page_size)) { page_size = "10"; } if (!StringUtils.isInteger(page_no)) { throw new YamiShopBindException("页码不是整数"); } if (Integer.valueOf(page_no).intValue() <= 0) { throw new YamiShopBindException("页码不能小于等于0"); } String partyId = SecurityUtils.getCurrentUserId(); int page_no_int = Integer.valueOf(page_no).intValue(); int page_size_int = 10; Long count = 0L; if ("orders".equals(type)) { data = this.contractOrderService.findSubmittedRedis(partyId, symbol, null, null, symbolType); count = (long) data.size(); } else if ("hisorders".equals(type)) { count = this.contractOrderService.getOrdersCount("hisorders", partyId, symbol, symbolType); if (page_size.equals("all")) { page_size_int = Math.toIntExact(count); } else { page_size_int = Integer.valueOf(page_size).intValue(); } data = this.contractOrderService.getPaged(page_no_int, page_size_int, partyId, symbol, type, startTime, endTime, symbolType); } String symbolsStr = ""; Set symbols = new HashSet(); for (int i = 0; i < data.size(); i++) { Map oneRow = data.get(i); String sym = oneRow.get("symbol").toString(); if (!symbols.contains(sym)) { symbols.add(sym); if (i != 0) { symbolsStr = symbolsStr + "," + sym; } else { symbolsStr = sym; } } if (org.springframework.util.ObjectUtils.isEmpty(oneRow.get("profit"))) { oneRow.put("profit", 0); } if (oneRow.get("create_time_ts") != null && StrUtil.isNotBlank(oneRow.get("create_time_ts").toString()) && !Objects.equals(oneRow.get("create_time_ts").toString(), "0")) { String oneValue = oneRow.get("create_time_ts").toString(); Long timestamp = Long.parseLong(oneValue); long showTimestamp = DateTimeTools.transferShowTimeToClientTime(timestamp); oneRow.put("create_time_ts", String.valueOf(showTimestamp)); } if (oneRow.get("close_time") != null && StrUtil.isNotBlank(oneRow.get("close_time").toString()) && !Objects.equals(oneRow.get("close_time").toString(), "0")) { String oneValue = oneRow.get("close_time").toString(); if (oneValue.contains("-")) { continue; } Long timestamp = Long.parseLong(oneValue); long showTimestamp = DateTimeTools.transferShowTimeToClientTime(timestamp); oneRow.put("close_time", String.valueOf(showTimestamp)); } } List realtime_all = this.dataService.realtime(symbolsStr); if (realtime_all.size() <= 0) { realtime_all = new ArrayList<>(); } Map realtimeMap = new HashMap<>(); for (int i = 0; i < realtime_all.size(); i++) { realtimeMap.put(realtime_all.get(i).getSymbol(), realtime_all.get(i)); } double profitAll = 0; double closeAll = 0; double inventory_charge_all = 0; double fee_all = 0; double deposit_all = 0; double profitAndLoss = 0; double expectedProfitAndLoss = 0; for (int i = 0; i < data.size(); i++) { Map map = data.get(i); // 标记价格 Realtime realtime = realtimeMap.get(map.get("symbol")); if (null == realtime) { map.put("mark_price", 0); } else { map.put("mark_price", realtime.getClose()); } double profit = Double.parseDouble(data.get(i).get("profit").toString()); if (org.springframework.util.ObjectUtils.isEmpty(data.get(i).get("close_avg_price"))) { if (profit <= 0) { data.get(i).put("close_avg_price", data.get(i).get("trade_avg_price")); } } //利润 if (data.get(i).containsKey("profit_state")) { String profit_state = data.get(i).get("profit_state").toString(); if (profit_state.equals("1")) { profitAll += Math.abs(profit); } else if (profit_state.equals("0")) { profitAll -= Math.abs(profit); } } else { profitAll += Math.abs(profit); } //入金 double close_avg_price = Double.parseDouble(data.get(i).get("close_avg_price").toString()); closeAll += close_avg_price; //库存费 double mark_price = Double.parseDouble(data.get(i).get("mark_price").toString()); double inventory_charge = mark_price - close_avg_price; inventory_charge_all += inventory_charge; //手续费 double fee = Double.parseDouble(data.get(i).get("fee").toString()); fee_all += fee; //保证金 double deposit = Double.parseDouble(data.get(i).get("deposit").toString()); deposit_all += deposit; //盈亏 double mark_price1 = Double.parseDouble(data.get(i).get("mark_price").toString()); // double trade_avg_price1 = Double.parseDouble(data.get(i).get("trade_avg_price").toString()); double volume1 = Double.parseDouble(data.get(i).get("volume").toString()); double price1 = 0; if (!org.springframework.util.ObjectUtils.isEmpty(data.get(i).get("price"))) { price1 = Double.parseDouble(data.get(i).get("price").toString()); } //盈亏 (cur.mark_price - cur.trade_avg_price) * cur.volume // 如果 volume1 为0 说明是当前平仓了,直接算利润 profitAndLoss += profit; //预期盈亏 double expectedProfitAndLossOne = 0; expectedProfitAndLossOne += (mark_price1 - price1) * volume1; expectedProfitAndLoss += expectedProfitAndLossOne; } Map dateN = new HashMap<>(); dateN.put("profit_all", Double.valueOf(String.format("%.5f", profitAll))); //利润 dateN.put("cash_deposit", Double.valueOf(String.format("%.5f", closeAll))); //入金 dateN.put("inventory_charge_all", Double.valueOf(String.format("%.5f", inventory_charge_all))); //库存费 dateN.put("fee_all", fee_all); //手续费 dateN.put("deposit_all", Double.valueOf(String.format("%.5f", deposit_all))); dateN.put("profitAndLoss", Double.valueOf(String.format("%.4f", profitAndLoss))); dateN.put("expectedProfitAndLoss", Double.valueOf(String.format("%.2f", expectedProfitAndLoss))); dateN.put("count", count); return Result.ok(dateN); } /** * 新线程处理,直接拿到订单锁处理完成后退出 */ public class CloseDelayThread implements Runnable { private String partyId; private String order_no; private ContractOrderService contractOrderService; private boolean all = false; @Override public void run() { try { while (true) { if (true == all) { // 一键平仓 // if (ContractLock.add("all")) { if (contractLockService.getContractLock("all")) { this.contractOrderService.saveCloseRemoveAllByPartyId(partyId); // 处理完退出 break; } ThreadUtils.sleep(500); } else { // if (ContractLock.add(order_no)) { if (contractLockService.getContractLock(order_no)) { this.contractOrderService.saveClose(partyId, order_no); // 处理完退出 break; } ThreadUtils.sleep(500); } } } catch (Throwable t) { log.error("error:", t); } finally { if (true == all) { // ContractLock.remove("all"); contractLockService.removeContractLock("all"); } else { // ContractLock.remove(order_no); contractLockService.removeContractLock(order_no); } } } public CloseDelayThread(String partyId, String order_no, ContractOrderService contractOrderService, boolean all) { this.partyId = partyId; this.order_no = order_no; this.contractOrderService = contractOrderService; this.all = all; } } }