Skip to content
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
119 lines (83 sloc) 3.71 KB
{-# LANGUAGE ViewPatterns #-}
module Y2016.M10.D21.Solution where
import Control.Arrow (second, (&&&))
import Data.Array
import Data.Map (Map)
import qualified Data.Map as Map
import Data.Monoid (getSum)
import Analytics.Trading.Data.Row (Symbol) --
import Analytics.Trading.Scan.Top5s --
-- the below imports are available from 1HaskellADay git repository
import Data.Bag
import Graph.ScoreCard
import Y2016.M10.D19.Solution
Wow! Years, months, and days of exercises for 1HaskellADay. That's something.
Okay, enough musing! Onto today's problem.
Yesterday, you were able to convert the record of each day's top 5s stocks-by-
category into a record of, well, top5s by category, but in this case, it was a
category type -> stock-and-count
transformed from the original
date -> category -> (leaders stocks, losers stocks)
Today we (can) use what we did yesterday to transform the top5s stored at:
into a mapping of scorecards:
Symbol -> ScoreCard Symbol LeadersLosers Int
Let's do that.
type SCSyms = ScoreCard Symbol LeadersLosers Int
type MSyms a = Map Symbol a
top5s2ScoreCards :: FilePath -> IO (MSyms SCSyms)
top5s2ScoreCards =
fmap (Map.mapWithKey SC
. foldr (uncurry addCatForSyms) Map.empty
. Map.toList)
. countsInCategories
-- so we just flip keys and values and distribute the keys over the values
type ALI = Array LeadersLosers Int
addCatForSyms :: LeadersLosers -> Bag Symbol -> MSyms ALI -> MSyms ALI
addCatForSyms val (map (second getSum) . Map.toList -> keys) mm =
foldr (\(k, v) -> Map.alter (updateOneVal v) k) mm (redistribute (val,keys))
How did I arrive at the above line?
Actually, addCatForSyms is too big for this bear of a little brain. So, let's
break it down.
To update one value of the map (an array), we have
let updateOneVal arr = (arr //) . pure
But we don't know of the array exists yet. That's why we have mt (below). So
we need to conditionally update a pre-existing array or provide an empty array
if none pre-exists.
old code:
flip (foldr (Map.alter (xOr ((//) . pure) mt))) mm (redistribute (val, keys))
updateOneVal :: (LeadersLosers, Int) -> Maybe ALI -> Maybe ALI
updateOneVal kv Nothing = updateOneVal kv (Just mt)
updateOneVal kv (Just arr) = Just (arr // pure kv)
-- updateOneVal makes a lovely fold
redistribute :: (v, [(k, x)]) -> [(k, (v, x))]
redistribute = map (fst . snd &&& (fst &&& snd . snd)) . sequence
-- Now, since the domain is so small, I could just count each value explicitly
-- for the to/from enum values, but the underlying types are Enum-like enough
-- that I can just apply the product and sum types directly
instance Enum LeadersLosers where
fromEnum (Leader x) = fromEnum x * 2
fromEnum (Loser x) = fromEnum x * 2 + 1
toEnum x = let (y, z) = divMod x 2 in
(if z == 1 then Loser else Leader) $ toEnum y
instance Ix LeadersLosers where
range (a, b) = [a .. b]
inRange (a, b) c = fromEnum c >= fromEnum a && fromEnum b >= fromEnum c
index (a, b) c = fromEnum c - fromEnum a
mt :: ALI
mt = listArray (Leader Mkt_Cap, Leader Volume) (repeat 0)
{-- So:
*Y2016.M10.D21.Solution> top5s2ScoreCards "Y2016/M10/D17/top5s.csv" ~> tops
*Y2016.M10.D21.Solution> length tops ~> 1447
*Y2016.M10.D21.Solution> tops Map.! "AAPL" ~>
SC {idx = "AAPL", values = array (Leader Mkt_Cap,Leader Volume)
[(Leader Mkt_Cap,141),(Loser Mkt_Cap,67),
(Leader Price,0),(Loser Price,0),
(Leader Volume,208)]}
Next week we'll look at frequencies and runs for securities in the market.
You can’t perform that action at this time.