int CMT5TradeHistory::Select(ulong ulMagic,ECurrencySymbol csSymbol,datetime dtFrom = MIN_DATETIME,datetime dtTill = NEVER_EXPIRES)
{
ASSERT(dtFrom <= dtTill);
// Очистим список ядер позиции
m_aoPosCores.Clear();
// Запросим историю ордеров и сделокif(HistorySelect(dtFrom,dtTill)!=true)
return(WRONG_VALUE);
// Соберем тикеты исторических позиций// Просмотрим все сделки выхода, и выпишем оттуда тикеты позиций.int iHistoryDealsTotal=HistoryDealsTotal();
CArrayLong alHistoryPosIDs;
int iI = WRONG_VALUE;
ulong ulCurTicket = 0;
long lCurPosID = 0;
long lCurMagic = 0;
long lCurEntry = 0;
string strCurSymbol;
for(iI=0;iI<iHistoryDealsTotal; ++iI)
{
ulCurTicket = HistoryDealGetTicket(iI);
if(ulCurTicket == 0)
return(WRONG_VALUE);
// Получим направление сделки if(HistoryDealGetInteger(ulCurTicket,DEAL_ENTRY,lCurEntry)!=true)
{
TRACE_INTEGER("Не удалось получить направление сделки ! Тикет: ",ulCurTicket);
continue;
};
// Проверим направление сделкиif(lCurEntry != DEAL_ENTRY_OUT)
continue;
// Получим магик сделкиif(HistoryDealGetInteger(ulCurTicket,DEAL_MAGIC,lCurMagic)!=true)
{
TRACE_INTEGER("Не удалось получить магик сделки ! Тикет: ",ulCurTicket);
continue;
};
// Проверим магикif(ulMagic != NULL && lCurMagic != ulMagic)
{
//TRACE_INTEGER("Сделка не подходит ! Имеет неверный магик ! Magic сделки: ",lCurMagic);//TRACE_INTEGER("Требуемый Magic : ",ulMagic);continue;
};
// Получим символ сделкиif(HistoryDealGetString(ulCurTicket,DEAL_SYMBOL,strCurSymbol)!=true)
{
TRACE_INTEGER("Не удалось получить символ ордера ! Тикет: ",ulCurTicket);
continue;
};
// Проверим символif(csSymbol != CS_UNKNOWN)
if(csSymbol == CS_CURRENT)
{
if(_Symbol2CurrencyEnum(strCurSymbol) != _Symbol2CurrencyEnum(Symbol()))
{
//TRACE2("Symbol выбираемой позиции: ",_Enum2CurrencySymbol(csSymbol));//TRACE2("Выбранный ордер имеет неверный символ: ",strCurSymbol);continue;
};
}
else
{
if(_Symbol2CurrencyEnum(strCurSymbol) != csSymbol)
{
//TRACE2("Symbol выбираемой позиции: ",_Enum2CurrencySymbol(csSymbol));//TRACE2("Выбранный ордер имеет неверный символ ! Символ ордера: ",poiBuffer.GetSymbolString());continue;
};
};
// Получим ID позицииif(HistoryDealGetInteger(ulCurTicket,DEAL_POSITION_ID,lCurPosID)!=true)
{
TRACE_INTEGER("Не удалось получить ID позиции ! Тикет: ",ulCurTicket);
continue;
};
// Проверим ID позицииif(lCurPosID <= NULL)
continue;
if(alHistoryPosIDs.Add(lCurPosID)!=true)
return(WRONG_VALUE);
}; // цикл перебора всех сделок// Здесь ID всех позиций собраны в массиве alHistoryPosIDs, необходимо убрать повторения (в позиции может быть много ордеров)
CArrayLong alUnicalHistoryPosIDs;
if(_DeleteDoubles(GetPointer(alHistoryPosIDs),GetPointer(alUnicalHistoryPosIDs))!=true)
return(WRONG_VALUE);
TRACE_INTEGER("Уникальных ID позиций в истории: ",alUnicalHistoryPosIDs.Total());
// Здесь массив alUnicalHistoryPosIDs заполнен уникальными ID позиций в истории.// Заполним ядра позиции
CMT5HistoryPositionInfoCore* phpiHistPosCore = NULL;
for(iI=0;iI<alUnicalHistoryPosIDs.Total(); ++iI)
{
//TRACE_INTEGER("Выберем позицию: ",iI);// Выберем очередной тикет
lCurPosID = alUnicalHistoryPosIDs.At(iI);
// Позиция является нужной компонентой
ASSERT(phpiHistPosCore == NULL);
phpiHistPosCore = new CMT5HistoryPositionInfoCore;
if(phpiHistPosCore == NULL)
{
m_aoPosCores.Clear();
ASSERT_DSC(false,"Не удалось создать объект CMT5HistoryPositionInfoCore по new");
return(WRONG_VALUE);
};
ASSERT_MYPOINTER(phpiHistPosCore);
if(phpiHistPosCore.SelectByID(lCurPosID)!=true)
{
TRACE("Не удалось создать выбрать позицию ! Возможно, позиция открыта, и еще не полностью в истории.");
TRACE_INTEGER("ID невыбранной позиции: ",lCurPosID);
delete phpiHistPosCore;
phpiHistPosCore = NULL;
continue;
};
ASSERT(phpiHistPosCore.GetTPCOpenTime() > MIN_DATETIME && phpiHistPosCore.GetTPCOpenTime() < phpiHistPosCore.GetTPCCloseTime() && phpiHistPosCore.GetTPCCloseTime() < NEVER_EXPIRES);
// Найдена и выбрана еще одна компонента позицииif(m_aoPosCores.Add(phpiHistPosCore) == false)
{
delete phpiHistPosCore;
m_aoPosCores.Clear();
ASSERT_DSC(false,"Не удалось добавить новый объект в список ядер позиции");
return(WRONG_VALUE);
};
phpiHistPosCore = NULL;
}; // цикл перебора уникальных PosID// TRACE_INTEGER("Ядер в выбранной позиции: ",m_aoPosCores.Total()); return(m_aoPosCores.Total());
};
历史类本身是抽象的TradeHistoryI接口的后裔。
class CTradeHistoryI: public CMyObject
{
public:
void CTradeHistoryI() { SetMyObjectType(MOT_TRADE_HISTORY_I); };
virtualvoid ~CTradeHistoryI() {};
// Выбор существующей истории. // Указывается магик и символ, по которому выбираются исторические ордера, а также промежуток времени, в котором необходимо искать их.// Если ulMagic = 0 - выбираются все позиции по всем магикам.// Если ECurrencySymbol = CS_UNKNOWN - выбираются все позиции по всем символам// Если ECurrencySymbol = CS_CURRENT - запрашивается функция Symbol(), и выбираются все позиции по этому символу// Возвращает число компонент позиции внутри истории (может быть нулевым если ничего не найдено) или WRONG_VALUE в случае ошибок// NOTE !!! // При выборе - отложенные ордера не учитываются.virtualint Select(ulong ulMagic = 0,ECurrencySymbol csSymbol = CS_CURRENT,datetime dtFrom = MIN_DATETIME,datetime dtTill = NEVER_EXPIRES) = 0;
virtualuint GetTotalComponents() const = 0; // Получение общего числа компонентvirtual CHistoryPosComponentI* GetComponent(uint uiComponentIdx) const = 0;
// Расширенный интерфейсvirtualvoid Sort(ESortTPCMode stmMode = STM_BY_OPEN_TIME_A) = 0;
// Функция ищет внутри истории компоненту с указанным тикетом. // В случае, если ее нет - возвращается false.// Если компонента найдена - возвращается true, и uiComponentIdx устанавливается на индекс компоненты внутри позиции.virtualbool FindComponentByTicket(long lTicket,uint &uiComponentIdx) const = 0;
};
然后你必须查一下底部的那四个括号指的是什么。
顺便说一句,当嵌套超过两层时,我就会非常紧张。 我尽量不这样写,把代码分散到各个函数上。
即使有两层嵌套--也要确保在每个闭合括号后写上注释--它埋葬了哪个块(例如,重复的循环头)。
至于风格,这是我为MT5选择历史头寸 的代码(由指定的魔术师,符号,有指定的日期范围)。
历史类本身是抽象的TradeHistoryI接口的后裔。
通过选择所需的历史 - 你可以重新计算其组件(MT5的头寸或MT4的订单),并获得任何组件的抽象接口。
对于MT4 - 有相应的历史类也从这些接口继承 - 因此,在同一时间,提供了跨平台 - EA不需要找到它的工作地点,所有与历史的工作是通过抽象接口完成的。
不要用这种风格来写永远不变的函数,也不要写永远不变的函数
简明扼要地写,反正也没人看,而且只需要一半的行数。
既然这些函数没有变化,你为什么要在那里放一堆不必要的大括号?移除它们,一切都会被压缩。因为你的例子看起来很荒谬:你自己模糊了代码,然后发明拐杖来减少它。
我同意,你可以再剪掉3行,缩短代码,但目的不是为了把代码用上,事实上它根本不是我的,而是为了缩短,这样的功能可以在一个屏幕上放5个,而不是一个。此后,程序更容易阅读,你不必滚动150次。而文件的重量也会减少。
不错的工作,我喜欢,但我不喜欢OOP,并尽量不使用它。 我不喜欢有线程划分的处理器(例如,4个核心和8个线程)。 必须清楚,划分和任何虚拟化对其实现来说都是性能的损失和机器时间的损失,无论是内核中的线程划分还是代码中函数的虚拟化。
我同意,你可以再剪掉3行,缩短代码,但目的不是为了把代码用上,事实上它甚至不是我的,而是为了缩短它,你可以在一个屏幕上放五个这样的函数,而不是一个。此后,程序更容易阅读,你不必滚动150次。而且文件的重量也减少了。
真诚的。
27英寸工作屏幕
我不打算重读了,我只是引用。"不要写那些总是不变的函数,永远不要改变 这种风格"
为什么要为一个在平台发布时只写一次、将来永远不会改变的函数挑花眼?你是否经常修改/编辑函数中的代码以获得手数、订单数 和典型?那为什么要把它延伸到32英寸显示器的3个屏幕上呢?
P.S. 所附代码是从kodobase上伪造的。
反问))))。我的MyFunc.mqh文件中就有这样的函数,我看不出压缩它有什么意义。为什么,为了在磁盘上节省10-20KB?坦率地说,这样的代码流让我感到恶心 ))
反问))))。我在MyFunc.mqh文件中有这样的函数,我看不出压缩它有丝毫意义。为什么,为了在磁盘上节省10-20KB?说实话,这个代码流让我感到恶心))。
对我来说,代码应该是清晰的、简短的、快速工作的,并且应该在所有条件下无错误地工作。
真诚的。
反问))))。我在MyFunc.mqh文件中有这样的函数,我看不出压缩它有丝毫意义。为什么,为了在磁盘上节省10-20KB?坦率地说,这样的代码流让我感到恶心 ))
因此,计算一下:1000个EA x 10 Kb = 10 Mb - 你已经要考虑节约了 ))
反问))))。我在MyFunc.mqh文件中有这样的函数,我看不出压缩它有丝毫意义。为什么,为了在磁盘上节省10-20KB?坦率地说,这样的代码流让 我感到恶心))
我也是,但是很久以前我就得出结论,代码必须被压缩在人们从不看它的地方,在那里它永远不会被纠正,也不会被纠正。
将用户代码散落在各处是一个额外的头痛问题,当你需要将一个文件拖 放到另一个终端,或分享它时,你将需要拖放几个文件。当然,你可以把includniks转移到所有的终端,但如果你在一个终端中改变或增加了一些东西,那么所有的终端都必须用新的终端替换。
专家顾问和指标非常小,没有必要将它们与程序主体分开。更正确地说,它们并不小,它们是单一的文件,它不像一个有10000个页面的网站,你不能没有类和嵌套。此外,现在有了结构,它们足以写出紧凑、100%可行的代码。
顺便说一句,当嵌套超过两层时,我就会非常紧张。 我尽量不这样写,把代码分散到各个函数上。
即使有两个嵌套层次--也要确保在每个闭合小括号后写上注释,它埋葬了哪个块(例如,重复的循环头)。
至于风格,这是我为MT5选择历史位置 的代码(通过指定的magik,符号,指定的日期范围)。
历史类本身是抽象的TradeHistoryI接口的后裔。
通过选择所需的历史 - 你可以重新计算其组件(MT5的头寸或MT4的订单),并获得任何组件的抽象接口。
对于MT4有相应的历史类,它们也继承自这些接口 - 因此同时提供了跨平台性 - 专家顾问不需要找到它的工作地点,所有与历史的工作都是通过抽象接口完成的。
看起来不错,我们能不能也看看TRACE_***和ASSERT?
要拖放一个文件 到另一个终端,或分享它,你需要拖动的不仅仅是一个文件,而是几个文件。当然,你可以把inludes转移到所有的终端,但如果你在一个终端中改变或增加了一些东西,那么你需要在所有的终端中用新的东西来替换它。