mql5/Experts/RSI_Strategy.mq5
1Morty 50a3adba89
2025-09-08 21:00:32 +08:00

641 lines
No EOL
25 KiB
MQL5

//+------------------------------------------------------------------+
//| RSI_Strategy.mq5 |
//| Copyright 2025, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2025, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
#include <Trade\Trade.mqh>
CTrade trade;
//+------------------------------------------------------------------+
//| 输入参数 |
//+------------------------------------------------------------------+
input group "=====基本参数======"
input int MagicNumber = 123456;
input string OrderComment = "RSI_Strategy";
input group "=====马丁参数====="
input double MartinStartLots = 0.1; // 首次进场手数(基准:10000美元=0.1手)
input double MartinStepUSD = 3; // 马丁加仓间隔(美金,作为ATR不触发时的回退值)
input double MartinMultiplier = 1.3; // 马丁加仓倍数
input double TakeProfitUSD = 3; // 盈利出场(美金)
input int PriceDigits = 2; // 价格小数位(如XAUUSD有的平台是2,有的是3)
input int MaxAddCount = 15; // 最大加仓次数
input bool EnableDynamicLots = true; // 是否启用动态手数(按余额比例),关闭则固定用MartinStartLots
input group "=====动态加仓参数====="
input int ATRPeriod = 2; // ATR周期
input double ATRThresholdUSD = 0.6; // ATR阈值(美金)
input double ATRDistanceMultiplier = 1;// ATR加仓距离系数
input group "=====EMA加仓风控====="
input bool EnableEMARisk = false; // 开关:当加仓次数超过阈值后启用EMA风控
input int EMARiskStartAddCount = 10; // 超过该加仓次数后启用风控
input int EMARiskPeriod = 50; // EMA周期(默认50)
input group "=====指标参数====="
input double RSIUpperLevel = 85; // RSI超买水平
input double RSILowerLevel = 25; // RSI超卖水平
input bool EnableRSIFilter = false; // 是否启用RSI过滤
input double ADXThreshold = 50; // ADX阈值,大于此值时暂停加仓
input bool EnableADXFilter = true; // 是否启用ADX过滤功能
input group "=====交易方向开关====="
input bool EnableBuy = true; // 是否允许做多
input bool EnableSell = true; // 是否允许做空
input group "=====时间段控制====="
input bool EnableTimeControl = false; // 是否时间段控制
input string TradingHours = "1,2,3,4,5,6,7,8,9,10"; // 允许开仓的时间段(小时),用逗号分割
// RSI指标句柄
int rsiHandle = INVALID_HANDLE;
// ADX指标句柄
int adxHandle = INVALID_HANDLE;
// ATR指标句柄
int atrHandle = INVALID_HANDLE;
// EMA12指标句柄
int ema12Handle = INVALID_HANDLE;
// EMA风控指标句柄
int emaRiskHandle = INVALID_HANDLE;
// 记录上一次加仓价和当前加仓手数
static double lastLongAddPrice = 0;
static double lastLongAddLots = 0;
// 记录上一次空单加仓价和手数
static double lastShortAddPrice = 0;
static double lastShortAddLots = 0;
// 记录加仓次数
static int buyAddCount = 0;
static int sellAddCount = 0;
// 记录移动追踪止盈的历史最高/最低价
static double buyTrailingPrice = 0; // 多单移动追踪止盈位
static double sellTrailingPrice = 0; // 空单移动追踪止盈位
// 获取当前RSI值
double GetRSI() {
if(rsiHandle == INVALID_HANDLE)
rsiHandle = iRSI(_Symbol, _Period, 14, PRICE_CLOSE);
// 获取当前RSI值
double rsiArray[1];
if(CopyBuffer(rsiHandle, 0, 0, 1, rsiArray) <= 0) return 0.0;
return rsiArray[0];
// 获取上一根K线的RSI值
// double rsiArray[2];
// if(CopyBuffer(rsiHandle, 0, 1, 2, rsiArray) <= 0) return 0.0;
// return rsiArray[0];
}
// 获取基于ATR的动态加仓距离(单位:美金)。当ATR>阈值时使用 ATR*系数,否则使用固定MartinStepUSD
double CalculateDynamicAddDistanceUSD() {
if(atrHandle == INVALID_HANDLE)
atrHandle = iATR(_Symbol, _Period, ATRPeriod);
if(atrHandle != INVALID_HANDLE) {
double atrArray[1];
if(CopyBuffer(atrHandle, 0, 0, 1, atrArray) == 1) {
double atrNow = atrArray[0];
if(atrNow > ATRThresholdUSD) {
double distance = atrNow * ATRDistanceMultiplier;
return NormalizeDouble(distance, 2);
}
}
}
return NormalizeDouble(MartinStepUSD, 2);
}
// 读取上一根K线的开收盘
bool GetPrevCandle(double &prevOpen, double &prevClose) {
double o[1], c[1];
if(CopyOpen(_Symbol, _Period, 1, 1, o) != 1) return false;
if(CopyClose(_Symbol, _Period, 1, 1, c) != 1) return false;
prevOpen = o[0];
prevClose = c[0];
return true;
}
// 获取指定周期EMA在上一根K线的值
bool GetPrevEMA(int period, double &emaPrev) {
if(emaRiskHandle == INVALID_HANDLE)
emaRiskHandle = iMA(_Symbol, _Period, period, 0, MODE_EMA, PRICE_CLOSE);
if(emaRiskHandle == INVALID_HANDLE) return false;
double emaArr[1];
if(CopyBuffer(emaRiskHandle, 0, 1, 1, emaArr) != 1) return false;
emaPrev = emaArr[0];
return true;
}
// EMA风控:
// - 多单:上一根K线实体上穿EMA(上一根开盘<EMA 且 收盘>EMA)
// - 空单:上一根K线实体收在EMA下方(上一根收盘<EMA)
bool PassesEMARisk(int posType) {
double prevOpen = 0.0, prevClose = 0.0, emaPrev = 0.0;
if(!GetPrevCandle(prevOpen, prevClose)) return false;
if(!GetPrevEMA(EMARiskPeriod, emaPrev)) return false;
if(posType == POSITION_TYPE_BUY) {
return (prevOpen < emaPrev && prevClose > emaPrev);
} else {
return (prevClose < emaPrev);
}
}
// 获取当前ADX值
double GetADX() {
if(adxHandle == INVALID_HANDLE)
adxHandle = iADX(_Symbol, _Period, 14);
// 获取当前ADX值
double adxArray[1];
if(CopyBuffer(adxHandle, 0, 0, 1, adxArray) <= 0) return 0.0;
return adxArray[0];
}
// 获取上根K线收盘价
double GetPreviousClose() {
double closeArray[2];
if(CopyClose(_Symbol, _Period, 1, 2, closeArray) <= 0) return 0.0;
return closeArray[1]; // 上根K线收盘价
}
// 获取当前EMA12值
double GetEMA12() {
if(ema12Handle == INVALID_HANDLE)
ema12Handle = iMA(_Symbol, _Period, 12, 0, MODE_EMA, PRICE_CLOSE);
double emaArray[2];
if(CopyBuffer(ema12Handle, 0, 0, 2, emaArray) <= 0) return 0.0;
return emaArray[1];
}
//+------------------------------------------------------------------+
//| 检查当前时间是否在允许开仓的时间段内 |
//+------------------------------------------------------------------+
bool IsTradingTime() {
if(!EnableTimeControl) return true;
// 获取当前服务器时间
MqlDateTime dt;
TimeToStruct(TimeCurrent(), dt);
int currentHour = dt.hour;
// 解析允许的时间段
string hours[];
StringSplit(TradingHours, ',', hours);
for(int i = 0; i < ArraySize(hours); i++) {
// 去除空格并转换为整数
string hourStr = hours[i];
// 去除前后空格
while(StringLen(hourStr) > 0 && StringGetCharacter(hourStr, 0) == ' ') {
hourStr = StringSubstr(hourStr, 1);
}
while(StringLen(hourStr) > 0 && StringGetCharacter(hourStr, StringLen(hourStr)-1) == ' ') {
hourStr = StringSubstr(hourStr, 0, StringLen(hourStr)-1);
}
if(hourStr != "") {
int hour = (int)StringToInteger(hourStr);
if(hour == currentHour) {
return true; // 当前时间在允许的时间段内
}
}
}
return false; // 当前时间不在允许的时间段内
}
//+------------------------------------------------------------------+
//| 检查是否有指定方向的持仓 |
//+------------------------------------------------------------------+
bool HasPosition(int posType) {
for(int i=0; i<PositionsTotal(); i++) {
ulong ticket = PositionGetTicket(i);
if(PositionSelectByTicket(ticket)) {
if(PositionGetString(POSITION_SYMBOL) == _Symbol &&
PositionGetInteger(POSITION_MAGIC) == MagicNumber &&
PositionGetInteger(POSITION_TYPE) == posType) {
return true;
}
}
}
return false;
}
//+------------------------------------------------------------------+
//| 获取当前持仓类型 |
//+------------------------------------------------------------------+
int GetCurrentPosType() {
if(HasPosition(POSITION_TYPE_BUY)) return POSITION_TYPE_BUY;
if(HasPosition(POSITION_TYPE_SELL)) return POSITION_TYPE_SELL;
return -1;
}
//+------------------------------------------------------------------+
//| 开仓函数 |
//+------------------------------------------------------------------+
void OpenPosition(int posType, double lots, double price, string comment) {
trade.SetExpertMagicNumber(MagicNumber);
bool result = false;
if(posType == POSITION_TYPE_BUY) {
result = trade.Buy(lots, _Symbol, price, 0, 0, comment);
} else if(posType == POSITION_TYPE_SELL) {
result = trade.Sell(lots, _Symbol, price, 0, 0, comment);
}
if(result) {
string direction = (posType == POSITION_TYPE_BUY) ? "多单" : "空单";
}
}
//+------------------------------------------------------------------+
//| 执行开仓操作(包含开仓、更新变量、打印日志) |
//+------------------------------------------------------------------+
void ExecuteOpenPosition(int posType, double rsi, double rsiThreshold, double curPrice) {
double dynamicLots = GetDynamicLots(posType);
OpenPosition(posType, dynamicLots, curPrice, OrderComment);
// 更新加仓相关变量
double lastAddPrice = curPrice;
double lastAddLots = dynamicLots;
int currentAddCount = 1; // 首次进场算第一次
// 写回全局变量
UpdateGlobalVariables(posType, lastAddPrice, lastAddLots, currentAddCount);
}
//+------------------------------------------------------------------+
//| 平仓函数 |
//+------------------------------------------------------------------+
void ClosePosition(int posType) {
for(int i=PositionsTotal()-1; i>=0; i--) {
ulong ticket = PositionGetTicket(i);
if(PositionSelectByTicket(ticket)) {
if(PositionGetString(POSITION_SYMBOL) == _Symbol &&
PositionGetInteger(POSITION_MAGIC) == MagicNumber &&
PositionGetInteger(POSITION_TYPE) == posType) {
if(trade.PositionClose(ticket)) {
string direction = (posType == POSITION_TYPE_BUY) ? "多单" : "空单";
}
}
}
}
}
//+------------------------------------------------------------------+
//| 计算指定方向持仓的加权平均价 |
//+------------------------------------------------------------------+
double GetAvgPrice(int posType) {
double totalLots = 0;
double totalCost = 0;
for(int i=0; i<PositionsTotal(); i++) {
ulong ticket = PositionGetTicket(i);
if(PositionSelectByTicket(ticket)) {
if(PositionGetString(POSITION_SYMBOL) == _Symbol &&
PositionGetInteger(POSITION_MAGIC) == MagicNumber &&
PositionGetInteger(POSITION_TYPE) == posType) {
double lots = PositionGetDouble(POSITION_VOLUME);
double price = PositionGetDouble(POSITION_PRICE_OPEN);
totalLots += lots;
totalCost += lots * price;
}
}
}
if(totalLots == 0) return 0;
return totalCost / totalLots;
}
//+------------------------------------------------------------------+
//| 计算指定方向持仓的总手数 |
//+------------------------------------------------------------------+
double GetTotalLots(int posType) {
double totalLots = 0;
for(int i=0; i<PositionsTotal(); i++) {
ulong ticket = PositionGetTicket(i);
if(PositionSelectByTicket(ticket)) {
if(PositionGetString(POSITION_SYMBOL) == _Symbol &&
PositionGetInteger(POSITION_MAGIC) == MagicNumber &&
PositionGetInteger(POSITION_TYPE) == posType) {
totalLots += PositionGetDouble(POSITION_VOLUME);
}
}
}
return totalLots;
}
//+------------------------------------------------------------------+
//| 检查加仓条件 |
//+------------------------------------------------------------------+
bool CheckAddPosition(int posType, double curPrice, double lastAddPrice, double stepDistance, double totalLots, int currentAddCount) {
if(totalLots <= 0) return false;
// 检查时间段是否允许开仓
if(!IsTradingTime()) {
Print("当前时间不在允许开仓的时间段内,禁止加仓");
return false;
}
// 检查最大加仓次数
if(currentAddCount >= MaxAddCount) {
string direction = (posType == POSITION_TYPE_BUY) ? "多单" : "空单";
Print(direction, "已达到最大加仓次数(", currentAddCount, " >= ", MaxAddCount, "),停止加仓");
return false;
}
bool shouldAdd = false;
if(posType == POSITION_TYPE_BUY) {
shouldAdd = (curPrice <= lastAddPrice - stepDistance * SymbolInfoDouble(_Symbol, SYMBOL_POINT));
} else {
shouldAdd = (curPrice >= lastAddPrice + stepDistance * SymbolInfoDouble(_Symbol, SYMBOL_POINT));
}
if(!shouldAdd) return false;
// EMA风控:当开启且加仓次数达到阈值后,要求满足指定的K线与EMA关系
if(EnableEMARisk && currentAddCount >= EMARiskStartAddCount) {
if(!PassesEMARisk(posType)) {
string direction2 = (posType == POSITION_TYPE_BUY) ? "多单" : "空单";
Print(direction2, " EMA风控未通过(AddCount=", currentAddCount, ", 阈值=", EMARiskStartAddCount,
", EMA", EMARiskPeriod, "),暂停加仓");
return false;
}
}
// 检查ADX条件(趋势强度)
if(EnableADXFilter) {
double adx = GetADX();
if(adx > ADXThreshold) {
string direction = (posType == POSITION_TYPE_BUY) ? "多单" : "空单";
Print(direction, "ADX值过高(", adx, " > ", ADXThreshold, "),暂停加仓");
return false;
}
}
return true;
}
//+------------------------------------------------------------------+
//| 写回全局变量 |
//+------------------------------------------------------------------+
void UpdateGlobalVariables(int posType, double lastAddPrice, double lastAddLots, int currentAddCount) {
if(posType == POSITION_TYPE_BUY) {
lastLongAddPrice = lastAddPrice;
lastLongAddLots = lastAddLots;
buyAddCount = currentAddCount;
} else {
lastShortAddPrice = lastAddPrice;
lastShortAddLots = lastAddLots;
sellAddCount = currentAddCount;
}
}
//+------------------------------------------------------------------+
//| 检查80%移动追踪止盈条件,达到后全部平仓 |
//+------------------------------------------------------------------+
void CheckTrailingTakeProfit(int posType, double currentPrice, double avgPrice) {
// 检查盈亏平衡价是否有效
if(avgPrice == 0) {
return;
}
// 计算80%移动追踪止盈价格
double trailingPrice = 0;
if(posType == POSITION_TYPE_BUY) {
// 多单:当前价格 - (当前价格 - 盈亏平衡价) × 80%
double profitDistance = currentPrice - avgPrice;
if(profitDistance <= 0) return; // 没有利润,不检查
trailingPrice = currentPrice - (profitDistance * 0.3);
// 更新多单移动追踪止盈位(取最高值)
if(trailingPrice > buyTrailingPrice || buyTrailingPrice == 0) {
buyTrailingPrice = trailingPrice;
Print("多单移动追踪止盈位更新:", buyTrailingPrice, " 当前价:", currentPrice, " 盈亏平衡价:", avgPrice);
}
// 使用历史最高止盈位进行检查
trailingPrice = buyTrailingPrice;
} else {
// 空单:当前价格 + (盈亏平衡价 - 当前价格) × 80%
double profitDistance = avgPrice - currentPrice;
if(profitDistance <= 0) return; // 没有利润,不检查
trailingPrice = currentPrice + (profitDistance * 0.3);
// 更新空单移动追踪止盈位(取最低值)
if(trailingPrice < sellTrailingPrice || sellTrailingPrice == 0) {
sellTrailingPrice = trailingPrice;
Print("空单移动追踪止盈位更新:", sellTrailingPrice, " 当前价:", currentPrice, " 盈亏平衡价:", avgPrice);
}
// 使用历史最低止盈位进行检查
trailingPrice = sellTrailingPrice;
}
// 规范化价格
trailingPrice = NormalizeDouble(trailingPrice, _Digits);
// 检查是否达到移动追踪止盈条件
bool shouldClose = false;
if(posType == POSITION_TYPE_BUY) {
// 多单:当前价格回撤到移动止盈位以下
shouldClose = (currentPrice <= trailingPrice);
} else {
// 空单:当前价格反弹到移动止盈位以上
shouldClose = (currentPrice >= trailingPrice);
}
if(shouldClose) {
Print("达到80%移动追踪止盈条件,", (posType == POSITION_TYPE_BUY) ? "多单" : "空单", " 当前价:", currentPrice, " 移动止盈位:", trailingPrice);
// 调用现有的平仓函数
ClosePosition(posType);
Print("80%移动追踪止盈平仓完成");
// 重置移动追踪止盈位
if(posType == POSITION_TYPE_BUY) {
buyTrailingPrice = 0;
} else {
sellTrailingPrice = 0;
}
}
}
//+------------------------------------------------------------------+
//| 入场条件检查函数 |
//+------------------------------------------------------------------+
bool CheckEntryFirst(int posType, double rsi, double rsiThreshold, double totalLots) {
// 1. 检查是否已有持仓
if(totalLots > 0) return false;
// 2. 检查时间段是否允许开仓
if(!IsTradingTime()) {
Print("当前时间不在允许开仓的时间段内,禁止开仓");
return false;
}
// 3. 检查RSI过滤条件
bool shouldEnter = false;
if(EnableRSIFilter) {
shouldEnter = (posType == POSITION_TYPE_BUY) ? (rsi < rsiThreshold) : (rsi > rsiThreshold);
} else {
shouldEnter = true; // 不用RSI过滤时,只要没持仓就允许开仓
}
if(!shouldEnter) return false;
return true;
}
//+------------------------------------------------------------------+
//| 计算开仓手数:可选动态手数(按余额比例)或固定手数 |
//+------------------------------------------------------------------+
double GetDynamicLots(int posType) {
// 规范化工具
double minLots = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
double maxLots = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
double stepLots = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
if(!EnableDynamicLots) {
// 固定手数模式:直接使用 MartinStartLots,并按交易品种步进规范化
double fixedLots = MartinStartLots;
fixedLots = MathMax(minLots, MathMin(maxLots, fixedLots));
fixedLots = NormalizeDouble(fixedLots / stepLots, 0) * stepLots;
return fixedLots;
}
// 动态手数模式:当前余额 / 基准余额 * 基准手数
double accountBalance = AccountInfoDouble(ACCOUNT_BALANCE);
double baseBalance = 10000.0; // 基准余额
double baseLots = MartinStartLots; // 基准手数
double dynamicLots = (accountBalance / baseBalance) * baseLots;
// 规范化手数
dynamicLots = MathMax(minLots, MathMin(maxLots, dynamicLots));
dynamicLots = NormalizeDouble(dynamicLots / stepLots, 0) * stepLots;
return dynamicLots;
}
//+------------------------------------------------------------------+
//| 马丁策略主逻辑 |
//+------------------------------------------------------------------+
void MartinLogic(int posType, double rsi, double rsiThreshold) {
double curPrice = (posType == POSITION_TYPE_BUY) ?
SymbolInfoDouble(_Symbol, SYMBOL_ASK) :
SymbolInfoDouble(_Symbol, SYMBOL_BID);
double avgPrice = GetAvgPrice(posType);
double totalLots = GetTotalLots(posType);
double lastAddPrice = (posType == POSITION_TYPE_BUY) ? lastLongAddPrice : lastShortAddPrice;
double lastAddLots = (posType == POSITION_TYPE_BUY) ? lastLongAddLots : lastShortAddLots;
int currentAddCount = (posType == POSITION_TYPE_BUY) ? buyAddCount : sellAddCount;
string direction = (posType == POSITION_TYPE_BUY) ? "多单" : "空单";
// 计算实际点数(美金转点数),加仓距离采用动态计算
int multiplier = (PriceDigits == 2) ? 100 : ((PriceDigits == 3) ? 1000 : 1);
double stepDistanceUSD = CalculateDynamicAddDistanceUSD();
double stepDistance = stepDistanceUSD * multiplier;
double tpDistance = TakeProfitUSD * multiplier;
// 1. 首次进场
bool shouldEnter = CheckEntryFirst(posType, rsi, rsiThreshold, totalLots);
if(shouldEnter) {
ExecuteOpenPosition(posType, rsi, rsiThreshold, curPrice);
return;
}
// 2. 盈利出场
bool shouldTakeProfit = false;
if(posType == POSITION_TYPE_BUY) {
shouldTakeProfit = (totalLots > 0 && curPrice >= avgPrice + tpDistance * SymbolInfoDouble(_Symbol, SYMBOL_POINT));
} else {
shouldTakeProfit = (totalLots > 0 && curPrice <= avgPrice - tpDistance * SymbolInfoDouble(_Symbol, SYMBOL_POINT));
}
if(shouldTakeProfit) {
ClosePosition(posType);
lastAddPrice = 0;
lastAddLots = 0;
currentAddCount = 0;
// 为所有同方向持仓设置80%追踪止盈TP
// CheckTrailingTakeProfit(posType, curPrice, avgPrice);
// 写回全局变量
UpdateGlobalVariables(posType, lastAddPrice, lastAddLots, currentAddCount);
// 平仓后立即检查是否可以开新的首仓
bool shouldEnter = CheckEntryFirst(posType, rsi, rsiThreshold, 0); // 传入0因为刚平仓,没有持仓
if(shouldEnter) {
ExecuteOpenPosition(posType, rsi, rsiThreshold, curPrice);
}
return;
}
// 4. 马丁加仓
bool shouldAdd = CheckAddPosition(posType, curPrice, lastAddPrice, stepDistance, totalLots, currentAddCount);
if(shouldAdd) {
double nextLots = NormalizeDouble(lastAddLots * MartinMultiplier, 2);
OpenPosition(posType, nextLots, curPrice, OrderComment);
lastAddPrice = curPrice;
lastAddLots = nextLots;
currentAddCount++; // 增加加仓次数
Print("马丁加仓", direction, ",价格:", curPrice, " 手数:", nextLots, " 加仓次数:", currentAddCount, "/", MaxAddCount);
UpdateGlobalVariables(posType, lastAddPrice, lastAddLots, currentAddCount);
return;
}
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick() {
double rsi = GetRSI();
// 马丁策略逻辑
if(EnableBuy)
MartinLogic(POSITION_TYPE_BUY, rsi, RSILowerLevel); // 多单马丁
if(EnableSell)
MartinLogic(POSITION_TYPE_SELL, rsi, RSIUpperLevel); // 空单马丁
}
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit() {
// 打印允许开仓的时间段
Print("=== RSI策略EA初始化 ===");
Print("允许开仓的时间段: ", TradingHours);
Print("最大加仓次数: ", MaxAddCount);
Print("ADX过滤功能: ", (EnableADXFilter ? "启用" : "禁用"));
if(EnableADXFilter) {
Print("ADX过滤阈值: ", ADXThreshold);
}
Print("当前服务器时间: ", TimeToString(TimeCurrent(), TIME_DATE|TIME_MINUTES));
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason) {
if(rsiHandle != INVALID_HANDLE)
IndicatorRelease(rsiHandle);
if(adxHandle != INVALID_HANDLE)
IndicatorRelease(adxHandle);
if(ema12Handle != INVALID_HANDLE)
IndicatorRelease(ema12Handle);
if(atrHandle != INVALID_HANDLE)
IndicatorRelease(atrHandle);
if(emaRiskHandle != INVALID_HANDLE)
IndicatorRelease(emaRiskHandle);
}