Skip to content

Commit

Permalink
1.02
Browse files Browse the repository at this point in the history
  • Loading branch information
EarnForex authored Apr 13, 2022
1 parent 0086481 commit 825e6e2
Show file tree
Hide file tree
Showing 5 changed files with 720 additions and 0 deletions.
264 changes: 264 additions & 0 deletions HAN.mq4
Original file line number Diff line number Diff line change
@@ -0,0 +1,264 @@
//+------------------------------------------------------------------+
//| HAN |
//| Copyright © 2013-2022, EarnForex.com |
//| https://www.earnforex.com/ |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2013-2022, EarnForex"
#property link "https://www.earnforex.com/metatrader-expert-advisors/Heiken-Ashi-Naive/"
#property version "1.02"
#property strict

#property description "Uses Heiken Ashi candles."
#property description "Sells on bullish HA candle, its body is longer than previous body, previous also bullish, and current candle has no lower wick."
#property description "Buys on bearish HA candle, its body is longer than previous body, previous also bearish, and current candle has no upper wick."
#property description "Exit shorts on bearish HA candle and current candle has no upper wick, previous also bearish."
#property description "Exit longs on bullish HA candle and current candle has no lower wick, previous also bullish."

// Money management:
input double Lots = 0.1; // Lots: Basic lot size
input bool MM = false; // MM: If true - ATR-based position sizing
input int ATR_Period = 20;
input double ATR_Multiplier = 1;
input double Risk = 2; // Risk: Risk tolerance in percentage points
input double FixedBalance = 0; // FixedBalance: If >= 0, position size will use it instead of actual balance.
input double MoneyRisk = 0; // MoneyRisk: Risk tolerance in base currency
input bool UseMoneyInsteadOfPercentage = false;
input bool UseEquityInsteadOfBalance = false;

// Miscellaneous:
input string OrderCommentary = "HAN";
input int Slippage = 100; // Slippage: Tolerated slippage in points
input int Magic = 1520122013; // Magic: Order magic number

// Global variables
int LastBars = 0;
bool HaveLongPosition;
bool HaveShortPosition;
double StopLoss; // Not actual stop-loss - just a potential loss of MM estimation.

void OnTick()
{
if ((!IsTradeAllowed()) || (IsTradeContextBusy()) || (!IsConnected()) || ((!MarketInfo(Symbol(), MODE_TRADEALLOWED)) && (!IsTesting()))) return;

// Trade only if a new bar has arrived.
if (LastBars != Bars) LastBars = Bars;
else return;

if (MM)
{
// Getting the potential loss value based on current ATR.
StopLoss = iATR(NULL, 0, ATR_Period, 1) * ATR_Multiplier;
}

// Close conditions.
bool BearishClose = false;
bool BullishClose = false;

// Signals.
bool Bullish = false;
bool Bearish = false;

// Heiken Ashi indicator values.
double HAOpenLatest, HAOpenPrevious, HACloseLatest, HAClosePrevious, HAHighLatest, HALowLatest;

HAOpenLatest = iCustom(NULL, 0, "Heiken Ashi", 2, 1);
HAOpenPrevious = iCustom(NULL, 0, "Heiken Ashi", 2, 2);
HACloseLatest = iCustom(NULL, 0, "Heiken Ashi", 3, 1);
HAClosePrevious = iCustom(NULL, 0, "Heiken Ashi", 3, 2);
if (HAOpenLatest >= HACloseLatest) HAHighLatest = iCustom(NULL, 0, "Heiken Ashi", 0, 1);
else HAHighLatest = iCustom(NULL, 0, "Heiken Ashi", 1, 1);
if (HAOpenLatest >= HACloseLatest) HALowLatest = iCustom(NULL, 0, "Heiken Ashi", 1, 1);
else HALowLatest = iCustom(NULL, 0, "Heiken Ashi", 0, 1);

// REVERSED!!!

// Close signals.
// Bullish HA candle, current has no lower wick, previous also bullish.
if ((HAOpenLatest < HACloseLatest) && (HALowLatest == HAOpenLatest) && (HAOpenPrevious < HAClosePrevious))
{
BullishClose = true;
}
// Bearish HA candle, current has no upper wick, previous also bearish.
else if ((HAOpenLatest > HACloseLatest) && (HAHighLatest == HAOpenLatest) && (HAOpenPrevious > HAClosePrevious))
{
BearishClose = true;
}

// Sell entry condition
// Bullish HA candle, and body is longer than previous body, previous also bullish, current has no lower wick.
if ((HAOpenLatest < HACloseLatest) && (HACloseLatest - HAOpenLatest > MathAbs(HAClosePrevious - HAOpenPrevious)) && (HAOpenPrevious < HAClosePrevious) && (HALowLatest == HAOpenLatest))
{
Bullish = false;
Bearish = true;
}
// Buy entry condition
// Bearish HA candle, and body is longer than previous body, previous also bearish, current has no upper wick.
else if ((HAOpenLatest > HACloseLatest) && (HAOpenLatest - HACloseLatest > MathAbs(HAClosePrevious - HAOpenPrevious)) && (HAOpenPrevious > HAClosePrevious) && (HAHighLatest == HAOpenLatest))
{
Bullish = true;
Bearish = false;
}
else
{
Bullish = false;
Bearish = false;
}

GetPositionStates();

if ((HaveShortPosition) && (BearishClose)) ClosePrevious();
if ((HaveLongPosition) && (BullishClose)) ClosePrevious();

if (Bullish)
{
if (!HaveLongPosition) fBuy();
}
else if (Bearish)
{
if (!HaveShortPosition) fSell();
}
}

