对巴解组织的看法很有意思 - 页 11

 
Georgiy Merts:

"神化 "我认为是fxsaber的一种表达方式,关于这一点,他自己也说不出它是如何工作的,只是说 "这个代码已经被反复测试过,它是有效的"。在我看来,情况不应该是这样。

这段代码检查是否可以执行 otfFilingType命令,如果strSymbol上有该命令,则返回该命令,否则就正确。


我完全不知道它是如何工作的。而只依靠fxsaber的权威。

也许有人可以解释一下?

为了理解它,只要把这个繁琐的返回表达式拆成它的组成部分。

 
Igor Makanu:

你的例子来自 "目的决定手段"。

顺便说一下,这段代码就像意大利面条一样,但考虑到它可能是kodobase中目前最有用的作者,而且我自己也在使用他的代码,让别人来批评一下吧。

 
Andrei Trukhanovich:

顺便说一下,这段代码就像意大利面条,但鉴于它可能是kodobase中目前最有用的作者,而且我自己也按原样使用他的代码,让别人来批评一下吧。

这不是批评的问题,我想弄清楚它能做什么....。但正如采访所显示的,以及@fxsaber 自己所承认的--除了头疼,什么都没有


SZZ:这很有可能,最初的小怪物 的变体看起来更清楚;)

 
Igor Makanu:

ZS:高概率,原版的小怪物 看起来更明显;)

ZIP 中获取(包含第一个版本)。

  static bool VirtualOrderSelect( const TICKET_TYPE Index, const int Select, const int Pool = MODE_TRADES )
  {
    return(VIRTUAL::SelectOrders ? VIRTUAL::SelectOrders.OrderSelect(Index, Select, Pool) :
           #ifdef __MQL5__
             #ifdef __MT4ORDERS__
               ::OrderSelect(Index, Select, Pool)
             #else // __MT4ORDERS__
               false
             #endif // __MT4ORDERS__
           #else // __MQL5__
             ::OrderSelect(Index, Select, Pool)
           #endif // __MQL5__
           );
  }

但在那之后,需要的功能越来越多,代码也慢慢充实起来。填充功能则不同。那里没有什么东西是充实的,是一下子写出来的。

 
Vasiliy Sokolov:

只有编译器知道它到底要做什么。现代编译器具有惊人的启发式功能。他们适应一般的编码员,已经更清楚他或她需要什么。编译器能做的最好的事情就是用简短的函数 编写简单明了的代码。对于编译器来说,分析由许多函数节点组成的源代码图来构建所产生的程序是更容易和更有效的。它只会对生产力产生积极影响,因为所需的功能将被锁定在所有正确的地方。

你说得很对。

如果我们谈论的是MQL5,你可以忘记10-20-30年前的 "优化 "方法。你需要写出最可读的代码。就是它,而不是黑客的东西和纯粹的自作聪明。

为什么?

因为编译器会经过5-10个周期的代码重排,它的清晰度和简洁度令人惊叹,更不用说使用了几十种优化模式。

MQL5编译器对人类试图使+2%的速度感到好笑。


如果你有兴趣,可以看看数学计算 没有分支,一条命令(128位数据)就可以同时计算两个根

