美文网首页
恒易量化-市价马丁策略

恒易量化-市价马丁策略

作者: 往后余生9375 | 来源:发表于2023-05-27 14:51 被阅读0次

马丁策略

马丁格尔(Martingale)策略其实是一种赌博策略,理论上用这种策略是不会亏钱的,只要你拥有足够多的资金,理论上你将百战百胜

源码(只能运行在恒易量化服务器)

package com.hengyi.strategy.strategy;

import com.alibaba.fastjson.JSONObject;
import com.hengyi.tradesystem.entity.OrderProfit;
import com.hengyi.tradesystem.enums.AlarmLevel;
import com.hengyi.tradesystem.enums.OrderType;
import com.hengyi.tradesystem.strategy.impl.BaseStrategy;
import com.hengyi.tradesystem.vo.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;

/**
 * 马丁策略
 * 无限加仓,直到盈利
 * 限制下单次数  限制下单数量
 * 懂得止损
 * 下单改为限价单
 *
 *
 * 考虑加入平仓策略
 * 1.回调多少卖出
 * 2.均价+格子卖出
 * 3.双倍仓位 上涨一格卖出
 */
@Slf4j
@Component
@Scope("prototype")
public class MartinStrategy extends BaseStrategy {

    private static final String OPEN_MAX_PRICE = "OPEN_MAX_PRICE";


    /**
     * 策略参数
     */
    private BigDecimal highPrice = null;
    private BigDecimal lowPrice = null;
    private BigDecimal gridSize = null;
    private BigDecimal buyMultiple = null;
    private BigDecimal buyQty = null;
    private BigDecimal maxBuyQty = null;
    private BigDecimal lossAmount = null;
    private BigDecimal profitVal = null;
    private Boolean isProfitAmount = false;
    private BigDecimal triggerPrice = null;
    private int gridNum = 0;
    private int closeType = 0;

    @Override
    public void init(String accountStrategyId, String instanceId, JSONObject runParams, JSONObject localDict) {
        super.init(accountStrategyId, instanceId, runParams,localDict);
        if(!checkParams(
                "highPrice","lowPrice","gridSize","buyQty","buyMultiple","sendMail","maxBuyQty","lossAmount")){
            throw new RuntimeException("运行参数异常");
        }
        setSendMail(getRunParams().getBoolean("sendMail"));

        // 压力价
        highPrice = getRunParams().getBigDecimal("highPrice");
        // 支撑价格
        lowPrice = getRunParams().getBigDecimal("lowPrice");
        // 网格大小
        gridSize = getRunParams().getBigDecimal("gridSize");
        // 加仓倍数
        buyMultiple = getRunParams().getBigDecimal("buyMultiple");
        // 初始购买数量
        buyQty = getRunParams().getBigDecimal("buyQty");
        // 网格数量
        gridNum = highPrice.subtract(lowPrice).divide(gridSize,0,BigDecimal.ROUND_DOWN).intValue();
        // 最大下单数量
        maxBuyQty = getRunParams().getBigDecimal("maxBuyQty");
        // 最大亏损U平仓
        lossAmount = getRunParams().getBigDecimal("lossAmount");
        // 平仓方式
        closeType = getRunParams().getInteger("closeType");
        // 触发价格
        if(getRunParams().containsKey("triggerPrice")){
            triggerPrice = getRunParams().getBigDecimal("triggerPrice");
            if(triggerPrice.compareTo(highPrice) > 0){
                throw new RuntimeException("触发价格大于了最高价格");
            }
            if(triggerPrice.compareTo(lowPrice) < 0){
                throw new RuntimeException("触发价格小于了最低价格");
            }
        }

        // 参数校验
        if(lossAmount.compareTo(new BigDecimal("0")) <= 0){
            throw new RuntimeException("止损金额lossAmount参数设置不正确");
        }
        if(closeType == 2 && buyMultiple.compareTo(new BigDecimal("2")) < 0){
            throw new RuntimeException("该平仓方式购买倍数必须大于等于2");
        }
        if(closeType == 3 && !getRunParams().containsKey("profitVal")){
            throw new RuntimeException("该平仓方式需要填写参数:profitVal");
        }
        if(lowPrice.compareTo(highPrice) >= 0){
            throw new RuntimeException("最低 最高价格设置有误");
        }
        if(buyQty.compareTo(BigDecimal.ZERO) <= 0){
            throw new RuntimeException("购买数量设置有误");
        }
        if(maxBuyQty.compareTo(buyQty) < 0){
            throw new RuntimeException("最大购买数量设置有误");
        }
        if(buyMultiple.compareTo(BigDecimal.ONE) < 0){
            throw new RuntimeException("购买倍数设置有误");
        }

        // 收益值和收益率
        String profitValStr = getRunParams().getString("profitVal");
        profitVal = new BigDecimal(profitValStr);
        isProfitAmount = !profitValStr.contains("%");
    }