//+------------------------------------------------------------------+
//| Check what position is currently open. |
//+------------------------------------------------------------------+
void GetPositionStates()
{
int total = OrdersTotal();
for (int cnt = 0; cnt < total; cnt++)
{
if (OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES) == false) continue;
if (OrderMagicNumber() != Magic) continue;
if (OrderSymbol() != Symbol()) continue;

if (OrderType() == OP_BUY)
{
HaveLongPosition = true;
HaveShortPosition = false;
return;
}
else if (OrderType() == OP_SELL)
{
HaveLongPosition = false;
HaveShortPosition = true;
return;
}
}
HaveLongPosition = false;
HaveShortPosition = false;
}

//+------------------------------------------------------------------+
//| Buy |
//+------------------------------------------------------------------+
void fBuy()
{
RefreshRates();
int result = OrderSend(Symbol(), OP_BUY, LotsOptimized(), Ask, Slippage, 0, 0, OrderCommentary, Magic);
if (result == -1)
{
int e = GetLastError();
Print("OrderSend Error: ", e);
}
}

//+------------------------------------------------------------------+
//| Sell |
//+------------------------------------------------------------------+
void fSell()
{
RefreshRates();
int result = OrderSend(Symbol(), OP_SELL, LotsOptimized(), Bid, Slippage, 0, 0, OrderCommentary, Magic);
if (result == -1)
{
int e = GetLastError();
Print("OrderSend Error: ", e);
}
}

//+------------------------------------------------------------------+
//| Calculate position size depending on money management parameters.|
//+------------------------------------------------------------------+
double LotsOptimized()
{
if (!MM) return (Lots);

double Size, RiskMoney, PositionSize = 0;

if (AccountCurrency() == "") return(0);

if (FixedBalance > 0)
{
Size = FixedBalance;
}
else if (UseEquityInsteadOfBalance)
{
Size = AccountEquity();
}
else
{
Size = AccountBalance();
}

if (!UseMoneyInsteadOfPercentage) RiskMoney = Size * Risk / 100;
else RiskMoney = MoneyRisk;

double UnitCost = MarketInfo(Symbol(), MODE_TICKVALUE);
double TickSize = MarketInfo(Symbol(), MODE_TICKSIZE);
int LotStep_digits = CountDecimalPlaces(MarketInfo(Symbol(), MODE_LOTSTEP));

if ((StopLoss != 0) && (UnitCost != 0) && (TickSize != 0)) PositionSize = NormalizeDouble(RiskMoney / (StopLoss * UnitCost / TickSize), LotStep_digits);

if (PositionSize < MarketInfo(Symbol(), MODE_MINLOT)) PositionSize = MarketInfo(Symbol(), MODE_MINLOT);
else if (PositionSize > MarketInfo(Symbol(), MODE_MAXLOT)) PositionSize = MarketInfo(Symbol(), MODE_MAXLOT);

return PositionSize;
}

//+------------------------------------------------------------------+
//| Close previous position. |
//+------------------------------------------------------------------+
void ClosePrevious()
{
int total = OrdersTotal();
for (int i = 0; i < total; i++)
{
if (OrderSelect(i, SELECT_BY_POS) == false) continue;
if ((OrderSymbol() == Symbol()) && (OrderMagicNumber() == Magic))
{
if (OrderType() == OP_BUY)
{
RefreshRates();
if (!OrderClose(OrderTicket(), OrderLots(), Bid, Slippage))
{
int e = GetLastError();
Print("OrderClose Error: ", e);
}
}
else if (OrderType() == OP_SELL)
{
RefreshRates();
if (!OrderClose(OrderTicket(), OrderLots(), Ask, Slippage))
{
int e = GetLastError();
Print("OrderClose Error: ", e);
}
}
}
}
}

//+------------------------------------------------------------------+
//| Counts decimal places. |
//+------------------------------------------------------------------+
int CountDecimalPlaces(double number)
{
// 100 as maximum length of number.
for (int i = 0; i < 100; i++)
{
double pwr = MathPow(10, i);
if (MathRound(number * pwr) / pwr == number) return i;
}
return -1;
}
//+------------------------------------------------------------------+
Binary file added HAN.mq5
Binary file not shown.
Loading

0 comments on commit 825e6e2

Please sign in to comment.