"Apoteosi" considero un'espressione di fxsaber, sulla quale lui stesso non poteva dire come funziona, affermando semplicemente che "il codice è stato ripetutamente testato, e funziona". Questo, secondo me, non dovrebbe essere il caso:
Questo codice controlla seun ordine otfFilingType può essereeseguito, e lo restituisce se è disponibile su strSymbol, altrimenti è corretto.
Non ho assolutamente idea di come funzioni. E fare affidamento solo sull'autorità di fxsaber.
Forse qualcuno può spiegare?
Per capirlo, basta smontare questa ingombrante espressione di ritorno nei suoi componenti.
comunque questo codice è proprio come degli spaghetti, ma considerando che è probabilmente l'autore più utile in kodobase in questo momento e io stesso uso i suoi codici così come sono, lasciamo che qualcun altro critichi
comunque questo codice è proprio come degli spaghetti, ma dato che è probabilmente l'autore più utile in kodobase in questo momento e io stesso uso i suoi codici così come sono, lasciamo che qualcun altro critichi
non si tratta di critica, sto cercando di capire cosa può fare.... Ma come mostra l'intervista, e come ha ammesso lo stesso@fxsaber- nient'altro che mal di testa
SZZ: è molto probabile che la variante iniziale del piccolo mostro abbia un aspetto più chiaro ;)
Ma in seguito c'era bisogno di sempre più funzionalità, e il codice stava lentamente diventando più corposo. Era diverso con la funzione Filling. Non c'era niente di definito, è stato scritto in una volta sola.
Solo il compilatore sa esattamente cosa farà. I compilatori moderni hanno un'euristica sbalorditiva. Si adattano al codificatore medio e sanno già meglio di cosa ha bisogno. La cosa migliore che un compilatore può fare è scrivere codice semplice e diretto con funzioni brevi. È più facile ed efficiente per il compilatore analizzare il grafo del codice sorgente composto da molti nodi di funzione per costruire il programma risultante. Avrà solo un effetto positivo sulla produttività, poiché le funzioni necessarie saranno bloccate in tutti i posti giusti.
Hai assolutamente ragione.
Se stiamo parlando di MQL5, potete dimenticare i metodi di "ottimizzazione" di 10-20-30 anni fa. Dovete scrivere il codice più leggibile. È così, e non la roba da hacker e la pura furbizia.
Perché?
Poiché il compilatore passa attraverso 5-10 cicli di riordino del codice, è incredibilmente chiaro e conciso, per non parlare dell'uso di decine di modelli di ottimizzazione.
Il compilatore MQL5 è divertito dai tentativi umani di fare +2% di velocità.
Se vi interessa, guardate come calcoli SQRT + matematici vanno senza ramificazioni e un comando (128 bit di dati) calcola due radici in una volta
Questo codice si trasforma nel seguente codice assembler SSE:
Questa è un'opera d'arte in realtà. 8 radici sono state calcolate in 4 chiamate del comando assembler. Due numeri doppi sono stati calcolati in una chiamata.
Quando si lavora attraverso un array, tutto è normale, con controlli, ramificazioni e perdite sulla conversione di indici doppi -> interi
Quando si lavora con gli array in questo esempio c'è una costante mescolanza FPU/ALU che è molto negativa per le prestazioni
L'ottimizzazione dell'accesso dinamico all'array è grande - oltre ogni lode. Ma mischiare operazioni FPU/ALU + doppio -> intero + ramificazione fa perdere tempo
La conclusione generale: la matematica ha vinto in MQL5 grazie alla perfetta ottimizzazione. Qui non sono gli array a perdere, ma vince la matematica.
Al contrario, è molto più facile con due "se" che con l'operatore "o".
È più facile tracciare prima una condizione, e lasciare la funzione se è vera, e poi controllare l'altra condizione, e lasciare anche questa se è vera, che indovinare il risultato di una condizione complessa con "o" logico (che può essere facilmente confuso con "e"), e tracciare entrambe le opzioni di ritorno.
È piuttosto divertente leggere qui sotto che "la giustificazione per tale è il debugging", perché significa che tale codice è molto più comprensibile (altrimenti perché è in debugging?).
"Apoteosi" considero un'espressione di fxsaber, sulla quale lui stesso non poteva dire come funziona, affermando semplicemente che "il codice è stato ripetutamente testato, e funziona". Questo, secondo me, non dovrebbe essere il caso:
Questo codice controlla seun ordine otfFilingType può essereeseguito, e lo restituisce se è disponibile su strSymbol, altrimenti è corretto.
Non ho assolutamente idea di come funzioni. E fare affidamento solo sull'autorità di fxsaber.
Forsequalcuno può spiegare?
Una volta mi sono seduto e l'ho smontato passo dopo passo, sembra che abbia avuto bisogno di carta e penna)
Perché questo parsing è stato utile - ho capito che in caso di cambiamento della struttura di enum tutto sarà rotto) dato che vengono usate relazioni intere di valori enum (che secondo l'idea stessa di enumerazioni dovrebbero essere incapsulate). Io stesso cerco di evitarlo, al massimo il rapporto più-meno. Per coloro che hanno a che fare con WinAPI, è probabilmente familiare.
Se stiamo parlando di MQL5, potete dimenticare i metodi di "ottimizzazione" di 10-20-30 anni fa. Dovete scrivere il codice più leggibile. È così, e non la roba da hacker e la pura furbizia.
Esattamente. Sono arrivato a questa conclusione molto tempo fa. Ma non perché penso che il compilatore lo renderà migliore. Ma perché la principale fonte di problemi nel codice è l'essere umano stesso, il che significa che si dovrebbe scrivere il codice in modo da renderlo il più semplice e trasparente possibile.
Quando non può essere "trasparente", bisogna scrivere commenti dettagliati sul perché è così e non così.
E il compilatore... Anche se non lo fa in modo abbastanza efficiente, è meno un problema che un potenziale bug dovuto al fatto che non si tiene conto di alcuni aspetti del programma.
Il codice è molto semplice e breve(descrizione). Se lo scrivi su FP, sarebbe interessante confrontarlo.
Per favore. C# in stile FP:
using System;
using System.Linq;
using System.Collections.Generic;
using static FeesCalculator.FeesCalcs;
using System.Text;
using static System.Math;
namespace FeesCalculator
{
publicstaticclass 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>publicstaticvoid Map<T>(this IEnumerable<T> seq, Action<T> action)
{
foreach (var item in seq)
action(item);
}
}
/// <summary>/// Инвестиционный результат/// </summary>public record AccountRecord
{
publicdouble Investor { get; init; }
publicdouble Manager { get; init; }
publicdouble Summary { get; init; }
publicstatic AccountRecord operator *(AccountRecord r, double v)
{
returnnew AccountRecord
{
Investor = r.Investor * v,
Manager = r.Manager * v,
Summary = r.Summary * v
};
}
publicoverridestring 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>publicdouble Perfomance { get; init; }
/// <summary>/// Вознаграждение управляющего/// </summary>publicdouble Gift { get; init; }
/// <summary>/// Количество расчетных периодов/// </summary>publicint N { get; init; }
/// <inheritdoc/>publicoverridestring 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>publicclass FeesCalcs
{
/// <summary>/// Если управляющий снимает деньги в конце каждого расчетного периода/// </summary>/// <param name="Performance"></param>/// <param name="Gift"></param>/// <param name="N"></param>/// <returns></returns>publicstatic 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>publicstatic 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>publicstatic 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);
returnnew AccountRecord
{
Summary = summary(),
Investor = investor(),
Manager = summary() - investor()
};
}
/// <summary>/// Сопостовление: описание - функция расчета/// </summary>publicstatic readonly Dictionary<string, Func<PammSet, AccountRecord>> DescrToAccountRecord = new Dictionary<string, Func<PammSet, AccountRecord>>
{
{"Если управляющий снимает деньги в конце каждого расчетного периода (1)", Set1 },
{"Если ничего не делалось в расчетные периоды (2)", Set2 },
{"Если управляющий снимает деньги в конце каждого расчетного периода и реинвестирует их (3)", Set3 },
};
}
class Program
{
staticvoid 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 è abbastanza storto naturalmente (poiché è stato scritto da un codificatore FP storto, nel linguaggio FP incompleto C#).Ma l'obiettivo è mostrare che sul moderno gergo OOP si può fare anche in FP. Certo, è limitato, non è F# o Haskell, ma nessuno vieta di scrivere in stile FP. Usare l'immutabilità, funzioni di ordine superiore, chiusure, mappature, ecc. - sei il benvenuto a fare tutto. Ma questo non rende il codice perfetto per qualche motivo.
s.w. La struttura generale del codice imita deliberatamente l'originale. Anche se in senso buono dovrebbe essere molto diverso in FP, senza oggetti complessi e foreach che imitano Map, ma l'artista ha dipinto come poteva.
Capisco che è una questione di abitudine e di conoscenza della sintassi, ma ho molta difficoltà ad entrare nel codice anche se sono l'autore originale.
#property strict#property script_show_inputsinputdouble inPerformance = 100; // Сколько процентов дает система за периодinputdouble inGift = 50; // Награда управляющего в процентах (< 100)inputint inN = 12; // Сколько расчетных периодовstruct BASE
{
double Investor;
double Manager;
double Summary;
// Если управляющий снимает деньги в конце каждого расчетного периода.void Set1( constdouble Performance, constdouble Gift, constint 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( constdouble Performance, constdouble Gift, constint N )
{
this.Summary = ::MathPow(Performance, N);
this.Manager = (this.Summary - 1) * Gift;
this.Investor = this.Summary - this.Manager;
return;
}
// Если управляющий снимает деньги в конце каждого расчетного периода и реинвестирует их.void Set3( constdouble Performance, constdouble Gift, constint N )
{
this.Summary = ::MathPow(Performance, N);
this.Investor = ::MathPow(1 + (Performance - 1)* (1 - Gift), N);
this.Manager = this.Summary - this.Investor;
return;
}
voidoperator *=( constdouble Deposit = 1 )
{
this.Investor *= Deposit;
this.Manager *= Deposit;
this.Summary *= Deposit;
return;
}
#define TOSTRING(A) #A + " = " + ::DoubleToString(A, 4) + " "string ToString( constbool 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( constdouble dPerformance, constdouble dGift, constint 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);
}
voidoperator *=( constdouble 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( constbool FlagName = true, constbool 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));
}
};
voidOnStart()
{
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);
}
Tecnicamente, è probabilmente un OOP. Ma la parte più primitiva. Non potrei farlo senza, però. Possibilmente, stupido riarrangiamento del cervello e avvincente questo.
"Apoteosi" considero un'espressione di fxsaber, sulla quale lui stesso non poteva dire come funziona, affermando semplicemente che "il codice è stato ripetutamente testato, e funziona". Questo, secondo me, non dovrebbe essere il caso:
Questo codice controlla seun ordine otfFilingType può essereeseguito, e lo restituisce se è disponibile su strSymbol, altrimenti è corretto.
Non ho assolutamente idea di come funzioni. E fare affidamento solo sull'autorità di fxsaber.
Forse qualcuno può spiegare?
Per capirlo, basta smontare questa ingombrante espressione di ritorno nei suoi componenti.
Il tuo esempio di "il fine giustifica i mezzi"
comunque questo codice è proprio come degli spaghetti, ma considerando che è probabilmente l'autore più utile in kodobase in questo momento e io stesso uso i suoi codici così come sono, lasciamo che qualcun altro critichi
comunque questo codice è proprio come degli spaghetti, ma dato che è probabilmente l'autore più utile in kodobase in questo momento e io stesso uso i suoi codici così come sono, lasciamo che qualcun altro critichi
non si tratta di critica, sto cercando di capire cosa può fare.... Ma come mostra l'intervista, e come ha ammesso lo stesso@fxsaber- nient'altro che mal di testa
SZZ: è molto probabile che la variante iniziale del piccolo mostro abbia un aspetto più chiaro ;)
ZS: alta probabilità che la versione originale del mostriciattolo sembrasse più evidente ;)
Preso da ZIP (contiene la primissima versione).
Ma in seguito c'era bisogno di sempre più funzionalità, e il codice stava lentamente diventando più corposo. Era diverso con la funzione Filling. Non c'era niente di definito, è stato scritto in una volta sola.
Solo il compilatore sa esattamente cosa farà. I compilatori moderni hanno un'euristica sbalorditiva. Si adattano al codificatore medio e sanno già meglio di cosa ha bisogno. La cosa migliore che un compilatore può fare è scrivere codice semplice e diretto con funzioni brevi. È più facile ed efficiente per il compilatore analizzare il grafo del codice sorgente composto da molti nodi di funzione per costruire il programma risultante. Avrà solo un effetto positivo sulla produttività, poiché le funzioni necessarie saranno bloccate in tutti i posti giusti.
Hai assolutamente ragione.
Se stiamo parlando di MQL5, potete dimenticare i metodi di "ottimizzazione" di 10-20-30 anni fa. Dovete scrivere il codice più leggibile. È così, e non la roba da hacker e la pura furbizia.
Perché?
Poiché il compilatore passa attraverso 5-10 cicli di riordino del codice, è incredibilmente chiaro e conciso, per non parlare dell'uso di decine di modelli di ottimizzazione.
Il compilatore MQL5 è divertito dai tentativi umani di fare +2% di velocità.
Questa è un'opera d'arte in realtà. 8 radici sono state calcolate in 4 chiamate del comando assembler. Due numeri doppi sono stati calcolati in una chiamata.Se vi interessa, guardate come calcoli SQRT + matematici vanno senza ramificazioni e un comando (128 bit di dati) calcola due radici in una volta
Questo codice si trasforma nel seguente codice assembler SSE:
La conclusione generale: la matematica ha vinto in MQL5 grazie alla perfetta ottimizzazione. Qui non sono gli array a perdere, ma vince la matematica.
Perché?
Al contrario, è molto più facile con due "se" che con l'operatore "o".
È più facile tracciare prima una condizione, e lasciare la funzione se è vera, e poi controllare l'altra condizione, e lasciare anche questa se è vera, che indovinare il risultato di una condizione complessa con "o" logico (che può essere facilmente confuso con "e"), e tracciare entrambe le opzioni di ritorno.
È piuttosto divertente leggere qui sotto che "la giustificazione per tale è il debugging", perché significa che tale codice è molto più comprensibile (altrimenti perché è in debugging?).
"Apoteosi" considero un'espressione di fxsaber, sulla quale lui stesso non poteva dire come funziona, affermando semplicemente che "il codice è stato ripetutamente testato, e funziona". Questo, secondo me, non dovrebbe essere il caso:
Questo codice controlla seun ordine otfFilingType può essereeseguito, e lo restituisce se è disponibile su strSymbol, altrimenti è corretto.
Non ho assolutamente idea di come funzioni. E fare affidamento solo sull'autorità di fxsaber.
Forsequalcuno può spiegare?
Una volta mi sono seduto e l'ho smontato passo dopo passo, sembra che abbia avuto bisogno di carta e penna)
Perché questo parsing è stato utile - ho capito che in caso di cambiamento della struttura di enum tutto sarà rotto) dato che vengono usate relazioni intere di valori enum (che secondo l'idea stessa di enumerazioni dovrebbero essere incapsulate). Io stesso cerco di evitarlo, al massimo il rapporto più-meno. Per coloro che hanno a che fare con WinAPI, è probabilmente familiare.
Per capire, basta smontare quell'espressione ingombrante di retournee.
Sì, è quello che ho cercato di fare. Ma non c'era abbastanza motivazione per smontarlo...
Assolutamente giusto.
Se stiamo parlando di MQL5, potete dimenticare i metodi di "ottimizzazione" di 10-20-30 anni fa. Dovete scrivere il codice più leggibile. È così, e non la roba da hacker e la pura furbizia.
Esattamente. Sono arrivato a questa conclusione molto tempo fa. Ma non perché penso che il compilatore lo renderà migliore. Ma perché la principale fonte di problemi nel codice è l'essere umano stesso, il che significa che si dovrebbe scrivere il codice in modo da renderlo il più semplice e trasparente possibile.
Quando non può essere "trasparente", bisogna scrivere commenti dettagliati sul perché è così e non così.
E il compilatore... Anche se non lo fa in modo abbastanza efficiente, è meno un problema che un potenziale bug dovuto al fatto che non si tiene conto di alcuni aspetti del programma.
Il codice è molto semplice e breve(descrizione). Se lo scrivi su FP, sarebbe interessante confrontarlo.
Per favore. C# in stile FP:
FP è abbastanza storto naturalmente (poiché è stato scritto da un codificatore FP storto, nel linguaggio FP incompleto C#).Ma l'obiettivo è mostrare che sul moderno gergo OOP si può fare anche in FP. Certo, è limitato, non è F# o Haskell, ma nessuno vieta di scrivere in stile FP. Usare l'immutabilità, funzioni di ordine superiore, chiusure, mappature, ecc. - sei il benvenuto a fare tutto. Ma questo non rende il codice perfetto per qualche motivo.
s.w. La struttura generale del codice imita deliberatamente l'originale. Anche se in senso buono dovrebbe essere molto diverso in FP, senza oggetti complessi e foreach che imitano Map, ma l'artista ha dipinto come poteva.
Per favore. C# in stile FP:
Capisco che è una questione di abitudine e di conoscenza della sintassi, ma ho molta difficoltà ad entrare nel codice anche se sono l'autore originale.
Forum sul trading, sistemi di trading automatico e test di strategia
Interessante opinione su OOP
fxsaber, 2021.01.29 13:39
Un'inezia.
Tecnicamente, è probabilmente un OOP. Ma la parte più primitiva. Non potrei farlo senza, però. Possibilmente, stupido riarrangiamento del cervello e avvincente questo.