package project.contract.job; import java.sql.PreparedStatement; import java.sql.SQLException; import java.text.DecimalFormat; import java.util.List; import java.util.Map; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import kernel.util.StringUtils; import kernel.web.ApplicationUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import kernel.util.Arith; import kernel.util.ThreadUtils; import org.springframework.beans.BeansException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.jdbc.core.BatchPreparedStatementSetter; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.datasource.DataSourceTransactionManager; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.support.DefaultTransactionDefinition; import org.springframework.util.ObjectUtils; import project.contract.ContractLock; import project.contract.ContractOrder; import project.contract.ContractOrderService; import project.contract.ContractRedisKeys; import project.data.DataService; import project.data.model.Realtime; import project.redis.RedisHandler; import project.syspara.SysparaService; import project.wallet.AssetService; import project.wallet.Wallet; import project.wallet.WalletRedisKeys; import project.wallet.WalletService; import project.wallet.consumer.WalletDao; import project.wallet.consumer.WalletMessage; public class ContractOrderCalculationServiceImpl implements ContractOrderCalculationService, ApplicationContextAware { private ApplicationContext applicationContext; private static final Logger logger = LoggerFactory.getLogger(ContractOrderCalculationServiceImpl.class); private ContractOrderService contractOrderService; private DataService dataService; private WalletService walletService; private WalletDao walletDao; // private RedisHandler redisHandler; private AssetService assetService; public final static String STATE_SUBMITTED = "submitted"; public final static String STATE_CREATED = "created"; /** * 平仓线 110%(订金价值 /收益=110%) */ public double order_close_line = 1.1; /** * 平仓方式 1全仓 2单个持仓 */ public int order_close_line_type = 1; private SysparaService sysparaService; public void saveCalculation(String order_no) { try { ContractOrder order = contractOrderService.findByOrderNo(order_no); if (order == null || !ContractOrder.STATE_SUBMITTED.equals(order.getState())) { /** * 状态已改变,退出处理 */ return; } List list = this.dataService.realtime(order.getSymbol()); if (list.size() == 0) { return; } Realtime realtime = list.get(0); double close = realtime.getClose(); if (ContractOrder.DIRECTION_BUY.equals(order.getDirection())) { /* * 0 买涨 */ if (close >= Arith.add(order.getTrade_avg_price(), order.getPips())) { settle(order, "profit", close); } if (close <= Arith.sub(order.getTrade_avg_price(), order.getPips())) { settle(order, "loss", close); } } else { /* * 1 买跌 */ if (close <= Arith.sub(order.getTrade_avg_price(), order.getPips())) { settle(order, "profit", close); } if (close >= Arith.add(order.getTrade_avg_price(), order.getPips())) { settle(order, "loss", close); } } } catch (Throwable e) { logger.error("OrderCalculationServiceImpll run fail", e); } } private static final Lock lock = new ReentrantLock(); // 全局锁,避免重复执行 private static final long SLEEP_TIME = 500; // 重试间隔 /** * 盈亏计算 * * @param profit_loss profit 盈 loss亏 * @param currentPrice 当前点位 */ public void settle(ContractOrder order, String profit_loss, double currentPrice) { double mul = Arith.mul(order.getDeposit_open(), order.getLever_rate());//仓位 double div = Arith.div(mul, order.getTrade_avg_price());//持有币的数量 double amount = Arith.mul(div, Arith.sub(currentPrice, order.getTrade_avg_price())); RedisHandler redisHandler = getRedisHandler(); if ("profit".equals(profit_loss)) { /** * 盈 正数 */ order.setProfit(Arith.add(0.0D, Math.abs(amount))); Object profit = redisHandler.get("MONEY_CONTRACT_PROFIT_" + order.getPartyId().toString()); if(!ObjectUtils.isEmpty(profit)){ if(Double.parseDouble(profit.toString()) < 0 ){ redisHandler.setSync("MONEY_CONTRACT_PROFIT_"+order.getPartyId().toString(), 0); Object money = redisHandler.get("PARTY_ID_MONEY_" + order.getPartyId().toString()); if(!ObjectUtils.isEmpty(money)){ Wallet wallet = this.walletService.saveWalletByPartyId(order.getPartyId().toString()); wallet.setMoney(Double.parseDouble(money.toString())); redisHandler.setSync(WalletRedisKeys.WALLET_PARTY_ID + wallet.getPartyId().toString(), wallet); redisHandler.pushAsyn(WalletRedisKeys.WALLET_QUEUE_UPDATE, new WalletMessage(order.getPartyId().toString(), amount)); } } } } else if ("loss".equals(profit_loss)) { order.setProfit(Arith.sub(0.0D,Math.abs(amount) )); //定义一个 总浮动亏损的值 Double contractAssetsProfit = (Double) redisHandler.get(ContractRedisKeys.CONTRACT_ASSETS_PROFIT_PARTY_ID + order.getPartyId().toString()); double contractProfit = null == contractAssetsProfit ? 0.000D : contractAssetsProfit; List list = contractOrderService.findSubmitted(order.getPartyId().toString(), null, null); double deposit = 0; for (int i = 0; i < list.size(); i++) { ContractOrder close_line = list.get(i); deposit = Arith.add(deposit, close_line.getDeposit()); } double profitt = Arith.add(contractProfit,deposit); if(profitt <= 0){ redisHandler.setSync("MONEY_CONTRACT_PROFIT_"+order.getPartyId().toString(), profitt); }else{ redisHandler.setSync("MONEY_CONTRACT_PROFIT_"+order.getPartyId().toString(), 0); } //修改余额,每次修改取平仓前余额减去浮动亏损 Wallet wallet = this.walletService.saveWalletByPartyId(order.getPartyId().toString()); Object money = redisHandler.get("PARTY_ID_MONEY_" + order.getPartyId().toString()); Object profit = redisHandler.get("MONEY_CONTRACT_PROFIT_" + order.getPartyId().toString()); if(!ObjectUtils.isEmpty(money) && !ObjectUtils.isEmpty(profit)){ double residueMoney = Arith.add(Double.parseDouble(money.toString()), Double.parseDouble(profit.toString())); //如果当前余额减去浮动亏损小于0,将进入强平,这里不再进行余额更新 if(residueMoney > 0){ wallet.setMoney(residueMoney); redisHandler.setSync(WalletRedisKeys.WALLET_PARTY_ID + wallet.getPartyId().toString(), wallet); } } } double changeRatio; changeRatio = Arith.mul(Arith.div(order.getProfit(), order.getDeposit_open()), 100); DecimalFormat df = new DecimalFormat("#.##"); order.setChange_ratio(Double.valueOf(df.format(changeRatio))); /** * 多次平仓价格不对,后续修 */ order.setClose_avg_price(currentPrice); this.contractOrderService.update(order); /** * 止盈价 */ Double profit_stop = order.getStop_price_profit(); if (profit_stop != null && profit_stop > 0 && ContractOrder.DIRECTION_BUY.equals(order.getDirection())) { /* * 买涨 */ if (currentPrice >= profit_stop) { this.contractOrderService.saveClose(order.getPartyId().toString(), order.getOrder_no()); return; } } else if (profit_stop != null && profit_stop > 0 && ContractOrder.DIRECTION_SELL.equals(order.getDirection())) { /** * 买跌 */ if (currentPrice <= profit_stop) { this.contractOrderService.saveClose(order.getPartyId().toString(), order.getOrder_no()); return; } } /** * 止亏线 */ Double loss_stop = order.getStop_price_loss(); if (loss_stop != null && loss_stop > 0 && ContractOrder.DIRECTION_BUY.equals(order.getDirection())) { /* * 买涨 */ if (currentPrice <= loss_stop) { this.contractOrderService.saveClose(order.getPartyId().toString(), order.getOrder_no()); return; } } else if (loss_stop != null && loss_stop > 0 && ContractOrder.DIRECTION_SELL.equals(order.getDirection())) { /** * 买跌 */ if (currentPrice >= loss_stop) { this.contractOrderService.saveClose(order.getPartyId().toString(), order.getOrder_no()); return; } } logger.info("order_close_line_type:"+order_close_line_type); if (order_close_line_type == 1) { /** * 收益 */ double profit = 0; List list = contractOrderService.findSubmitted(order.getPartyId().toString(), null, null); for (int i = 0; i < list.size(); i++) { ContractOrder close_line = list.get(i); profit = Arith.add(profit, Arith.add(close_line.getProfit(), close_line.getDeposit())); } Wallet wallet = this.walletService.saveWalletByPartyId(order.getPartyId().toString()); Object money = redisHandler.get("PARTY_ID_MONEY_" + order.getPartyId().toString()); double totleMoney = 0; if(ObjectUtils.isEmpty(money)){ totleMoney = wallet.getMoney(); }else{ totleMoney = Double.parseDouble(money.toString()); } if (Arith.add(profit,totleMoney) <= 0) { redisHandler.setSync("MONEY_CONTRACT_PROFIT_"+order.getPartyId().toString(), 0); /** * 触发全仓强平 */ this.contractOrderService.saveClose(order.getPartyId().toString(), order.getOrder_no()); for (int i = 0; i < list.size(); i++) { ContractOrder close_line = list.get(i); synchronized (close_line.getOrder_no()){ this.contractOrderService.saveClose(close_line.getPartyId().toString(), close_line.getOrder_no()); } } //钱包归零 extracted(order, wallet, redisHandler); } } else { if (order.getProfit() < 0 && (Arith.div(order.getDeposit(), Math.abs(order.getProfit())) <= Arith .div(order_close_line, 100))) { /** * 低于系统默认平仓线,进行强平 */ this.contractOrderService.saveClose(order.getPartyId().toString(), order.getOrder_no()); return; } } } private void extracted(ContractOrder order, Wallet wallet, RedisHandler redisHandler) { DataSourceTransactionManager transactionManager = ApplicationUtil.getBean(DataSourceTransactionManager.class); JdbcTemplate jdbcTemplate = ApplicationUtil.getBean(JdbcTemplate.class); TransactionStatus status = null; try { // 开启事务 status = transactionManager.getTransaction(new DefaultTransactionDefinition()); wallet.setMoney(0); redisHandler.setSync(WalletRedisKeys.WALLET_PARTY_ID + wallet.getPartyId().toString(), wallet); // 更新数据库 int update = jdbcTemplate.update("UPDATE T_WALLET SET MONEY=ROUND(?,8) WHERE PARTY_ID=?", 0, wallet.getPartyId().toString()); // 保存钱包信息 Wallet ww = this.walletService.saveWalletByPartyId(order.getPartyId().toString()); // 更新 redis redisHandler.setSync("PARTY_ID_MONEY_" + wallet.getPartyId().toString(), wallet.getMoney()); // 提交事务 transactionManager.commit(status); } catch (Exception e) { // 回滚事务 if (status != null) { transactionManager.rollback(status); } logger.error("更新钱包时发生错误:", e); throw e; } } public void setDataService(DataService dataService) { this.dataService = dataService; } public void setSysparaService(SysparaService sysparaService) { this.sysparaService = sysparaService; } public void setContractOrderService(ContractOrderService contractOrderService) { this.contractOrderService = contractOrderService; } public void setWalletService(WalletService walletService) { this.walletService = walletService; } public void setOrder_close_line(double order_close_line) { this.order_close_line = order_close_line; } public void setOrder_close_line_type(int order_close_line_type) { this.order_close_line_type = order_close_line_type; } public RedisHandler getRedisHandler() { return applicationContext.getBean(RedisHandler.class); } public void setAssetService(AssetService assetService) { this.assetService = assetService; } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } }