#include <Math\Stat\T.mqh> //+------------------------------------------------------------------+ void OnStart() { int err = 0; double qT = MathQuantileT(0.05, 100, err); if (err != 0) Print("MathQuantileT() error ", err); Print(qT); }
MathQuantileT() error 4
nan
должно быть около -1.660234
Собственно вычислениями занимается эта функция из T.mqh
double MathQuantileT(const double probability,const double nu,const bool tail,const bool log_mode,int &error_code) { //--- check NaN if(!MathIsValidNumber(probability) || !MathIsValidNumber(nu)) { error_code=ERR_ARGUMENTS_NAN; return QNaN; } //--- check nu if(nu!=MathRound(nu) || nu<0.0) { error_code=ERR_ARGUMENTS_INVALID; return QNaN; } //--- calculate real probability double prob=TailLogProbability(probability,tail,log_mode); //--- check probability range if(prob<0.0 || prob>1.0) { error_code=ERR_ARGUMENTS_INVALID; return QNaN; } //--- check cases when probability==0 or 1 if(prob==0.0 || prob==1.0) { error_code=ERR_RESULT_INFINITE; //--- if(prob==0.0) return(QNEGINF); else return(QPOSINF); } error_code=ERR_OK; //--- special case nu=1 if(nu==1.0) return MathTan(M_PI*(prob-0.5)); //--- special case if(prob==0.5) return 0.0; //--- int max_iterations=50; int iterations=0; //--- initial values double h=1.0; double h_min=10E-20; double x=0.5; int err_code=0; //--- Newton iterations while(iterations<max_iterations) { //--- check convegence if((MathAbs(h)>h_min && MathAbs(h)>MathAbs(h_min*x))==false) break; //--- calculate pdf and cdf double pdf=MathProbabilityDensityT(x,nu,err_code); double cdf=MathCumulativeDistributionT(x,nu,err_code); //--- calculate ratio h=(cdf-prob)/pdf; //--- double x_new=x-h; //--- check x if(x_new<0.0) x_new=x*0.1; else if(x_new>1.0) x_new=1.0-(1.0-x)*0.1; x=x_new; iterations++; } //--- check convergence if(iterations<max_iterations) return x; else { error_code=ERR_NON_CONVERGENCE; return QNaN; } }
Ошибка с кодом 4 - это ERR_NON_CONVERGENCE - не сходится метод Ньютона.
Ошибка с кодом 4 - это ERR_NON_CONVERGENCE - не сходится метод Ньютона.
Имхо, если целью была простота кода, то лучше было сделать поиск корня делением пополам.
Для Ньютона нужно аккуратно выбирать начальную точку, аккуратнее относиться к близости плотности к нулю в хвостах и тд.
С помощью ИИ набросал на скорую руку. На первый взгляд вроде работает - особо тщательно не проверял, поскольку код просто для примера
double MathQuantileT(const double probability, const double nu, const bool tail, const bool log_mode, int &error_code) { // 1. Проверка на NaN if(!MathIsValidNumber(probability) || !MathIsValidNumber(nu)) { error_code = ERR_ARGUMENTS_NAN; return QNaN; } // 2. Проверка nu (убрали nu != MathRound(nu), так как df могут быть дробными) if(nu <= 0.0) { error_code = ERR_ARGUMENTS_INVALID; return QNaN; } // 3. Расчет реальной вероятности (учитываем хвосты и логарифмы) double prob = TailLogProbability(probability, tail, log_mode); // 4. Проверка диапазона вероятности if(prob < 0.0 || prob > 1.0) { error_code = ERR_ARGUMENTS_INVALID; return QNaN; } // 5. Обработка предельных случаев if(prob == 0.0) return QNEGINF; if(prob == 1.0) return QPOSINF; if(prob == 0.5) return 0.0; // 6. Спецкейс для nu=1 (распределение Коши) if(nu == 1.0) return MathTan(M_PI * (prob - 0.5)); error_code = ERR_OK; int err_code = 0; // 7. Метод бисекции (надежный поиск корня) double x_low = -1.0; double x_high = 1.0; // Динамически расширяем границы поиска, пока корень не окажется внутри [x_low, x_high] while(MathCumulativeDistributionT(x_low, nu, err_code) > prob && x_low > -1e6) x_low *= 2.0; while(MathCumulativeDistributionT(x_high, nu, err_code) < prob && x_high < 1e6) x_high *= 2.0; double x = 0.0; int max_iterations = 100; double precision = 1e-12; // Высокая точность for(int i = 0; i < max_iterations; i++) { x = (x_low + x_high) / 2.0; double cdf = MathCumulativeDistributionT(x, nu, err_code); if(MathAbs(x_high - x_low) < precision) break; if(cdf < prob) x_low = x; else x_high = x; if(i == max_iterations - 1) error_code = ERR_NON_CONVERGENCE; } return x; }
Предлагаю начать с ошибки вычисления квантилей Т-распределения Стьюдента. Уже было об этом на форуме, но повторю ещё раз.
MathQuantileT() error 4
nan
должно быть около -1.660234
Странно, что функция ожидает пять обязательных параметров
double MathQuantileT(const double probability, const double nu, const bool tail, const bool log_mode, int &error_code)
вы передаёте всего три
double qT = MathQuantileT(0.05, 100, err);
И при этом не возникает ошибки компиляции?
вы передаёте всего три
Их два варианта. Та что с тремя параметрами вызывает ту что с пятью (в Math\Stat\T.mqh)
double MathQuantileT(const double probability,const double nu,int &error_code) { return MathQuantileT(probability,nu,true,false,error_code); }
#include <Math\Stat\Beta.mqh> #include <Math\Stat\Math.mqh> //+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ void OnStart() { int err = 0; double qT = MathQuantileT(0.05, 100,true,false, err); if (err != 0) Print("MathQuantileT() error ", err); Print(qT); } //+------------------------------------------------------------------+ double MathQuantileT(const double probability, const double nu, const bool tail, const bool log_mode, int &error_code) { //--- 1. Проверка на NaN if(!MathIsValidNumber(probability) || !MathIsValidNumber(nu)) { error_code = ERR_ARGUMENTS_NAN; return QNaN; } //--- 2. Проверка степеней свободы (nu > 0) // Примечание: Стьюдент определен и для нецелых nu (например, 2.5) if(nu <= 0.0) { error_code = ERR_ARGUMENTS_INVALID; return QNaN; } //--- 3. Вычисление реальной вероятности если передали probability как логарифм double prob = TailLogProbability(probability, tail, log_mode); //--- 4. Проверка диапазона вероятности if(prob < 0.0 || prob > 1.0) { error_code = ERR_ARGUMENTS_INVALID; return QNaN; } //--- 5. Обработка предельных случаев if(prob == 0.0) return QNEGINF; if(prob == 1.0) return QPOSINF; if(prob == 0.5) return 0.0; //--- 6. Спецслучай nu=1 (Распределение Коши) if(nu == 1.0) return MathTan(M_PI * (prob - 0.5)); error_code = ERR_OK; //--- 7. ОСНОВНОЙ РАСЧЕТ ЧЕРЕЗ BETA // Используем симметрию t-распределения bool is_lower = (prob < 0.5); double p_beta = is_lower ? 2.0 * prob : 2.0 * (1.0 - prob); // Вызываем встроенную функцию MQL5 для квантиля Бета-распределения int beta_err = 0; double x = MathQuantileBeta(p_beta, nu / 2.0, 0.5, beta_err); if(beta_err != 0 || !MathIsValidNumber(x)) { error_code = ERR_NON_CONVERGENCE; return QNaN; } // Финальная трансформация: x из Beta в t-значение // Формула: t = sqrt( nu * (1-x) / x ) double t = MathSqrt(nu * (1.0 - x) / x); return is_lower ? -t : t; }Проверил разные варианты, совпадает со значениями в матлаб.
С помощью встроенной функции для Бета распределения чуть проще
Спасибо!
Пишите если найдёте ещё ошибки в библиотеке.
Вроде какие-то проблемы были с гипергеометрическим и биномиальным, но точно уже не помню. Наверно надо просто все функции протестить на рандомных данных и сравнить с результатом в R.
Библиотека вроде бы есть, а пользоваться страшновато)
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования