Harden HIT entry and manager state handling
This commit is contained in:
@@ -1068,86 +1068,4 @@ bool CancelExpiredOrders()
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| 時間が経過したポジションをクローズする関数
|
||||
//+------------------------------------------------------------------+
|
||||
/**
|
||||
* @brief 実時間でCLOSE_H1_LIMIT時間を超えた保有ポジションをクローズします。
|
||||
*
|
||||
* @return 1件以上クローズに成功した場合はtrue。
|
||||
*
|
||||
* 対象は`_Symbol` と `magic_number` が一致するポジションのみです。
|
||||
*/
|
||||
bool CloseExpiredPositions()
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
// ポジションを逆順でループ
|
||||
for(int i = PositionsTotal() - 1; i >= 0; i--)
|
||||
{
|
||||
string position_symbol = PositionGetSymbol(i);
|
||||
if(position_symbol!="")
|
||||
{
|
||||
// Magic Number とシンボルでフィルタリング
|
||||
if(position_symbol != _Symbol)
|
||||
continue;
|
||||
if(PositionGetInteger(POSITION_MAGIC) == magic_number)
|
||||
{
|
||||
// ポジションのエントリー時刻を取得
|
||||
datetime entry_time = (datetime)PositionGetInteger(POSITION_TIME);
|
||||
|
||||
int expiration_seconds = CLOSE_H1_LIMIT * PeriodSeconds(PERIOD_H1);
|
||||
if(entry_time <= 0 || expiration_seconds <= 0)
|
||||
continue;
|
||||
|
||||
if(TimeCurrent() - entry_time >= expiration_seconds)
|
||||
{
|
||||
MqlTradeRequest request = {};
|
||||
MqlTradeResult trade_result = {};
|
||||
|
||||
// ポジションタイプに応じてリクエストを設定
|
||||
int position_type = (int)PositionGetInteger(POSITION_TYPE);
|
||||
request.action = TRADE_ACTION_DEAL;
|
||||
request.position = PositionGetInteger(POSITION_TICKET); // ポジションのチケット番号
|
||||
request.symbol = position_symbol; // シンボル
|
||||
request.volume = PositionGetDouble(POSITION_VOLUME); // ポジションサイズ
|
||||
request.price = (position_type == POSITION_TYPE_BUY)
|
||||
? SymbolInfoDouble(position_symbol, SYMBOL_BID) // BUYの場合はBIDでクローズ
|
||||
: SymbolInfoDouble(position_symbol, SYMBOL_ASK); // SELLの場合はASKでクローズ
|
||||
request.deviation = slippage;
|
||||
request.type = (position_type == POSITION_TYPE_BUY)
|
||||
? ORDER_TYPE_SELL // BUYポジションをSELLでクローズ
|
||||
: ORDER_TYPE_BUY; // SELLポジションをBUYでクローズ
|
||||
request.type_filling = GetOrderFillingPolicy(position_symbol); // 注文執行ポリシー
|
||||
request.magic = magic_number;
|
||||
|
||||
// 注文送信
|
||||
if(!OrderSend(request, trade_result))
|
||||
{
|
||||
Print("Failed to close position. Ticket: ", request.position, " Error: ", GetLastError());
|
||||
continue;
|
||||
}
|
||||
|
||||
// 結果の確認
|
||||
if(trade_result.retcode == TRADE_RETCODE_DONE || trade_result.retcode == TRADE_RETCODE_DONE_PARTIAL)
|
||||
{
|
||||
Print("Position closed successfully due to a time limit. Ticket: ", request.position);
|
||||
result = true; // 少なくとも1つ成功した場合
|
||||
}
|
||||
else
|
||||
{
|
||||
Print("Failed to close position. Ticket: ", request.position, " Retcode: ", trade_result.retcode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Print("Failed to select position at index ", i, ". Error: ", GetLastError());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -335,12 +335,14 @@ public:
|
||||
continue;
|
||||
|
||||
double candidate_sl = 0.0;
|
||||
const double position_open_price = PositionGetDouble(POSITION_PRICE_OPEN);
|
||||
const double evaluation_price = (type == POSITION_TYPE_BUY) ? tick.bid : tick.ask;
|
||||
if (!CalcHighVolatilitySL(type,
|
||||
evaluation_price,
|
||||
open_m1,
|
||||
open_m3,
|
||||
open_m5,
|
||||
evaluation_price,
|
||||
position_open_price,
|
||||
open_m1,
|
||||
open_m3,
|
||||
open_m5,
|
||||
open_m10,
|
||||
open_m15,
|
||||
pip_size,
|
||||
@@ -590,6 +592,7 @@ private:
|
||||
/// @return いずれかの時間足でしきい値を超え、SL候補を出力した場合は true。
|
||||
bool CalcHighVolatilitySL(const ENUM_POSITION_TYPE type,
|
||||
const double current_price,
|
||||
const double position_open_price,
|
||||
const double open_m1,
|
||||
const double open_m3,
|
||||
const double open_m5,
|
||||
@@ -612,13 +615,36 @@ private:
|
||||
if (!has_candidate)
|
||||
return false;
|
||||
|
||||
if (!IsProfitProtectingStopLoss(type, candidate_sl, position_open_price))
|
||||
return false;
|
||||
|
||||
sl_value = NormalizeDouble(candidate_sl, digits);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// @brief 急変時SL候補が建値より不利にならないことを確認する。
|
||||
bool IsProfitProtectingStopLoss(const ENUM_POSITION_TYPE type,
|
||||
const double candidate_sl,
|
||||
const double open_price)
|
||||
{
|
||||
if (open_price <= 0.0)
|
||||
return false;
|
||||
|
||||
const double point = SymbolInfoDouble(m_symbol, SYMBOL_POINT);
|
||||
const double tolerance = point * 0.1;
|
||||
|
||||
if (type == POSITION_TYPE_BUY)
|
||||
return (candidate_sl >= open_price - tolerance);
|
||||
|
||||
if (type == POSITION_TYPE_SELL)
|
||||
return (candidate_sl <= open_price + tolerance);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// @brief 1本の時間足始値から急変幅を評価し、有効なSL候補なら最良候補へ反映する。
|
||||
void EvaluateHighVolatilityOpen(const ENUM_POSITION_TYPE type,
|
||||
const double current_price,
|
||||
const double current_price,
|
||||
const double open_price,
|
||||
const double limit_pips,
|
||||
const double rate_ratio,
|
||||
|
||||
Reference in New Issue
Block a user