package com.bizzan.bitrade.engine;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSON;
import org.springframework.data.redis.core.RedisTemplate;
import java.util.List;
import com.bizzan.bitrade.constant.NotifyType;
import com.bizzan.bitrade.entity.CloseType;
import com.bizzan.bitrade.entity.ContractCoin;
import com.bizzan.bitrade.entity.ContractMoneyType;
import com.bizzan.bitrade.entity.ContractOrderDirection;
import com.bizzan.bitrade.entity.ContractOrderEntrust;
import com.bizzan.bitrade.entity.ContractOrderEntrustType;
import com.bizzan.bitrade.entity.ContractOrderType;
import com.bizzan.bitrade.entity.ContractPositionType;
import com.bizzan.bitrade.entity.MemberContractPosition;
import com.bizzan.bitrade.entity.MemberContractWallet;
import com.bizzan.bitrade.service.ContractCoinService;
import com.bizzan.bitrade.service.ContractOrderEntrustService;
import com.bizzan.bitrade.service.FundingRateHistoryService;
import com.bizzan.bitrade.service.MemberContractPositionService;
import com.bizzan.bitrade.service.MemberService;
import com.bizzan.bitrade.service.RedisLock;
import com.bizzan.bitrade.service.SysConfigService;
import com.bizzan.bitrade.service.UserPurseService;
import com.bizzan.bitrade.util.DateUtil;
import com.bizzan.bitrade.util.MessageResult;
import com.bizzan.bitrade.util.RedisManager;
import com.bizzan.bitrade.vo.MemberContractPositionWithCut;
import com.bizzan.bitrade.vo.MemberContractWalletVo;
import com.bizzan.bitrade.vo.TradingAccount;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Component
public class TradingAccountMonitor {

	@Autowired
	private UserPurseService userPurseService;
	@Autowired
	private MemberContractPositionService memberContractPositionService;
	@Autowired
	private SysConfigService sysConfigService;
	@Autowired
	private ContractCoinService contractCoinService;
	@Autowired
    private ContractCoinMatchFactory contractCoinMatchFactory;
	@Autowired
	private MemberService memberService;
	@Autowired
	private RedisLock redisLock;
	@Autowired
	private RedisManager redisManager;
    @Autowired
    private KafkaTemplate<String, String> kafkaTemplate;
    @Autowired
    private FundingRateHistoryService fundingRateHistoryService;
    @Autowired
    private RedisTemplate redisTemplate;

	private static final String REDIS_PRICE_KEY = "NEW_COIN_PRICE:";

	private ConcurrentHashMap<Long, TradingAccount> tradingAccountMap;
	
	private Map<String, BigDecimal> priceMapAtPresent = new HashMap<String, BigDecimal>();
	
	
	public void initAccounts() {
		tradingAccountMap = userPurseService.findAllWithPositions();
	}
	
	public Map<String, BigDecimal> getPriceMapAtPresent() {
		return priceMapAtPresent;
	}
	
	public void updateAccount(Long id) {
		TradingAccount tradingAccount = userPurseService.findOneVO(id);
		synchronized(tradingAccountMap) {
			if(tradingAccount.getCurrentPositionWithCutList()==null || tradingAccount.getCurrentPositionWithCutList().size()==0) {
				log.info("[账户更新] memberId={} 无持仓，从爆仓 map 移除", id);
				tradingAccountMap.remove(tradingAccount.getId());
			} else {
				// 账户从无仓位变为有仓位（重新开仓），清除爆仓/预警去重 key，确保下次仍能收到通知
				if (!tradingAccountMap.containsKey(id)) {
					redisManager.clearBlastEmail(id);
					redisManager.clearBlastPositionEmail(id);
					redisManager.clearBlastAlarm(id);
					log.info("[账户更新] memberId={} 新加入爆仓 map，持仓数={} frozenBalance={}",
							id, tradingAccount.getCurrentPositionWithCutList().size(), tradingAccount.getFrozenBalance());
				} else {
					log.info("[账户更新] memberId={} 刷新爆仓 map，持仓数={} frozenBalance={}",
							id, tradingAccount.getCurrentPositionWithCutList().size(), tradingAccount.getFrozenBalance());
				}
				tradingAccountMap.put(id, tradingAccount);
			}
		}
		userPurseService.deleteVOFromRedis(id);
	}
	
