//+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ int CProcessor::OnFXIResponse(Response *resp) { SLTPOrderRequest req = { 0 }; if (resp->status == OrderSLExecuted || resp->status == OrderTPExecuted) if (ExtProcessor.m_orderRequests.Dequeue(resp->requestId, &req)) { CharString str; str.Printf(FALSE, "FXI response on SL-TP order %d, price=%g", req.orderId, resp->price); ExtServer->LogsOut(CmdOK, PROGRAM_TITLE, str.ToArray()); // модифицировать ордер - активировать его TradeRecord order = { 0 }; if (ExtServer->OrdersGet(req.orderId, &order)) { UserInfo user = {0}; user.login = ExtProcessor.m_manager; COPY_STR(user.name, "Virtual Dealer"); COPY_STR(user.ip, "VirtualDealer"); order.close_price = resp->price; str.Printf(FALSE, "FXI response order detail: login=%d, volume=%d", order.login, order.volume); ExtServer->LogsOut(CmdOK, PROGRAM_TITLE, str.ToArray()); UserInfo us; if (GetUserInfo(order.login, &us)) { #pragma pack(push,1) TradeTransInfo tti; memset(&tti, 0, sizeof(tti)); tti.cmd = order.cmd; strcpy(tti.symbol, order.symbol); tti.volume = order.volume; tti.price = resp->price; tti.type = TT_ORDER_MK_CLOSE; tti.order = order.order; if (ExtServer->OrdersClose(&tti, &us) == FALSE) ExtServer->LogsOut(CmdOK, PROGRAM_TITLE, "OrdersClose failed"); else ExtServer->LogsOut(CmdOK, PROGRAM_TITLE, "OrdersClose OK"); #pragma pack(pop) } else ExtServer->LogsOut(CmdOK, PROGRAM_TITLE, "GetUserInfo failed"); } return TRUE; } return FALSE; }
//+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ int CProcessor::ProcessStopApply(TradeRecord *trade, const ConGroup *group, const int isTP) { char *groupStr = new char[50]; strcpy(groupStr, group->group); if (CheckGroup(m_groups, groupStr) == FALSE) { delete []groupStr; return FALSE; } delete []groupStr; double price = 0; // получим текущие цены для группы и установки символа double prices[2] = { 0, 0 }; int orderSide = trade->cmd == OP_BUY ? 1 : 0; if (ExtServer->HistoryPricesGroup(trade->symbol, group, prices) == RET_OK) { int orderSide = trade->cmd == OP_BUY ? 0 : 1; // меняется от знака сделки price = prices[orderSide]; } CharString strMsg; strMsg.Printf(FALSE, "%s (%s at %g) is applying to order %d", isTP ? "TP" : "SL", orderSide == 1 ? "BUY" : "SELL", price, trade->order); ExtServer->LogsOut(CmdOK, PROGRAM_TITLE, strMsg.ToArray()); SLTPOrderRequest req = { trade->order, price }; m_orderRequests.Enqueue(&req); // отправить запрос на сервер int requestId = m_nextStopRequestId++; strMsg.Printf(FALSE, "requestId=%d;type=%s;price=%g;login=%d;symbol=%s;volume=%d;", trade->order, isTP ? "TP" : "SL", price, trade->login, trade->symbol, trade->volume); m_sender->SendTo(&strMsg, m_sendHost, m_sendPort); return TRUE; }
//+------------------------------------------------------------------+ //| Позиция открылась (закрылась) - уведомить FXI | //+------------------------------------------------------------------+ void CProcessor::OnTradeHistoryRecord(TradeRecord *trade) { CharString str; PendingRequest req = { 0 }; if (extPendingRequestQueue.FindRequest(trade->login, trade->cmd, trade->symbol, trade->volume, trade->open_price, &req)) { str.Printf(FALSE, "type=NOTIFY;requestId=%d;order=%d;", req.requestId, trade->order); m_sender->SendTo(&str, m_sendHost, m_sendPort); return; } str.Printf(FALSE, "Request for order=%d not found", trade->order); ExtServer->LogsOut(CmdOK, PROGRAM_TITLE, str.ToArray()); str.Printf(FALSE, "Detail: login=%d, cmd=%d, symbol=%s, volume=%d, op_price=%g, state=%d", trade->login, trade->cmd, trade->symbol, trade->volume, trade->open_price, trade->state); ExtServer->LogsOut(CmdOK, PROGRAM_TITLE, str.ToArray()); }
DWORD WINAPI UdpListener::ThreadProc(LPVOID lpParameter) { UdpListener* thisObj = (UdpListener*) lpParameter; char buffer[MAXDATASIZE + 1]; // create socket if ((thisObj->m_hSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET) { // Failed creating socket SetEvent(thisObj->m_hShutdownCompletedEvent); ExtLogger.Out("socket was not created: %d", WSAGetLastError()); return -200; } sockaddr_in local_addr; local_addr.sin_family=AF_INET; local_addr.sin_addr.s_addr=INADDR_ANY; local_addr.sin_port=htons(thisObj->m_port); if (bind(thisObj->m_hSocket,(sockaddr *) &local_addr, sizeof(local_addr))) { closesocket(thisObj->m_hSocket); WSACleanup(); SetEvent(thisObj->m_hShutdownCompletedEvent); ExtLogger.Out("socket was not bound: %d", WSAGetLastError()); return -300; } while (1) { #ifdef DEBUG_MESSAGE_MODE CharString str; str.Printf("Listening on port %d", thisObj->m_port); Logger::LogMessage(str.ToArray()); #endif int retVal = recv(thisObj->m_hSocket, buffer, MAXDATASIZE, 0); if (retVal == 0) break; if (retVal < 0) { int erCode = WSAGetLastError(); if (erCode == WSAEINTR) break; else { CharString errStr; errStr.Printf("Error code is %d", erCode); ExtLogger.Out(CharString(errStr).ToArray()); } } if (retVal > 0) { buffer[retVal] = 0; (*thisObj->m_onRecv)(buffer, retVal); } } // close socket if (thisObj->m_hSocket > 0) closesocket(thisObj->m_hSocket); SetEvent(thisObj->m_hShutdownCompletedEvent); return 0; }
DWORD WINAPI UdpListener::ThreadProc(LPVOID lpParameter) { UdpListener* thisObj = (UdpListener*) lpParameter; CharString str; char buffer[MAXDATASIZE + 1]; // create socket if ((thisObj->m_hSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET) { // Failed creating socket SetEvent(thisObj->m_hShutdownCompletedEvent); str.Printf(FALSE, "Socket was not created: %d", WSAGetLastError()); ExtServer->LogsOut(CmdOK, PROGRAM_TITLE, str.ToArray()); //ExtLogger.Out(0, APP_NAME, msg.ToArray()); return -200; } sockaddr_in local_addr; local_addr.sin_family=AF_INET; local_addr.sin_addr.s_addr=INADDR_ANY; local_addr.sin_port=htons(thisObj->m_port); if (bind(thisObj->m_hSocket,(sockaddr *) &local_addr, sizeof(local_addr))) { closesocket(thisObj->m_hSocket); WSACleanup(); SetEvent(thisObj->m_hShutdownCompletedEvent); str.Printf(FALSE, "Socket was not bound: %d", WSAGetLastError()); ExtServer->LogsOut(CmdOK, PROGRAM_TITLE, str.ToArray()); return -300; } str.Printf(FALSE, "Now listening port %d", thisObj->m_port); ExtServer->LogsOut(CmdOK, PROGRAM_TITLE, str.ToArray()); while (1) { int retVal = recv(thisObj->m_hSocket, buffer, MAXDATASIZE, 0); if (retVal == 0) break; if (retVal < 0) { int erCode = WSAGetLastError(); if (erCode == WSAEINTR) break; else { CharString errStr; errStr.Printf(FALSE, "Error while recv. Error code is %d", erCode); ExtServer->LogsOut(CmdOK, PROGRAM_TITLE, errStr); } } if (retVal > 0) { buffer[retVal] = 0; (*thisObj->m_onRecv)(buffer, retVal); } } // close socket if (thisObj->m_hSocket > 0) closesocket(thisObj->m_hSocket); SetEvent(thisObj->m_hShutdownCompletedEvent); return 0; }
/* returns: FALSE - request should be deleted, TRUE - keep request */ int CProcessor::ProcessSingleRequest(Request *req) { UserInfo user = {0}; ConGroup group = {0}; double prices[2]; CharString str, strMsg; char strCmd[64], strType[64]; user.login = m_manager; COPY_STR(user.name, "Virtual Dealer"); COPY_STR(user.ip, "VirtualDealer"); ExtServer->GroupsGet(req->group, &group); // получим текущие цены для группы и установки символа if (ExtServer->HistoryPricesGroup(req->trans.symbol, &group, prices) != RET_OK) { ExtServer->RequestsReset(req->id, &user, DC_RESETED); str.Printf(FALSE, "ProcessSingleRequest: HistoryPricesGroup (symbol [%s], group [%s]) failed", req->trans.symbol, req->group); ExtServer->LogsOut(CmdOK, PROGRAM_TITLE, str.ToArray()); return FALSE; } // если это запрос на открытие позы... if (req->trans.type == TT_ORDER_IE_OPEN || req->trans.type == TT_ORDER_IE_CLOSE || req->trans.type == TT_ORDER_MK_OPEN || req->trans.type == TT_ORDER_MK_CLOSE) { // запрос был отправлен, ответа нет - таймаут if (req->sent && (GetTickCount() > req->time + m_waitForFXIReply)) { str.Printf(FALSE, "Таймаут для запроса %d (нет ответа от сервера FXI)", req->id); ExtServer->LogsOut(CmdOK, PROGRAM_TITLE, str.ToArray()); // !! добавить открытие сделки (отложенное) ExtServer->RequestsRequote(req->id, &user, prices, FALSE); return FALSE; } // запрос к FXI еще не был отправлен - отправить if (!req->sent) { ExtServer->LogsOut(CmdOK, PROGRAM_TITLE, "Отправка UDP"); CharString reqStr; reqStr.Printf(FALSE, "requestId=%d;group=%s;time=%d;login=%d;", req->id, req->group, req->time, req->login); reqStr.Printf(TRUE, "type=%s;side=%d;order=%d;orderby=%d;price=%g;symbol=%s;volume=%d;tp=%g;sl=%g;slippage=%d;pending=%d;stopout=%d", req->trans.type == TT_ORDER_IE_OPEN || req->trans.type == TT_ORDER_MK_OPEN ? "OPEN" : "CLOSE", req->trans.cmd == OP_BUY || req->trans.cmd == OP_BUY_LIMIT || req->trans.cmd == OP_BUY_STOP ? FXI_OP_BUY : FXI_OP_SELL, req->trans.order, req->trans.orderby, req->trans.price, req->trans.symbol, req->trans.volume, req->trans.tp, req->trans.sl, req->trans.ie_deviation, req->isPending, req->isStopout); FormatCommand(req->trans.cmd, strCmd); FormatRequestType(req->trans.type, strType); str.Printf(FALSE, "Отправка запроса FXI [%s] типа [%s] по цене [%g], ордер [%d]", strCmd, strType, req->trans.price, req->trans.order); ExtServer->LogsOut(CmdOK, PROGRAM_TITLE, str.ToArray()); m_sender->SendTo(&reqStr, m_sendHost, m_sendPort); req->sent = TRUE; ExtServer->LogsOut(CmdOK, PROGRAM_TITLE, "Отправка UDP::OK"); return TRUE; } Response resp = { 0 }; int requestId = req->trans.type == TT_ORDER_MK_CLOSE || req->trans.type == TT_ORDER_IE_CLOSE ? req->trans.order : req->id; int respFound = extQueue->FindAndDequeue(requestId, &resp); if (!respFound) return TRUE; // получен ответ от FXI ExtServer->LogsOut(CmdOK, PROGRAM_TITLE, "Обработка ответа FXI"); // обработан успешно if (resp.status == RequestCompleted) { strMsg.Printf(FALSE, "Запрос (%d) подтвержден по цене (%g), сейчас цена (%g)", req->id, req->trans.cmd == OP_BUY ? prices[1] : prices[0], resp.price); ExtServer->LogsOut(CmdOK, PROGRAM_TITLE, strMsg.ToArray()); double newPrices[2] = { resp.price, resp.price }; req->trans.price = resp.price; // отложенный ордер if (resp.isPendingActivate) { ActivatePendingOrder(&resp); return FALSE; } // обработка ответа на закрытие (стопаут) if (resp.isStopoutReply) { ClosePositionStopout(&resp, req); return FALSE; } // обычный ордер // подтвердить запрос if (ExtServer->RequestsConfirm(req->id, &user, newPrices) == RET_OK) { // если запрос на открытие... if (req->trans.type == TT_ORDER_IE_OPEN || req->trans.type == TT_ORDER_MK_OPEN) // сохранить подтвержденный запрос (потом ассоциировать его с открывшейся // позицией) extPendingRequestQueue.AddRequest(resp.requestId, req->login, req->trans.cmd, req->trans.symbol, req->trans.volume, resp.price); } else { // сделка открыта у брокера, но не открылась в МТ4 } return FALSE; } // обработан с ошибкой if (resp.status == RequestFailed) { ExtServer->LogsOut(CmdOK, PROGRAM_TITLE, "Запрос не подтвержден (отрицательная квитанция)"); ExtServer->RequestsReset(req->id, &user, DC_RESETED); return FALSE; } // прочие возвраты strMsg.Printf(FALSE, "Запрос: код ответа [%d]", resp.status); ExtServer->LogsOut(CmdOK, PROGRAM_TITLE, strMsg.ToArray()); return FALSE; } // if (req->trans.type == TT_ORDER_IE_OPEN ... // запрос цены, не более if (req->trans.type == TT_PRICES_GET) { ExtServer->RequestsPrices(req->id, &user, prices, FALSE); return FALSE; } if (req->trans.type == TT_ORDER_DELETE) { ExtServer->LogsOut(CmdOK, PROGRAM_TITLE, "Удаление отложенного ордера"); ExtServer->RequestsConfirm(req->id, &user, prices); ExtServer->LogsOut(CmdOK, PROGRAM_TITLE, "Отложенный ордер удален"); return FALSE; } // остальные запросы подтверждаем ExtServer->RequestsConfirm(req->id, &user, prices); return FALSE; }
int CProcessor::Add(const UserInfo *user, const ConGroup *group, const ConSymbol *symbol, const TradeRecord *pending, TradeRecord *trade) { Request *temp; UINT id; static int uid = 1; CharString str; if (pending == NULL || trade == NULL) return(FALSE); // проверки - кто управляет счетом if (m_delay == 0 || CheckGroup(m_groups, group->group) == FALSE) return (TRUE); double prices[2]; // получим текущие цены для группы и установки символа if (ExtServer->HistoryPricesGroup(symbol->symbol, group, prices) != RET_OK) { str.Printf(FALSE, "CProcessor::Add Pending (symbol [%s], group [%s]) failed", symbol->symbol, group->group); ExtServer->LogsOut(CmdOK, PROGRAM_TITLE, str.ToArray()); return FALSE; } m_sync.Lock(); // проверить - нет ли такого запроса в списке Request *reqTmp; if (m_requests != NULL) { int i = 0; for (reqTmp = m_requests; i < m_requests_total; i++, reqTmp++) { if (reqTmp->isPending) if (reqTmp->pendingId == pending->order) { ExtServer->LogsOut(CmdOK, PROGRAM_TITLE, "Отложенный ордер уже в списке"); m_sync.Unlock(); return (TRUE); } } } // лог /*char reqCmdStr[64]; FormatCommand(pending->cmd, reqCmdStr); str.Printf(FALSE, "CProcessor::Add Pending(order [%d], cmd [%s], req Id [%d])", pending->order, reqCmdStr, startPendingRequestId); ExtServer->LogsOut(CmdOK, PROGRAM_TITLE, str.ToArray());*/ //---- если место для запросов нет выделим if(m_requests == NULL) { if((m_requests = new Request[256]) == NULL) { m_sync.Unlock(); return (FALSE); } m_requests_max = 256; m_requests_total = 0; } //---- посмотрим может надо перевыделить if (m_requests_total >= m_requests_max) { if((temp = new Request[m_requests_max + 256]) == NULL) { m_sync.Unlock(); return(FALSE); } //---- скопируем старое memcpy(temp, m_requests, sizeof(Request) * m_requests_total); //---- удалим уже не нужное delete m_requests; m_requests = temp; m_requests_max += 256; } //---- вставляем запрос m_requests[m_requests_total].pendingId = pending->order; m_requests[m_requests_total].isPending = TRUE; m_requests[m_requests_total].id = startPendingRequestId++; m_requests[m_requests_total].time = GetTickCount(); m_requests[m_requests_total].sent = FALSE; m_requests[m_requests_total].login = user->login; memcpy(&m_requests[m_requests_total].trans, pending, sizeof(TradeTransInfo)); m_requests[m_requests_total].trans.volume = trade->volume; Out(CmdOK, "Pending order %d added of volume %d", m_requests[m_requests_total].id, trade->volume); COPY_STR(m_requests[m_requests_total].group, group->group); // поправить команду char origTradeCmd[32], newTradeCmd[32]; FormatCommand(m_requests[m_requests_total].trans.cmd, origTradeCmd); int pendCmd = trade->cmd; //m_requests[m_requests_total].trans.cmd; pendCmd = (pendCmd == OP_BUY_LIMIT || pendCmd == OP_BUY_STOP) ? OP_BUY : (pendCmd == OP_SELL_LIMIT || pendCmd == OP_SELL_STOP) ? OP_SELL : pendCmd; m_requests[m_requests_total].trans.cmd = pendCmd; FormatCommand(m_requests[m_requests_total].trans.cmd, newTradeCmd); m_requests[m_requests_total].trans.type = TT_ORDER_MK_OPEN; m_requests[m_requests_total].trans.price = pendCmd == OP_BUY ? prices[1] : prices[0]; strcpy(m_requests[m_requests_total].trans.symbol, symbol->symbol); m_requests[m_requests_total].trans.order = pending->order; str.Printf(FALSE, "Отложенный ордер %d добавлен, всего %d (%s, теперь %s)", pending->order, m_requests_total, origTradeCmd, newTradeCmd); ExtServer->LogsOut(CmdOK, PROGRAM_TITLE, str.ToArray()); m_requests_total++; //---- запускаем поток if (m_thread == NULL) if ((m_thread = (HANDLE)_beginthreadex(NULL, 256000, ThreadFunction, this, 0, &id))==NULL) { m_sync.Unlock(); return(FALSE); } m_sync.Unlock(); return(TRUE); }
//+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ int CProcessor::Add(RequestInfo *request, int isStopout) { Request *temp; UINT id; Request req = {0}; static int uid = 1; if (request == NULL) return(FALSE); // проверки - кто управляет счетом if (m_delay == 0 || CheckGroup(m_groups, request->group) == FALSE) return (TRUE); // лог char reqTypeStr[64]; char reqCmdStr[64]; FormatCommand(request->trade.cmd, reqCmdStr); FormatRequestType(request->trade.type, reqTypeStr); CharString str; str.Printf(FALSE, "CProcessor::Add(тип [%s], cmd [%s])", reqTypeStr, reqCmdStr); ExtServer->LogsOut(CmdOK, PROGRAM_TITLE, str.ToArray()); m_sync.Lock(); //---- если место для запросов нет выделим if(m_requests == NULL) { if((m_requests = new Request[256]) == NULL) { m_sync.Unlock(); return (FALSE); } m_requests_max = 256; m_requests_total = 0; } //---- посмотрим может надо перевыделить if (m_requests_total >= m_requests_max) { if((temp = new Request[m_requests_max + 256]) == NULL) { m_sync.Unlock(); return(FALSE); } //---- скопируем старое memcpy(temp, m_requests, sizeof(Request) * m_requests_total); //---- удалим уже не нужное delete m_requests; m_requests = temp; m_requests_max += 256; } //---- вставляем запрос m_requests[m_requests_total].isStopout = isStopout; m_requests[m_requests_total].isPending = FALSE; m_requests[m_requests_total].id = request->id; m_requests[m_requests_total].time = GetTickCount(); m_requests[m_requests_total].sent = FALSE; m_requests[m_requests_total].login = request->login; memcpy(&m_requests[m_requests_total].trans, &request->trade, sizeof(TradeTransInfo)); COPY_STR(m_requests[m_requests_total].group, request->group); m_requests_total++; //---- запускаем поток if (m_thread == NULL) if ((m_thread = (HANDLE)_beginthreadex(NULL, 256000, ThreadFunction, this, 0, &id))==NULL) { m_sync.Unlock(); return(FALSE); } m_sync.Unlock(); return(TRUE); }