market timing


Write a function accepting a sequence of stock prices and returning a pair of dates such that the stock bought on the first date and sold on the second date produces the maximum return of all possible date pairs.

 $ cat mt.rkt 
 #lang racket 
  
 (define (linear-market-timer prices) 
    
   ; Return a pair containing indices into the given price vector 
   ; indicating the days on which to buy (car) and sell (cdr) a stock 
   ; for maximum return. 
    
   (let* 
  
     ((n (vector-length prices)) 
      (n-1 (- n 1))) 
      
     (if (= n 0) 
  
       (raise-user-error 'linear-market-timer 
         "zero-length price vector given") 
  
       (let loop 
  
         ((buy-i (- n-1 1)) 
          (sell-i n-1) (min-i n-1) (max-i n-1) (best-return 0)) 
  
         (if (< buy-i 0) 
  
           (cons min-i max-i) 
  
           (let* 
  
             ((next-buy-i (- buy-i 1)) 
              (buy-p (vector-ref prices buy-i)) 
              (sell-p (vector-ref prices sell-i)) 
              (return (- sell-p buy-p))) 
  
             (cond 
               ((< sell-p buy-p) 
                  (loop next-buy-i buy-i min-i max-i best-return)) 
  
               ((< best-return return) 
                  (loop next-buy-i sell-i buy-i sell-i return)) 
  
               (#t 
                  (loop next-buy-i sell-i min-i max-i best-return))))))))) 
  
  
 (define (quadradic-market-timer prices) 
  
   ; Return a pair containing indices into the given price vector 
   ; indicating the days on which to buy (car) and sell (cdr) a stock 
   ; for maximum return. 
    
   (let* 
  
     ((n (vector-length prices)) 
      (n-1 (- n 1))) 
  
     (if (= n 0) 
       (raise-user-error 'linear-market-timer 
         "zero-length price vector given") 
  
       (let outer-loop ((i 0) (min-i 0) (max-i 0) (best-return 0)) 
         (if (= i n-1) 
           (cons min-i max-i) 
           (let inner-loop 
  
             ((j (+ i 1)) 
              (min-i min-i) (max-i max-i) (best-return best-return)) 
  
             (if (= j n) 
               (outer-loop (+ i 1) min-i max-i best-return) 
               (let ((return 
                       (- (vector-ref prices j) (vector-ref prices i))) 
                     (next-j (+ j 1))) 
                 (if (< best-return return) 
                   (inner-loop next-j i j return) 
                   (inner-loop next-j min-i max-i best-return)))))))))) 
  
  
 (require rackunit "utl.rkt") 
  
 (call-with-vector-permutations 
  (iota-vector 9) 
  (lambda (prices) 
    (let* ((return (lambda (p) 
             (- (vector-ref prices (cdr p)) (vector-ref prices (car p))))) 
           (r1 (return (linear-market-timer prices))) 
           (r2 (return (quadradic-market-timer prices)))) 
      (check-eq? r1 r2 (format "~a" prices))))) 
  
 $ mzscheme mt.rkt 
 #t 
  
 $