    @Override
    public void pre() {

    }

    /**
     * 获取当前价格所在的网格
     * @param m
     * @param gridSize
     * @param nowPrice
     * @param gridNum
     * @return
     */
    private int getCurrentGrid(BigDecimal m, BigDecimal gridSize,BigDecimal nowPrice,int gridNum){
        int num = -1;
        for(int i = 0; i<gridNum;i++){
            BigDecimal price1 = m.subtract(gridSize.multiply(new BigDecimal(i)));
            BigDecimal price2 = m.subtract(gridSize.multiply(new BigDecimal(i + 1)));
            if(price1.compareTo(nowPrice) >= 0 && price2.compareTo(nowPrice) < 0){
                num = i + 1;
                break;
            }
        }
        return num;
    }

    @Override
    public void run(Long currentTime) {
        /**
         * 支持 盈利多少平仓  支持 盈利百分比平仓 支持网格数平仓
         * 支持最大开仓数
         * maxBuyQty   最大开仓数量 (加仓到这个数量就停止操作)
         * lossAmount     止损数,亏损
         * profitAmount     盈利金额
         * callbackPrice   回调金额  超过这个金额就平仓
         */
        // 当前价格
        BigDecimal markPrice = getMarkPrice();
        // 当前所属的网格个数(当前价格位于该网格的下面或相等价格)
        int currentGrid = getCurrentGrid(highPrice,gridSize,markPrice,gridNum);
        log.info("最高价格{} 最低价格{} 网格大小{} 当前在网格{} 当前价格{} 加仓倍数{}",highPrice,lowPrice,gridSize,currentGrid,markPrice,buyMultiple);

        // 只在格子里面才下单
        if(currentGrid != -1) {
            // 如果设置了触发价格 那么第一次开仓需要判断当前标记价格
            if(!localDict.containsKey("minOpenGrid") && triggerPrice != null && triggerPrice.compareTo(markPrice) <= 0){
                return;
            }
            openOrder(currentGrid,markPrice);
        }

        // 平仓 止损
        if(hasOpenOrder(true) && closeType > 0){
            closeOrder(currentGrid, markPrice);
        }
    }

    /**
     * 开仓
     * @param currentGrid
     */
    private void openOrder(int currentGrid,BigDecimal markPrice){
        // 进来网格只要小于中位价格就开单,只要跌处网格就加仓。
        // 开单记录开仓的网格数,跌了继续加仓

        // 记录第一次开仓
        if(!localDict.containsKey("minOpenGrid")) {
            Result result = openLong(OrderType.MARKET, String.valueOf(System.currentTimeMillis()), "", "", buyQty.toString());
            if (result.getStatus()) {
                localDict.put("minOpenGrid", currentGrid);
                localDict.put("minOpenPrice",markPrice);
                localDict.put("qty",buyQty);
                saveLocalDict();
                log.info("马丁第一次开单成功,目前开仓网格是:{}",currentGrid);
            }
        }else {
            BigDecimal isFilledQty = getOpenQty(true);
            int minOpenGrid = localDict.getInteger("minOpenGrid");
            BigDecimal minOpenPrice = localDict.getBigDecimal("minOpenPrice");
            if (currentGrid > minOpenGrid && minOpenPrice.subtract(markPrice).compareTo(gridSize) >= 0) {

                BigDecimal buy_qty = localDict.getBigDecimal("qty").multiply(buyMultiple);

                if(buy_qty.add(isFilledQty).compareTo(maxBuyQty) > 0){
                    log.info("当前下单数量+已有仓位数量大于了设置的数量,不允许开仓!");
                    return;
                }
                Result result = openLong(OrderType.MARKET, String.valueOf(System.currentTimeMillis()), "", "", buy_qty.toString());
                if (result.getStatus()) {
                    localDict.put("minOpenGrid", currentGrid);
                    localDict.put("minOpenPrice", markPrice);
                    localDict.put("qty",buy_qty);
                    saveLocalDict();
                    log.info("马丁开单成功,目前开仓网格是:{} 购买数量:{}", currentGrid, buy_qty);
                }
            }
        }
    }