	public TradingAccount get(Long id) {
		TradingAccount tradingAccount = tradingAccountMap.get(id);
		if (tradingAccount!=null) {
			String currentDate = DateUtil.getDate();
	    	if(tradingAccount.getCurrentDate()==null || !tradingAccount.getCurrentDate().equals(currentDate)) {
	    		tradingAccount.setCurrentDate(currentDate);
	    		tradingAccount.setTodayRevenue(userPurseService.getTodayRevenue(tradingAccount.getId()));
	    		tradingAccount.setTodayInitialCapital(userPurseService.getBalanceBeforToday(tradingAccount.getId()));
	    	}
			log.debug("[contract-asset-new] get from map: memberId={}, currentCapital={}", id, tradingAccount.getCurrentCapital());
			return tradingAccount;
		} else {
			tradingAccount = userPurseService.findOneVOFromRedis(id);
			// 诊断：从Redis/DB加载，当返回0时便于排查
			if (tradingAccount.getCurrentCapital() == null || tradingAccount.getCurrentCapital().compareTo(BigDecimal.ZERO) == 0) {
				BigDecimal dbBalance = userPurseService.getBalanceById(id);
			}
			String currentDate = DateUtil.getDate();
	    	if(tradingAccount.getSpotWallet()==null || tradingAccount.getCurrentDate()==null || !tradingAccount.getCurrentDate().equals(currentDate)) {
	    		userPurseService.deleteVOFromRedis(id);
	    		tradingAccount = userPurseService.findOneVOFromRedis(id);
	    	}
			tradingAccount.setCurrentPriceMap(priceMapAtPresent);
			return tradingAccount;
		}
	}
	
	public TradingAccount getActive(Long id) {
		return tradingAccountMap.get(id);
	}
	
	@Scheduled(fixedDelay = 1500)
	public void checkBlast() {
		List<ContractCoin> coinList = contractCoinService.findAllEnabled();
		for (ContractCoin coin : coinList) {
			Object priceObj = redisTemplate.opsForHash().get(REDIS_PRICE_KEY, coin.getId().toString());
			if (priceObj != null) {
				try { priceMapAtPresent.put(coin.getSymbol(), new BigDecimal(priceObj.toString())); } catch (Exception ignored) {}
			}
		}
		if (contractCoinMatchFactory.getMatchMap().size() != priceMapAtPresent.size()) {
			log.info("waiting for the price to be ready, matchMap={}, priceMap={}", contractCoinMatchFactory.getMatchMap().size(), priceMapAtPresent.size());
			return;
		}
		int marginRate = sysConfigService.get().getContractMarginRate();
		
		if(tradingAccountMap == null)
			return;
		
		synchronized(tradingAccountMap) {
			for(TradingAccount tradingAccount:tradingAccountMap.values()) {
				tradingAccount.setCurrentPriceMap(priceMapAtPresent);
				//log.info("checking blast memberID={}, currentCapital={}", tradingAccount.getId(), tradingAccount.getCurrentCapital());
				
				if (tradingAccount.getPositionType() == ContractPositionType.INTEGRAL
						|| tradingAccount.getPositionType() == ContractPositionType.SEPARATE) {
					// 全仓与分仓统一使用账户级保证金率检查，触发后清仓逻辑相同
					// 体验金仓位由 checkExperienceGiftPositions 独立处理，全部为体验金仓位时跳过
					boolean hasNonTrialPosition = tradingAccount.getCurrentPositionWithCutList().stream()
							.anyMatch(p -> p.getExperienceRecordId() == null);
					if (!hasNonTrialPosition) continue;
					if(tradingAccount.getFrozenBalance().compareTo(BigDecimal.ZERO)==0) {
						continue;
					}
					BigDecimal currentMargin = tradingAccount.getCurrentMargin();
					if(currentMargin.compareTo(BigDecimal.ZERO)==0) {
						continue;
					}
					double currentMarginRate = tradingAccount.getCurrentCapital().divide(currentMargin, 4, BigDecimal.ROUND_DOWN).doubleValue()*100;
					if(currentMarginRate<100) {
						sendBlastAlarmEmail(tradingAccount.getId(), currentMarginRate);
					}
					if(currentMarginRate<marginRate) {
						tradingAccountMap.remove(tradingAccount.getId());
						log.info("[爆仓检查][触发] memberId={} marginRate={}% 已发送 swap-account-blast", tradingAccount.getId(), currentMarginRate);
						kafkaTemplate.send("swap-account-blast", JSON.toJSONString(tradingAccount));
					}
				}
				// 逐仓模式爆仓逻辑预留扩展点
			}
		}
	}
	
