量化魔方
标题:
金猫眼猎金NOVA源码(全功能解限版)
[打印本页]
作者:
量化魔方
时间:
昨天 18:00
标题:
金猫眼猎金NOVA源码(全功能解限版)
//+----------------金猫眼猎金NOVA源码(全功能解限版)-----------------------------------+
//+----------------·索罗斯·逆向·源码修正与逻辑重构--------------------------------------+
#property copyright ""
#property version "2.15"
#include <Trade\Trade.mqh>
CTrade trade;
enum ENUM_PARAM_MODE
{
PM_CONSERVATIVE = 0,
PM_AGGRESSIVE = 1
};
input group "一、交易设置"
input bool InpAcceptTradingRisk = true; // 开启自动交易功能
input ENUM_PARAM_MODE InpParamMode = PM_CONSERVATIVE;
input double InpBaseLot = 0.03;
input ENUM_TIMEFRAMES InpSignalTF = PERIOD_M1;
input double InpMaxSpreadPrice = 0.3;
input double InpMaxSlippagePrice = 0.03;
input group "二、NOVA智能识别系统(自动跟随档位)"
input bool InpAIRSIMonitor = false;
input bool InpAIADXMonitor = false;
input bool InpAIBollMonitor = false;
input bool InpAIATRMonitor = false;
input group "三、手动加单管理"
input bool InpIncludeManualAddRecovery = false;
input bool InpSetManualAddStopLoss = true;
double g_debt = 0;
double g_lotCap = 0;
double g_targetPL = 0;
double g_calcLot = 0;
double g_nextLot = 0;
double g_lastSigPrice= 0;
double g_minMoveThresh = 30*_Point;
int g_cooldown = 0;
int g_state = 6; // 默认直接进入 ST_READY (6) 状态
int g_prevPosCount= 0;
bool g_firstScan = false;
bool g_useOrigMagicFilter = true;
datetime g_pnlStart = 0;
int hRSI = INVALID_HANDLE, hADX = INVALID_HANDLE,
hBAND = INVALID_HANDLE, hATR = INVALID_HANDLE;
int hEmaTrendF = INVALID_HANDLE;
int hEmaTrendS = INVALID_HANDLE;
double IndVal(int h, int buf = 0)
{
double b[1];
if(h == INVALID_HANDLE) return EMPTY_VALUE;
if(CopyBuffer(h, buf, 0, 1, b) < 1) return EMPTY_VALUE;
return b[0];
}
#define ORIG_MAGIC_CONST 26063849
#define ST_INIT 0
#define ST_RUNTIME_WAIT 1
#define ST_DATA_WAIT 2
#define ST_IND_REBUILD 3
#define ST_IND_REBUILD_FAIL 4
#define ST_DATA_RESTORED 5
#define ST_READY 6
#define ST_CONFIG_BLOCK 7
int OnInit()
{
trade.SetExpertMagicNumber(ORIG_MAGIC_CONST);
g_nextLot = MathMax(InpBaseLot, SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN));
if(_Point > 0)
trade.SetDeviationInPoints((ulong)MathMax(1.0, InpMaxSlippagePrice / _Point));
if(InpParamMode == PM_AGGRESSIVE) g_minMoveThresh *= 0.5;
ENUM_TIMEFRAMES sigTf = (ENUM_TIMEFRAMES)InpSignalTF;
hEmaTrendF = iMA(_Symbol, sigTf, 10, 0, MODE_EMA, PRICE_CLOSE);
hEmaTrendS = iMA(_Symbol, sigTf, 20, 0, MODE_EMA, PRICE_CLOSE);
if(InpAIRSIMonitor) hRSI = iRSI (_Symbol, sigTf, 14, PRICE_CLOSE);
if(InpAIADXMonitor) hADX = iADX (_Symbol, sigTf, 14);
if(InpAIBollMonitor) hBAND = iBands(_Symbol, sigTf, 20, 0, 2.0, PRICE_CLOSE);
if(InpAIATRMonitor) hATR = iATR (_Symbol, sigTf, 14);
string key = "NOVA_GM_0E286BFB_";
if(GlobalVariableCheck(key + "DEBT")) g_debt = GlobalVariableGet(key+"DEBT");
if(GlobalVariableCheck(key + "PARSIG")) g_lastSigPrice= GlobalVariableGet(key+"PARSIG");
if(GlobalVariableCheck(key + "LOT")) g_calcLot = GlobalVariableGet(key+"LOT");
if(GlobalVariableCheck(key + "TGT")) g_targetPL = GlobalVariableGet(key+"TGT");
if(g_targetPL <= 0) g_targetPL = AccountInfoDouble(ACCOUNT_EQUITY) * 0.02;
g_lotCap = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
string pk = "CATEYE_NOVA_PNL2_" + _Symbol;
if(GlobalVariableCheck(pk + "_START"))
g_pnlStart = (datetime)GlobalVariableGet(pk + "_START");
else
{
g_pnlStart = TimeCurrent();
GlobalVariableSet(pk + "_START", (double)g_pnlStart);
}
g_state = ST_READY; // 确保直接就绪
PrintFormat("[猫眼猎金 NOVA 2.15][INIT] %s 信号模块已就绪 | 状态=正常 | 余额=%.2f | 净值=%.2f | 待追回=%.2f | 下一手=%.2f",
InpParamMode == PM_CONSERVATIVE ? "保守档" : "激进档",
AccountInfoDouble(ACCOUNT_BALANCE), AccountInfoDouble(ACCOUNT_EQUITY),
g_debt, CurrentLot());
EventSetMillisecondTimer(500);
PanelRefresh();
return(INIT_SUCCEEDED);
}
void OnTimer()
{
PanelRefresh();
}
double CurrentLot()
{
double lot = NormalizeLot(g_calcLot);
double step = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
if(step > 0) lot = MathFloor(lot/step)*step;
return MathMax(lot, SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN));
}
void OnDeinit(const int reason)
{
EventKillTimer();
ObjectsDeleteAll(0, "CATEYE_NOVA");
Comment("");
if(hRSI != INVALID_HANDLE) IndicatorRelease(hRSI);
if(hADX != INVALID_HANDLE) IndicatorRelease(hADX);
if(hBAND != INVALID_HANDLE) IndicatorRelease(hBAND);
if(hATR != INVALID_HANDLE) IndicatorRelease(hATR);
if(hEmaTrendF != INVALID_HANDLE) IndicatorRelease(hEmaTrendF);
if(hEmaTrendS != INVALID_HANDLE) IndicatorRelease(hEmaTrendS);
}
#define PNL_X 12
#define PNL_Y 22
#define C_BG C'18,23,30'
#define C_HDR C'22,29,38'
#define C_CARD C'26,34,45'
#define C_BRD C'42,56,72'
#define C_LBL C'142,157,174'
#define C_VAL C'220,228,236'
#define C_OK C'38,208,124'
#define C_GOLD C'229,169,60'
#define C_GOLD2 C'168,124,40'
#define C_WARN C'240,164,60'
#define C_BAD C'240,80,80'
string PanelFont(int idx)
{
switch(idx)
{
case 0: return "Microsoft YaHei UI";
case 1: return "Microsoft YaHei UI Semibold";
case 2: return "Consolas";
}
return "Microsoft YaHei UI";
}
void PnlObj(const string id, ENUM_OBJECT type, int x, int y, int dx, int dy,
color bg, color tx, int fs, const string font)
{
string name = "CATEYE_NOVA_" + id;
if(ObjectFind(0, name) < 0)
{
ObjectCreate(0, name, type, 0, 0, 0);
ObjectSetInteger(0, name, OBJPROP_BACK, false);
ObjectSetInteger(0, name, OBJPROP_SELECTABLE, false);
ObjectSetInteger(0, name, OBJPROP_HIDDEN, true);
}
ObjectSetInteger(0, name, OBJPROP_XDISTANCE, x);
ObjectSetInteger(0, name, OBJPROP_YDISTANCE, y);
ObjectSetInteger(0, name, OBJPROP_XSIZE, dx);
ObjectSetInteger(0, name, OBJPROP_YSIZE, dy);
ObjectSetInteger(0, name, OBJPROP_BGCOLOR, bg);
ObjectSetInteger(0, name, OBJPROP_BORDER_COLOR, bg);
ObjectSetInteger(0, name, OBJPROP_COLOR, tx);
ObjectSetInteger(0, name, OBJPROP_FONTSIZE, fs);
ObjectSetString (0, name, OBJPROP_FONT, font);
}
void PnlLbl(const string id, int x, int y, const string txt, color c, int fs,
const string font)
{
PnlObj(id, OBJ_LABEL, x, y, 0, 0, clrNONE, c, fs, font);
ObjectSetString(0, "CATEYE_NOVA_" + id, OBJPROP_TEXT, txt);
}
string HeroText()
{
if(!InpAcceptTradingRisk) return "交易功能已安全暂停";
int nEA = CountManagedPositions();
if(nEA <= 0 && g_debt > 0)
return "债务账本已接管,等待下一次有效行情";
if(nEA > 0)
return "当前持仓 " + IntegerToString(nEA) + " 笔 · ";
if(g_cooldown > 0) return "等待行情";
return "EA已就绪,等待下一次有效信号";
}
double RealizedSinceStart(int &settledCount)
{
double s = 0;
settledCount = 0;
if(!HistorySelect(g_pnlStart, TimeCurrent())) return 0;
for(int i = HistoryDealsTotal()-1; i >= 0; i--)
{
ulong dk = HistoryDealGetTicket(i);
if(HistoryDealGetString(dk, DEAL_SYMBOL) != _Symbol) continue;
if(HistoryDealGetInteger(dk, DEAL_MAGIC) != ORIG_MAGIC_CONST) continue;
if(HistoryDealGetInteger(dk, DEAL_ENTRY) != DEAL_ENTRY_OUT) continue;
s += HistoryDealGetDouble(dk, DEAL_PROFIT)
+ HistoryDealGetDouble(dk, DEAL_SWAP)
+ HistoryDealGetDouble(dk, DEAL_COMMISSION)
+ HistoryDealGetDouble(dk, DEAL_FEE);
settledCount++;
}
return s;
}
string PositionMainLine()
{
int nBuy = 0, nSell = 0;
double volBuy = 0, volSell = 0, wsumBuy = 0, wsumSell = 0;
for(int i = PositionsTotal()-1; i >= 0; i--)
{
ulong tk = PositionGetTicket(i);
if(PositionGetString(POSITION_SYMBOL) != _Symbol) continue;
long mg = PositionGetInteger(POSITION_MAGIC);
if(mg != ORIG_MAGIC_CONST && !InpIncludeManualAddRecovery) continue;
long t = PositionGetInteger(POSITION_TYPE);
double v = PositionGetDouble(POSITION_VOLUME);
double p = PositionGetDouble(POSITION_PRICE_OPEN);
if(t == POSITION_TYPE_BUY) { nBuy++; volBuy += v; wsumBuy += v * p; }
else { nSell++; volSell += v; wsumSell += v * p; }
}
int digits = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);
if(nBuy + nSell == 0)
return "当前无持仓 · 预计开仓 " + DoubleToString(CurrentLot(), 2) + " 手";
string dir = (volBuy >= volSell) ? "多单" : "空单";
double vol = (volBuy >= volSell) ? volBuy : volSell;
double avg = (volBuy >= volSell)
? (volBuy > 0 ? wsumBuy / volBuy : 0)
: (volSell > 0 ? wsumSell / volSell : 0);
double cur = (volBuy >= volSell)
? SymbolInfoDouble(_Symbol, SYMBOL_BID)
: SymbolInfoDouble(_Symbol, SYMBOL_ASK);
string manual = ((InpIncludeManualAddRecovery && CountManualPositions() > 0) ? " · 含手动" : "");
return dir
+ " " + DoubleToString(vol, 2) + " 手 · "
+ "均价 " + DoubleToString(avg, digits)
+ " · 现价 " + DoubleToString(cur, digits) + manual;
}
string AiFactorsLine(double &rsi, double &adx, double &bollPct, double &atrV)
{
bool any = InpAIRSIMonitor || InpAIADXMonitor || InpAIBollMonitor || InpAIATRMonitor;
if(!any) return "未开启AI因子监测";
rsi = IndVal(hRSI);
adx = IndVal(hADX);
double mid = IndVal(hBAND, 0), up = IndVal(hBAND, 1), lo_ = IndVal(hBAND, 2);
atrV = IndVal(hATR);
double cls = SymbolInfoDouble(_Symbol, SYMBOL_BID);
bollPct = (up != EMPTY_VALUE && lo_ != EMPTY_VALUE && up > lo_)
? (cls - lo_) / (up - lo_) * 100.0 : 50.0;
string s = "";
if(InpAIRSIMonitor && rsi != EMPTY_VALUE)
s += StringFormat("RSI %.1f", rsi);
if(InpAIADXMonitor && adx != EMPTY_VALUE)
s += (s == "" ? "" : " · ") + StringFormat("ADX %.1f", adx);
if(InpAIBollMonitor)
s += (s == "" ? "" : " · ") + StringFormat("BOLL %.0f%%", bollPct);
if(InpAIATRMonitor && atrV != EMPTY_VALUE)
s += (s == "" ? "" : " · ") + StringFormat("ATR %.2f", atrV);
return (s == "") ? "观测数据准备中" : s;
}
string AiStateLine(double rsi)
{
if(!InpAIRSIMonitor) return "市场状态 · 正常运行";
string w = "动能均衡";
if(rsi > 55) w = "动能偏强";
if(rsi < 45) w = "动能偏弱";
return "市场状态 · " + w;
}
void PanelRefresh()
{
static uint last = 0;
if(GetTickCount() - last < 500) return;
last = GetTickCount();
int x = PNL_X, y = PNL_Y;
int digits = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);
PnlObj("SHADOW", OBJ_RECTANGLE_LABEL, x+2, y+2, 300, 430, C_BG, C_BG, 0, "");
PnlObj("BG", OBJ_RECTANGLE_LABEL, x, y, 300, 430, C_BG, C_BRD, 0, "");
bool runok = InpAcceptTradingRisk;
string pill = runok ? "运行正常" : "暂停新开";
PnlLbl("TITLE", x+10, y+6, "猫眼猎金 • NOVA 2.1 极简版", runok ? C_GOLD : C_LBL, 10, PanelFont(1));
PnlLbl("ENGINE_DOT", x+234, y+7, runok ? "■" : "□", runok ? C_OK : C_WARN, 9, PanelFont(0));
PnlLbl("ENGINE_TEXT", x+248, y+7, pill, runok ? C_OK : C_WARN, 9, PanelFont(0));
PnlLbl("STATUS", x+10, y+24,
_Symbol + " · "
+ StringSubstr(EnumToString(InpSignalTF == PERIOD_CURRENT ? _Period : InpSignalTF), 7)
+ " · " + (InpParamMode == PM_CONSERVATIVE ? "保守档" : "激进档"),
C_VAL, 8, PanelFont(1));
// 移除到期授权显示
PnlLbl("AUTH_TEXT", x+150, y+24, "无限制完整版", C_GOLD, 8, PanelFont(1));
int cy = y + 44;
PnlObj("POS_CARD", OBJ_RECTANGLE_LABEL, x+8, cy, 284, 62, C_CARD, C_BRD, 0, "");
PnlObj("POS_ACCENT", OBJ_RECTANGLE_LABEL, x+8, cy, 3, 62, CountManagedPositions() > 0 ? C_OK : C_LBL, C_CARD, 0, "");
int nPos = CountManagedPositions();
double volTot2 = 0;
for(int i = PositionsTotal()-1; i >= 0; i--)
{
ulong tk = PositionGetTicket(i);
if(PositionGetString(POSITION_SYMBOL) != _Symbol) continue;
if(PositionGetInteger(POSITION_MAGIC) != ORIG_MAGIC_CONST && !InpIncludeManualAddRecovery) continue;
volTot2 += PositionGetDouble(POSITION_VOLUME);
}
PnlLbl("POSITION_MAIN", x+16, cy+5, nPos <= 0 ? HeroText() : PositionMainLine(), nPos > 0 ? C_OK : C_LBL, 9, PanelFont(1));
PnlLbl("POSITION_TRAIL", x+16, cy+22, TrailLine(digits), C_GOLD, 9, PanelFont(1));
PnlLbl("POSITION_CNT", x+16, cy+40, nPos > 0 ? StringFormat("当前持仓 %d 笔 · %.2f 手", nPos, volTot2) : "当前空仓", C_VAL, 8, PanelFont(1));
double floatPL = TotalFloatingPL(true);
PnlLbl("FLOAT_LABEL", x+196, cy+8, "当前浮盈 / USD", C_LBL, 8, PanelFont(0));
PnlLbl("FLOAT_VALUE", x+196, cy+26, (floatPL >= 0 ? "+" : "") + DoubleToString(floatPL, 2), floatPL >= 0 ? C_OK : C_BAD, 12, PanelFont(2));
cy = y + 116;
int sc = 0;
double realized = RealizedSinceStart(sc);
PnlObj("SESSION_CARD", OBJ_RECTANGLE_LABEL, x+8, cy, 138, 66, C_CARD, C_BRD, 0, "");
PnlLbl("SESSION_TITLE", x+14, cy+5, "EA累计盈亏", C_WARN, 9, PanelFont(1));
PnlLbl("SESSION_VALUE", x+14, cy+21, (realized + floatPL >= 0 ? "+" : "") + DoubleToString(realized + floatPL, 2), realized + floatPL >= 0 ? C_OK : C_BAD, 13, PanelFont(2));
PnlLbl("SESSION_DETAIL", x+14, cy+41, "已结算 +" + DoubleToString(realized, 2) + " · 浮动 " + (floatPL >= 0 ? "+" : "") + DoubleToString(floatPL, 2), C_LBL, 7, PanelFont(0));
PnlLbl("SESSION_START", x+14, cy+53, "起始 " + TimeToString(g_pnlStart, TIME_DATE) + " · 结算 " + IntegerToString(sc) + " 笔", C_LBL, 7, PanelFont(0));
long sprPt = SymbolInfoInteger(_Symbol, SYMBOL_SPREAD);
double avgPx = 0, vv = 0;
{
double wv = 0;
for(int i = PositionsTotal()-1; i >= 0; i--)
{
ulong tk = PositionGetTicket(i);
if(PositionGetString(POSITION_SYMBOL) != _Symbol) continue;
if(PositionGetInteger(POSITION_MAGIC) != ORIG_MAGIC_CONST && !InpIncludeManualAddRecovery) continue;
double v = PositionGetDouble(POSITION_VOLUME);
wv += v * PositionGetDouble(POSITION_PRICE_OPEN);
vv += v;
}
if(vv > 0) avgPx = wv / vv;
}
double curPx = SymbolInfoDouble(_Symbol, SYMBOL_BID);
PnlObj("OVER_CARD", OBJ_RECTANGLE_LABEL, x+154, cy, 138, 66, C_CARD, C_BRD, 0, "");
PnlLbl("POSITION_TITLE", x+160, cy+5, "持仓概览", C_WARN, 9, PanelFont(1));
PnlLbl("POSITION_SPREAD", x+160, cy+22, "点差 " + DoubleToString(sprPt * _Point, digits), C_VAL, 8, PanelFont(2));
PnlLbl("POSITION_DESC", x+160, cy+38, PositionMainLine(), C_VAL, 8, PanelFont(1));
PnlLbl("POSITION_PX", x+160, cy+53, vv > 0 ? "均价 " + DoubleToString(avgPx, digits) + " 现价 " + DoubleToString(curPx, digits) : "—", C_LBL, 7, PanelFont(0));
cy = y + 190;
PnlLbl("REC_TITLE", x+12, cy, "追回与下一步", C_LBL, 9, PanelFont(1));
PnlLbl("REC_VALUE", x+12, cy+17, g_debt > 0 ? "待追回 " + DoubleToString(g_debt, 2) : "当前无追回", g_debt > 0 ? C_VAL : C_OK, 10, PanelFont(2));
PnlLbl("NEXT_TEXT", x+120, cy+18, nPos > 0 ? "下一步 管理现有持仓" : "下一步 等待有效信号", C_LBL, 8, PanelFont(0));
PnlObj("ACTION_BTN", OBJ_BUTTON, x+8, y+222, 284, 26, C'90,30,37', C'255,165,165', 9, PanelFont(1));
ObjectSetString(0, "CATEYE_NOVA_ACTION_BTN", OBJPROP_TEXT, "平仓并回归初始");
cy = y + 258;
PnlObj("AI_CARD", OBJ_RECTANGLE_LABEL, x+8, cy, 284, 54, C_CARD, C_GOLD2, 0, "");
double rsi = 50, adx = 0, bp = 50, av = 0;
PnlLbl("AI_TITLE", x+16, cy+5, "NOVA智能观测", C_GOLD, 9, PanelFont(1));
PnlLbl("AI_FACTORS", x+16, cy+22, AiFactorsLine(rsi, adx, bp, av), C_VAL, 8, PanelFont(2));
PnlLbl("AI_STATE", x+16, cy+38, "市场状态·" + (InpParamMode == PM_CONSERVATIVE ? "保守" : "激进") + "档位联动 · " + AiStateLine(rsi), C_LBL, 8, PanelFont(0));
PnlLbl("AD_LINE", x+12, y+324, "EA策略自动化量化运行中", C_GOLD, 9, PanelFont(0));
PnlLbl("AD_SUB", x+12, y+342, "智能止盈 · 动态追回 · 风险风控系统", C_LBL, 8, PanelFont(0));
PnlLbl("FOOT_OK", x+12, y+364, runok ? "系统正常运行" : "交易功能暂停", runok ? C_OK : C_WARN, 8, PanelFont(0));
PnlLbl("FOOT_RISK", x+150, y+364, "市场有风险,交易需谨慎", C_LBL, 8, PanelFont(0));
ChartRedraw();
}
bool g_modalUp = false;
void ShowResetModal()
{
int x = PNL_X + 40, y = PNL_Y + 40;
PnlObj("MODAL_BG", OBJ_RECTANGLE_LABEL, x-2, y-2, 300, 110, C_HDR, C_HDR, 0, "");
PnlObj("MODAL", OBJ_RECTANGLE_LABEL, x, y, 296, 106, C_BG, C_BG, 0, "");
PnlLbl("M_TTL", x+10, y+8, "确认平仓归零", C_VAL, 11, PanelFont(1));
PnlLbl("M_L1", x+10, y+34, "关闭本EA当前持仓,全部成功后清除债务并恢复基础手数", C_LBL, 9, PanelFont(0));
PnlObj("M_OK", OBJ_BUTTON, x+10, y+66, 132, 26, C'190,60,60', C'255,245,245', 9, PanelFont(1));
ObjectSetString(0, "CATEYE_NOVA_M_OK", OBJPROP_TEXT, "确认平仓并归零");
PnlObj("M_NO", OBJ_BUTTON, x+154, y+66, 132, 26, C'60,70,90', C'235,238,245', 9, PanelFont(1));
ObjectSetString(0, "CATEYE_NOVA_M_NO", OBJPROP_TEXT, "取消");
g_modalUp = true;
}
void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
{
if(id != CHARTEVENT_OBJECT_CLICK) return;
if(sparam == "CATEYE_NOVA_ACTION_BTN")
ShowResetModal();
else if(sparam == "CATEYE_NOVA_M_OK")
{
ObjectsDeleteAll(0, "CATEYE_NOVA_M_");
g_modalUp = false;
OnResetButton();
PanelRefresh();
}
else if(sparam == "CATEYE_NOVA_M_NO")
{
ObjectsDeleteAll(0, "CATEYE_NOVA_M_");
g_modalUp = false;
ChartRedraw();
}
}
int g_fzState = 0;
int g_fzChecks = 0;
int g_fzOk = 0;
int g_fzStallSec = 0;
long g_fzLastMsc = 0;
bool g_fzProtectMsg= false;
#define FZ_STALL_LIMIT 15
#define FZ_CHECKS_NEED 3
#define FZ_CONFIRM_NEED 2
void FreezeGuardCheck()
{
long msc = SymbolInfoInteger(_Symbol, SYMBOL_TIME_MSC);
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
if(msc != g_fzLastMsc) { g_fzLastMsc = msc; g_fzStallSec = 0; }
else { g_fzStallSec++; }
switch(g_fzState)
{
case 0:
g_fzChecks = 0;
if(g_fzStallSec >= FZ_STALL_LIMIT)
{
g_fzState = 1; g_fzChecks = 1;
}
break;
case 1:
if(g_fzStallSec == 0) { g_fzState = 0; break; }
g_fzChecks++;
if(g_fzChecks >= FZ_CHECKS_NEED)
{
g_fzState = 2; g_fzOk = 0; g_fzProtectMsg = false;
}
break;
case 2:
break;
case 3:
if(g_fzStallSec >= FZ_STALL_LIMIT)
{
g_fzState = 2; g_fzOk = 0;
break;
}
g_fzOk++;
if(g_fzOk >= FZ_CONFIRM_NEED)
{
g_fzState = 0;
}
break;
}
}
bool FrozenBlock() { return (g_fzState == 2 || g_fzState == 3); }
bool g_trailOn = false;
double g_trailExtreme = 0;
double g_trailOpenRef = 0;
datetime g_slLastPush = 0;
#define TRAIL_TRIGGER_BASE 700*_Point
#define TRAIL_INITIAL_SL 800*_Point
#define TRAIL_RETRACE_STEP 100*_Point
string TrailLine(int digits)
{
if(CountManagedPositions() <= 0) return "移动止盈 开仓后计算";
if(!g_trailOn) return "移动止盈触发距离 计算中";
return "移动止盈触发距离 " + DoubleToString(TRAIL_TRIGGER_BASE, digits);
}
void TrailManage()
{
int n = CountManagedPositions();
if(n <= 0) { g_trailOn = false; g_trailExtreme = 0; return; }
double volBuy=0, volSell=0, wsumBuy=0, wsumSell=0;
for(int i = PositionsTotal()-1; i >= 0; i--)
{
ulong tk = PositionGetTicket(i);
if(PositionGetString(POSITION_SYMBOL) != _Symbol) continue;
long mg = PositionGetInteger(POSITION_MAGIC);
if(mg != ORIG_MAGIC_CONST && !InpIncludeManualAddRecovery) continue;
double v = PositionGetDouble(POSITION_VOLUME);
double p = PositionGetDouble(POSITION_PRICE_OPEN);
if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
{ volBuy += v; wsumBuy += v*p; }
else { volSell += v; wsumSell += v*p; }
}
if(volBuy+volSell <= 0) { g_trailOn = false; return; }
bool isLong = volBuy >= volSell;
double avg = isLong ? (volBuy>0 ? wsumBuy/volBuy : 0)
: (volSell>0 ? wsumSell/volSell : 0);
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double volTot = volBuy + volSell;
double trig = TRAIL_TRIGGER_BASE + g_debt / (100.0 * volTot);
double dist = isLong ? (bid - avg) : (avg - ask);
if(g_trailExtreme == 0) g_trailExtreme = isLong ? bid : ask;
else if(isLong && bid > g_trailExtreme) g_trailExtreme = bid;
else if(!isLong && ask < g_trailExtreme) g_trailExtreme = ask;
if(!g_trailOn)
{
if(dist >= trig)
{
g_trailOn = true;
g_trailOpenRef = avg;
}
return;
}
bool hit = isLong ? (bid <= g_trailExtreme - TRAIL_RETRACE_STEP)
: (ask >= g_trailExtreme + TRAIL_RETRACE_STEP);
if(hit)
{
Print("[猫眼猎金 NOVA 2.15][移动止盈] 回撤保护触发 全部平仓");
CloseOwnPositions();
g_trailOn = false;
return;
}
datetime now = TimeTradeServer();
if(now - g_slLastPush < 1) return;
int dg = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);
for(int i = PositionsTotal()-1; i >= 0; i--)
{
ulong tk = PositionGetTicket(i);
if(PositionGetString(POSITION_SYMBOL) != _Symbol) continue;
long mg = PositionGetInteger(POSITION_MAGIC);
if(mg != ORIG_MAGIC_CONST && !InpIncludeManualAddRecovery) continue;
bool lng = PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY;
double want = lng ? MathMin(g_trailExtreme, SymbolInfoDouble(_Symbol, SYMBOL_BID)) - TRAIL_RETRACE_STEP
: MathMax(g_trailExtreme, SymbolInfoDouble(_Symbol, SYMBOL_ASK)) + TRAIL_RETRACE_STEP;
want = NormalizeDouble(want, dg);
double have = PositionGetDouble(POSITION_SL);
if(MathAbs(want - have) <= 0.5 * _Point) continue;
if(trade.PositionModify(tk, want, PositionGetDouble(POSITION_TP)))
g_slLastPush = now;
}
}
void OnTick()
{
PanelRefresh();
FreezeGuardCheck();
TrailManage();
TakeoverCheck();
SltpGuardCheck();
DealSettleScan();
UpdateRecoveryLot();
if(InpAcceptTradingRisk && !FrozenBlock())
BreakoutEngine();
}
void UpdateRecoveryLot()
{
if(g_cooldown > 0) { g_cooldown--; }
g_calcLot = g_nextLot;
}
double CeilStepLot(double lot)
{
double st = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
if(st <= 0) return NormalizeLot(lot);
return MathMax(MathCeil(lot / st - 1e-9) * st,
SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN));
}
datetime g_settleScanFrom = 0;
ulong g_lastDealTicket = 0;
void DealSettleScan()
{
datetime now = TimeCurrent();
if(g_settleScanFrom == 0) g_settleScanFrom = now - 86400;
if(!HistorySelect(g_settleScanFrom - 3600, now + 60)) return;
int total = HistoryDealsTotal();
for(int i = 0; i < total; i++)
{
ulong dt = HistoryDealGetTicket(i);
if(dt == 0 || dt <= g_lastDealTicket) continue;
if(HistoryDealGetString(dt, DEAL_SYMBOL) != _Symbol) continue;
if(HistoryDealGetInteger(dt, DEAL_MAGIC) != ORIG_MAGIC_CONST) continue;
long e = HistoryDealGetInteger(dt, DEAL_ENTRY);
if(e != DEAL_ENTRY_OUT && e != DEAL_ENTRY_INOUT && e != DEAL_ENTRY_OUT_BY) continue;
double res = HistoryDealGetDouble(dt, DEAL_PROFIT)
+ HistoryDealGetDouble(dt, DEAL_SWAP)
+ HistoryDealGetDouble(dt, DEAL_COMMISSION)
+ HistoryDealGetDouble(dt, DEAL_FEE);
if(res < -0.005 && g_debt >= 0)
{
g_debt += -res;
g_nextLot = CeilStepLot(g_nextLot * 1.4);
}
else if(res > 0.005 && g_debt > 0.005)
{
if(res >= g_debt - 0.005)
{
g_debt = 0;
g_nextLot = MathMax(InpBaseLot, SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN));
}
else
{
g_debt -= res;
}
}
DebtPersist();
}
if(total > 0)
g_lastDealTicket = HistoryDealGetTicket(total - 1);
g_settleScanFrom = now;
}
void DebtPersist()
{
string key = "NOVA_GM_0E286BFB_";
GlobalVariableSet(key + "DEBT", g_debt);
GlobalVariableSet(key + "TGT", g_targetPL);
}
void TakeoverCheck()
{
int now = PositionsTotal();
if(!g_firstScan) { g_firstScan = true; }
if(now > g_prevPosCount && InpSetManualAddStopLoss)
ManualAddStopLoss();
g_prevPosCount = now;
}
void ManualAddStopLoss()
{
double spr = SymbolInfoDouble(_Symbol, SYMBOL_ASK) - SymbolInfoDouble(_Symbol, SYMBOL_BID);
double dist = MathMax(spr + InpMaxSlippagePrice, 10 * _Point) * 10.0;
int digits = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);
for(int i = PositionsTotal()-1; i >= 0; i--)
{
ulong tk = PositionGetTicket(i);
if(PositionGetString(POSITION_SYMBOL) != _Symbol) continue;
if(PositionGetInteger(POSITION_MAGIC) == ORIG_MAGIC_CONST) continue;
if(PositionGetDouble(POSITION_SL) > 0) continue;
long type = PositionGetInteger(POSITION_TYPE);
double op = PositionGetDouble(POSITION_PRICE_OPEN);
double sl = (type == POSITION_TYPE_BUY) ? op - dist : op + dist;
sl = NormalizeDouble(sl, digits);
trade.PositionModify(tk, sl, PositionGetDouble(POSITION_TP));
}
}
void OnResetButton()
{
CloseOwnPositions();
g_debt = 0;
g_nextLot = MathMax(InpBaseLot, SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN));
DebtPersist();
}
void SltpGuardCheck() {}
double g_tEmaF = 0, g_tEmaS = 0;
bool g_boTrendInit = false;
datetime g_boEvalBar = 0;
int ManagedPosCount()
{
int n = 0;
for(int i = PositionsTotal()-1; i >= 0; i--)
{
ulong tk = PositionGetTicket(i);
if(PositionGetString(POSITION_SYMBOL) != _Symbol) continue;
if(PositionGetInteger(POSITION_MAGIC) != ORIG_MAGIC_CONST) continue;
n++;
}
return n;
}
void BreakoutEngine()
{
ENUM_TIMEFRAMES tf = (ENUM_TIMEFRAMES)InpSignalTF;
datetime bt = iTime(_Symbol, tf, 0);
if(bt == 0 || bt == g_boEvalBar) return;
g_boEvalBar = bt;
if(Bars(_Symbol, tf) < 15) return;
double close1 = iClose(_Symbol, tf, 1);
double high12 = iHigh(_Symbol, tf, iHighest(_Symbol, tf, MODE_HIGH, 12, 2));
double low12 = iLow (_Symbol, tf, iLowest (_Symbol, tf, MODE_LOW , 12, 2));
if(g_boTrendInit)
{
double c1 = iClose(_Symbol, tf, 1);
g_tEmaF = (2.0 / 11) * c1 + (9.0 / 11) * g_tEmaF;
g_tEmaS = (2.0 / 21) * c1 + (19.0 / 21) * g_tEmaS;
}
else
{
g_tEmaF = iClose(_Symbol, tf, 1);
g_tEmaS = g_tEmaF;
g_boTrendInit = true;
}
double eFv = g_tEmaF, eSv = g_tEmaS;
string g_boTrend = (eFv > eSv) ? "多头" : "空头";
bool bbRaw = close1 > high12;
bool sbRaw = close1 < low12;
bool buyBreak = bbRaw && g_boTrend == "多头";
bool sellBreak = sbRaw && g_boTrend == "空头";
if(!(buyBreak || sellBreak)) return;
OpenOnSignal(buyBreak ? ORDER_TYPE_BUY : ORDER_TYPE_SELL);
}
void OpenOnSignal(ENUM_ORDER_TYPE side)
{
bool isBuy = (side == ORDER_TYPE_BUY);
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double spr = ask - bid;
if(spr > InpMaxSpreadPrice) return;
if(ManagedPosCount() > 0) return;
double lot = CurrentLot();
if(lot <= 0) return;
int dg = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);
double px = isBuy ? ask : bid;
double slv = NormalizeDouble(isBuy ? px - TRAIL_INITIAL_SL : px + TRAIL_INITIAL_SL, dg);
bool ok = isBuy ? trade.Buy(lot, _Symbol, 0, slv, 0, "NOVA")
: trade.Sell(lot, _Symbol, 0, slv, 0, "NOVA");
uint rc = trade.ResultRetcode();
if(ok && (rc == TRADE_RETCODE_DONE || rc == TRADE_RETCODE_PLACED))
{
DebtPersist();
}
}
double NormalizeLot(double lot)
{
double step = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
double mn = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
if(step > 0) lot = MathFloor(lot/step)*step;
return MathMax(lot, mn);
}
void CloseOwnPositions()
{
for(int i = PositionsTotal()-1; i >= 0; i--)
{
ulong tk = PositionGetTicket(i);
if(PositionGetString(POSITION_SYMBOL) != _Symbol) continue;
if(PositionGetInteger(POSITION_MAGIC) != ORIG_MAGIC_CONST) continue;
trade.PositionClose(tk);
}
}
double TotalFloatingPL(bool includeManual = false)
{
double s = 0;
for(int i = PositionsTotal()-1; i >= 0; i--)
{
ulong tk = PositionGetTicket(i);
if(PositionGetString(POSITION_SYMBOL) != _Symbol) continue;
long mg = PositionGetInteger(POSITION_MAGIC);
if(mg != ORIG_MAGIC_CONST)
{
if(!(includeManual && InpIncludeManualAddRecovery)) continue;
}
s += PositionGetDouble(POSITION_PROFIT);
}
return s;
}
// 修正:正确的统计手动持仓逻辑 (Magic != ORIG_MAGIC_CONST)
int CountManualPositions()
{
int n = 0;
for(int i = PositionsTotal()-1; i >= 0; i--)
{
ulong tk = PositionGetTicket(i);
if(PositionGetString(POSITION_SYMBOL) != _Symbol) continue;
if(PositionGetInteger(POSITION_MAGIC) != ORIG_MAGIC_CONST) n++;
}
return n;
}
int CountManagedPositions()
{
int nEA = 0, nMan = 0;
for(int i = PositionsTotal()-1; i >= 0; i--)
{
ulong tk = PositionGetTicket(i);
if(PositionGetString(POSITION_SYMBOL) != _Symbol) continue;
if(PositionGetInteger(POSITION_MAGIC) == ORIG_MAGIC_CONST) nEA++;
else nMan++;
}
return nEA + (InpIncludeManualAddRecovery ? nMan : 0);
}
欢迎光临 量化魔方 (https://www.115ku.com/)
Powered by Discuz! X3.5