구현을 비판하는 개인의 경우 구현이 "원시"라고 말할 때 무엇을 기준으로 하는지 완전히 명확하지 않습니다.
나는 많은 사람들이 대기 중인 주문을 하기 위해 스크립트로 작업하는 것이 매우 편리하다는 것을 알게 될 것이라고 확신합니다.
그리고 시장에서 진입하기를 원하는 사람들을 위해 Forex Magazine의 페이지에서 이미 제안했습니다(2005년 1월 24일 기사 "함수 라이브러리와 프로그램에서의 사용" 기사). 설정된 정지 손실을 기반으로 크기 로트를 자동으로 계산합니다. 그런 다음 MQL4에서는 스크립트가 차트에서 "떨어진" 가격을 얻을 수 없었으므로 이 스크립트의 가격은 항상 시장에 나와 있습니다.
동일한 프로그램은 예를 들어 일정한 정지가 있는 하나의 미니 로트로 열리도록 쉽게 수정할 수 있습니다. 그러나 MessageBox를 사용한 이 트릭을 사용하면 스크립트에 기능을 추가할 수 있습니다.
//+------------------------------------------------------------------+ //| order_buy.mq4 | //| Copyright c 2004, Alexander Ivanov. | //| mailto:alexander@indus.ru | //+------------------------------------------------------------------+ #property copyright "Copyright c 2004, Alexander Ivanov." #property link "mailto:alexander@indus.ru" #include <WinUser32.mqh> #include <stderror.mqh> // Далее константа DAYS_TO_CONSIDER будет нам заменять количество // дней, на которых мы будем искать минимум для выставления Stop loss'а #define DAYS_TO_CONSIDER 3 ////////////////////////////////////////////////////////////////// // // Необходимо разрешить импорт функций из библиотек. Для этого // нужно поставив галочку 'Разрешить импортирование внешних экспертов' // на закладке 'Советники' окна 'Настройки' вызываемого выбором пункта // меню 'Сервис'->'Настройки' // ////////////////////////////////////////////////////////////////// #include <stdlib.mqh> // содержит нужную нам функцию ErrorDescription(...) int init() { return(0); } int start() { double DaysLowArray[]; int nBarWithMinimum = 0; double dMyStopLoss = 0; double dMyPrice = 0; double dMyTakeProfit = 0; double dMyLots = 0; if(ArrayCopySeries(DaysLowArray, MODE_LOW, Symbol(),PERIOD_D1) < DAYS_TO_CONSIDER) { return(PrintErrorDescription()); } dMyPrice = Ask; dMyStopLoss = DaysLowArray[Lowest(Symbol(),PERIOD_D1,MODE_LOW,DAYS_TO_CONSIDER)]; dMyTakeProfit = dMyPrice + 2*MathMax((MathAbs(Ask-Bid)/2),MathAbs(dMyPrice-dMyStopLoss)); dMyStopLoss -= 10*Point; dMyLots = 0.1; Print("Цена = ", dMyPrice, " Стоп = ", dMyStopLoss, " Тейк профит = ", dMyTakeProfit, " Лот = ", dMyLots); ObjectCreate( "order_buy_Stop_Loss_Line", OBJ_HLINE, 0, 0, dMyStopLoss, 0, 0, 0, 0 ); ObjectSet( "order_buy_Stop_Loss_Line", OBJPROP_COLOR, Red ); ObjectSetText( "order_buy_Stop_Loss_Line", "Stop_Loss_Line", 6, "Arial", Red ); ObjectCreate( "order_buy_Take_Profit_Line", OBJ_HLINE, 0, 0, dMyTakeProfit, 0, 0, 0, 0 ); ObjectSet( "order_buy_Take_Profit_Line", OBJPROP_COLOR, Lime ); ObjectSetText( "order_buy_Take_Profit_Line", "Take_Profit_Line", 6, "Arial", Lime ); int MyError = 0; int Answer = MessageBoxA( 0, "\"order_buy\"\nПереместите линии на необходимые уровни, и нажмите ОК", "Установка ордера", MB_OKCANCEL | MB_ICONASTERISK | MB_TOPMOST); if ( Answer == IDOK ) { dMyStopLoss = ObjectGet( "order_buy_Stop_Loss_Line", OBJPROP_PRICE1); dMyTakeProfit = ObjectGet( "order_buy_Take_Profit_Line", OBJPROP_PRICE1); while(true) { if(OrderSend(Symbol(),OP_BUY,dMyLots,dMyPrice,3,dMyStopLoss,dMyTakeProfit, "Ordered by \"order_buy\" script" ,255,0,HotPink) <= 0) { MyError = PrintErrorDescription(); if((MyError == ERR_NOT_ENOUGH_MONEY) || (MyError == ERR_TRADE_DISABLED) || (MyError == ERR_INVALID_TRADE_PARAMETERS)) { MessageBoxA(0,ErrorDescription(MyError), "Ошибка", MB_OK | MB_ICONERROR); break; } else if(MyError == ERR_INVALID_STOPS) { dMyStopLoss = ObjectGet( "order_buy_Stop_Loss_Line", OBJPROP_PRICE1); dMyTakeProfit = ObjectGet( "order_buy_Take_Profit_Line", OBJPROP_PRICE1); Print("Цена = ", dMyPrice, " Стоп = ", dMyStopLoss, " Тейк профит = ", dMyTakeProfit, " Лот = ", dMyLots); } else if(MyError == ERR_PRICE_CHANGED) { MessageBoxA(0,"Цена успела измениться", "Ошибка", MB_OK | MB_ICONERROR); RefreshRates(); } else { // 10 seconds wait Sleep(10000); } } else { Answer = MessageBoxA( 0, "Ордер успешно исполнен\nРаспечатать ордер?", "Установка ордера", MB_OKCANCEL | MB_ICONASTERISK | MB_TOPMOST); if(Answer == IDOK ) { OrderPrint(); } break; } } } return(MyError); } int PrintErrorDescription() { int error=GetLastError(); Print("Error = ",ErrorDescription(error)); return(error); } int deinit() { ObjectDelete( "order_buy_Stop_Loss_Line"); ObjectDelete( "order_buy_Take_Profit_Line"); return(0); }
Lowest 및 ArrayMinimum 함수 는 EURUSD_H1 차트 에서 부적절하게 작동합니다.
사실은 최소값이 마지막 금요일 값과 일치해야 하지만 이러한 일이 발생하지 않고 최소 2일의 최소값을 반환합니다.
코드는 위의 코드이며 일정은 변경되지 않았으니 확인해주세요(일요일 밤까지).
내가 뭔가 잘못하고 있는 건 아닐까?
구현은 정말 생소해요 :) 한시간 반동안 이 스크립트를 썼어요.....
아이디어로 제안했는데 마음에 드시면 다듬어 주셔야 합니다...
경적 06.02.05 06:45
존경해 주셔서 감사합니다 ;) 그리고 정말 기회의 바다가 있습니다 - 당신은 그것을 찾아야만 합니다!
추신: "모든 창 위에" 메시지를 만드는 방법을 아는 사람이 있으면 알려주세요. ....그렇지 않으면 너무 불편합니다.....
일상적인 작업을 자동화합니다.
다음은 시각적으로 주문하기 위한 스크립트의 심각하게 수정되고 작동하는 버전입니다.
//+------------------------------------------------------------------+ //| order_buy.mq4 | //| Copyright c 2004, Alexander Ivanov. | //| mailto:alexander@indus.ru | //+------------------------------------------------------------------+ //| Разрешите импорт функций из библиотек через: | //| "Сервис -> Настройки -> Советники -> Разрешить импорт DLL" | //+------------------------------------------------------------------+ #property copyright "Copyright c 2004, Alexander Ivanov." #property link "mailto:alexander@indus.ru" #include <WinUser32.mqh> #include <stdlib.mqh> #include <stderror.mqh> //+------------------------------------------------------------------+ //| Указываем количество последних дней, на которых ищем минимум | //| для установки стоплосса | //+------------------------------------------------------------------+ #define DAYS_TO_CONSIDER 3 //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ int init() { return(0); } int deinit() { //---- просто удалим свои линии стопов ObjectDelete( "order_buy_Stop_Loss_Line"); ObjectDelete( "order_buy_Take_Profit_Line"); //---- return(0); } //+------------------------------------------------------------------+ //| Основная функция скрипта | //+------------------------------------------------------------------+ int start() { double DaysLowArray[]; double dMyStopLoss = 0; double dMyPrice = 0; double dMyTakeProfit = 0; double dMyLots = 0; //---- скопируем массив дневных данных if(ArrayCopySeries(DaysLowArray, MODE_LOW, Symbol(),PERIOD_D1) < DAYS_TO_CONSIDER) { return(-1); } //---- расчет цен dMyPrice = Ask; dMyStopLoss = DaysLowArray[Lowest(Symbol(),PERIOD_D1,MODE_LOW,DAYS_TO_CONSIDER,0)]; dMyTakeProfit = dMyPrice + 2*MathMax((MathAbs(Ask-Bid)/2),MathAbs(dMyPrice-dMyStopLoss)); dMyStopLoss -= 10*Point; dMyLots = 0.1; //---- выставим линии для визуального управления стопами ObjectCreate( "order_buy_Stop_Loss_Line", OBJ_HLINE, 0, 0, dMyStopLoss, 0, 0, 0, 0 ); ObjectSet( "order_buy_Stop_Loss_Line", OBJPROP_COLOR, Red ); ObjectSetText( "order_buy_Stop_Loss_Line", "Stop_Loss_Line", 6, "Arial", Red ); ObjectCreate( "order_buy_Take_Profit_Line", OBJ_HLINE, 0, 0, dMyTakeProfit, 0, 0, 0, 0 ); ObjectSet( "order_buy_Take_Profit_Line", OBJPROP_COLOR, Lime ); ObjectSetText( "order_buy_Take_Profit_Line", "Take_Profit_Line", 6, "Arial", Lime ); //---- запросим подтверждение на отработку string quest="Вы хотите купить "+DoubleToStr(dMyLots,2)+" "+Symbol()+" по цене Ask "+ DoubleToStr(dMyPrice,Digits)+" \n\n"+ "Переместите выставленные линии на необходимые уровни и нажмите ОК \n"+ "(красная линия - Stop Loss, зеленая - Take Profit)\n\n"+ "Нажмите Отмена чтобы отказаться от сделки"; if(MessageBoxA(0,quest,"Визуальная установка ордера на покупку", MB_OKCANCEL | MB_ICONASTERISK | MB_TOPMOST)!=IDOK) return(-2); //---- трейдер согласился, возьмем новые уровни стопов и обязательно проверим их! dMyStopLoss =NormalizeDouble(ObjectGet( "order_buy_Stop_Loss_Line", OBJPROP_PRICE1),Digits); dMyTakeProfit=NormalizeDouble(ObjectGet( "order_buy_Take_Profit_Line",OBJPROP_PRICE1),Digits); if((dMyStopLoss>0 && dMyStopLoss>Ask) || (dMyTakeProfit>0 && dMyTakeProfit<Ask)) { Print("Неправильно выставлены уровни Stop Loss и Take Profit!"); MessageBoxA(0,"Неправильно выставлены уровни Stop Loss и Take Profit! \n"+ "Операция отменена\n\n", "Визуальная установка ордера на покупку",MB_OK | MB_ICONSTOP | MB_TOPMOST); return(-3); } //---- выведем в лог сообщение об заявке Print("buy ",DoubleToStr(dMyLots,2)," ",Symbol()," at ",DoubleToStr(dMyPrice,Digits), "sl ",DoubleToStr(dMyStopLoss,Digits)," tp ",DoubleToStr(dMyTakeProfit,Digits)); //---- пробуем послать команду int ticket=OrderSend(Symbol(),OP_BUY,dMyLots,dMyPrice,3,dMyStopLoss,dMyTakeProfit, "Ordered by \"order_buy\" script" ,255,0,HotPink); if(ticket>0) // все отлично - заявка прошла { //---- сразу же выведем в лог подтверждение Print("#",ticket," buy ",DoubleToStr(dMyLots,2)," ",Symbol()," at ", DoubleToStr(dMyPrice,Digits)," is done"); //---- покажем окно if(MessageBoxA(0,"Ордер успешно исполнен \nРаспечатать его?", "Визуальная установка ордера на покупку", MB_YESNO | MB_ICONASTERISK | MB_TOPMOST)==IDYES) { OrderPrint(); } //---- все ок, выходим return(0); } //---- тут все плохо - выведем в лог сообщение int err=GetLastError(); Print("buy ",DoubleToStr(dMyLots,2)," ",Symbol()," at ", DoubleToStr(dMyPrice,Digits)," failed [",ErrorDescription(err),"]"); //----покажем окно MessageBoxA(0,ErrorDescription(err), "Ошибка визуальной установки ордера", MB_OK | MB_ICONERROR | MB_TOPMOST); return(-4); } //+------------------------------------------------------------------+
수정된 사항:
1) 모든 매개변수는 Lowest(Symbol(),PERIOD_D1,MODE_LOW,DAYS_TO_CONSIDER,0)에 지정됩니다.
Horn의 실수는 기본값이 없는 것 같습니다. 우리는 Lowest 함수의 호출과 동작을 확인할 것입니다.
2) NormalizeDouble을 통한 중고 가격 정상화 - 이것은 매우 중요합니다!
3) 주문을 보내기 전에 중지 수준의 정확성을 위한 사전 검사
4) 거래자는 창에서 더 많은 정보를 받습니다(스크립트의 첫 번째 버전에서는 코드를 읽지 않고 이 스크립트가 무엇을 하는지 이해하기가 매우 어려웠습니다)
5) 상세하고 시기적절한 로그 출력
6) 코멘트 추가
7) 응용 프로그램을 보내려는 주기적 시도가 제거되었습니다. 이것은 매우 중요 합니다.
불행히도 다음 형식의 루프 알고리즘을 사용합니다.
while(true) { if(OrderSend(....)<=0) { // проверимся Sleep(10000); } }
절대 금기, 심지어 금지.
나는 그 이유를 대략적으로 설명하려고 노력할 것입니다.
오류를 발견하더라도 모든 유형의 오류를 직접 처리할 수는 없습니다. 5개 정도의 인기 있는 오류를 잡아내고 이에 대해 조치를 취하지만 여전히 _다른 모든 오류에 대해 작업을 반복할 가능성이 높습니다. 그리고 어떤 Sleep(10000)도 스크립트가 유효하지 않은 요청을 보낸다는 사실에 대한 변명 역할을 하지 않습니다. 브로커는 계정을 차단합니다.
전문 작가로 활동하는 방법:
1) 지원서 준비 단계
a) 정확성 을 위해 전문가의 입력 매개변수를 확인하십시오
b) 응용 프로그램의 모든 가격과 볼륨(예, 역시!)을 독립적으로 정규화합니다.
c) 가장 어리석은 실수에 대해 응용 프로그램의 모든 필드를 독립적으로 확인하여 모든 가격이 다소 정확하도록 합니다.
d) 응용 프로그램을 보내기 전에 로그에 응용 프로그램의 세부 정보를 표시합니다.
2) 지원서 발송 주기의 구성
a) 루프는 유한해야 합니다. 예를 들어 for(i=0;i<3;i++) 의 경우 3번을 넘지 않아야 하며 어떠한 경우에도 while(true)
b) 주문이 통과되면 모든 것이 쉽습니다. 로그에 출력하고 거래자에게 알리고 종료합니다.
c) 오류를 포착한 다음 단락 3
3) 지원서 발송 오류 처리
) 복구할 수 있는 상황을 확인하고 기타 오류가 있는 경우 가능한 한 빨리 알림으로 종료합니다.
b) 가능한 한 적은 수의 복구 사례를 선택하고 가장 중요하고 잠재적으로 복구 가능한 경우만 선택합니다.
c) "아직도 받아들일 수 있을까?"라는 생각으로 재신청을 "푸시"하려는 시도 없음
d) 슬리피지 회계 의무화, 최소 1점
MQL4에서 주문 실행을 사용하는 주요 포인트 중 하나는 주문 수를 최소화하는 것입니다.
이는 서비스 품질에 직접적인 영향을 미칩니다.
또한 대중에게 글을 쓰는 전문가의 경우 가장 안전한 풀프루프 코드를 작성해야 합니다.
예, 내부용도 마찬가지입니다.
MB_TOPMOST를 사용해 보았는데 성공한 것 같습니다.
어제 나는 생각했습니다. 왜 그것을 구현하지 않습니까?
2005년 3월 19일자 판
사용 전 주의사항을 꼭 읽어주세요 =)
누구든지 아이디어가 있다면 - 우리는 생각할 것입니다.
우리 스스로 GDO를 할 수도 있습니다...........;)