请选择 进入手机版 | 继续访问电脑版
楼主: littleDreamXX
5112 0

[源码分享] 我也分享一个量化入门资料,我试着写的MACD策略 [推广有奖]

  • 0关注
  • 2粉丝

大专生

28%

还不是VIP/贵宾

-

威望
0
论坛币
107 个
通用积分
0.0601
学术水平
1 点
热心指数
1 点
信用等级
1 点
经验
768 点
帖子
34
精华
0
在线时间
26 小时
注册时间
2016-5-3
最后登录
2019-1-16

+2 论坛币
k人 参与回答

经管之家送您一份

应届毕业生专属福利!

求职就业群
赵安豆老师微信:zhaoandou666

经管之家联合CDA

送您一个全额奖学金名额~ !

感谢您参与论坛问题回答

经管之家送您两个论坛币!

+2 论坛币
# 带你进入量化世界之-----MACD双向操作滑动止损代码分析 #
>看到论坛里的大神拿出了自己的代码,我也分享一个最近几个月的学习资料,我也是才开始学习量化知识,大神轻拍,我之前在金融、投资、证券等方面也完全是小白一枚。甚至都搞不懂期货的交易流程,
更是被眼花缭乱、听所未闻的名词、术语搞的头昏脑涨,(其实现在也是略懂!略懂!)。通过自己百度、查资料等一一补脑。这个是BTC的,但是 感觉和商品期货、现货、股票有共同点。都是指标量化择时。
查阅了相关内容,心中有了基本的概念,结合自己略懂的JS语言,简单写了一个。最初不懂什么是K线、均线、MACD指标。
在这里简单说下,K线是记录一定周期内的市场行情,便于观察市场动态。均线是上一篇文章用到的指标,和MACD指标一样,都是反映市场行情趋势的指标。
这2种指标的概念、算法、公式推导等就不一一赘述了。不明白的请查百度。(我就是在百度看的!)

|变量名|初始值| 说明 |
|-|-|-|
|Interval|  2000|    这个变量是轮询周期,就是程序暂停等待的时间量,单位是毫秒,1000毫秒为1秒,所以这个变量初始值为2秒。|
|STATE\_FREE|  0 |    这个是一个表示状态的变量,表示空闲。用于状态判断。|
|STATE\_BUY | 1    |  这个是一个表示状态的变量,表示多头持仓。 就是 买开仓。|
|STATE\_SELL | 2   |  状态变量,表示空头持仓。  就是卖开仓。|
|ORDER\_INVALID | 3 |  持仓状态变量,表示未持仓。|
|ORDER\_VALID | 4  |   表示持仓中... |
|state | STATE\_FREE|  状态变量,用空闲状态初始化。|
|SignalDelay | 0  |   最初计划 信号延迟,暂时无用。|
|stopProfit | 0.002 | 这个变量比较重要,止损率, 比如  本金 * 止损率(0.002)  表示 最多赔  本金的0.002倍,损失上限。|
|step | 0.5        |  滑动止损的步长值。用于提升、下调 止损价的等级。|
|opAmount | 1    |    固定的操作量。|
|profit | 0       |   盈亏。|
## 全局对象,用于记录持仓信息,包含一些方法,主要 实现 滑动止损。(我写的比较啰嗦,仅供参考。 ^-^)

        var holdOrder = {//持仓信息对象
                    orderState: ORDER_INVALID,// 持仓状态
                    price: 0, //持仓均价
                    amount: 0, //持仓量
                    time: null, // 操作时间
                    stopPrice: 0, // 止损价
                    level: 1,   //止损等级
                    updateCurrentProfit: function(lastPrice,amount){//更新当前盈亏
                        if(state === STATE_SELL){//当前 空头持仓
                                return (lastPrice - this.price) * amount;
                        }
                        if(state === STATE_BUY){//当前 多头持仓
                                return - (lastPrice - this.price) * amount;
                        }
                    },
                    SetStopPrice: function(ticker,stopState){//更新止损价
                            if(stopState === STATE_FREE){ //更新止损时状态 为空闲
                                    return this.stopPrice;
                            }
                            if(stopState === STATE_BUY){ //更新止损时状态 为多仓
                            if(this.orderState === ORDER_INVALID){
                                    return this.stopPrice;
                            }
                            if(this.stopPrice === 0){//初始 止损价为0 时
                                    this.stopPrice = this.price * ( 1 - stopProfit );
                            }
                            if( ticker.Last <= this.price ){ //最后成交价 小于等于  持仓均价时
                                this.stopPrice = this.price * ( 1 - stopProfit );
                                this.level = 1;
                            }else{//其它情况
                                    if( ticker.Last - this.price > this.level * step ){//超出当前等级   设置滑动止损
                                    this.stopPrice = this.price * (1 - stopProfit) + (ticker.Last - this.price );
                                    //更新止损价为滑动后的止损价
                                    this.level++;//上调止损等级
                                    }else{//其它
                                            this.stopPrice = this.stopPrice;//保持当前止损价不变
                                    }
                            }
                            }else if( stopState === STATE_SELL){//空头持仓类似
                                    if(this.orderState === ORDER_INVALID){
                                    return this.stopPrice;
                            }
                            if(this.stopPrice === 0){
                                    this.stopPrice = this.price * ( 1 + stopProfit );
                            }
                            if( ticker.Last >= this.price ){
                                this.stopPrice = this.price * ( 1 + stopProfit );
                                this.level = 1;
                            }else{
                                    if( this.price - ticker.Last > this.level * step ){
                                    this.stopPrice = this.price * (1 + stopProfit) - ( this.price - ticker.Last );
                                    this.level++;
                                    }else{
                                            this.stopPrice = this.stopPrice;
                                    }
                            }
                            }
                        return this.stopPrice;//返回止损价
                    },
                    initHoldOrder: function(){//平仓后  用于 初始化持仓信息的  函数
                        this.orderState = ORDER_INVALID;
                        this.price = 0;
                        this.amount = 0;
                        this.time = null;
                        this.stopPrice = 0;
                        this.level = 1;
                    }
                };

