//+------------------------------------------------------------------+ //| osc_position.mqh | //| Copyright 2019, OS Corp | //| http://www.os.org | //| | //| Versao 0.001 Mantem banco de dados de ordens e posicoes. | //| 1. | //| | //| 2. | //| | //+------------------------------------------------------------------+ // // Uma posicao tem: // - um identificador // - ordens de entrada // - ordens de saida // Uma ordem tem: // - identificador #property copyright "Copyright 2020, OS Corp." #property link "http://www.os.org" #property version "1.0" #include #include #include #include // log para ontradetransaction class OsOrdem : public CObject{ public: int inOut ; // 1(in); -1(out) ; 0(desconhecida) ulong idOrd ; // ticket da ordem ulong idDea ; // ticket da negociacao; ulong idPos ; // ticket da posicao a qual pertence a ordem; ulong idToClose; // id deal da ordem que esta ordem estah fechando. ulong mag ; // numero magico desta ordem; ulong magMeClose; // numero magico da ordem de fechamento dessa ordem; ulong magToClose; // numero magico da ordem que esta ordem estah fechando; string symbol ; // ticker double price ; // preco double vol ; // volume ENUM_TRADE_TRANSACTION_TYPE typTra; // ultimo tipo de transacao (evento) informado para a ordem ENUM_DEAL_TYPE typDea; ENUM_ORDER_TYPE typOrd; ENUM_ORDER_STATE status; ENUM_TRADE_REQUEST_ACTIONS reqAction; // acao solicitada na ultima requisicao double reqPrice ; // preco da ultima requisicao double reqVol ; // volume da ultima requisicao ENUM_ORDER_TYPE reqTypOrd; // tipo de ordem feito na ultima requisicao string reqComent; // comentario uint retCode ; // codigo de retorno da ultima requisicao ulong retOrder; // numero de ordem gerada, caso tenha sido colocada. double retVol ; // volume da ultima gerada, confirmado pela corretora. uint reqId ; // requist_id eh o identificador da requisicao. Eh definido pelo terminal durante a despacho da solicitacao. //------------------------------------ // req.action , // ENUM_TRADE_REQUEST_ACTIONS // Tipo de operação de negociação // req.magic , // ulong // Expert Advisor -conselheiro- ID (número mágico) // req.order , // ulong // Bilhetagem da ordem // req.symbol , // string // Símbolo de negociação // req.volume , // double // Volume solicitado para uma encomenda em lotes // req.price , // double // Preço // req.stoplimit , // double // Nível StopLimit da ordem // req.sl , // double // Nível Stop Loss da ordem // req.tp , // double // Nível Take Profit da ordem // req.deviation , // ulong // Máximo desvio possível a partir do preço requisitado // req.type , // ENUM_ORDER_TYPE // Tipo de ordem // req.type_filling , // ENUM_ORDER_TYPE_FILLING // Tipo de execução da ordem // req.type_time , // ENUM_ORDER_TYPE_TIME // Tipo de expiração da ordem // req.expiration , // datetime // Hora de expiração da ordem (para ordens do tipo ORDER_TIME_SPECIFIED)) // req.comment , // string // Comentário sobre a ordem // req.position , // ulong // Bilhete da posição // req.position_by , // ulong // Bilhete para uma posição oposta //------------------------------------ virtual int Compare( const CObject* node, // Node to compare with const int mode=0){// Compare mode if( this.mag > ((OsOrdem*)node).mag ) return 1; if( this.mag < ((OsOrdem*)node).mag ) return -1; return 0; } string toString(){ string str; StringConcatenate(str ,"|ttr ",EnumToString(typTra) ,"|ord ",idOrd ,"|dea ",idDea ,"|pos ",idPos ,"|mag ",mag ,"|mml ",magMeClose ,"|mtc ",magToClose ,"|sym ",symbol ,"|io " ,inOut ,"|prc ",price ,"|vol ",vol ,"|tor ",EnumToString(typOrd) ,"|tde ",EnumToString(typDea) ,"|stt ",EnumToString(status) ); return str; } }; /* class CArrayOsOrdem : public CArrayObj{ public: string toString(){ string str; for(int i=0; i{ public: string toString(){ ulong chave[]; OsOrdem* valor[]; int qtd = CopyTo(chave,valor); string str; for(int i=0; i ver como se comportarah se chegar apos a retirada de uma ordem da colecao. } // este evento ocorre quando uma ordem sai da lista de ordens pendentes void osc_position::processarOrderDelete(const MqlTradeTransaction& tran){ // ordem que estah saindo da lista estah cancelada, entao retiramos do nosso banco de dados... if( tran.order_state == ORDER_STATE_CANCELED ){ m_ordens.Remove(tran.order); } } void osc_position::processarTransactionRequest(const MqlTradeTransaction& tran, const MqlTradeRequest& req , const MqlTradeResult& res ){ // nao processmos requisicoes de delecao de ordens. // as ordens deletedas sao retiradas do nosso banco de dados (m_ordens) durante o // processamento da transacao TRADE_TRANSACTION_ORDER_DELETE. if(req.action == TRADE_ACTION_REMOVE) return; // posicao vazia, adicione a ordem OsOrdem* ord; // Descobrindo qual a ordem da requisicao. // Na primeira requisicao de uma ordem, seu numero fica no resultado, nas demais, fica na requisicao. ulong order = req.order>0?req.order:res.order; // se a ordem jah estiver neste controle, atualizamos suas informacoes de requisicao e resultado senao, a incluimos. if( m_ordens.TryGetValue(order,ord) ){ // Como a ordem jah estava neste controle, soh atualizamos o tipo de transacao, caso esteja nulo. if (ord.typTra == NULL ) ord.typTra = tran.type; ord.reqAction = req.action ; // ENUM_TRADE_REQUEST_ACTIONS // Tipo de operação de negociação ord.mag = req.magic ; // ulong // Expert Advisor -conselheiro- ID (número mágico) // req.order ; // ulong // Bilhetagem da ordem //ord.symbol = req.symbol ; // string // Símbolo de negociação ord.reqVol = req.volume ; // double // Volume solicitado para uma encomenda em lotes ord.reqPrice = req.price ; // double // Preço // req.stoplimit ; // double // Nível StopLimit da ordem // req.sl ; // double // Nível Stop Loss da ordem // req.tp ; // double // Nível Take Profit da ordem // req.deviation ; // ulong // Máximo desvio possível a partir do preço requisitado //ord.reqTypOrd = req.type ; // ENUM_ORDER_TYPE // Tipo de ordem // req.type_filling ; // ENUM_ORDER_TYPE_FILLING // Tipo de execução da ordem // req.type_time ; // ENUM_ORDER_TYPE_TIME // Tipo de expiração da ordem // req.expiration ; // datetime // Hora de expiração da ordem (para ordens do tipo ORDER_TIME_SPECIFIED)) ord.reqComent = req.comment ; // string // Comentário sobre a ordem // req.position ; // ulong // Bilhete da posição // req.position_by ; // ulong // Bilhete para uma posição oposta ord.retCode = res.retcode ; ord.retOrder = res.order ; ord.retVol = res.volume ; ord.reqId = res.request_id ; // eh um fechamento de posicao, gravamos no log pra checar a perfomance... if( req.action==TRADE_ACTION_PENDING && strEhNumero(req.comment, ord.idToClose) ){ ord.inOut = -1; StringConcatenate( m_logPosicao,m_logPosicao,"CLOSE_BY:",ord.idOrd,":",ord.inOut,":",EnumToString(ord.typOrd),":",ord.vol,":",ord.reqPrice,":",ord.idToClose,":",getMicrosec(),":"); // string com os eventos ao longo da vida da posicao. } return; } // ordem ainda nao estah no controle. Colocamos agora... ord = new OsOrdem; ord.typTra = tran.type ; ord.idOrd = order ; ord.reqAction = req.action ; // ENUM_TRADE_REQUEST_ACTIONS // Tipo de operação de negociacao ord.mag = req.magic ; // ulong // Expert Advisor -conselheiro- ID (número magico) ord.symbol = req.symbol ; // string // Símbolo de negociacao ord.reqVol = req.volume ; // double // Volume solicitado para uma encomenda em lotes ord.reqPrice = req.price ; // double // Preco ord.reqTypOrd = req.type ; // ENUM_ORDER_TYPE // Tipo de ordem ord.reqComent = req.comment ; // string // Comentario sobre a ordem ord.retCode = res.retcode ; ord.retOrder = res.order ; ord.retVol = res.volume ; ord.reqId = res.request_id; m_ordens.Add(ord.idOrd, ord); return; } void osc_position::processarDealAdd(const MqlTradeTransaction& tran , const MqlTradeRequest& req , const MqlTradeResult& res , bool& closer , // true: trade eh um fechamento de posicao bool& toClose , // true: trade deve ser fechado ulong& toCloseidDeal , // se toClose=true este serah o ticket do trade a ser fechado double& toCloseVol , // se toClose=true este serah o volume do trade a ser fechado ENUM_DEAL_TYPE& toCloseTypeDeal, // se toClose=true este serah o sentido do trade a ser fechado, conforme ENUM_DEAL_TYPE double& toClosePriceIn , // se toClose=true este serah o preco do trade a ser fechado bool& toCloseOpenPos ){ // se toClose=true esta indicarah se a posicao foi aberta agora (primeiraOrdem) //Print(__FUNCTION__, ":-| Processandi ORDEM:",tran.order, " DEAL:", tran.deal, " POS ",tran.position, " deal_type:", EnumToString(tran.deal_type) ); closer = true; OsOrdem* ord; if( m_ordens.TryGetValue(tran.order, ord) ){ //Print(__FUNCTION__, ":-| ORDEM:",tran.order, " encontrada!" ); //ord.idOrd = tran.order ; // ok ord.idDea = tran.deal ; // ok ord.idPos = tran.position ; // ok ord.typTra = tran.type ; // ok //ord.typOrd = tran.order_type ; // ok ord.typDea = tran.deal_type ; // ok //ord.status = tran.order_state; // ok //ord.symbol = tran.symbol ; // ok ord.price = tran.price ; // ok ord.vol = tran.volume ; // ok }else{ //deal de uma ordem nao registrada, incluimos agora... //Print(__FUNCTION__, ":-| ORDEM:",tran.order, " NAO encontrada! Criando uma agora..." ); ord = new OsOrdem; ord.idOrd = tran.order ; // ok ord.idDea = tran.deal ; // ok ord.idPos = tran.position ; // ok ord.typTra = tran.type ; // ok //ord.typOrd = tran.order_type ; // ok ord.typDea = tran.deal_type ; // ok // ord.status = tran.order_state; // ok ord.symbol = tran.symbol ; // ok ord.price = tran.price ; // ok ord.vol = tran.volume ; // ok m_ordens.Add(ord.idOrd,ord); } // atualisando resumo da posicao e definindo se a ordem eh IN ou OUT... if( m_idPos==0 || m_idPos!=ord.idPos ){ // ordem de abertura da posicao //Print(__FUNCTION__, ":-| ORDEM:",tran.order," POSICAO estava zerada. Incluindo ordem na posicao:",ord.idPos ); Print(__FUNCTION__, ":-| NOVA POS:",ord.idPos," idDeal:",ord.idDea," ord:",tran.order," tranDealTyp:",EnumToString(tran.deal_type)," posAnt:",m_idPos ); m_idPos = ord.idPos ; // id da posicao atual m_type = ord.typDea; // o mesmo tipo do primeiro trade da posicao (compra ou venda). m_volIn = ord.vol ; // volume de trades IN. ord.inOut = 1; //---------- trade deve ser fechado toClose = true ; closer=false; toCloseVol = ord.vol ; toCloseidDeal = ord.idDea ; toCloseTypeDeal = ord.typDea; toClosePriceIn = ord.price ; toCloseOpenPos = true ; // esta eh a transacao de abertura da posicao //---------- }else{ // colocar o codigo para tratar a chegada de um deal de outra posicao //m_idPos = tran.position ; // id da posicao atual //Print(__FUNCTION__, ":-| ORDEM:",tran.order," Checando se eh a mesma direcao da posicao:", EnumToString(m_type) ); // transacao com o mesmo tipo da posicao, eh IN, senao eh OUT. if( m_type == ord.typDea ){ //&& m_volIn>m_volOut //Print(__FUNCTION__, ":-| direcao da posicao e da transacao sao iguais..." ); m_volIn += ord.vol; ord.inOut = 1; //---------- trade deve ser fechado toClose = true; closer=false; toCloseVol = ord.vol; toCloseidDeal = ord.idDea; toCloseTypeDeal = ord.typDea; toClosePriceIn = ord.price ; //---------- }else{ //Print(__FUNCTION__, ":-| direcao da posicao e da transacao sao diferentes..."); m_volOut += ord.vol; ord.inOut = -1; } toCloseOpenPos = false; // esta NAO eh a transacao de abertura da posicao //Print(__FUNCTION__, ":-| MESM POS:",ord.idPos," idDeal:",ord.idDea," ord:",tran.order," tranDealTyp:",EnumToString(tran.deal_type)); } //StringConcatenate( m_logPosicao,m_logPosicao,"\n:",tran.position,":",ord.idDea,":",ord.idOrd,":",ord.inOut,":",EnumToString(ord.typDea),":",ord.vol,":",ord.price,":",getMicrosec(),":::"); // string com os eventos ao longo da vida da posicao. //Print(__FUNCTION__, ":-| gravando no log da posicao...", m_logPosicao); // verificando se chegou o final da posicao... if( m_volIn <= m_volOut ){ StringConcatenate( m_logPosicao,m_logPosicao,"FINAL:"); // string com os eventos ao longo da vida da posicao. Print(m_logPosicao); //Print(__FUNCTION__, ":-| gravando FINAL no log da posicao..."); initialize(); } return; } //---------------------------------------------------------------------------- // Busca e retorna o comentario de uma ordem. // Se encontrar a ordem, retorna true grava o comentario na variavel comment // Se nao encontrar a ordem, retorna false. //---------------------------------------------------------------------------- bool osc_position::getComment( const ulong ticket, string& comment ){ OsOrdem* ord; if( m_ordens.TryGetValue(ticket, ord) ){ comment = ord.reqComent; return true; } return false; } //---------------------------------------------------------------------------- //+-----------------------------------------------------------+ //| | //+-----------------------------------------------------------+ void osc_position::onTradeTransaction( const MqlTradeTransaction& tran , // transacao const MqlTradeRequest& req , // request const MqlTradeResult& res , // result bool& closer , // true: trade eh um fechamento de posicao bool& toClose , // true: trade deve ser fechado ulong& toCloseidDeal , // se toClose=true este serah o ticket do trade a ser fechado double& toCloseVol , // se toClose=true este serah o volume do trade a ser fechado ENUM_DEAL_TYPE& toCloseTypeDeal, // se toClose=true este serah o sentido do trade a ser fechado, conforme ENUM_DEAL_TYPE double& toClosePriceIn , // se toClose=true este serah o preco do trade a ser fechado bool& toCloseOpenPos ){ // se toClose=true esta indicarah se a posicao foi aberta agora (primeiraOrdem) toClose = false; switch(tran.type){ case TRADE_TRANSACTION_ORDER_ADD: // adicao de nova ordem aberta... //processarOrderAdd (tran,req,res); break; case TRADE_TRANSACTION_ORDER_UPDATE: // modificacao de uma ordem em aberto //processarOrderUpdate (tran,req,res); break; case TRADE_TRANSACTION_REQUEST: // foi feito um pedido processarTransactionRequest(tran,req,res); break; case TRADE_TRANSACTION_DEAL_ADD: // adicao de novo negocio para o historico... processarDealAdd(tran,req,res,closer,toClose,toCloseidDeal,toCloseVol,toCloseTypeDeal, toClosePriceIn, toCloseOpenPos); break; case TRADE_TRANSACTION_ORDER_DELETE: // remocao de uma ordem da lista de ordens em aberto processarOrderDelete(tran); //Print(__FUNCTION__, ":", strTransaction (tran,req,res) ); break; case TRADE_TRANSACTION_HISTORY_ADD: // adicao de uma nova ordem para o historico... //Print(__FUNCTION__, ":", strTransaction (tran,req,res) ); break; //default: // Print(__FUNCTION__, ":", strTransaction(tran,req,res) ); } //Print( m_ordens.toString() ); }