GKFX ECN запускает стакан цен (Level II) д...
Rann 18 Feb 2013
GKFX ECN запускает стакан цен (Level II) для MetaTrader 4
Мы рады сообщить, что с 18 февраля 2013 года Компания GKFX запускает для всех владельцев демо и реальных торговых счетов ECN.MT4 сервис просмотра глубины рынка (Level II) - «стакан цен».
Приложение «стакан цен» является собственной разработкой специалистов нашей Компании, которая позволяет значительно расширить возможности торговой платформы MetaTrader4.
Функционал стакана цен GKFX ECN
- Отображение текущей ликвидности Компании позволяет трейдерам иметь более глубокую информацию о состоянии рынка.
- Торговля в один клик - значительная оптимизация скорости работы трейдеров в ситуациях, когда скорость входа в позицию оказывает существенное влияние на результат торговли (скальпинговые стратегии, пипсовка).
Скачать приложение, а также ознакомиться с детальным описанием и настройками стакана цен GKFX.Level2 вы можете в специальном разделе нашего сайта.
AlexSilver 19 Feb 2013
Детальное описание есть, а как запустить стакан в МТ4 нету. Его как советник надо запускать, но советники привязываются к какому-то графику обычно, что не очень удобно или он как-то по-другому запускается?
Еще такой вопрос - можно ли этот стакан переписать в папку терминала от другого брокера, а запускать только при работе с GKFX или надо обязательно заводить терминал от GKFX?
Rann 20 Feb 2013
Детальное описание есть, а как запустить стакан в МТ4 нету. Его как советник надо запускать, но советники привязываются к какому-то графику обычно, что не очень удобно или он как-то по-другому запускается?
Еще такой вопрос - можно ли этот стакан переписать в папку терминала от другого брокера, а запускать только при работе с GKFX или надо обязательно заводить терминал от GKFX?
Расширим описание.
Стакан работает на Windows Vista и выше (на ХР не работает).
Работает как советник. По каждой паре надо открывать график (любой) и кидать на него советник. По другому не получится реализовать торговлю в один клик, т.к. в МТ4 нет клиентского АПИ.
Подключаться стакана может только к нашим серверам. От терминала не зависит.
AlexSilver 20 Feb 2013
PS Ок. Уже установил, пока бегло посмотрел - фишка интересная, надо поподробнее будет разобраться
Rann 26 Feb 2013
C 26.02.2013 в GKFX ECN доступна для скачивания обновленная версия приложения GKFX.Level2 (стакан цен) для просмотра глубины рынка.
В новую версию добавлены:
- сохранение позиции стакана по каждому инструменту на экране (после
перезагрузки MT4 "стаканы" запускаются на последних запомненных
позициях); - скрипт (для запуска приложения скриптом, а не советником).
DRV 06 Mar 2013
Дмитрий, а за что XP обделили?.
На WinServer2003 главное запустился и вырубился, а на XP не работает.
Хочу на XP и WinServer2003, можно услышать комменты от ваших программистов как сделать.
Вообще интересно получить программно данные bid/price/ask/время обновления. Остальное без надобности.
интересует текстовый файл, чтоб с ним можно было работать на MQL или
сторонними программами.
А то толку от вашего стакана.
А документация где, мне ваши флешки полдня выкачивать по мобиле.
Как то вы не серьезно подходите.
Переходить ни на не висту ни на 8 ку нет ни какого желания.
Тем более все мобильное оборудование менять тогда придется.
С VPS что делать? WinServer2003.
Хотелось бы услышать подробные коменты. Каковы дальнейшие планы?
Если поддержка на XP и WinServer2003 не планируется, то вопрос ваш стакан на кого рассчитан?
DRV 08 Mar 2013
Дмитрий, спасибо, обрадовали.
На WinServer2003 работает, только не обновляется графика на
панельке. Помогает перезагрузка метатрейдера, через раз. Приложение стакана
иногда приходится убивать вручную в диспетчере.
Подредактировал ваш советник. Сделал вывод бандов в файл. С вашим файлом не совсем разобрался, поэтому точка вывода принтов у меня не совсем правильно расположена.
За час на еврее получил 11тыс блоков записей бандов в час или 3 записи в секунду. Файл .csv размером 6.6Mb (1.5 Gb за 2 недели), в виде зипа 100 Kb. Т.е 1 пара за сутки в архиве будет около 2,4Mb или менее 1Gb за год. Т.е да же на VPS можно накапливать.
На WinServer2003 при работе стакана на одной паре процессор грузит не сильно (2-15%).
При двух парах загрузка 100%, данные поступают только по одной паре.
Два МТ то же грузят процессор. Данные поступают только в один терминал.
Похоже, что проблемы с графической панелькой.
Подключался к одному счету, может быть и в этом проблема?
Поэтому такие пожелания.
1) хотелось бы, что бы панелька была сворачиваемой.
2) сделать вариант без панели совсем, оставить dll, получающую данные по бандам и передающую их в советник.
Тем более, что на сколько я понял, по структуре советника
именно так и задумано, либо такой вариант предполагался изначально.
прилагаю файл советника - изменения в функции start и deinit()
//+------------------------------------------------------------------+ //| GKFX.Level2.Advisor.mq4 | //| Copyright © 2011-2013, GKFX | //| http://www.gkfx.ru | //+------------------------------------------------------------------+ #property copyright "Copyright © 2011-2013, GKFX" #property link "http://www.gkfx.ru" extern int Max_Market_Depth = 10; // 1 ... 16 extern double Default_Amount = 0.01; // 0.01 ... 100.0 extern double Window_Transparency = 1.0; // 0.0 ... 1.0 extern color Button_Up_Color = MediumBlue; extern color Button_Down_Color = FireBrick; extern color Button_Text_Color = White; extern color Table_Asks_Color = C'227,240,255'; extern color Table_Bids_Color = C'255,236,236'; extern color Table_Background_Color = White; extern color Table_Text_Color = Black; extern double Support_Vs_Resist_Level = 0.0; extern color Support_Vs_Resist_Level_Color = SpringGreen; // LightGreen, PaleGreen string FileName; int FileHandle; //----------------------------------------------------------- #include <stderror.mqh> #include <stdlib.mqh> //----------------------------------------------------------- #import "Level2.dll" int Mql4Connect(int parent); int Mql4Disconnect(int parent); int Mql4Event(int parent); int Mql4SetStringProperty(int parent, string name, string value); int Mql4SetIntegerProperty(int parent, string name, int value); int Mql4SetRealProperty(int parent, string name, double value); int Mql4SetColorProperty(int parent, string name, color value); double Mql4GetRealProperty(int parent, string name); int Mql4SnapshotBidBandCount(int parent); int Mql4SnapshotAskBandCount(int parent); double Mql4SnapshotBidBandPrice(int parent, int index); double Mql4SnapshotBidBandAmount(int parent, int index); double Mql4SnapshotAskBandPrice(int parent, int index); double Mql4SnapshotAskBandAmount(int parent, int index); #import //----------------------------------------------------------- #define RESULT_SUCCESS 0 #define RESULT_FAIL -1 #define CONNECT_OK 0 #define CONNECT_ALREADY_CONNECTED 1 #define CONNECT_RESPAWN_FAILED 2 #define CONNECT_EXPECTED_LOGIN 3 #define CONNECT_EXPECTED_COMPANY 4 #define CONNECT_EXPECTED_SERVER 5 #define CONNECT_EXPECTED_DIGITS 6 #define CONNECT_EXPECTED_POINT 7 #define CONNECT_EXPECTED_LOT 8 #define CONNECT_EXPECTED_INSTRUMENT 9 #define CONNECT_EXPECTED_PARENT 10 #define EVENT_INVALID_MESSAGE_SIZE -7 #define EVENT_READ_MESSAGE_FAILED -6 #define EVENT_DIFFERENT_MESSAGE_SIZE -5 #define EVENT_UNKNOWN_MESSAGE -4 #define EVENT_INVALID_HEADER_SIZE -3 #define EVENT_READ_HEADER_FAILED -2 #define EVENT_INVALID_PIPE -1 #define EVENT_NONE 0 #define EVENT_AUTHORIZED 3 #define EVENT_NON_AUTHORIZED 4 #define EVENT_SUBSCRIBED 5 #define EVENT_NON_SUBSCRIBED 6 #define EVENT_BUY 7 #define EVENT_SELL 8 #define EVENT_HEARTBEAT 9 #define EVENT_SNAPSHOT 10 //----------------------------------------------------------- int init() { Log( "[init] starting advisor..." ); if(checkEnabled() != RESULT_SUCCESS) return(RESULT_FAIL); Log("[init] complete"); return( RESULT_SUCCESS ); } //----------------------------------------------------------- int start() { Log( "[start] enter"); int parent = WindowHandle(Symbol(), Period()); Mql4SetIntegerProperty(parent, "auth.login", AccountNumber()); Mql4SetStringProperty(parent, "auth.company", AccountCompany()); Mql4SetStringProperty(parent, "auth.server", AccountServer()); Mql4SetIntegerProperty(parent, "instrument.digits", Digits); Mql4SetRealProperty(parent, "instrument.point", Point); Mql4SetRealProperty(parent, "instrument.lot", MarketInfo(Symbol(), MODE_LOTSIZE)); Mql4SetStringProperty(parent, "instrument.name", Symbol()); Mql4SetIntegerProperty(parent, "parent", parent); Mql4SetIntegerProperty(parent, "config.maxMarketDepth", Max_Market_Depth); Mql4SetRealProperty(parent, "config.defaultAmount", Default_Amount); Mql4SetRealProperty(parent, "config.windowTransparency", Window_Transparency); Mql4SetColorProperty(parent, "config.buttonUpColor", Button_Up_Color); Mql4SetColorProperty(parent, "config.buttonDownColor", Button_Down_Color); Mql4SetColorProperty(parent, "config.buttonTextColor", Button_Text_Color); Mql4SetColorProperty(parent, "config.tableAsksColor", Table_Asks_Color); Mql4SetColorProperty(parent, "config.tableBidsColor", Table_Bids_Color); Mql4SetColorProperty(parent, "config.tableBackgroundColor", Table_Background_Color); Mql4SetColorProperty(parent, "config.tableTextColor", Table_Text_Color); Mql4SetRealProperty(parent, "config.supportVsResistLevel", Support_Vs_Resist_Level); Mql4SetColorProperty(parent, "config.supportVsResistLevelColor", Support_Vs_Resist_Level_Color); bool isActive = true; while(isActive && checkEnabled() == RESULT_SUCCESS) { Sleep(10); int connectResult = Mql4Connect(parent); if(FileHandle<=0) { WR(); } FileWrite(FileHandle,0,GetTickCount(),TimeToStr(TimeCurrent(),TIME_DATE|TIME_SECONDS)); for(int i=13;i>=0;i--) { FileWrite(FileHandle,i,Mql4SnapshotAskBandPrice(parent, i),Mql4SnapshotAskBandAmount(parent,i)); } FileWrite(FileHandle,"---","---","---"); for(int j=15;j>=0;j--) { FileWrite(FileHandle,j,Mql4SnapshotBidBandPrice(parent, j),Mql4SnapshotBidBandAmount(parent,j)); } FileWrite(FileHandle,"end","end","end"); /* Print (GetTickCount( )); Print (Mql4SnapshotBidBandCount(parent)); Print (Mql4SnapshotAskBandCount(parent)); Print ("BidBand"); Print (DoubleToStr(Mql4SnapshotBidBandPrice(parent, 0),5)); Print (Mql4SnapshotBidBandAmount(parent,0)); Print (DoubleToStr(Mql4SnapshotBidBandPrice(parent, 1),5)); Print (Mql4SnapshotBidBandAmount(parent, 1)); Print (DoubleToStr(Mql4SnapshotBidBandPrice(parent, 2),5)); Print (Mql4SnapshotBidBandAmount(parent, 2)); Print ("AskBand"); Print (DoubleToStr(Mql4SnapshotAskBandPrice(parent,0),5)); Print (Mql4SnapshotAskBandAmount(parent, 0)); Print (DoubleToStr(Mql4SnapshotAskBandPrice(parent, 1),5)); Print (Mql4SnapshotAskBandAmount(parent, 1)); Print (DoubleToStr(Mql4SnapshotAskBandPrice(parent, 2),5)); Print (Mql4SnapshotAskBandAmount(parent, 2)); */ switch(connectResult) { case CONNECT_OK: Log("[start] connected"); break; case CONNECT_ALREADY_CONNECTED: break; case CONNECT_RESPAWN_FAILED: return(Log("[start] error : respawn failed")); case CONNECT_EXPECTED_LOGIN: return(Log("[start] error: expected login")); case CONNECT_EXPECTED_COMPANY: return(Log("[start] error: expected company name")); case CONNECT_EXPECTED_SERVER: return(Log("[start] error: expected server name")); case CONNECT_EXPECTED_DIGITS: return(Log("[start] error: expected instrument digits")); case CONNECT_EXPECTED_POINT: return(Log("[start] error: expected instrument point")); case CONNECT_EXPECTED_LOT: return(Log("[start] error: expected lot amount")); case CONNECT_EXPECTED_INSTRUMENT: return(Log("[start] error: expected instrument name")); case CONNECT_EXPECTED_PARENT: return(Log("[start] error: expected window chart handle")); default: return(Log("[start] error : unknown connection result")); } int eventId = Mql4Event(parent); switch(eventId) { case EVENT_INVALID_MESSAGE_SIZE: Log("[start] error : invalid message size"); isActive = false; continue; case EVENT_READ_MESSAGE_FAILED: Log("[start] error : reading message failed"); isActive = false; continue; case EVENT_DIFFERENT_MESSAGE_SIZE: Log("[start] error : different message size"); isActive = false; continue; case EVENT_UNKNOWN_MESSAGE: Log("[start] error : unknown message"); isActive = false; continue; case EVENT_INVALID_HEADER_SIZE: Log("[start] error : invalid header size"); isActive = false; continue; case EVENT_READ_HEADER_FAILED: Log("[start] error : reading header failed"); isActive = false; continue; case EVENT_INVALID_PIPE: Log("[start] error : invalid pipe"); isActive = false; continue; case EVENT_NONE: //Log("[start] empty message" ); continue; case EVENT_AUTHORIZED: Log("[start] authorized" ); continue; case EVENT_NON_AUTHORIZED: Log("[start] error : non authorized" ); // isActive = false; continue; case EVENT_SUBSCRIBED: Log( "[start] subscribed" ); continue; case EVENT_NON_SUBSCRIBED: Log( "[start] error : non subscribed" ); isActive = false; continue; case EVENT_BUY: Log( "[start] BUY" ); MakeOrder(OP_BUY, Mql4GetRealProperty(parent, "trade.amount"), Mql4GetRealProperty(parent, "trade.price")); continue; case EVENT_SELL: Log( "[start] SELL" ); MakeOrder(OP_SELL, Mql4GetRealProperty(parent, "trade.amount"), Mql4GetRealProperty(parent, "trade.price")); continue; case EVENT_HEARTBEAT: continue; case EVENT_SNAPSHOT: /*Log( "[start] snapshot (" + Mql4SnapshotBidBandCount(parent) + " bids, " + Mql4SnapshotAskBandCount(parent) + " asks) [bid " + Mql4SnapshotBidBandPrice(parent, 0) + " " + Mql4SnapshotBidBandAmount(parent, 0) + " / ask " + Mql4SnapshotAskBandPrice(parent, 0) + " " + Mql4SnapshotAskBandAmount(parent, 0) + " ]" );*/ continue; default: Log("[start] unknown event"); continue; } // switch action } // while not Stopped Mql4Disconnect(parent); Log( "[start] complete (return 0)" ); return( RESULT_SUCCESS ); } //----------------------------------------------------------- // Expert finalization int deinit() { if(FileHandle>0) { FileClose(FileHandle); Print("Файл записан"); } Log("[deinit] start"); switch(UninitializeReason()) { case REASON_REMOVE: Log( "[deinit] Reason(1): [program was removed from chart]" ); break; case REASON_RECOMPILE: Log( "[deinit] Reason(2): [program was recompiled]" ); break; case REASON_CHARTCHANGE: Log( "[deinit] Reason(3): [symbol or chart was chanched]" ); break; case REASON_CHARTCLOSE: Log( "[deinit] Reason(4): [chart closed]" ); break; case REASON_PARAMETERS: Log( "[deinit] Reason(5): [input param(s) was changed]" ); break; case REASON_ACCOUNT: Log( "[deinit] Reason(6): [account was changed]" ); break; } Mql4Disconnect(WindowHandle(Symbol(), Period())); Log( "[deinit] complete" ); return( 0 ); } //----------------------------------------------------------- int Log(string message) { Print(message); return(-1); } //----------------------------------------------------------- int LogAlert(string message) { Log(message); Alert(message); return(-1); } //----------------------------------------------------------- int checkEnabled() { int errorCode = GetLastError(); if(ERR_NO_ERROR != errorCode) return(LogAlert("[checkEnabled] error : " + ErrorDescription(errorCode))); if(!IsLibrariesAllowed()) return(LogAlert("[checkEnabled] DLL calls not allowed")); if(!IsExpertEnabled()) return(LogAlert("[checkEnabled] experts disabled")); if(IsStopped()) return(Log("[checkEnabled] expert stopped")); //if(!IsTradeAllowed()) return(Log("[checkEnabled] trade is not allowed")); return(RESULT_SUCCESS); } //----------------------------------------------------------- // price correction double CorrectPrice( int side, double price ) { RefreshRates(); if( OP_BUY == side ) { return( Ask ); } return( Bid ); } //----------------------------------------------------------- void MakeOrder(int operation, double _nAmount, double _dPrice) { if(!IsTradeAllowed()) { Log("Trading is not allowed: "); return; } double nAmount = NormalizeDouble(_nAmount, 2); // At opening of a market order (OP_SELL or OP_BUY), only the latest prices // of Bid (for selling) or Ask (for buying) can be used as open price. double dCorrectedPrice = CorrectPrice( operation, _dPrice ); Print("try to send order amount = " + nAmount + " price = " + _dPrice + " correctedPrice = " + dCorrectedPrice); int ticket = OrderSend(Symbol(), operation, nAmount, dCorrectedPrice, 10000, 0.0, 0.0); string message = ""; if(-1 == ticket) { message = "[start] unable to send order, code #" + GetLastError() + " (symbol " + Symbol() + ", amount " + nAmount + ", price " + dCorrectedPrice + ")"; Log(message); return; } else { message = "[start] order was sent (symbol " + Symbol() + ", amount " + nAmount + ", price " + dCorrectedPrice + ")"; Log(message); } } //----------------------------------------------------------- int WR() { //---- string k; int h=TimeHour(TimeCurrent()); int day=Day(); int Mn=Month(); k=StringConcatenate(Mn,"_",day,"_",h); FileName=Symbol()+"Bands"+k+".csv"; FileHandle=FileOpen(FileName,FILE_WRITE | FILE_CSV,";"); if (FileHandle<1) { Print("Не удалось открыть файл, ошибка ",GetLastError()); return; } //---- return(0); } //+------------------------------------------------------------------+
че то прикреплялка не работает. выкладываю в коде.
Edited by DRV, 08 March 2013 - 11:03.
Rann 08 Mar 2013
Странно, что на 2003 вообще стакан хоть как-то запустился.
Сворачивание добавим, но не в самое ближайшее время. Сейчас есть другие задача, более приоритетные.
На счет логирования, там есть закомментенный код:
case EVENT_SNAPSHOT: /*Log( "[start] snapshot (" + Mql4SnapshotBidBandCount(parent) + " bids, " + Mql4SnapshotAskBandCount(parent) + " asks) [bid " + Mql4SnapshotBidBandPrice(parent, 0) + " " + Mql4SnapshotBidBandAmount(parent, 0) + " / ask " + Mql4SnapshotAskBandPrice(parent, 0) + " " + Mql4SnapshotAskBandAmount(parent, 0) + " ]" );*/ continue;
На всех не угодишь, но постараемся стакан развивать по мере возможности.
DRV 10 Mar 2013
Дмитрий, мы (я так понимаю я не один такой) вас и не торопим.
Ждали мультибанк и еще подождем.
На всех угождать и не требуется – выбрать оптимальные варианты, которые требуются либо большинству, либо тем, кто приносит больше денег.
Поэтому собственно и вопросы о минимальной документации, чтоб можно было попробовать не тыкаясь об стену. Обсудить с народом.
Я, думаю, вы в состоянии найти сотрудника и выделить человеко-день для выполнения следующей задачи:
Написать черновой вариант документации и выложить его на собственный форум и сайт. Прописать там о совместимости с операционными системами.
Прописать пункт о возможностях логирования работы программы.
Закомментировать на русском языке советник стакана, в общих чертах, что бы было понятно, что и где там выполняется и куда выводится.
Я, думаю, это в ваших же интересах. Так как,
во первых, вы получите обратную связь с конечными пользователями.
Во вторых, клиент, хотя бы поймет, какие вы возможности предлагаете. Таких возможностей в рамка МТ4 для
простого пользователя пока нет ни где.
В третьих, вы дадите клиенту дополнительное время переварить эти новые возможности и че-то, может быть, родить, прежде чем ваши конкуренты реализуют то же самое.
Парочка ссылок в тему.
Обсуждение высокочастотной торговли на МТ5 http://www.mql5.com/ru/forum/10454
Альпари о стакане и ленте сделок http://forum.alpari....=30968&page=255
(посты 2541 и 2542).
Метаквоты родили собственную панельку. http://forum.mql4.com/ru/54430
Если данные ссылки не уместны на вашем форуме, то просьба организовать отдельную ветку по стакану и дать на нее ссылку.
Rann 10 Mar 2013
Человека можно выделить на день, но тогда он не будет делать в этот день что-то другое. Дело в том, что мы это что-то другое считаем более важным, чем стакан, который нужен на такому уж большому количеству людей, а его скрытые особенности и того меньше. Расставляем, так сказать, приоритеты.
Но стаканом занимаемся по мере сил. И обновления готовятся серьезные.
EA4U 16 Oct 2013
Спасибо, Дмитрий, за большую проделанную работу, но несколько удивила пара критических недоработок (на мой взгляд конечно) в эксперте Level 2. Пожелания я отразил на рисунке:
Эксперт GKFX.Level2.Advisor я могу доработать (так как есть исходный код) добавив поиск и закрытие сначала встречных заявок а затем уже одиночных, если Вы позволите, и это будет кому-нибудь нужно. А в приложение мне уже не залезть чтобы отшлифовать.
С уважением, Владимир.
Edited by EA4U, 16 October 2013 - 05:52.