Guest User

Untitled

a guest
Nov 4th, 2023
188
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 10.78 KB | None | 0 0
  1. /******************************************************************************/
  2. /*                                                                            */
  3. /*  TrnBias - Explore training bias                                           */
  4. /*                                                                            */
  5. /******************************************************************************/
  6.  
  7. #include <stdio.h>
  8. #include <string.h>
  9. #include <math.h>
  10. #include <float.h>
  11. #include <stdlib.h>
  12.  
  13.  
  14. /*
  15. --------------------------------------------------------------------------------
  16.  
  17.    This is a random int generator suggested by Marsaglia in his DIEHARD suite.
  18.    It provides a great combination of speed and quality.
  19.  
  20.    We also have unifrand(), a random 0-1 generator based on it.
  21.  
  22. --------------------------------------------------------------------------------
  23. */
  24.  
  25. static unsigned int Q[256], carry=362436 ;
  26. static int MWC256_initialized = 0 ;
  27. static int MWC256_seed = 123456789 ;
  28. static unsigned char i=255 ;
  29.  
  30.  
  31. void RAND32M_seed ( int iseed ) { // Optionally set seed
  32.    MWC256_seed = iseed ;
  33.    MWC256_initialized = 0 ;
  34.    carry = 362436 ;
  35.    for (int k=0 ; k<256 ; k++) {
  36.       Q[k] = 0;
  37.    }
  38.    i = 255;
  39.    }
  40.  
  41. unsigned int RAND32M ()
  42. {
  43.    uint64_t t;
  44.    uint64_t a=809430660 ;
  45.  
  46.    if (! MWC256_initialized) {
  47.       unsigned int k,j=MWC256_seed ;
  48.       MWC256_initialized = 1 ;
  49.       for (k=0 ; k<256 ; k++) {
  50.          j = 69069 * j + 12345 ; // This overflows, doing an automatic mod 2^32
  51.          Q[k] = j ;
  52.          }
  53.       }
  54.  
  55.    i += 1;
  56.    t = a * Q[i] + carry ;  // This is the 64-bit op, forced by a being 64-bit
  57.    carry = (unsigned int) (t >> 32) ;
  58.    Q[i] = (unsigned int) (t & 0xFFFFFFFF) ;
  59.    return Q[i] ;
  60. }
  61.  
  62.  
  63. double unifrand ()
  64. {
  65.    static double mult = 1.0 / 0xFFFFFFFF ;
  66.    return mult * RAND32M() ;
  67. }
  68.  
  69.  
  70.  
  71. /*
  72. --------------------------------------------------------------------------------
  73.  
  74.    Local routine computes optimal short-term and long-term lookbacks
  75.    for a primitive moving-average crossover system
  76.  
  77. --------------------------------------------------------------------------------
  78. */
  79.  
  80. double opt_params (
  81.    int which ,       // 0=mean return; 1=profit factor; 2=Sharpe ratio
  82.    int ncases ,      // Number of log prices in X
  83.    double *x ,       // Log prices
  84.    int *short_term , // Returns optimal short-term lookback
  85.    int *long_term    // Returns optimal long-term lookback
  86.    )
  87. {
  88.    int i, j, ishort, ilong, ibestshort, ibestlong ;
  89.    double short_sum, long_sum, short_mean, long_mean, total_return, best_perf ;
  90.    double ret, win_sum, lose_sum, sum_squares, sr ;
  91.  
  92.    best_perf = -1.e60 ;                          // Will be best performance across all trials
  93.    for (ilong=2 ; ilong<200 ; ilong++) {         // Trial long-term lookback
  94.       for (ishort=1 ; ishort<ilong ; ishort++) { // Trial short-term lookback
  95.  
  96.          // We have a pair of lookbacks to try.
  97.          // Cumulate performance for all valid cases
  98.  
  99.          total_return = 0.0 ;                    // Cumulate total return for this trial
  100.          win_sum = lose_sum = 1.e-60 ;           // Cumulates for profit factor
  101.          sum_squares = 1.e-60 ;                  // Cumulates for Sharpe ratio
  102.  
  103.          for (i=ilong-1 ; i<ncases-1 ; i++) {    // Compute performance across history
  104.  
  105.             if (i == ilong-1) { // Find the short-term and long-term moving averages for the first valid case.
  106.                short_sum = 0.0 ;                 // Cumulates short-term lookback sum
  107.                for (j=i ; j>i-ishort ; j--)
  108.                   short_sum += x[j] ;
  109.                long_sum = short_sum ;            // Cumulates long-term lookback sum
  110.                while (j>i-ilong)
  111.                   long_sum += x[j--] ;
  112.                }
  113.  
  114.             else {                               // Update the moving averages
  115.                short_sum += x[i] - x[i-ishort] ;
  116.                long_sum += x[i] - x[i-ilong] ;
  117.                }
  118.  
  119.             short_mean = short_sum / ishort ;
  120.             long_mean = long_sum / ilong ;
  121.  
  122.             // We now have the short-term and long-term moving averages ending at day i
  123.             // Take our position and cumulate performance
  124.  
  125.             if (short_mean > long_mean)       // Long position
  126.                ret = x[i+1] - x[i] ;
  127.             else if (short_mean < long_mean)  // Short position
  128.                ret = x[i] - x[i+1] ;
  129.             else
  130.                ret = 0.0 ;
  131.  
  132.             total_return += ret ;
  133.             sum_squares += ret * ret ;
  134.             if (ret > 0.0)
  135.                win_sum += ret ;
  136.             else
  137.                lose_sum -= ret ;
  138.  
  139.             } // For i, summing performance for this trial
  140.  
  141.          // We now have the performance figures across the history
  142.          // Keep track of the best lookbacks
  143.  
  144.          if (which == 0) {      // Mean return criterion
  145.             total_return /= ncases - ilong ;
  146.             if (total_return > best_perf) {
  147.                best_perf = total_return ;
  148.                ibestshort = ishort ;
  149.                ibestlong = ilong ;
  150.                }
  151.             }
  152.  
  153.          else if (which == 1  &&  win_sum / lose_sum > best_perf) { // Profit factor criterion
  154.             best_perf = win_sum / lose_sum ;
  155.             ibestshort = ishort ;
  156.             ibestlong = ilong ;
  157.             }
  158.  
  159.          else if (which == 2) { // Sharpe ratio criterion
  160.             total_return /= ncases - ilong ;   // Now mean return
  161.             sum_squares /= ncases - ilong ;
  162.             sum_squares -= total_return * total_return ;  // Variance (may be zero!)
  163.             sr = total_return / (sqrt ( sum_squares ) + 1.e-8) ;
  164.             if (sr > best_perf) { // Profit factor criterion
  165.                best_perf = sr ;
  166.                ibestshort = ishort ;
  167.                ibestlong = ilong ;
  168.                }
  169.             }
  170.  
  171.          } // For ishort, all short-term lookbacks
  172.       } // For ilong, all long-term lookbacks
  173.  
  174.    *short_term = ibestshort ;
  175.    *long_term = ibestlong ;
  176.  
  177.    return best_perf ;
  178. }
  179.  
  180.  
  181. /*
  182. --------------------------------------------------------------------------------
  183.  
  184.    Local routine tests a trained crossover system
  185.    This computes the mean return.  Users may wish to change it to
  186.    compute other criteria.
  187.  
  188. --------------------------------------------------------------------------------
  189. */
  190.  
  191. double test_system (
  192.    int ncases ,
  193.    double *x ,
  194.    int short_term ,
  195.    int long_term
  196.    )
  197. {
  198.    int i, j ;
  199.    double sum, short_mean, long_mean ;
  200.  
  201.    sum = 0.0 ;                          // Cumulate performance for this trial
  202.    for (i=long_term-1 ; i<ncases-1 ; i++) { // Sum performance across history
  203.       short_mean = 0.0 ;                // Cumulates short-term lookback sum
  204.       for (j=i ; j>i-short_term ; j--)
  205.          short_mean += x[j] ;
  206.       long_mean = short_mean ;          // Cumulates short-term lookback sum
  207.       while (j>i-long_term)
  208.          long_mean += x[j--] ;
  209.       short_mean /= short_term ;
  210.       long_mean /= long_term ;
  211.       // We now have the short-term and long-term means ending at day i
  212.       // Take our position and cumulate return
  213.       if (short_mean > long_mean)       // Long position
  214.          sum += x[i+1] - x[i] ;
  215.       else if (short_mean < long_mean)  // Short position
  216.          sum -= x[i+1] - x[i] ;
  217.       } // For i, summing performance for this trial
  218.    sum /= ncases - long_term ;              // Mean return across the history we just tested
  219.  
  220.    return sum ;
  221. }
  222.  
  223.  
  224. /*
  225. --------------------------------------------------------------------------------
  226.  
  227.    Main routine
  228.  
  229. --------------------------------------------------------------------------------
  230. */
  231.  
  232. int main (
  233.    int argc ,    // Number of command line arguments (includes prog name)
  234.    char *argv[]  // Arguments (prog name is argv[0])
  235.    )
  236. {
  237.    int i, which, ncases, irep, nreps, short_lookback, long_lookback ;
  238.    double save_trend, trend, *x, IS_perf, OOS_perf, IS_mean, OOS_mean ;
  239.  
  240. /*
  241.    Process command line parameters
  242. */
  243.  
  244. #if 1
  245.    if (argc != 5) {
  246.       printf ( "\nUsage: TrnBias  which  ncases trend  nreps" ) ;
  247.       printf ( "\n  which - 0=mean return  1=profit factor  2=Sharpe ratio" ) ;
  248.       printf ( "\n  ncases - number of training and test cases" ) ;
  249.       printf ( "\n  trend - Amount of trending, 0 for flat system" ) ;
  250.       printf ( "\n  nreps - number of test replications" ) ;
  251.       exit ( 1 ) ;
  252.       }
  253.  
  254.    which = atoi ( argv[1] ) ;
  255.    ncases = atoi ( argv[2] ) ;
  256.    save_trend = atof ( argv[3] ) ;
  257.    nreps = atoi ( argv[4] ) ;
  258. #else
  259.    which = 1 ;
  260.    ncases = 1000 ;
  261.    save_trend = 0.2 ;
  262.    nreps = 10 ;
  263. #endif
  264.  
  265.    if (ncases < 2  ||  which < 0  ||  which > 2  ||  nreps < 1) {
  266.       printf ( "\nUsage: TrnBias  which  ncases trend  nreps" ) ;
  267.       printf ( "\n  which - 0=mean return  1=profit factor  2=Sharpe ratio" ) ;
  268.       printf ( "\n  ncases - number of training and test cases" ) ;
  269.       printf ( "\n  trend - Amount of trending, 0 for flat system" ) ;
  270.       printf ( "\n  nreps - number of test replications" ) ;
  271.       exit ( 1 ) ;
  272.       }
  273.  
  274.    printf ( "\n\nwhich=%d ncases=%d trend=%.3lf nreps=%d", which, ncases, save_trend, nreps ) ;
  275.  
  276. /*
  277.    Initialize
  278. */
  279.  
  280.    x = (double *) malloc ( ncases * sizeof(double) ) ;
  281.  
  282. /*
  283.    Main replication loop
  284. */
  285.  
  286.    IS_mean = OOS_mean = 0.0 ;
  287.    for (irep=0 ; irep<nreps ; irep++) {  // Do many trials to get a stable average
  288.  
  289.       // Generate the in-sample set (log prices)
  290.       trend = save_trend ;
  291.       x[0] = 0.0 ;
  292.       for (i=1 ; i<ncases ; i++) {
  293.          if (i % 50 == 0) // Reverse the trend
  294.             trend = -trend ;
  295.          x[i] = x[i-1] + trend + unifrand() + unifrand() - unifrand() - unifrand() ;
  296.          }
  297.  
  298.       // Compute optimal parameters, evaluate return with same dataset
  299.       opt_params ( which , ncases , x , &short_lookback , &long_lookback ) ;
  300.       IS_perf = test_system ( ncases , x , short_lookback , long_lookback ) ;
  301.  
  302.       // Generate the out_of-sample set (log prices)
  303.       trend = save_trend ;
  304.       x[0] = 0.0 ;
  305.       for (i=1 ; i<ncases ; i++) {
  306.          if (i % 50 == 0)
  307.             trend = -trend ;
  308.          x[i] = x[i-1] + trend + unifrand() + unifrand() - unifrand() - unifrand() ;
  309.          }
  310.  
  311.       // Test the OOS set and cumulate means across replications
  312.       OOS_perf = test_system ( ncases , x , short_lookback , long_lookback ) ;
  313.  
  314.       IS_mean += IS_perf ;
  315.       OOS_mean += OOS_perf ;
  316.       printf ( "\n%3d: %3d %3d  %8.4lf %8.4lf (%8.4lf)", irep, short_lookback, long_lookback, IS_perf, OOS_perf, IS_perf - OOS_perf ) ;
  317.       } // For irep
  318.  
  319.    // Done.  Print results and clean up.
  320.    IS_mean /= nreps ;
  321.    OOS_mean /= nreps ;
  322.    printf ( "\nMean IS=%.4lf  OOS=%.4lf  Bias=%.4lf", IS_mean, OOS_mean, IS_mean - OOS_mean ) ;
  323.  
  324.    free ( x ) ;
  325.  
  326.    return 0 ;
  327. }
  328.  
Advertisement
Add Comment
Please, Sign In to add comment