这段代码变成了以下汇编的SSE代码:

         D1=sqrt((X1-X)*(X1-X)+(Y1-Y)*(Y1-Y));
         D2=sqrt((X2-X)*(X2-X)+(Y2-Y)*(Y2-Y));
         D3=sqrt((X3-X)*(X3-X)+(Y3-Y)*(Y3-Y));
         D4=sqrt((X4-X)*(X4-X)+(Y4-Y)*(Y4-Y));
         D5=sqrt((X5-X)*(X5-X)+(Y5-Y)*(Y5-Y));
         D6=sqrt((X6-X)*(X6-X)+(Y6-Y)*(Y6-Y));
         D7=sqrt((X7-X)*(X7-X)+(Y7-Y)*(Y7-Y));
         D8=sqrt((X8-X)*(X8-X)+(Y8-Y)*(Y8-Y));
        ...
        sqrtsd  xmm1, xmm1
        unpcklpd        xmm4, xmm4
        movapd  xmm3, xmmword ptr [rsp + 432]
        unpcklpd        xmm3, xmmword ptr [rsp + 384]
        subpd   xmm3, xmm4
        mulpd   xmm3, xmm3
        unpcklpd        xmm0, xmm0
        movapd  xmm5, xmmword ptr [rsp + 416]
        unpcklpd        xmm5, xmmword ptr [rsp + 400]
        subpd   xmm5, xmm0
        mulpd   xmm5, xmm5
        addpd   xmm5, xmm3
        sqrtpd  xmm8, xmm5
        movapd  xmm5, xmmword ptr [rsp + 464]
        subpd   xmm5, xmm4
        mulpd   xmm5, xmm5
        movapd  xmm7, xmm9
        subpd   xmm7, xmm0
        mulpd   xmm7, xmm7
        addpd   xmm7, xmm5
        movapd  xmm6, xmm10
        unpcklpd        xmm6, xmm11
        subpd   xmm6, xmm4
        movapd  xmm3, xmmword ptr [rsp + 368]
        unpcklpd        xmm3, xmmword ptr [rsp + 352]
        subpd   xmm3, xmm0
        movapd  xmm4, xmm8
        shufpd  xmm4, xmm4, 1
        sqrtpd  xmm5, xmm7
        mulpd   xmm6, xmm6
        mulpd   xmm3, xmm3
        addpd   xmm3, xmm6
        sqrtpd  xmm15, xmm3
        movapd  xmm0, xmm14
        unpcklpd        xmm0, xmmword ptr [rsp + 336]
        subpd   xmm0, xmm2
        mulpd   xmm0, xmm0
        movapd  xmm2, xmm0
        shufpd  xmm2, xmm2, 1
        addsd   xmm2, xmm0
        movapd  xmm0, xmm15
        shufpd  xmm0, xmm0, 1
        sqrtsd  xmm12, xmm2
