Skip to content

Instantly share code, notes, and snippets.

@sarkologist
Created June 13, 2018 14:26
Show Gist options
  • Save sarkologist/7e1a223bfb538ba8855da4c407b2138d to your computer and use it in GitHub Desktop.
Save sarkologist/7e1a223bfb538ba8855da4c407b2138d to your computer and use it in GitHub Desktop.
RSI with composable folds
import qualified Control.Foldl as Fold
import Control.Applicative
import Data.Profunctor
type Price = Double
type Prices = [ Price ]
type Period = Int
changes :: Prices -> Prices
changes ps = zipWith (-) (tail ps) ps
avg :: Period -> Fold.Fold Price (Maybe Price)
avg period = Fold.Fold step (Left []) (either (const Nothing) Just)
where
step :: Either Prices Price -> Price -> Either Prices Price
step (Left ps) p =
let ps' = p : ps
in if (period == length ps')
then Right (sum ps' / fromIntegral period)
else Left ps'
step (Right rs) p =
let rs' = (rs * (fromIntegral period - 1) + p) / fromIntegral period
in Right rs'
averageGain = lmap (\x -> if x>0 then x else 0) . avg
averageLoss = lmap (\x -> if x<0 then -x else 0) . avg
rs = (liftA2.liftA2.liftA2) (/) averageGain averageLoss
rsi = (fmap.fmap.fmap) (\rs -> 100 - 100 / (1 + rs)) rs
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment