Skip to content

Commit d70c217

Browse files
committed
Trying Fixed E30 as faster alternative of Rational, but more precise than Double
1 parent b442dee commit d70c217

File tree

4 files changed

+47
-30
lines changed

4 files changed

+47
-30
lines changed

pub/bfx/src/Bfx/Indicator/Rsi.hs

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
{-# OPTIONS_GHC -Wno-deprecations #-}
12
{-# OPTIONS_HADDOCK show-extensions #-}
23

34
module Bfx.Indicator.Rsi
@@ -14,9 +15,10 @@ import qualified Conduit as C
1415
import qualified Data.Conduit.List as C
1516
import Functora.Money
1617
import Functora.Prelude
18+
import qualified Prelude
1719

1820
newtype Rsi = Rsi
19-
{ unRsi :: Double
21+
{ unRsi :: Fixed E30
2022
}
2123
deriving stock
2224
( Eq,
@@ -59,12 +61,14 @@ mkRsiConduit mkCandle (RsiPeriod natPer) =
5961
C.yield
6062
( c2,
6163
-- Loss
62-
via @Rational @(Ratio Natural) @Double
64+
fromRational @(Fixed E30)
65+
. from @(Ratio Natural) @Rational
6366
$ if p1 >= p2
6467
then p1 - p2
6568
else 0,
6669
-- Gain
67-
via @Rational @(Ratio Natural) @Double
70+
fromRational @(Fixed E30)
71+
. from @(Ratio Natural) @Rational
6872
$ if p1 <= p2
6973
then p2 - p1
7074
else 0
@@ -76,23 +80,26 @@ mkRsiConduit mkCandle (RsiPeriod natPer) =
7680
.| ( do
7781
seed <- C.take intPer
7882
when (length seed == intPer) $ do
79-
let initAvgLoss = sum (fmap snd3 seed) / dblPer
80-
let initAvgGain = sum (fmap thd3 seed) / dblPer
83+
let initAvgLoss = sum (fmap snd3 seed) / fixPer
84+
let initAvgGain = sum (fmap thd3 seed) / fixPer
8185
flip loopM (initAvgLoss, initAvgGain)
8286
$ \(prevAvgLoss, prevAvgGain) -> do
8387
mcandle <- C.await
8488
case mcandle of
8589
Nothing -> pure $ Right ()
8690
Just (c, loss, gain) -> do
87-
let nextAvgLoss = (prevAvgLoss * (dblPer - 1) + loss) / dblPer
88-
let nextAvgGain = (prevAvgGain * (dblPer - 1) + gain) / dblPer
91+
let nextAvgLoss = (prevAvgLoss * (fixPer - 1) + loss) / fixPer
92+
let nextAvgGain = (prevAvgGain * (fixPer - 1) + gain) / fixPer
8993
let rs = nextAvgGain / nextAvgLoss
9094
let rsi = Rsi $ 100 - (100 / (1 + rs))
9195
C.yield (c, rsi)
9296
pure $ Left (nextAvgLoss, nextAvgGain)
9397
)
9498
where
95-
dblPer = unsafeFrom @Natural @Double natPer
99+
fixPer :: Fixed E30
100+
fixPer =
101+
Prelude.fromInteger $ from @Natural @Integer natPer
102+
intPer :: Int
96103
intPer =
97104
case unsafeFrom @Natural @Int natPer of
98105
x | x < 2 -> error $ "Bad RSI period " <> inspect natPer

pub/functora-witch/source/library/Functora/Witch/Instances.hs

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -936,15 +936,19 @@ instance (Fixed.HasResolution a) => TryFrom.TryFrom Rational (Fixed.Fixed a) whe
936936

937937
-- Fixed
938938

939-
-- | Uses 'Fixed.MkFixed'. This means @from \@Integer \@Centi 2@ is @0.02@
940-
-- rather than @2.00@.
941-
instance From.From Integer (Fixed.Fixed a) where
942-
from = Fixed.MkFixed
943-
944-
-- | Uses 'Fixed.MkFixed'. This means @from \@Centi \@Integer 3.00@ is @300@
945-
-- rather than @3@.
946-
instance From.From (Fixed.Fixed a) Integer where
947-
from (Fixed.MkFixed t) = t
939+
--
940+
-- TODO : update after fix https://github.com/tfausak/witch/issues/121
941+
--
942+
943+
-- -- | Uses 'Fixed.MkFixed'. This means @from \@Integer \@Centi 2@ is @0.02@
944+
-- -- rather than @2.00@.
945+
-- instance From.From Integer (Fixed.Fixed a) where
946+
-- from = Fixed.MkFixed
947+
948+
-- -- | Uses 'Fixed.MkFixed'. This means @from \@Centi \@Integer 3.00@ is @300@
949+
-- -- rather than @3@.
950+
-- instance From.From (Fixed.Fixed a) Integer where
951+
-- from (Fixed.MkFixed t) = t
948952

949953
-- | Uses 'toRational'.
950954
instance (Fixed.HasResolution a) => From.From (Fixed.Fixed a) Rational where

pub/functora-witch/source/test-suite/Main.hs

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1660,19 +1660,19 @@ spec = describe "Witch" $ do
16601660
f 12.3 `shouldBe` Just 12.3
16611661
f 0.12 `shouldBe` Nothing
16621662

1663-
describe "From Integer (Fixed a)" $ do
1664-
let f = Witch.from @Integer @Fixed.Deci
1665-
it "works" $ do
1666-
f 1 `shouldBe` 0.1
1667-
f 10 `shouldBe` 1
1668-
f 120 `shouldBe` 12
1669-
1670-
describe "From (Fixed a) Integer" $ do
1671-
let f = Witch.from @Fixed.Deci @Integer
1672-
it "works" $ do
1673-
f 0.1 `shouldBe` 1
1674-
f 1 `shouldBe` 10
1675-
f 12 `shouldBe` 120
1663+
-- describe "From Integer (Fixed a)" $ do
1664+
-- let f = Witch.from @Integer @Fixed.Deci
1665+
-- it "works" $ do
1666+
-- f 1 `shouldBe` 0.1
1667+
-- f 10 `shouldBe` 1
1668+
-- f 120 `shouldBe` 12
1669+
1670+
-- describe "From (Fixed a) Integer" $ do
1671+
-- let f = Witch.from @Fixed.Deci @Integer
1672+
-- it "works" $ do
1673+
-- f 0.1 `shouldBe` 1
1674+
-- f 1 `shouldBe` 10
1675+
-- f 12 `shouldBe` 120
16761676

16771677
describe "From (Fixed a) Rational" $ do
16781678
let f = Witch.from @Fixed.Deci @Rational

pub/functora/src/prelude/Functora/Prelude.hs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ module Functora.Prelude
119119
dropAround,
120120
dropWhileEnd,
121121
AscOrDesc (..),
122+
E30,
122123

123124
-- * DerivingVia
124125
-- $derivingVia
@@ -1151,6 +1152,11 @@ data AscOrDesc
11511152
Bounded
11521153
)
11531154

1155+
data E30
1156+
1157+
instance HasResolution E30 where
1158+
resolution = const 1_0000000000_0000000000_0000000000
1159+
11541160
-- $derivingVia
11551161
-- Newtypes to simplify deriving via.
11561162
-- We have to expose default constructors/accessors

0 commit comments

Comments
 (0)