ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

简易波动EMV策略

2021-08-25 10:03:32  阅读:178  来源: 互联网

标签:bar1 arr emv exchange 波动 简易 EMV position


一、摘要

与其他技术指标不同,简易波动(Ease of Movement Value)反映的是价格、成交量、人气的变化,是一种将价格与成交量变化相结合的技术,它通过衡量单位成交量的价格变动,形成一个价格波动指标。当市场人气聚集,交易活跃时提示买入信号;当成交量低迷,市场能量即将耗尽时提示卖出信号。

简易波动EMV根据等量图和压缩图的原理设计而成,它的核心理念是:场价格仅在发趋势转折或即将转折时,才会消耗大量能量,外在表现是成交量变。当价格在上升的过程中,由于推波助澜的作用,不会消耗太多的能量。虽然这个理念与量价同升的观点相悖,但的确有其独特的地方。

二、EMV计算公式

第一步:计算mov_mid
其中TH代表当天最高价,TL代表当天最低价,YH表前日最高价,YL代表前日最低价。那么如果MID > 0意味着今天的平均价高于昨天的平均价。

第二步:计算ratio
其中TVOL代表当天交易量,TH代表当天最高价,TL代当天最低价。

第三步:计算emv

三、EMV用法

EMV的作者认为,巨量上涨伴的是能量的快速枯竭,上涨往往不会持续太久;反而温和的成交量,能够保存一定的能量,往往使上涨持续更久。一旦上涨趋势形成,较少的成交量就能推动价格上涨,EMV的数值就会升高。一旦下跌趋势行情形成,往往伴随的是无量或少量下跌,EMV的数值就会下降。如果价格处于震荡行情或者价格上涨和下跌都伴随较大成交量时,EMV的数值也会接近于零。因你会发现,EMV在大部分行情中都处于零轴下方,这也是这个指标的一大特色。站在另一个角度看,EMV重视大趋势且能够产生足够利润的行情。

EMV的用法相当简单,只要看EMV是否穿越零轴即,当EMV在0以下时,代表市场弱市;当EMV在0以上时,代表市场强市。让EMV由负数转为正数时应该买进;当EMV由正数转为负数时应该卖出。其特点是不仅能较好的避免市场中的震荡行情,而且还能在趋势行情启动的时候及时入场。但由于EMV反映的是价格在变动时的交量的变化情况,所以仅对中长期走势有作用。对于短线或交易周期比小的行情EMV的效果很差。

四、策略实现

第1步:编写策略框架

# 策略主函数
def onTick():
    pass


# 程序入口
def main():
    while True:  # 进入无限循环模式
        onTick()  # 执行策略主函数
        Sleep(1000)  # 休眠1秒

发明者量化采用轮训模式,首先要定义一个main函数和一个onTick函数,main函数是策略的入口数,程序会从main函数开始逐行执行代码。在main函数中,写入while循环,重复执行onTick函数,所有的策略核心代码都写在onTick函数中。

第2步:获取持仓数据

def get_position():
    position = 0                              # 赋值持仓数量为0
    position_arr = _C(exchange.GetPosition)   # 获取持仓数组
    if len(position_arr) > 0:                 # 如果持仓数组长度大于0
        for i in position_arr:                # 遍历持仓数组
            if i['ContractType'] == 'IH000':  # 如果持仓品种等于订阅品种
                if i['Type'] % 2 == 0:        # 如果是多单
                    position = i['Amount']    # 赋值持仓数量为正数
                else:
                    position = -i['Amount']   # 赋值持仓数量为负数
    return position  # 返回持仓量

因为在这个策略中,只使用了实时的持仓数量,为了方便维护,这里使用get_position封装了持仓量,如果当前持有多单就返回正数,如果当前持有空单就返回负数。

第3步:获取K线数据

exchange.SetContractType('IH000')   # 订阅期货品种
bars_arr = exchange.GetRecords()    # 获取K线数组
if len(bars_arr) < 10:              # 如果K线数量小于10根
    return

在获取具体的K线数据之前,首先要先订阅具体的合约,使用发明者量化的SetContractType函数,传入约代码即可,如果想知道该合约的其他信息,也可以使用一个变量来接收这个数据。接着使用GetRecords函数就可以获取K线数据,因为返回的是一个数组,所以我们使用变量bars_arr来接受它。

第4步:计算emv

bar1 = bars_arr[-2]  # 获取上一根K线数据
bar2 = bars_arr[-3]  # 获取前一根K线数据
# 计算mov_mid的值
mov_mid = (bar1['High'] + bar1['Low']) / 2 - (bar2['High'] + bar2['Low']) / 2
if bar1['High'] != bar1['Low']:  # 如果被除数不为0
    # 计算ratio的值
    ratio = (bar1['Volume'] / 10000) / (bar1['High'] - bar1['Low'])
else:
    ratio = 0
# 如果ratio的值大于0
if ratio > 0:
    emv = mov_mid / ratio
else:
    emv = 0

