资源加载中... loading...

利弗莫尔买入法原理及其在商品期货市场的应用

Author: ianzeng123, Created: 2024-07-19 15:20:12, Updated: 2024-07-22 16:59:10

img

一、利弗莫尔买入法原理

杰西·利弗莫尔(Jesse Livermore)是20世纪初美国著名的股票和商品期货交易员,被誉为“股市之王”。他的买入法原理是通过逐步加仓来扩大收益,并通过及时止损来控制风险。该原理的核心思想是“让利润奔跑,及时止损”。

利弗莫尔买入法的步骤:
  1. 初次开仓:买入总仓位的20%。
  2. 止损:如果开仓后价格下跌10%,立即止损,损失金额为总仓位的2%。
  3. 加仓:当价格上涨10%时,加仓20%;再上涨10%时再加20%;最后一次直接加仓40%。
  4. 平仓:只要价格没有回撤10%,就继续持有;一旦价格回撤10%,立即将仓位全部卖出。

这个策略通过逐步加仓的方式,在市场走势符合预期时逐步增加仓位,从而将胜利成果最大化。而在市场走势不符合预期时,通过及时止损将损失控制在可接受范围内。

二、利弗莫尔买入法在商品期货市场的应用

由于商品期货市场的波动性较大,将利弗莫尔买入法应用于商品期货市场时,需要进行一些调整,以适应期货市场的特性。具体的调整包括:

  1. 开仓信号:采用短期均线与长期均线的金叉和死叉作为开仓信号。当短期均线上穿长期均线时,视为金叉信号,买入做多;当短期均线下穿长期均线时,视为死叉信号,卖出做空。
  2. 止损和加仓幅度:根据市场特性,调整止损和加仓的具体幅度。

三、调整后的策略逻辑

  1. 开仓:当短期均线(金叉)上穿长期均线时买入,当短期均线(死叉)下穿长期均线时卖出。
  2. 止损:如果开仓后价格下跌(多仓)或者上涨(空仓)到相应的幅度时,立即止损并退出市场。
  3. 加仓:当价格延续上涨或下跌相应幅度时,按照总仓位的20%进行加仓;趋势再延续,再加仓20%;最后一次加仓40%。
  4. 平仓:当价格从最高点或最低点回撤相应幅度时,应保护利润,立即将所有仓位平仓。

调整后的策略实现

以下是根据上述调整后的策略逻辑编写的脚本:

/*backtest
start: 2024-01-03 09:00:00
end: 2024-07-16 14:01:00
period: 1d
basePeriod: 1m
exchanges: [{"eid":"Futures_CTP","currency":"FUTURES"}]
args: [["MaxLots",3]]
*/

var _q = $.NewTaskQueue();
var openNumber = 0 //开仓次数
var cumaddNumber = 0 //累计加仓次数
var curaddNumber = 0 //本轮加仓次数
var winNumber = 0 //成功次数
var lossNumber = 0 //失败次数
var cumProfit = 0 //累计利润
var cumLoss = 0 //累计损失
var holdSymbol = '' //持仓品种
var holdAmount = 0 //持仓数量
var holdPrice = 0 //持仓价格
var holdProfit = 0 //持仓利润
var holdDir = '' //持仓方向
var openPrice = 0 //最新开仓价格,判断加仓
var winRate = 0 //胜率
var plRatio = 0 //盈亏比
var InitBalance = 0 //未开仓金额
var addList = [0.2, 0.2, 0.2, 0.4] //按照20,20,20,40%账面资金分别加仓
var bestpricelist = [] //保持持仓期间价格列表