	/**
	 * 资金费率结算（隔夜费收取）
	 *
	 * <p>触发时机：每日 00:00、08:00、16:00 各结算一次，每 8 小时一个资金费率周期，
	 * 与主流永续合约交易所（Binance、OKX 等）保持一致。</p>
	 *
	 * <p>结算逻辑：
	 * <ol>
	 *   <li>从 Redis 读取各合约当前资金费率快照（Map&lt;coinId, rate&gt;）。</li>
	 *   <li>遍历内存中所有活跃持仓账户（tradingAccountMap），注入最新行情价格。</li>
	 *   <li>按合约维度汇总该账户的当前占用保证金（findMarginMap）。</li>
	 *   <li>计算本次应扣资金费 = 合约保证金 × 资金费率。</li>
	 *   <li>调用钱包服务完成实际扣款，当前版本返佣金额固定为 0（返佣功能已注释）。</li>
	 *   <li>刷新账户快照，确保下次风控检查使用最新数据。</li>
	 * </ol>
	 * </p>
	 *
	 * <p>结算完成后：等待 1 秒再将本期资金费率写入历史表，避免与扣款事务产生并发冲突。</p>
	 *
	 * <p><b>注意事项：</b>
	 * <ul>
	 *   <li>资金费率可为负值：费率为负时多头向空头支付，空头收取费用；系统侧统一按绝对值处理方向。</li>
	 *   <li>若某合约在 Redis 中没有对应费率记录，则跳过该合约，不予结算。</li>
	 *   <li>返佣逻辑（fundingRebate）已被注释屏蔽，当前版本不向用户返还任何费率收益。</li>
	 *   <li>历史费率持久化（fundingRateHistoryService.save）在 sleep 后执行，为异步补偿性操作，
	 *       若进程在此期间重启将丢失本期历史记录（不影响已完成的扣款）。</li>
	 * </ul>
	 * </p>
	 *
	 * @author system
	 * @date 2026-04-27
	 */
	@Scheduled(cron = "0 0 0,8,16 * * ?")
	public void collectOvernightFee() {
		log.info("start collecting overnight fee");

		// 1. 从 Redis 获取各合约当前资金费率快照：key=合约ID(int)，value=费率(小数，如 0.0003 表示 0.03%)
		Map<Integer, BigDecimal> fundingRateMap = redisManager.getFundingRateMap();

		// 2. 注释说明：以下两行为历史方案（固定费率 + 返佣比例），已切换为动态资金费率，保留供回退参考
		//int fundingRebate = sysConfigService.get().getFundingRebate();
		//int overnightRate = sysConfigService.get().getOvernightRate();

		// 3. 加锁遍历活跃账户，防止与爆仓检测（checkBlast）并发修改同一账户数据
		synchronized(tradingAccountMap) {
			for (TradingAccount tradingAccount : tradingAccountMap.values()) {

				// 3.1 注入最新行情价格，保证保证金计算使用当前价而非缓存旧价
				tradingAccount.setCurrentPriceMap(priceMapAtPresent);

				// 3.2 按合约维度汇总该账户当前占用保证金：key=合约对象，value=保证金金额(USDT)
				Map<ContractCoin, BigDecimal> marketValueMap = tradingAccount.findMarginMap();

				// 3.3 逐合约计算并扣收资金费
				for (ContractCoin coin : marketValueMap.keySet()) {

					// 3.3.1 若该合约本期无费率配置则跳过，不作任何操作
					if (!fundingRateMap.containsKey(coin.getId().intValue())) {
						continue;
					}

					// 3.3.2 取出当前合约资金费率（可正可负，正值=多头付空头，负值=空头付多头）
					BigDecimal fundingRate = fundingRateMap.get(coin.getId().intValue());

					// 3.3.3 计算本次应扣资金费 = 占用保证金 × 资金费率
					//       历史方案（固定费率）：marketValue × (overnightRate / 100000)，已废弃
					BigDecimal overnightFee = marketValueMap.get(coin).multiply(fundingRate);

					log.info("overnightFee={}, fundingRate={}", overnightFee, fundingRate);

					// 3.3.4 执行扣款：第4参数为返佣金额，当前固定传 ZERO（返佣功能已关闭）
					//       若开启返佣：返佣 = overnightFee × (fundingRebate / 100.0)
					userPurseService.clearContractOvernightFee(tradingAccount.getId(), coin, overnightFee, BigDecimal.ZERO);
					// 返佣开启时的历史逻辑（已注释）：
					// userPurseService.clearContractOvernightFee(tradingAccount.getId(), coin, overnightFee,
					//     overnightFee.multiply(BigDecimal.valueOf(fundingRebate / 100.0)));
				}

				// 3.4 刷新账户快照到内存/Redis，确保后续风控使用最新余额和保证金数据
				updateAccount(tradingAccount.getId());
			}
		}

		log.info("end collecting overnight fee");

		// 4. 延迟 1 秒后将本期资金费率持久化到历史表
		//    延迟目的：等待扣款事务完全落库，降低历史记录与实际扣款不一致的概率
		try {
			Thread.sleep(1000);
			fundingRateHistoryService.save(fundingRateMap);
			// 以下为动态重新生成下期费率的预留逻辑，当前未启用
			// Map<Integer, BigDecimal> newFundingRateMap = fundingRateHistoryService.generateNewRateMap();
			// log.info("newFundingRateMap={}", newFundingRateMap);
		} catch (InterruptedException e) {
			// 线程中断时记录异常，不影响已完成的扣款流程
			e.printStackTrace();
		}
	}
	