在这里我们并没有使用最新的价格来计算EMV的值,而是采用相对滞后的当前K线出信号,下根K线发单的方法。这么的目的是让回测更接近于实盘易。我们知道,尽管现在量化交易软件已经非常先进了,但还是很难做到完全模拟真实的实盘Tick环境,特别是面对回测Bar级超长数据时,所以就采用这个折中的方法。

第5步:下单交易

current_price = bars_arr[-1]['Close']  # 最新价格
position = get_position()              # 获取最新持仓量
if position > 0:   # 如果持有多单
    if emv < 0:    # 如果当前格小于牙齿
        exchange.SetDirection("closebuy")    # 设置交易方向和类型
        exchange.Sell(round(current_price - 0.2, 2), 1)  # 平多单
if position < 0:   # 如果持有空单
    if emv > 0:    # 如果当前价格大于牙齿
        exchange.SetDirection("closesell")   # 设置交易方向和类型
        exchange.Buy(round(current_price + 0.2, 2), 1)   # 平空单
if position == 0:  # 如果无持仓
    if emv > 0:    # 如果当前价格大于上唇
        exchange.SetDirection("buy")         # 设置交易方向和类型
        exchange.Buy(round(current_price + 0.2, 2), 1)   # 开多单
    if emv < 0:    # 如果当前价格小于下巴
        exchange.SetDirection("sell")        # 设置交易方向和类型
        exchange.Sell(round(current_price - 0.2, 2), 1)  # 空单

在下单交易之前,我们需要先确定两个数据,一个是下单的价格,另一个是当前的持仓状态。下单的价格很简单,直接使用当前的收盘价加减品种的最小变动价位即可。由于我们之前已经使用get_position函数封装了持仓量,所以这里直接调用即可。最后就是根据EMV与零轴的位置关系开平仓了。

# 回测配置
'''backtest
start: 2019-01-01 00:00:00
end: 2020-01-01 00:00:00
period: 1d
basePeriod: 1d
exchanges: [{"eid":"Futures_CTP","currency":"FUTURES"}]
'''


# 获取持仓数量
def get_position():
    position = 0                              # 赋值持仓数量为0
    position_arr = _C(exchange.GetPosition)   # 获取持仓数组
    if len(position_arr) > 0:                 # 如果持仓数组长度大于0
        for i in position_arr:                # 遍历持仓数组
            if i['ContractType'] == 'IH000':  # 如果持仓品种等于订阅品种
                if i['Type'] % 2 == 0:        # 如果是多单
                    position = i['Amount']    # 赋值持仓数量为正数
                else:
                    position = -i['Amount']   # 赋值持仓数量为负数
    return position  # 返回持仓量


# 策略主函数
def onTick():
    # 获取数据
    exchange.SetContractType('IH000')   # 订阅期货品种
    bars_arr = exchange.GetRecords()    # 获取K线数组
    if len(bars_arr) < 10:              # 如果K线数量小于10根
        return

    # 计算emv
    bar1 = bars_arr[-2]  # 获取上一根K线数据
    bar2 = bars_arr[-3]  # 获取前一根K线数据
    # 计算mov_mid的值
    mov_mid = (bar1['High'] + bar1['Low']) / 2 - (bar2['High'] + bar2['Low']) / 2
    if bar1['High'] != bar1['Low']:  # 如果被除数不为0
        # 计算ratio的值
        ratio = (bar1['Volume'] / 10000) / (bar1['High'] - bar1['Low'])
    else:
        ratio = 0
    # 如果ratio的值大于0
    if ratio > 0:
        emv = mov_mid / ratio
    else:
        emv = 0

    # 下单交易
    current_price = bars_arr[-1]['Close']  # 最新价格
    position = get_position()              # 获取最新持仓量
    if position > 0:   # 如果持多单
        if emv < 0:    # 如果当前价格小于牙齿
            exchange.SetDirection("closebuy")    # 设置交易方向和类型
            exchange.Sell(round(current_price - 0.2, 2), 1)  # 平多单
    if position < 0:   # 如果持有空单
        if emv > 0:    # 如果当前价格大于牙齿
            exchange.SetDirection("closesell")   # 设置交易方向和类型
            exchange.Buy(round(current_price + 0.2, 2), 1)   # 平空单
    if position == 0:  # 如果无持仓
        if emv > 0:    # 如果当前价格大于上唇
            exchange.SetDirection("buy")         # 设置交易方向和类型
            exchange.Buy(round(current_price + 0.2, 2), 1)   # 开多单
        if emv < 0:    # 如果当前价格小于下巴
            exchange.SetDirection("sell")        # 设置交易向和类型
            exchange.Sell(round(current_price - 0.2, 2), 1)  # 开空
        

# 程序入口函数
def main():
    while True:      # 循环
        onTick()     # 执行策略主函数
        Sleep(1000)  # 休眠1秒

标签:bar1,arr,emv,exchange,波动,简易,EMV,position
来源: https://www.cnblogs.com/fkjl/p/15183632.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有