using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.ApplicationModel;
using Windows.ApplicationModel.Activation;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
// СTradePositionI переносимый интерфейс торговой позиции // Позиция состоит из компонент-наследников интерфейса CTradePosComponentI// // Реально для МТ4 имплементацией интерфейса является объект CMT4PositionInfo, для МТ5 - объект CMT5PositionInfo// CMT4PositionInfo представляет из себя массив объектов CMT4OrderInfo, наследников интерфейса CTradePosComponentI.// Фактически это массив МТ4-ордеров.// CMT5PositionInfo представляет из себя массив объектов CMT5PositionInfoCore, наследников интерфейса CTradePosComponentI.// Объект CMT5PositionInfoCore не имеет прямого аналога в МТ5-терминах, это два массива ордеров и сделок, а также структура данных,// имеющуая идентификатор позиции (m_lPosID или POSITION_IDENTIFIER), тикет магик, вид позиции, и так далее, по аналогии с МТ4-ордером,// фактически, массивы ордеров и сделок - это аналоги ордеров и сделок обычной неттинговой МТ5-позиции, а структура данных - относится// к хеджевой позиции, и имеет аналог МТ4-ордера. //// Реально при запросе у позиции компоненты CTradePosComponentI в МТ4 мы получаем указатель на ордер (класс CMT4OrderInfo),// а в МТ5 - на ядро позиции (класс CMT5PositionInfoCore) #include <MyLib\DebugOrRelease\DebugSupport.mqh>
#include <MyLib\Common\MyObject.mqh>
#include <MyLib\Common\CurSymEnum.mq5>
#include <MyLib\Common\TrendEnums.mqh>
#include <MyLib\Trade\TradePosComponentI.mqh>
class CTradePositionI: public CMyObject
{
public:
void CTradePositionI() { SetMyObjectType(MOT_TRADE_POSITION_I); };
virtualvoid ~CTradePositionI() {};
// Выбор существующей позиции. // Указывается магик и символ, по которому выбираются действующие ордера.// Если ulMagic = 0 - выбираются все позиции по всем магикам.// Если ECurrencySymbol = CS_UNKNOWN - выбираются все позиции по всем символам// Если ECurrencySymbol = CS_CURRENT - запрашивается функция Symbol(), и выбираются все позиции по этому символу// Возвращает число компонент позиции внутри позиции (может быть нулевым если позиции нет) или WRONG_VALUE в случае ошибок// Каждая фабрика (наследник CEAPartsFactoryT) имеет одну позицию, которая на каждом CEAPartsFactoryT::OnRefresh()// обновляется в соответствии с магиком и рабочим символом фабрики. virtualint Select(ulong ulMagic = 0,ECurrencySymbol csSymbol = CS_CURRENT) = 0;
virtualuint GetTotalComponents() const = 0; // Получение общего числа компонентvirtualuint GetNumOfComponentsOnDirection(ENUM_POSITION_TYPE etDirection) const = 0; // Получение числа компонент указанного направления (если tdDirection = TD_FLAT - то всех компонент) и интерфейс отдельной компонентыvirtual CTradePosComponentI* GetComponent(uint uiComponentIdx) const = 0;
// Расширенный интерфейс// Функция исследует позицию, и возвращает ее направление:// Если все компоненты - лонги, то вверх.// Если все компоненты - шорты, то вниз.// Если компонент нет - то флет. // Если компоненты обоих типов, то смотрим на флаг bFlatIfBoth. // Если этот флаг установлен - то возвращаем флет.// Если этот флаг сброшен - то смотрим на флаг bConsiderVolume.// Если этот флаг установлен - то сравниваем общие объемы лонгов и шортов. Если сброшен - сравниваем количество лонгов и шортов.// Каких позиций (или объемов) больше - то направление и возвращаем. // Если позиций (или объемов) одинаково - возвращаем флет.// NOTE !!! Функция не проверяет магик и символ компонент !virtual ETrendDirection GetDirection(bool bFlatIfBoth = true,bool bConsiderVolume = true) const = 0;
// Функция ищет внутри позиции компоненту с указанным тикетом. // В случае, если ее нет - возвращается false.// Если компонента найдена - возвращается true, и uiComponentIdx устанавливается на индекс компоненты внутри позиции.virtualbool FindComponentByTicket(long lTicket,uint &uiComponentIdx) const = 0;
};
贸易组件接口的文件如下(我已经在上面给出了,但我要重复一下。
// СTradePositionComponentI переносимый интерфейс компоненты торговой позиции #include <MyLib\DebugOrRelease\DebugSupport.mqh>
#include <MyLib\Common\MyObject.mqh>
#include <MyLib\Common\CurSymEnum.mq5>
#include <MyLib\Common\EnumsMT5ForMT4.mqh>
// CTradePosComponentI - компонента позиции. Имеет определенный магик, определенный символ, определенный тикет. // Для МТ4 компонента позиции - это МТ4-ордер.// Для МТ5 компонента позиции - это МТ5-позиция (одна для каждого символа при неттинге, и много для каждого символа при хедже).class CTradePosComponentI: public CMyObject
{
public:
void CTradePosComponentI() { SetMyObjectType(MOT_TRADEPOS_COMPONENT_I); };
virtualvoid ~CTradePosComponentI() {};
// Основной интерфейсvirtuallong GetTPCTicket() const = 0;
virtuallong GetTPCMagic() const = 0;
virtual ECurrencySymbol GetTPCSymbol() const = 0;
virtualENUM_POSITION_TYPE GetTPCType() const = 0;
virtualdatetime GetTPCOpenTime() const = 0;
virtualdouble GetTPCVolume() const = 0;
virtualdouble GetTPCOpenPrice() const = 0;
virtualdouble GetTPCStopLoss() const = 0;
virtualdouble GetTPCTakeProfit() const = 0;
virtualstring GetTPCCommentary() const = 0;
virtualbool IsTPCInUnloss() const { if(GetTPCStopLoss() <= 0 || GetTPCStopLoss() == EMPTY_VALUE) return(false); if(GetTPCType() == POSITION_TYPE_BUY) { if(GetTPCStopLoss() >= GetTPCOpenPrice()) return(true); } else { if(GetTPCStopLoss() <= GetTPCOpenPrice())return(true); }; return (false); };
virtualdouble GetTPDistance() const { if(GetTPCTakeProfit() == 0 || GetTPCTakeProfit() == EMPTY_VALUE) return(EMPTY_VALUE); if(GetTPCType() == POSITION_TYPE_BUY) return(GetTPCTakeProfit() - GetTPCOpenPrice()); return(GetTPCOpenPrice() - GetTPCTakeProfit()); };
virtualdouble GetSLDistance() const { if(GetTPCStopLoss() == 0 || GetTPCStopLoss() == EMPTY_VALUE) return(EMPTY_VALUE); if(GetTPCType() == POSITION_TYPE_BUY) return(GetTPCOpenPrice()- GetTPCStopLoss()); return(GetTPCStopLoss() - GetTPCOpenPrice()); };
};
class CHistoryPosComponentI: public CTradePosComponentI
{
public:
void CHistoryPosComponentI() { SetMyObjectType(MOT_HISTORYPOS_COMPONENT_I); };
virtualvoid ~CHistoryPosComponentI() {};
virtualdatetime GetTPCCloseTime() const = 0;
virtualdouble GetTPCClosePrice() const = 0;
virtualdouble GetTPCProfit() const = 0; // Возвращает профит по исторической позицииvirtualbool IsProfitClosePrice() const = 0; // Возвращает true, если цена зарытия отличается от цены открытия в прибыльную сторону // Возвращает профит исторической позиции для случая, когда бы ход цены (в сторону профита) был бы равен dPriceMove, а лот был бы единичным.// Функция используется для расчета лота для такой же позиции с нужным ходом цены // Рекомендуется отнимать от цены двойной спред.virtualdouble CalculateOneLotProfit(double dPriceMove) const = 0;
};
是的,这些单位都有。但相信我--它们被压缩到最大,而且用途广泛,因为它们能解决广泛的问题。
如果没有很多选择,你可以用ifs和swipe来解决。
为什么没有人决定争论 "带函数指针的程序化编程与不带函数指针的程序化编程"?
如果没有很多选择,你可以用ifs和swipe来解决。
Реter Konow:
1. Дело в работе которую нужно провести чтобы сжать в коде решения огромного количества задач.
2.关键是要普及代码,其中任何额外的语法技术和外壳都只是破坏性的。这是一项艰苦的工作,但它摆脱了一切多余的东西,使你能够不断发展,达到新的高度。
1.如果你能让工作变得轻松简单,为什么还要做这些工作?如果你能让它变得简单,为什么还要让它变得困难?
2.如果你使用OOP,通用化就不是破坏性的,而是成为一种自然的可能性,不会给任何东西带来负担。
1.既然可以轻松自如地完成工作,为什么还要做呢?为什么要做一些容易做的事,而做起来却很困难?
2.如果你使用OOP,那么通用化就不会被破坏,而是成为一种自然的可能性,不会给任何东西带来负担。
我们可以继续这个论点很长时间。用一个100个拖曳任务的例子,我表明了我对这种解决方法的态度。我认为,愚蠢的任务不应该被解决,而应该被修复。如果OOP能帮助那些在提出和正确解决任务方面比较弱的人,就让它帮助他们吧。但是对于那些在开始解决任务之前就对任务进行优化的人来说,可能根本不需要OOP。
我们可以不断地进行这种争论。用一个100个拖曳任务的例子,我表明了我对这种解决方法的态度。我认为,愚蠢的任务不应该被解决,而应该被修复。如果OOP能帮助那些在提出和正确解决任务方面比较弱的人,就让它帮助他们吧。但是对于那些在开始解决任务之前就对任务进行优化的人来说,可能根本不需要OOP。
你没怎么编过代码(可能),OOP就像一股空气。
大多数人编码不是为了兴趣或自我发展,这是他们的工作,而结果才是最重要的。
它没有那么方便,但就速度能力而言,你可以只用指针就能搞定。
而方便是一个相对的概念。
Dmitry,当然使用OOP 会降低一些性能。但这是百分之一的几分之一。
但是,OOP是如何提高程序员的性能的!?
这是我的一个项目中的一个小例子,它是为了感知而切割的,但实际上还有很多其他的东西被考虑在内。
例如,让我们以.NET为例,因为所有的API都由类组成。
我非常喜欢.NET范式。 顺便说一下,有一个伟大的终端cAlgo,你可以直接在Visual Studio中用C#编写
Dimitri,当然使用OOP 会降低一些性能。但这是百分之一的零头。
如果变体数量少,就会减慢速度,但如果变体数量太多,就会成为一种优势。
最重要的是,OOP中变体的数量并不影响性能。而在程序化编程中,你的头顶上有一个天花板。
好吧,你把事情搞得一团糟......。
很明显,任何任务都可以用OOP风格来解决,包括分配接口、建立继承层次、声明虚拟函数,也可以用纯程序风格来解决--你甚至可以把所有东西都放在一个巨大的函数中。
问题在于支持的便利和效率。
在MT--最适合OOP的地方是订单系统。就个人而言,我有 "位置 "和 "位置组件 "的虚拟接口。"头寸 "在MT4中是一组订单,在MT5中是一组头寸。"头寸组成部分 "是指单个订单或单个MT5头寸(对冲或净值)。
这是实际的界面文件(Retag Konow,你可以欣赏到与代码量相比,注释的数量,当我遇到我不记得一些细微之处,我定期在那里添加注释。例如,我经常忘记哪些真实物体构成了 "位置组件"。我只是不需要记住它--专家顾问根据界面与组件一起工作,现实中界面后面是什么并不重要。但是,我必须在修改过程中回到它 - 这就是为什么我经常需要这个文件中的第一个注释)。
贸易组件接口的文件如下(我已经在上面给出了,但我要重复一下。
根据这些接口--我同时实现了MT4和MT5的订单系统,用于真实和历史订单。
请求建仓的专家顾问收到这个界面,不必考虑MT4和MT5订单之间的差异。如果增加了一个新的订单类型,或者改变了与它们的工作顺序--对专家顾问来说不会有任何改变,只会增加新的订单类型类,它也将支持这个接口。
在引入对冲账户时,该系统有很大的意义。专家们一点也没有改变。
Reg Konow,你是如何处理MT4和MT5中订单类型的差异的?
如果引入一个新的账户类型(除了套期保值和净额结算外)--需要做哪些改变,而且是在同一个地方?
我的看法是,如果你把所有的代码都记得一清二楚,而且你可以很容易地说出为什么你的代码中的这一行或那一行是一年前写的--那么,这是真的,所有这些OOP的改进都只是不必要的姿态。
当你在修改代码时不记得所有的事情时,OOP是必要的--OOP允许将区块相互隔离,将任何特定时刻可用的实体集合限制在程序的特定位置。
好吧,你把事情搞得一团糟......。
1.很明显,任何任务都可以用OOP风格来解决,包括分配接口、建立继承层次、声明虚拟函数,也可以用纯程序风格来解决--我们甚至可以把所有东西都放到一个巨大的函数里。
问题在于支持的便利和效率。
2.在MT--最适合OOP的地方是订单系统。就个人而言,我有虚拟接口 "位置 "和 "位置组件"。"头寸 "在MT4中是一组订单,在MT5中是一组头寸。"头寸组成部分 "是指单个订单或单个MT5头寸(套期保值或净值化)。
3.这是实际的界面文件(Retag Konow,你可以欣赏到与代码量相比,注释的数量,当我遇到我不记得一些细微之处,我定期在那里添加注释。例如,我经常忘记哪些真实物体构成了 "位置组件"。我只是不需要记住它--专家顾问根据界面与组件一起工作,现实中界面后面是什么并不重要。但是,我必须在修改过程中回到它 - 这就是为什么我经常需要这个文件中的第一个注释)。
贸易组件接口的文件如下(我已经在上面给出了,但我要重复一下。
根据这些接口--我同时实现了MT4和MT5的订单系统,用于真实和历史订单。
请求建仓的专家顾问收到这个界面,不必考虑MT4和MT5订单之间的差异。而如果增加了新的订单类型,或者改变了与它们的工作顺序--对专家顾问来说,什么都不会改变,只是增加了一个新的订单类型,它也将支持这个界面。
该系统被证明是非常合理的,当时引入了对冲账户。专家们在这一点上没有任何改变。
4.Reg Konow,你是如何处理MT4和MT5中订单类型的差异的?
如果引入一个新的账户类型(除了套期保值和净额结算外)--需要做哪些改变,而且是在同一个地方?
我认为,如果你对你的所有代码都记得一清二楚,而且你可以很容易地说出一年前为什么要在你的代码中写这一行或那一行--那么所有这些OOP增强器都只是不必要的姿态。
恰恰是当你在修改代码时不记得所有的东西时,OOP是必要的--OOP允许你将块相互隔离,以限制在任何特定时刻可用的实体集在程序中的特定位置。
1.1.我完全同意。唯一的区别在于以这种或那种方式解决任务的有效性。
2.我没有真正使用过订单系统,也看不出它的结构有什么技术问题。也许有,但我们需要一个具体的任务,然后就会清楚我在没有OOP的情况下能如何有效地解决它。
3.在我看来,从可读性的角度来看,给出的代码样本简直是糟糕透顶。难怪需要这么多评论,也难怪你会忘记它的内容。对不起,但这是我主观的第一印象。这只是令人毛骨悚然。
下面是我的代码可读性的一个例子--定义控件项颜色的函数。
正如你所看到的,评论在这里几乎是不必要的。我所有的代码都是用这种风格写的。所以我对它非常了解,不管它是什么尺寸,我都能记住它。
在我看来,你的问题解决系统中存在一些缺陷。问题本身应该是非常清晰和准确的,因此它的解决方案也是如此。如果解决方案是云里雾里的,并由 "事实证明系统是非常合理的 "这句话来定义(在270Kb的代码中怎么可能是合理的呢!),这意味着作者对他的系统如何工作有一个粗略的理解。而解决方案中可怕的语法构思和多余的实体,使他无法理解到最后。
为了使解决方案有效,必须切断不必要的实体,而且必须完全看清问题。