function main(){
    SetErrorFilter("login|ready|流控|连接失败|初始|Timeout");
    
    var pretime = 0
    var checklock = true
    while (true) {
        if(exchange.IO("status")) {
            var symbolDetail = _C(exchange.SetContractType, Instruments)
            var record = exchange.GetRecords()

            var lastPrice = record[record.length - 1].Close
            var shortMean = TA.MA(record, shortPeriod)
            var longMean = TA.MA(record, longPeriod)
            var longSignal = shortMean[shortMean.length - 2] > longMean[longMean.length - 2] && shortMean[shortMean.length - 3] < longMean[longMean.length - 3]
            var shortSignal = shortMean[shortMean.length - 2] < longMean[longMean.length - 2] && shortMean[shortMean.length - 3] > longMean[longMean.length - 3]

            // 检查主力合约
            var DRecords = exchange.GetRecords(PERIOD_D1)
            var curTime = DRecords[DRecords.length - 1].Time
            var mainSymbol = symbolDetail.InstrumentID;

            var curPos = exchange.GetPosition()

            // 开仓/加仓手数计算
            if(checklock){
                var initAccount = _q.GetAccount(exchange);
                var initMargin = JSON.parse(exchange.GetRawJSON()).CurrMargin;
                InitBalance = initAccount.Balance + initMargin;
            }

            var account = _q.GetAccount(exchange);
            var availmoney = (account.Balance) * addList[curaddNumber]
            var unit = parseInt((availmoney) / (longSignal ? 0.2 : 0.2) / (lastPrice * 1.2) / symbolDetail.VolumeMultiple); //金额制约手数

            if (unit < symbolDetail.MinLimitOrderVolume) {
                Log("可开 " + unit + " 手 无法开仓, " + (unit >= symbolDetail.MinLimitOrderVolume ? "风控触发" : "资金限制") + "可用: " + account.Balance);
                continue 
            }

            // 开仓
            if(curPos && curPos.length == 0 && (longSignal || shortSignal)){
                
                _q.pushTask(exchange, mainSymbol, (longSignal ? "buy" : "sell"), unit, function(task, ret) {
                    Log('现有仓位:',curPos.length, "做多信号:", longSignal, "做空信号:", shortSignal)
                    if(ret){
                        checklock = false
                        openNumber += 1
                        openPrice = ret.price
                    }
                    
                });
            }

            // 移仓+加仓+平仓
            if(curPos && curPos.length > 0){
                holdPrice = curPos[0].Price
                holdAmount = curPos[0].Amount
                holdProfit = (curPos[0].Type % 2) == 0 ? (lastPrice - holdPrice) * holdAmount * symbolDetail.VolumeMultiple : (holdPrice - lastPrice) * holdAmount * symbolDetail.VolumeMultiple
                holdDir = curPos[0].Type % 2 == 0 ? "多" : "空"
                holdSymbol = curPos[0].ContractType

                bestpricelist.push(lastPrice);
                var bestprice = holdDir == '多' ? Math.max.apply(null, bestpricelist) : Math.min.apply(null, bestpricelist);

                // 移仓
                var moveSignal = pretime != curTime && holdSymbol != mainSymbol
                
                if (moveSignal) {
                    _q.pushTask(exchange, holdSymbol, "coverall", holdAmount, function(task, ret) {
                        if (ret) {
                            Log(holdSymbol, "移仓平仓成功 #ff0000");
                            pretime = curTime
                            curaddNumber = 0 //本轮加仓次数归零
                            var afterAccount = _q.GetAccount(exchange);
                            var afterMargin = JSON.parse(exchange.GetRawJSON()).CurrMargin;
                            var afterBalance = afterAccount.Balance + afterMargin;

                            var curprofit = afterBalance - InitBalance

                            if(curprofit > 0){
                                cumProfit += curprofit
                                winNumber += 1
                            }else{
                                cumLoss += curprofit
                                lossNumber += 1
                            }

                            curaddNumber = 0
                            holdSymbol = '' 
                            holdAmount = 0 
                            holdPrice = 0 
                            holdProfit = 0 
                            holdDir = '' 
                            openPrice = 0 
                            checklock = true
                        }
                    })
                }

                //加仓
                var spread = holdDir == '多' ? (holdPrice - lastPrice) : (lastPrice - holdPrice)
                var addInterval = holdPrice * 0.02

                var addLongSignal = -spread > addInterval && curaddNumber <= MaxLots && holdDir == '多'
                var addShortSignal = -spread > addInterval && cumaddNumber <= MaxLots && holdDir == '空'

                if(addLongSignal){
                    Log("多头加仓乘数:", lastPrice / holdPrice - 1)
                    _q.pushTask(exchange, mainSymbol, "buy", unit, function(task, ret) {
                        Log('满足加仓条件,进行多头方向加仓#ff0000')
                        if(ret){
                            curaddNumber += 1
                            cumaddNumber += 1
                        }
                        
                    });
                }

                if(addShortSignal){
                    Log("空头加仓乘数:", holdPrice / lastPrice - 1)
                    _q.pushTask(exchange, mainSymbol, "sell", unit, function(task, ret) {
                        Log('满足加仓条件,进行空头方向加仓#ff0000')
                        if(ret){
                            curaddNumber += 1
                            cumaddNumber += 1
                        }
                    });
                }

                //平仓
                //var coverLongSignal = lastPrice / bestprice < 0.95 && holdDir == '多'
                //var coverShortSignal = lastPrice / bestprice > 1.05 && holdDir == '空'

                if(curaddNumber < 2){
                    var coverLongSignal = lastPrice / bestprice < (1 - 0.03 ) && holdDir == '多'
                    var coverShortSignal = lastPrice / bestprice > (1 + 0.03) && holdDir == '空'
                }else{
                    var coverLongSignal = lastPrice < bestprice * (1 - 0.005 ) && holdDir == '多'
                    var coverShortSignal = lastPrice > bestprice * (1 + 0.005) && holdDir == '空'
                }

                if(coverLongSignal || coverShortSignal){
                    Log('当前最优价格:', bestprice, lastPrice)
                    Log(lastPrice / bestprice)
                    if(coverLongSignal){
                        Log("多头减仓乘数:",1- lastPrice / bestprice)
                    }
                    if(coverShortSignal){
                        Log("空头减仓乘数:",lastPrice / bestprice - 1)
                    }

                    _q.pushTask(exchange, mainSymbol, "coverall", 0, function(task, ret) {
                        if(ret){
                            var afterAccount = _q.GetAccount(exchange);
                            var afterMargin = JSON.parse(exchange.GetRawJSON()).CurrMargin;
                            var afterBalance = afterAccount.Balance + afterMargin;

                            var curprofit = afterBalance - InitBalance

                            Log('平仓后资金:', afterAccount.Balance, afterMargin, afterBalance)
                            Log('平仓后利润:', afterBalance - InitBalance)

                            if(curprofit > 0){
                                cumProfit += curprofit
                                winNumber += 1
                            }else{
                                cumLoss += curprofit
                                lossNumber += 1
                            }
                            curaddNumber = 0
                            holdSymbol = '' 
                            holdAmount = 0 
                            holdPrice = 0 
                            holdProfit = 0 
                            holdDir = '' 
                            openPrice = 0 
                            checklock = true
                            bestpricelist = []
                            bestprice = null
                        }
                    })
                }
            }

            var tblStatus = {
                type: "table",
                title: "持仓信息",
                cols: ["合约名称", "持仓方向", "持仓均价", "持仓数量", "持仓盈亏", "本轮加仓次数"],
                rows: []
            };

            var tblStrategy = {
                type: "table",
                title: "策略评价",
                cols: ["开仓次数", "成功次数", "累计利润", "失败次数", "累计亏损", "胜率", "盈亏比"],
                rows: []
            };

            if(openNumber){
                winRate = winNumber / openNumber
            }

            winRate = openNumber ? winNumber / openNumber : 0

            if(cumLoss == 0 && cumProfit != 0 ) plRatio = 1
            if(cumLoss != 0 && cumProfit == 0) plRatio = -1
            if(cumProfit && cumLoss) plRatio = cumProfit / cumLoss

            tblStatus.rows.push([holdSymbol, holdDir, holdPrice, holdAmount, holdProfit, curaddNumber]);
            tblStrategy.rows.push([openNumber, winNumber, cumProfit, lossNumber, cumLoss, winRate, Math.abs(plRatio)]);
            var now = new Date();

            lastStatus = '`' + JSON.stringify([tblStatus, tblStrategy]) + '`\n' + '`' + ' 当前时间: ' + _D() + ', 星期' + ['日', '一', '二', '三', '四', '五', '六'][now.getDay()] + ", 交易任务: " + _q.size();
            LogStatus(lastStatus);
            _q.poll();

            Sleep(5 * 1000);
        }
    }
}

img

img

结论

通过应用调整后的利弗莫尔买入法,我们可以在商品期货市场中实现较为稳健的交易策略。该策略通过短期均线与长期均线的金叉和死叉信号进行开仓,并结合止损和加仓策略,实现了在市场走势符合预期时最大化收益,同时在市场走势不符合预期时及时止损,控制风险。通过实际测试,调整后的策略在胜率和盈亏比上表现出较好的效果。

该策略具有较强的灵活性,适用于不同的市场环境,能够有效地捕捉市场趋势,实现稳健盈利。同时,交易者可以根据市场的具体情况,进一步调整策略参数,以适应不同的市场波动和风险偏好。

通过持续优化和完善该策略,可以进一步提高其在实际交易中的表现,助力交易者在复杂的市场环境中获得更为稳健的投资回报。


更多内容