* 代码以上传github 地址:
点击[github](https://github.com/LittleLittleDream/botvs.git "github")进入。
- 这里没有加入官方QQ群的请加入:309368835    BotVS EA交流(BotVS)。
***
#### 下面我们来快速预览将用到的函数
        function MACD_Cross(){//检测MACD指标,交叉状态的函数
            var records = exchange.GetRecords();//获取K线数据
            while(!records || records.length < 45){ //K线数据不能为null,要大于45个柱,不符合标准 循环获取直到符合
                    records = exchange.GetRecords();
                    Sleep(Interval);
            }
            var macd = TA.MACD(records,12,26,9);//调用指标函数, 参数为MACD 默认的参数。
            var dif = macd[0];  //dif线
            var dea = macd[1];  //dea线
            var column = macd[2]; // MACD柱
            var len = records.length;  //K线周期长度
            if( (dif[len-1] > 0 && dea[len-1] > 0) && dif[len-1] > dea[len-1] && dif[len-2] < dea[len-2] && column[len-1] > 0.2 ){
        //判断金叉条件:dif 与 dea 此刻均大于0 , 且dif由下上穿dea , 且 MACD量柱大于0.2
                    return 1; //返回1  代表 金叉信号。
            }
            if( (dif[len-1] < 0 && dea[len-1] < 0) && dif[len-1] < dea[len-1] && dif[len-2] > dea[len-2] && column[len-1] < -0.2 ){
        //判断死叉条件:
                return 2;//返回2  代表 死叉信号。
            }   
            return 0;  //金叉  、死叉  信号以外,为等待信号 0 。
        }
        function getTimeByNormal(time){// 获取时间的 函数 把毫秒时间 转换 标准时间
            var timeByNormal = new Date();
            timeByNormal.setTime(time);
            var strTime = timeByNormal.toString();
            var showTimeArr = strTime.split(" ");
            var showTime = showTimeArr[3]+"-"+showTimeArr[1]+"-"+showTimeArr[2]+"-"+showTimeArr[4];
            return showTime;
        }
***
### 下面开始进入策略的主函数,这个策略同上一篇 30行均线策略 一样 使用了 交易模板类库 封装了交易下单细节,有兴趣的朋友可以在BotVS上找到代码,注释版的在官方QQ群共享、github。
        function main(){
            var initAccount = $.GetAccount(exchange);//首先我们来记录初始时的账户信息,这里调用了模板类库的导出函数
            var nowAccount = initAccount;//再声明一个 变量 表示 现在账户信息
            var diffMoney = 0; //钱 差额
            var diffStocks = 0;//币 差额
            var repair = 0; //计算 盈亏时   用于修正的 量
            var ticker = exchange.GetTicker(); //获取此刻市场行情
            Log("初始账户:",initAccount); //输出显示  初始账户信息。
            while(true){//主函数循环
                scan(); //扫描函数,  稍后讲解,主要是判断  开仓、平仓 以及 操作 开仓 、 平仓。
                ticker = exchange.GetTicker();//在while循环内 获取 市场行情
                if(!ticker){//如果 没有获取到  (null) 跳过以下 重新循环
                        continue;
                }
                if(holdOrder.orderState == ORDER_VALID){//判断当前是否  持仓
                        Log("当前持仓:",holdOrder); //如果 当前持仓   输出  持仓 信息
                }
                if(holdOrder.orderState == ORDER_INVALID){//如果 未持仓(已平仓)
                        nowAccount = $.GetAccount(exchange); //获取当前账户信息
                    diffMoney = nowAccount.Balance - initAccount.Balance; //计算  当前账户  与 初始账户之间的  钱 差额
                    diffStocks = nowAccount.Stocks - initAccount.Stocks; // 计算  当前账户  与  初始账户之间的  币 差额
                    repair = diffStocks * ticker.Last; //把 币的差额 * 最后成交价  ,转为等值的钱, 用于计算 盈亏
                    LogProfit(diffMoney + repair ,"RMB","现在账户:",nowAccount,"本次盈亏:",profit);//输出 盈亏 信息
                }
                    Sleep(Interval);//轮询
            }
        }
***
### 接下来是策略的主要部分,开仓平仓检测,以及开仓平仓操作。
        function scan(){
                var sellInfo = null; //声明  储存平仓信息的变量  , 初始化null
                var buyInfo = null;  //声明  开仓的 , 初始化null
                var opFun = null;//  开仓函数, 两种状态 ,  开多仓 ,  开空仓。
                var singal = 0; //信号
            while(true){//检测 及操作 循环
                var ticker = exchange.GetTicker(); //获取市场行情
                if(!ticker){ //判断 获取失败  跳过以下 ,继续循环获取
                        continue;
                }
                holdOrder.SetStopPrice(ticker,state); //设置 持仓 止损价
                if(state === STATE_FREE &&  (singal = MACD_Cross()) !== 0  ){
                        //判断策略运行状态是否空闲、此刻MACD指标信号是否空闲, 符合 策略运行状态空闲 且 有金叉或死叉执行以下
                        holdOrder.initHoldOrder();//初始化持仓信息
                    opFun = singal === 1 ?  $.Buy : $.Sell ;//根据MACD_Cross函数返回结果,判断开多仓、开空仓。
                    buyInfo = opFun(opAmount);//开仓操作
                    holdOrder.orderState = ORDER_VALID;//设置持仓信息,状态为持仓
                    holdOrder.price = buyInfo.price; //设置持仓均价  由 开仓操作函数 opFun返回。
                    holdOrder.amount = buyInfo.amount; //设置持仓量
                    holdOrder.time = getTimeByNormal((new Date()).getTime());//设置持仓开始的时间
                    state = singal === 1 ? STATE_BUY : STATE_SELL; //更新策略状态为多仓 或 空仓
                    var account = $.GetAccount(exchange); //获取账户信息
                    if(singal === 1){//输出开仓方向 和 当前账户信息
                            Log("开多仓。","账户:",account);
                    }else{
                        Log("开空仓。","账户:",account);
                    }
                    break;
                }else{
                        var lastPrice = holdOrder.price;// 把持仓均价 赋值 给 lastPrice
                        if( state === STATE_BUY && holdOrder.orderState === ORDER_VALID && ticker.Last < holdOrder.stopPrice ){
                //如果 多仓 且 持仓信息为持仓 且 最后成交价 小于止损价,执行以下
                            Log("多头止损平仓","初始止损价:",holdOrder.price * (1 - stopProfit),"--滑动止损价:",holdOrder.stopPrice,"最后成交价:",ticker.Last,"止损等级:",holdOrder.level);//多头止损平仓信息
                            sellInfo = $.Sell(holdOrder.amount);//平仓
                        holdOrder.orderState = ORDER_INVALID;//平仓信息 更新进对象
                        holdOrder.price = sellInfo.price;
                        holdOrder.amount = sellInfo.amount;
                        holdOrder.time = getTimeByNormal((new Date()).getTime());
                        profit = holdOrder.updateCurrentProfit(lastPrice,sellInfo.amount);//更新浮动盈亏
                            state = STATE_FREE;//更新状态
                            break;//跳出
                        }
                        if( state === STATE_SELL && holdOrder.orderState === ORDER_VALID && ticker.Last > holdOrder.stopPrice ){//同上 , 这个是空头止损平仓
                            Log("空头止损平仓","初始止损价:",holdOrder.price * (1 + stopProfit),"--滑动止损价:",holdOrder.stopPrice,"最后成交价:",ticker.Last,"止损等级:",holdOrder.level);//测试
                            sellInfo = $.Buy(holdOrder.amount);
                        holdOrder.orderState = ORDER_INVALID;
                        holdOrder.price = sellInfo.price;
                        holdOrder.amount = sellInfo.amount;
                        holdOrder.time = getTimeByNormal((new Date()).getTime());
                        profit = holdOrder.updateCurrentProfit(lastPrice,sellInfo.amount);
                            state = STATE_FREE;
                            break;
                        }
                    if(state === STATE_BUY && MACD_Cross() === 2 ){//做多时,MACD指标死叉 -- 死叉平仓
                            sellInfo = $.Sell(holdOrder.amount);
                            Log("死叉平仓","初始止损价:",holdOrder.price * (1 - stopProfit),"--滑动止损价:",holdOrder.stopPrice,"最后成交价:",ticker.Last,"止损等级:",holdOrder.level);//测试
                        holdOrder.orderState = ORDER_INVALID;
                        holdOrder.price = sellInfo.price;
                        holdOrder.amount = sellInfo.amount;
                        holdOrder.time = getTimeByNormal((new Date()).getTime());
                        profit = holdOrder.updateCurrentProfit(lastPrice,sellInfo.amount);
                            state = STATE_FREE;
                            break;
                    }
                     if(state === STATE_SELL && MACD_Cross() === 1 ){//做空时,MACD指标金叉 ---金叉平仓
                            sellInfo = $.Buy(holdOrder.amount);
                            Log("金叉平仓","初始止损价:",holdOrder.price * (1 + stopProfit),"--滑动止损价:",holdOrder.stopPrice,"最后成交价:",ticker.Last,"止损等级:",holdOrder.level);//测试
                        holdOrder.orderState = ORDER_INVALID;
                        holdOrder.price = sellInfo.price;
                        holdOrder.amount = sellInfo.amount;
                        holdOrder.time = getTimeByNormal((new Date()).getTime());
                        profit = holdOrder.updateCurrentProfit(lastPrice,sellInfo.amount);
                            state = STATE_FREE;
                            break;
                    }
                }
                Sleep(Interval);//轮询间隔,就是让程序暂停一会儿。
            }
        }
***
#### 代码看累了,喝口水歇歇~流程图直观些~上图!
>先说说关于滑动止损的原理。图片右边,再大致看下 程序执行流程。

![左边流程,右边滑动止损算法]()
### 大家可以先跑跑回测实验一下,记得要引用“数字货币交易类库”这个模板!另外写的简陋欢迎指正、修改。
> 参考资料

- [策略源码](https://www.botvs.com/strategy/12822)
- [github上的代码库](https://github.com/LittleLittleDream/botvs.git)
- [BotVS的代码广场](https://www.botvs.com/square)


二维码

扫码加我 拉你入群

请注明:姓名-公司-职位

以便审核进群资格,未注明则拒绝

关键词:MACD Mac ACD exchange function 量化 量化交易策略

已有 1 人评分经验 论坛币 收起 理由
fantuanxiaot + 33 + 33 精彩帖子

总评分: 经验 + 33  论坛币 + 33   查看全部评分

您需要登录后才可以回帖 登录 | 我要注册

本版微信群
加好友,备注jr
拉您进交流群

京ICP备16021002-2号 京B2-20170662号 京公网安备 11010802022788号 论坛法律顾问:王进律师 知识产权保护声明   免责及隐私声明

GMT+8, 2024-3-29 00:51