	public void cancelOpenOrders(Long memberId) {
		for(ContractCoinMatch match: contractCoinMatchFactory.getMatchMap().values()) {
			match.cancelOpenOrdersByMemberId(memberId);
		}
	}
	
	public void sendBlastEmail(TradingAccount tradingAccount) {
		// 24小时内同一用户只发一次爆仓通知，防止重复触发导致邮件轰炸
		if (!redisManager.tryMarkBlastEmail(tradingAccount.getId())) {
			return;
		}
		net.sf.json.JSONObject jsonObject = new net.sf.json.JSONObject();
		net.sf.json.JSONArray positionJsonArray = new net.sf.json.JSONArray();
		for(MemberContractPosition position: tradingAccount.getCurrentPositionWithCutList()) {
			net.sf.json.JSONObject positionJsonObject = new net.sf.json.JSONObject();
			positionJsonObject.put("volume", position.getCurrentPosition());
			positionJsonObject.put("leverage", position.getLeverage());
			positionJsonObject.put("direction", position.getDirection().ordinal());
			positionJsonObject.put("contractName", position.getCoin().getSymbol());
			positionJsonArray.add(positionJsonObject);
		}
		jsonObject.put("positions", positionJsonArray);

        log.info("jsonObject={}", jsonObject.toString());
        memberService.notifyByEmail(tradingAccount.getId(), NotifyType.BLAST, jsonObject);
	}
	
	private void sendBlastAlarmEmail(Long memberId, double marginRate) {
		net.sf.json.JSONObject jsonObject = new net.sf.json.JSONObject();
		jsonObject.put("marginRate", String.format("%.2f", marginRate));
        
        log.info("alarm jsonObject={}", jsonObject.toString());
        if(redisManager.getBlastAlarm(memberId)) {
        	memberService.notifyByEmail(memberId, NotifyType.BLAST_ALARM, jsonObject);
        }
	}
	
	public void sendPositionBlastEmail(MemberContractPosition position) {
		// 24小时内同一用户只发一次逐仓爆仓通知，防止重复发送
		if (!redisManager.tryMarkBlastPositionEmail(position.getMemberId())) {
			return;
		}
		net.sf.json.JSONObject jsonObject = new net.sf.json.JSONObject();
		net.sf.json.JSONArray positionJsonArray = new net.sf.json.JSONArray();

		net.sf.json.JSONObject positionJsonObject = new net.sf.json.JSONObject();
		positionJsonObject.put("volume", position.getCurrentPosition());
		positionJsonObject.put("leverage", position.getLeverage());
		positionJsonObject.put("direction", position.getDirection().ordinal());
		positionJsonObject.put("contractName", position.getCoin().getSymbol());
		positionJsonArray.add(positionJsonObject);

		jsonObject.put("positions", positionJsonArray);

        log.info("jsonObject={}", jsonObject.toString());
        memberService.notifyByEmail(position.getMemberId(), NotifyType.POSITION_BLAST, jsonObject);
	}
	
