Guest User

Untitled

a guest
Nov 8th, 2023
105
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Rust 8.26 KB | None | 0 0
  1. use std::{num::Wrapping, time::SystemTime};
  2.  
  3. use rand::distributions::Distribution;
  4. use rand::{RngCore, SeedableRng};
  5.  
  6. // This is a random int generator suggested by Marsaglia in his DIEHARD suite.
  7. // It provides a great combination of speed and quality.
  8. // We also have unifrand(), a random 0-1 generator based on it.
  9. pub struct MarsagliaRng {
  10.     q: [u32; 256],
  11.     carry: u32,
  12.     mwc256_initialized: bool,
  13.     mwc256_seed: i32,
  14.     i: Wrapping<u8>,
  15. }
  16. #[derive(Default)]
  17. pub struct MarsagliaRngDist {}
  18.  
  19. impl Distribution<f64> for MarsagliaRngDist {
  20.     fn sample<R: rand::Rng + ?Sized>(&self, rng: &mut R) -> f64 {
  21.         let mult: f64 = 1.0 / (0xFFFFFFFF as u64) as f64;
  22.         mult * rng.next_u32() as f64
  23.     }
  24. }
  25.  
  26. impl Default for MarsagliaRng {
  27.     fn default() -> Self {
  28.         let duration_since_epoch = SystemTime::now()
  29.             .duration_since(SystemTime::UNIX_EPOCH)
  30.             .unwrap();
  31.         let ts_nano = duration_since_epoch.as_nanos(); // u128
  32.         MarsagliaRng::from_seed([
  33.             ts_nano as u8,
  34.             (ts_nano >> 8) as u8,
  35.             (ts_nano >> 16) as u8,
  36.             (ts_nano >> 24) as u8,
  37.         ])
  38.     }
  39. }
  40.  
  41. impl RngCore for MarsagliaRng {
  42.     fn next_u32(&mut self) -> u32 {
  43.         let a: u64 = 809430660;
  44.  
  45.         if !self.mwc256_initialized {
  46.             let mut j = Wrapping(self.mwc256_seed as u32);
  47.             let c1 = Wrapping(69069);
  48.             let c2 = Wrapping(12345);
  49.             self.mwc256_initialized = true;
  50.             for k in 0..256 {
  51.                 j = c1 * j + c2;
  52.                 self.q[k] = j.0;
  53.             }
  54.         }
  55.  
  56.         self.i += 1;
  57.         let t = a * self.q[self.i.0 as usize] as u64 + self.carry as u64;
  58.         self.carry = (t >> 32) as u32;
  59.         self.q[self.i.0 as usize] = (t & 0xFFFFFFFF) as u32;
  60.  
  61.         self.q[self.i.0 as usize]
  62.     }
  63.  
  64.     fn next_u64(&mut self) -> u64 {
  65.         self.next_u32() as u64
  66.     }
  67.  
  68.     fn fill_bytes(&mut self, dest: &mut [u8]) {
  69.         todo!()
  70.     }
  71.  
  72.     fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand::Error> {
  73.         todo!()
  74.     }
  75. }
  76.  
  77. impl SeedableRng for MarsagliaRng {
  78.     type Seed = [u8; 4];
  79.  
  80.     fn from_seed(seed: Self::Seed) -> Self {
  81.         MarsagliaRng {
  82.             q: [0; 256],
  83.             carry: 362436,
  84.             mwc256_initialized: false,
  85.             mwc256_seed: i32::from_le_bytes(seed),
  86.             i: Wrapping(255u8),
  87.         }
  88.     }
  89. }
  90.  
  91. struct ParamsResult {
  92.     short_term: usize,
  93.     long_term: usize,
  94.     performance: f64,
  95. }
  96.  
  97. fn opt_params(which: usize, ncases: usize, x: &[f64]) -> ParamsResult {
  98.     let mut best_perf = f64::MIN;
  99.     let mut ibestshort = 0;
  100.     let mut ibestlong = 0;
  101.  
  102.     for ilong in 2..200 {
  103.         for ishort in 1..ilong {
  104.             let mut total_return = 0.0;
  105.             let mut win_sum = 1e-60;
  106.             let mut lose_sum = 1e-60;
  107.             let mut sum_squares = 1e-60;
  108.             let (mut short_sum, mut long_sum) = (0.0, 0.0);
  109.  
  110.             for i in (ilong - 1)..(ncases - 1) {
  111.                 if i == ilong - 1 {
  112.                     short_sum = (i + 1 - ishort..=i).map(|j| x[j]).sum();
  113.                     long_sum = (i + 1 - ilong..=i).map(|j| x[j]).sum();
  114.                 } else {
  115.                     short_sum += x[i] - x[i - ishort];
  116.                     long_sum += x[i] - x[i - ilong];
  117.                 }
  118.  
  119.                 let short_mean = short_sum / ishort as f64;
  120.                 let long_mean = long_sum / ilong as f64;
  121.  
  122.                 let ret = if short_mean > long_mean {
  123.                     x[i + 1] - x[i]
  124.                 } else if short_mean < long_mean {
  125.                     x[i] - x[i + 1]
  126.                 } else {
  127.                     0.0
  128.                 };
  129.  
  130.                 total_return += ret;
  131.                 sum_squares += ret * ret;
  132.                 if ret > 0.0 {
  133.                     win_sum += ret;
  134.                 } else {
  135.                     lose_sum -= ret;
  136.                 }
  137.             }
  138.  
  139.             match which {
  140.                 0 => {
  141.                     total_return /= (ncases - ilong) as f64;
  142.                     if total_return > best_perf {
  143.                         best_perf = total_return;
  144.                         ibestshort = ishort;
  145.                         ibestlong = ilong;
  146.                     }
  147.                 }
  148.                 1 => {
  149.                     let pf = win_sum / lose_sum;
  150.                     if pf > best_perf {
  151.                         best_perf = pf;
  152.                         ibestshort = ishort;
  153.                         ibestlong = ilong;
  154.                     }
  155.                 }
  156.                 2 => {
  157.                     total_return /= (ncases - ilong) as f64;
  158.                     sum_squares /= (ncases - ilong) as f64;
  159.                     sum_squares -= total_return * total_return;
  160.                     let sr = total_return / (sum_squares.sqrt() + 1e-8);
  161.                     if sr > best_perf {
  162.                         best_perf = sr;
  163.                         ibestshort = ishort;
  164.                         ibestlong = ilong;
  165.                     }
  166.                 }
  167.                 _ => {}
  168.             }
  169.         }
  170.     }
  171.  
  172.     ParamsResult {
  173.         performance: best_perf,
  174.         short_term: ibestshort,
  175.         long_term: ibestlong,
  176.     }
  177. }
  178.  
  179. fn test_system(ncases: usize, x: &[f64], short_term: usize, long_term: usize) -> f64 {
  180.     let mut sum = 0.0;
  181.  
  182.     for i in (long_term - 1)..(ncases - 1) {
  183.         let short_mean = (i + 1 - short_term..=i).map(|j| x[j]).sum::<f64>() / short_term as f64;
  184.         let long_mean = (i + 1 - long_term..=i).map(|j| x[j]).sum::<f64>() / long_term as f64;
  185.  
  186.         if short_mean > long_mean {
  187.             sum += x[i + 1] - x[i];
  188.         } else if short_mean < long_mean {
  189.             sum -= x[i + 1] - x[i];
  190.         }
  191.     }
  192.  
  193.     sum / (ncases - long_term) as f64
  194. }
  195.  
  196. fn main() {
  197.     let which = std::env::args()
  198.         .nth(1)
  199.         .expect("which metric to optimize - 0=mean return  1=profit factor  2=Sharpe ratio")
  200.         .parse::<usize>()
  201.         .unwrap();
  202.  
  203.     let ncases = std::env::args()
  204.         .nth(2)
  205.         .expect("ncases - number of training and test cases")
  206.         .parse::<usize>()
  207.         .unwrap();
  208.  
  209.     let save_trend = std::env::args()
  210.         .nth(3)
  211.         .expect("trend - Amount of trending, 0 for flat system, 0.02 small trend, 0.2 large trend")
  212.         .parse::<f64>()
  213.         .unwrap();
  214.  
  215.     let nreps = std::env::args()
  216.         .nth(4)
  217.         .expect("nreps - number of test replications - at least a few thousand for statistical significance")
  218.         .parse::<usize>()
  219.         .unwrap();
  220.  
  221.     let mut x = vec![0.0; ncases];
  222.  
  223.     let mut is_mean = 0.0;
  224.     let mut oos_mean = 0.0;
  225.  
  226.     let mut rnd = MarsagliaRng::from_seed(33i32.to_le_bytes());
  227.     let dist = MarsagliaRngDist::default();
  228.  
  229.     for irep in 0..nreps {
  230.         //generate in sample
  231.         let mut trend = save_trend;
  232.         x[0] = 0.0;
  233.         for i in 1..ncases {
  234.             if i % 50 == 0 {
  235.                 trend = -trend;
  236.             }
  237.             x[i] = x[i - 1] + trend + dist.sample(&mut rnd) + dist.sample(&mut rnd)
  238.                 - dist.sample(&mut rnd)
  239.                 - dist.sample(&mut rnd);
  240.         }
  241.  
  242.         let ParamsResult {
  243.             short_term,
  244.             long_term,
  245.             performance: is_perf,
  246.         } = opt_params(which, ncases, &x);
  247.  
  248.         // genearte oos
  249.         trend = save_trend;
  250.         x[0] = 0.0;
  251.         for i in 1..ncases {
  252.             if i % 50 == 0 {
  253.                 trend = -trend;
  254.             }
  255.             x[i] = x[i - 1] + trend + dist.sample(&mut rnd) + dist.sample(&mut rnd)
  256.                 - dist.sample(&mut rnd)
  257.                 - dist.sample(&mut rnd);
  258.         }
  259.  
  260.         let oos_perf = test_system(ncases, &x, short_term, long_term);
  261.  
  262.         is_mean += is_perf;
  263.         oos_mean += oos_perf;
  264.  
  265.         println!(
  266.             "{:3}: {:3} {:3}  {:8.4} {:8.4} ({:8.4})",
  267.             irep,
  268.             short_term,
  269.             long_term,
  270.             is_perf,
  271.             oos_perf,
  272.             is_perf - oos_perf
  273.         );
  274.     }
  275.  
  276.     is_mean /= nreps as f64;
  277.     oos_mean /= nreps as f64;
  278.  
  279.     println!(
  280.         "Mean IS={:.4}  OOS={:.4}  Bias={:.4}",
  281.         is_mean,
  282.         oos_mean,
  283.         is_mean - oos_mean
  284.     );
  285. }
  286.  
Add Comment
Please, Sign In to add comment