    /**
     * 全平仓
     * @param currentGrid
     */
    private void closeOrder(int currentGrid, BigDecimal markPrice){
        OrderProfit orderProfit = getOrderProfit();
        if(orderProfit == null){
            return;
        }

        // 计算开仓后达到的盈利最高价
        BigDecimal lastNewPrice = null;
        BigDecimal nowNewPrice = getNewPrice();

        if(localDict.containsKey(OPEN_MAX_PRICE)){
            lastNewPrice = localDict.getBigDecimal(OPEN_MAX_PRICE);
            if(nowNewPrice.compareTo(lastNewPrice) > 0){
                localDict.put(OPEN_MAX_PRICE,nowNewPrice);
            }
            log.info("当前开仓后的最高价是:{} 现价:{}",lastNewPrice,nowNewPrice);
        }else {
            lastNewPrice = getNewPrice();
            localDict.put(OPEN_MAX_PRICE,lastNewPrice);
        }

        // 止损
        if(orderProfit.getProfitValue().compareTo(lossAmount.multiply(new BigDecimal("-1"))) <= 0){
            closePosition();
            localDict.clear();
            saveLocalDict();
            alarm("止损平仓","亏损大于了设置的值", AlarmLevel.INFO);
            sleep(2000);
        }

        if(closeType == 1){
            if(nowNewPrice.subtract(gridSize).compareTo(orderProfit.getAvgPrice()) >= 0){
                closePosition();
                localDict.clear();
                saveLocalDict();
                alarm("方式1平仓","价格上涨均价上方格子平仓", AlarmLevel.INFO);
                sleep(2000);
            }
        }


        // 平仓方式2
        if(closeType == 2){
            int minOpenGrid = localDict.getInteger("minOpenGrid");
            BigDecimal minOpenPrice = localDict.getBigDecimal("minOpenPrice");
            if(currentGrid < minOpenGrid){
                // 计算预计平单的手续费
                BigDecimal closeCommission = orderProfit.getTotalValue().multiply(new BigDecimal("0.0004"));
                // 计算预计平仓成本价格
                BigDecimal closePrice = orderProfit.getProfitValue().subtract(orderProfit.getCommission()).subtract(closeCommission);

                if(minOpenPrice.add(gridSize).compareTo(markPrice) <= 0 && closePrice.compareTo(new BigDecimal("0.05")) > 0){
                    closePosition();
                    localDict.clear();
                    saveLocalDict();
                    alarm("方式2平仓","达到平仓条件平仓", AlarmLevel.INFO);
                    sleep(2000);
                }
            }
        }

        // 平仓方式3
        if(closeType == 3){
            if(isProfitAmount) {
                if (orderProfit.getProfitValue().compareTo(profitVal) >= 0) {
                    closePosition();
                    localDict.clear();
                    saveLocalDict();
                    alarm("方式3平仓", "达到设置的止盈金额", AlarmLevel.INFO);
                    sleep(2000);
                }
            }else {
                if (orderProfit.getProfitRate().compareTo(profitVal) >= 0) {
                    closePosition();
                    localDict.clear();
                    saveLocalDict();
                    alarm("方式3平仓", "达到设置的止盈率", AlarmLevel.INFO);
                    sleep(2000);
                }
            }
        }
    }

    @Override
    public void post() {

    }

    @Override
    public void destroy() {
        log.info("策略结束,销毁中");
    }
}

相关文章

网友评论

      本文标题:恒易量化-市价马丁策略

      本文链接:https://www.haomeiwen.com/subject/byaledtx.html