	public int genVolumeForOrder(ContractOrderEntrust order, boolean limitPrice) {
		if(order.getType()!=ContractOrderType.MARKET_PRICE && order.getType()!=ContractOrderType.LIMIT_PRICE)
			return 1;
		
		try {
			Map<String, BigDecimal> priceMap = new HashMap<String, BigDecimal>();
			priceMap.putAll(this.getPriceMapAtPresent());
			
	    	TradingAccount tradingAccount = userPurseService.findOneVO(order.getMemberId());
	    	tradingAccount.setCurrentPriceMap(priceMap);
	    	MemberContractWalletVo wallet = tradingAccount.getWalletByContractId(order.getContractId());
	    	ContractCoin contractCoin = contractCoinService.findOne(order.getContractId());
	    	memberContractPositionService.adjustMarginByCurrentPrice(order.getMemberId(), priceMap);
	    	BigDecimal leverage = wallet.getUsdtBuyLeverage();
	    	BigDecimal currentContractMargin = tradingAccount.sumCurrentMarginByContractId(order.getContractId());
	    	
	    	int volumeScale = 0;
	    	BigDecimal tradedPrice = BigDecimal.ZERO;
	    	ContractCoinMatch contractCoinMatch = contractCoinMatchFactory.getContractCoinMatch(contractCoin.getSymbol());
	    	BigDecimal openPrice = contractCoinMatch.getAdjustedNowPrice(order.getDirection());
	    	if(order.getType() == ContractOrderType.MARKET_PRICE) {
	    		tradedPrice = openPrice;
	    	} else if(order.getType() == ContractOrderType.LIMIT_PRICE) {
	    		if(limitPrice) {
	    			tradedPrice = order.getEntrustPrice();
	    		} else {
		    		if (order.getDirection() == ContractOrderDirection.BUY) {
		        		if(order.getEntrustPrice().compareTo(openPrice) > 0) {
		        			tradedPrice = openPrice;
		        			order.setIsLimitPrice(1);
		        		} else
		        			tradedPrice = order.getEntrustPrice();
		        	} else {
		        		if(order.getEntrustPrice().compareTo(openPrice) < 0) {
		        			tradedPrice = openPrice;
		        			order.setIsLimitPrice(1);
		        		} else
		        			tradedPrice = order.getEntrustPrice();
		        	}
	    		}
	    	}
	    	order.setTradedPrice(tradedPrice);
	    	if(tradedPrice.compareTo(BigDecimal.ZERO)<=0)
	    		return 1;
	    	
	    	Integer isPercentage = order.getIsPercentage();
	    	BigDecimal volume = order.getVolume();
	    	if(tradingAccount.getMoneyType() == ContractMoneyType.COIN) {
		    	if(tradingAccount.getPositionType() == ContractPositionType.INTEGRAL) {
		    		MemberContractPosition position = memberContractPositionService.getIntegralMemberContractPosition(order.getMemberId(), order.getContractId(), order.getDirection(), tradingAccount.getMoneyType());
		    		if(position.getDecimalScale()!=null)
		    			volumeScale = position.getDecimalScale();
		    		else {
		    			//volumeScale = String.valueOf(tradedPrice.divide(contractCoin.getShareNumber().multiply(BigDecimal.valueOf(0.1))).intValue()).length();
		    			volumeScale = contractCoin.getMinScale();
		    		}
		    	} else
		    		volumeScale = String.valueOf(tradedPrice.divide(contractCoin.getShareNumber().multiply(BigDecimal.valueOf(0.1))).intValue()).length();
		        if (isPercentage==null || isPercentage!=1) {
		        	volume = volume.setScale(volumeScale, BigDecimal.ROUND_DOWN);
		        	if(volume.multiply(tradedPrice).divide(leverage, 8, BigDecimal.ROUND_DOWN).add(currentContractMargin.add(wallet.getUsdtFrozenBalance())).compareTo(contractCoin.getMaxTotalShare())>0) {
		        		order.setVolume(BigDecimal.ZERO);
		        		return 1;
		        	}
			        
		        } else {
		        	BigDecimal availableBalanceForOpen = tradingAccount.getAvailableBalanceForOpen();
		        	BigDecimal maxBalanceForOpen = contractCoin.getMaxTotalShare().subtract(currentContractMargin.add(wallet.getUsdtFrozenBalance())).multiply(BigDecimal.ONE.add(leverage.multiply(contractCoin.getOpenFee())));
		        	if(availableBalanceForOpen.compareTo(maxBalanceForOpen)>0)
		        		availableBalanceForOpen = maxBalanceForOpen;
		        	volume = availableBalanceForOpen
		        			.multiply(volume.divide(BigDecimal.valueOf(100), 2, BigDecimal.ROUND_DOWN))
		        			.divide(tradedPrice.multiply(contractCoin.getOpenFee().add(BigDecimal.ONE.divide(leverage, 8, BigDecimal.ROUND_UP))), volumeScale, BigDecimal.ROUND_DOWN);
		        	
		        }
		        order.setDecimalScale(volumeScale);
			} else {
				int defaultVolumeScale = 1;
		    	if (isPercentage==null || isPercentage!=1) {
		        	volume = volume.setScale(defaultVolumeScale, BigDecimal.ROUND_DOWN);
		        } else {
		        	volume = tradingAccount.getAvailableBalanceForOpen()
		        			.multiply(volume.divide(BigDecimal.valueOf(100), 2, BigDecimal.ROUND_DOWN))
		        			.divide(contractCoin.getShareNumber().multiply(contractCoin.getOpenFee().add(BigDecimal.ONE.divide(leverage, 8, BigDecimal.ROUND_UP))), defaultVolumeScale, BigDecimal.ROUND_DOWN);
		
		        }
		    	order.setDecimalScale(defaultVolumeScale);
		    }
	    	if(volume.compareTo(BigDecimal.ZERO)<=0)
	    		return 1;
	    	if(volume.compareTo(contractCoin.getMinShare())<0)
	    		return 2;
	    	
	    	
	        order.setVolume(volume);
	        BigDecimal tradedMoney;
	        if(tradingAccount.getMoneyType() == ContractMoneyType.COIN)
	        	tradedMoney = volume.multiply(tradedPrice);
	        else
	        	tradedMoney = volume.multiply(contractCoin.getShareNumber());
	        BigDecimal principalAmount = tradedMoney.divide(leverage, 8, BigDecimal.ROUND_DOWN);
	        BigDecimal openFee = tradedMoney.multiply(contractCoin.getOpenFee()).setScale(8, BigDecimal.ROUND_DOWN);
	        /*Member member = memberService.findOne(order.getMemberId());
	        if(member.getIsTrader()!=null && member.getIsTrader() == 1) {
	        	openFee = openFee.multiply(BigDecimal.valueOf(0.6));
	        }*/
	
	    	if(tradingAccount.getAvailableBalanceForOpen().compareTo(principalAmount.add(openFee))<=0) {
	        	return 1;
	        }
	        
	        order.setPrincipalAmount(principalAmount);
	        order.setOpenFee(openFee);
	        
	        BigDecimal currentOrderFrozenMargin = BigDecimal.ZERO;
	        List<ContractOrderEntrust> currentOrderList = ContractCoinMatch.getListByMemberId(order.getMemberId());
	        for(ContractOrderEntrust currentOrder: currentOrderList) {
	        	//log.info("currentOrder.getId()={}, order.getId()={}, currentOrder.getType()={}, currentOrder.getEntrustType()={}", currentOrder.getId(), order.getId(), currentOrder.getType(), currentOrder.getEntrustType());
	        	if (currentOrder.getType() == ContractOrderType.LIMIT_PRICE
	        			&& currentOrder.getEntrustType() == ContractOrderEntrustType.OPEN) {
	        		currentOrderFrozenMargin = currentOrderFrozenMargin.add(currentOrder.getPrincipalAmount());
	        	}
	        }
	        order.setIsPercentage(0);
	        order.setPercentageVolume(principalAmount.divide(tradingAccount.getAvailableBalanceForOpen().add(currentOrderFrozenMargin), 4, BigDecimal.ROUND_DOWN));
	        
	        return userPurseService.freezeMarginAndFee(order.getMemberId(), contractCoin, principalAmount.add(openFee)) ? 0:1;
		} catch (Exception e) {
			log.error(e.getMessage(), e);
			return 1;
		}

    }
}