这实际上是一件艺术作品。8个根是在4次调用汇编命令中计算出来的。在一次通话中计算了两个双数。

  • 当在数组中工作时,一切都很正常,有检查、分支和双数->整数索引转换的损失。

  • 在这个例子中,当处理数组时,会出现持续的FPU/ALU混合,这对性能非常不利。

  • 对动态数组访问的优化非常好--无可非议。但混合FPU/ALU操作+双数->整数+分支的方式会浪费时间

  • 总的结论是:由于完美的优化,数学在MQL5中获胜。这里输的不是数组,而是数学赢了。


     
    Georgiy Merts:

    这是为什么呢?

    相反,用两个 "if "比用 "or "运算符要容易得多。

    显然,先追踪一个条件,如果为真就离开函数,然后检查另一个条件,如果为真也离开,比通过逻辑上的 "或"(很容易与 "和 "混淆)来弄清一个复杂条件的结果,并追踪两种返回方式更容易。

    在下面读到 "这样做的理由是调试 "是相当有趣的,因为这意味着这样的代码更容易理解(否则为什么在调试?)

    "神化 "我认为是fxsaber的一种表达方式,关于这一点,他自己也说不出它是如何工作的,只是说 "这个代码已经被反复测试过,它是有效的"。在我看来,情况不应该是这样。

    这段代码检查是否可以执行 otfFilingType命令,如果strSymbol上有该命令,则返回该命令,否则就正确。


    我完全不知道它是如何工作的。而只依靠fxsaber的权威。

    也许有人可以解释一下?

    我曾经坐下来,一步一步地把它拆开,似乎需要笔和纸)

    为什么这种解析是有用的--我的理解是,在改变枚举结构的情况下,一切都会被破坏),因为使用了枚举值的整数关系(根据枚举的概念本身应该被封装起来)。我自己也尽量避免这种情况,最多是多一事不如少一事的比例。对于那些与WinAPI打交道的人来说,它可能是熟悉的。

     
    Andrey Khatimlianskii:

    为了理解,你所要做的就是把那个不方便的retournee表述拆开。

    是的,这就是我所尝试的。但我没有足够的动力去拆开它......。

     
    Renat Fatkhullin:

    完全正确。

    如果我们谈论的是MQL5,你可以忘记10-20-30年前的 "优化 "方法。你需要写出最可读的代码。就是它,而不是黑客的东西和纯粹的自作聪明。

    正是如此。我很久以前就得出了这个结论。但不是因为我认为编译器会让它变得更好。但因为代码中问题的主要来源是人本身,这意味着人们在写代码时应该尽可能地使其简单和透明。

    如果你不能使它 "透明",你必须写出详细的评论,为什么是这样,而不是那样。

    而编译器...即使它做得不够有效,也不至于因为你没有考虑到程序的某些方面而成为一个潜在的错误。

     
    fxsaber:

    该代码非常简单和简短(描述)。如果你把它写在FP上,比较起来会很有趣。

    请。FP风格的C#。


    using System;
    using System.Linq;
    using System.Collections.Generic;
    using static FeesCalculator.FeesCalcs;
    using System.Text;
    using static System.Math;
    
    namespace FeesCalculator
    {
        public static class EnumerableExt
        {
            /// <summary>
            /// Call of function 'action' for each element if sequence (mapping).
            /// </summary>
            /// <typeparam name="T"></typeparam>
            /// <param name="seq">Enumerable sequence</param>
            /// <param name="action">Need action</param>
            public static void Map<T>(this IEnumerable<T> seq, Action<T> action)
            {
                foreach (var item in seq)
                    action(item);
            }
        }
        /// <summary>
        /// Инвестиционный результат
        /// </summary>
        public record AccountRecord
        {
            public double Investor { get; init; }
            public double Manager { get; init; }
            public double Summary { get; init; }
    
            public static AccountRecord operator *(AccountRecord r, double v)
            {
                return new AccountRecord
                {
                    Investor = r.Investor * v,
                    Manager = r.Manager * v,
                    Summary = r.Summary * v
                };
            }
            public override string ToString()
            {
                StringBuilder sb = new StringBuilder();
                sb.Append(nameof(Investor)).Append(" = ").Append(Investor.ToString("F4")).Append(' ');
                sb.Append(nameof(Manager)).Append(" = ").Append(Manager.ToString("F4")).Append(' ');
                sb.Append(nameof(Summary)).Append(" = ").Append(Summary.ToString("F4"));
                return sb.ToString();
            }
        }
        /// <summary>
        /// Параметры оферты
        /// </summary>
        public record PammSet
        {
            /// <summary>
            /// Доходность за расчетный период
            /// </summary>
            public double Perfomance { get; init; }
            /// <summary>
            /// Вознаграждение управляющего
            /// </summary>
            public double Gift { get; init; }
            /// <summary>
            /// Количество расчетных периодов
            /// </summary>
            public int N { get; init; }
            /// <inheritdoc/>
            public override string ToString()
            {
                StringBuilder str = new StringBuilder();
                str.Append("Доходность за расчетный период: ").Append((Perfomance * 100.0).ToString("F1")).Append("%\t\n");
                str.Append("Вознаграждение управляющего: ").Append((Gift * 100.0).ToString("F1")).Append("%\t\n");
                str.Append("Количество расчетных периодов: ").Append(N);
                return str.ToString();
            }
    
        }
        /// <summary>
        /// Формулы расчета
        /// </summary>
        public class FeesCalcs
        {
            /// <summary>
            /// Если управляющий снимает деньги в конце каждого расчетного периода
            /// </summary>
            /// <param name="Performance"></param>
            /// <param name="Gift"></param>
            /// <param name="N"></param>
            /// <returns></returns>
            public static AccountRecord Set1(PammSet set)
            {
                Func<double> investor = () => Pow(1 + (set.Perfomance) * (1 - set.Gift), set.N);
                Func<double> manager = () => (investor() - 1) * set.Gift / (1 - set.Gift);
                AccountRecord ac = new AccountRecord
                {
                    Investor = investor(),
                    Manager = manager(),
                    Summary = investor() + manager()
                };
                return ac;
            }
            /// <summary>
            /// Если ничего не делалось в расчетные периоды
            /// </summary>
            /// <param name="Performance"></param>
            /// <param name="Gift"></param>
            /// <param name="N"></param>
            /// <returns></returns>
            public static AccountRecord Set2(PammSet set)
            {
                Func<double> summary = () => Pow(set.Perfomance + 1, set.N);
                Func<double> manager = () => (summary() - 1) * set.Gift;
                double s = summary();
                double d = manager();
                AccountRecord ac = new AccountRecord
                {
                    Summary = summary(),
                    Manager = manager(),
                    Investor = summary() - manager()
                };
                return ac;
            }
            /// <summary>
            /// Если управляющий снимает деньги в конце каждого расчетного периода и реинвестирует их
            /// </summary>
            /// <param name="Performance"></param>
            /// <param name="Gift"></param>
            /// <param name="N"></param>
            /// <returns></returns>
            public static AccountRecord Set3(PammSet set)
            {
                Func<double> summary = () => Pow(set.Perfomance + 1, set.N);
                Func<double> investor = () => Pow(1 + (set.Perfomance) * (1 - set.Gift), set.N);
                return new AccountRecord
                {
                    Summary = summary(),
                    Investor = investor(),
                    Manager = summary() - investor()
                };
            }
            /// <summary>
            /// Сопостовление: описание - функция расчета
            /// </summary>
            public static readonly Dictionary<string, Func<PammSet, AccountRecord>> DescrToAccountRecord = new Dictionary<string, Func<PammSet, AccountRecord>>
            {
                {"Если управляющий снимает деньги в конце каждого расчетного периода (1)", Set1 },
                {"Если ничего не делалось в расчетные периоды (2)", Set2 },
                {"Если управляющий снимает деньги в конце каждого расчетного периода и реинвестирует их (3)", Set3 },
            };
        }
        class Program
        {
            static void Main(string[] args)
            {
                var _ = args.Select((a) => double.Parse(a)).Take(3).ToList();
                PammSet pamm = new PammSet
                {
                    Perfomance = _[0]/100.0,
                    Gift = _[1]/100.0,
                    N = (int)_[2]
                };
                Console.WriteLine($"Данные для инвестиционного счета со следующими характеристиками:\n\n{pamm}\n");
                Console.WriteLine("Конечный результат для Инвестора, Управляющего и Суммарно:\n");
                Func<KeyValuePair<string, Func<PammSet, AccountRecord>>, string> f = (kvp) => kvp.Key + ".\n" + kvp.Value(pamm).ToString() + "\n";
                Enumerable.Select(DescrToAccountRecord, f).Map((s) => Console.WriteLine(s));
                Console.WriteLine(pamm);
                Func<int, PammSet> toPamm = (n) => new PammSet { Perfomance = pamm.Perfomance, Gift = pamm.Gift, N = n };
                Func<PammSet, IEnumerable<AccountRecord>> toAccs = (n) => DescrToAccountRecord.Select((s) => s.Value(n));
                var accounts = Enumerable.Repeat(1, pamm.N).Select((a, b) => a + b).Select(toPamm).Select(toAccs);
                Func<AccountRecord, string> toString = (ar) => ar.Investor.ToString("F2") + "\t" +
                                                               ar.Manager.ToString("F2") + "\t" +
                                                               ar.Summary.ToString("F2") + "\t";
                int period = default;
                accounts.Map
                (
                    (en) => 
                    {
                        Console.Write($"{++period}:\t");
                        en.Map((ar) =>
                            Console.Write(toString(ar)));
                        Console.WriteLine();
                    }
                );
            }
        }
    }
    

    当然,FP是相当歪的(因为它是由一个歪的FP编码员写的,在不完整的FP语言C#中).但目标是表明,在现代OOP术语上,你也可以用FP来做。当然,它是有限的,它不是F#或Haskell,但没有人禁止用FP风格写作。使用不可变性、高阶函数、闭包、映射等。- 欢迎你来做这一切。但由于某些原因,这并不能使代码变得完美。

    s.w.整体的代码结构刻意模仿了原作。虽然在一个好的方式,它应该是相当不同的FP,没有复杂的对象和foreach模仿地图,但艺术家画,因为他可以。

     
    Vasiliy Sokolov:

    请。FP风格的C#。

    我明白这是一个习惯和语法知识的问题,但我很难进入代码,尽管我是原作者。

    关于交易、自动交易系统和策略测试的论坛

    关于OOP的有趣观点

    fxsaber, 2021.01.29 13:39

    一个小事。

    #property strict
    #property script_show_inputs
    
    input double inPerformance = 100; // Сколько процентов дает система за период
    input double inGift = 50;         // Награда управляющего в процентах (< 100)
    input int inN = 12;               // Сколько расчетных периодов
    
    struct BASE
    {
      double Investor;
      double Manager;
      double Summary;
    
      // Если управляющий снимает деньги в конце каждого расчетного периода.
      void Set1( const double Performance, const double Gift, const int N )
      {
        this.Investor = ::MathPow(1 + (Performance - 1)* (1 - Gift), N);
        this.Manager = (this.Investor - 1) * Gift / (1 - Gift);
        this.Summary = this.Investor + this.Manager;
    
        return;
      }
    
      // Если ничего не делалось в расчетные периоды.
      void Set2( const double Performance, const double Gift, const int N )
      {
        this.Summary = ::MathPow(Performance, N);
        this.Manager = (this.Summary - 1) * Gift;
        this.Investor = this.Summary - this.Manager;
    
        return;
      }
    
      // Если управляющий снимает деньги в конце каждого расчетного периода и реинвестирует их.
      void Set3( const double Performance, const double Gift, const int N )
      {
        this.Summary = ::MathPow(Performance, N);
        this.Investor = ::MathPow(1 + (Performance - 1)* (1 - Gift), N);
        this.Manager = this.Summary - this.Investor;
    
        return;
      }
    
      void operator *=( const double Deposit = 1 )
      {
        this.Investor *= Deposit;
        this.Manager *= Deposit;
        this.Summary *= Deposit;
    
        return;
      }
    #define  TOSTRING(A) #A + " = " + ::DoubleToString(A, 4) + " "
      string ToString( const bool FlagName = true ) const
      {
        return(FlagName ? TOSTRING(Investor) + TOSTRING(Manager) + TOSTRING(Summary)
                        : ::StringFormat("||%-12.4f||%-12.4f||%-12.4f||", this.Investor, this.Manager, this.Summary));
      }
    #undef  TOSTRING
    
    };
    
    struct PAMM
    {
      double Performance; // Доходность за расчетный период
      double Gift;        // Вознагражение управляющего.
      int N;              // Сколько расчетных периодов.
    
      BASE Base1; // Если управляющий снимает деньги в конце каждого расчетного периода.
      BASE Base2; // Если ничего не делалось в расчетные периоды.
      BASE Base3; // Если управляющий снимает деньги в конце каждого расчетного периода и реинвестирует их.
    
      void Set( const double dPerformance, const double dGift, const int iN )
      {
        this.Performance = dPerformance;
        this.Gift = dGift;
        this.N = iN;
    
        this.Base1.Set1(1 + this.Performance / 100, this.Gift / 100, this.N);
        this.Base2.Set2(1 + this.Performance / 100, this.Gift / 100, this.N);
        this.Base3.Set3(1 + this.Performance / 100, this.Gift / 100, this.N);
      }
    
      void operator *=( const double Deposit = 1 )
      {
        this.Base1 *= Deposit;
        this.Base2 *= Deposit;
        this.Base3 *= Deposit;
    
        return;
      }
    
      string GetDescription( void ) const
      {
        return("Доходность за расчетный период " + ::DoubleToString(this.Performance, 1) + "%\n" +
               "Вознагражение управляющего " + ::DoubleToString(this.Gift, 1) + "%\n" +
               "Количество расчетных периодов. " + (string)this.N);
      }
    
      string ToString( const bool FlagName = true, const bool FlagDescription = true ) const
      {
        return(FlagDescription ? "Данные для инвестиционного счета со следующими характеристиками:\n\n" + this.GetDescription() +
                                 "\n\nКонечный результат для Инвестора, Управляющего и Суммарно:"
                                 "\n\nЕсли управляющий снимает деньги в конце каждого расчетного периода (1).\n" + this.Base1.ToString(FlagName) +
                                 "\n\nЕсли ничего не делалось в расчетные периоды (2).\n" + this.Base2.ToString(FlagName) +
                                 "\n\nЕсли управляющий снимает деньги в конце каждого расчетного периода и реинвестирует их (3).\n" + this.Base3.ToString(FlagName)
                               : this.Base1.ToString(FlagName) + this.Base2.ToString(FlagName) + this.Base3.ToString(FlagName));
      }
    };
    
    void OnStart()
    {
      PAMM Pamm;
    
      Pamm.Set(inPerformance, inGift, inN);
    
      Print(Pamm.ToString());
    
      string Str = Pamm.GetDescription() + "\n   ";
    
      for (int i = 1; i <= 3; i++ )
        Str += ::StringFormat("||%-12s||%-12s||%-12s||", "Investor" + (string)i, "Manager" + (string)i, "Summary" + (string)i);
    
      for (int i = 1; i <= inN; i++ )
      {
        Pamm.Set(inPerformance, inGift, i);
    
        Str += StringFormat("\n%-2d:", i) + Pamm.ToString(false, false);
      }
    
      Print(Str);
    }

    从技术上讲,这可能是一个OOP。但其中最原始的部分。不过,没有它就做不到。可能是,笨重的大脑重新排列,铆足了劲儿这。