hunk ./HQuant.cabal 63 - colour + colour, + data-accessor, + Finance-Quote-Yahoo addfile ./HQuant/Chart.hs hunk ./HQuant/Chart.hs 1 +module HQuant.Chart where + +import Data.List +--import Data.Time.Calendar (Day) +import HQuant.History +--import Data.Maybe +import Graphics.Rendering.Chart +import Graphics.Rendering.Chart.Gtk +import Data.Colour +import Data.Colour.Names +import Data.Colour.SRGB +import Data.Accessor +import Data.Time.LocalTime + +lwidth :: Double +lwidth = 0.4 + +lineStyle :: AlphaColour Double -> CairoLineStyle +lineStyle color = line_width ^= 3 * lwidth + $ line_color ^= color + $ defaultPlotLines ^. plot_lines_style + +limitLineStyle :: Colour Double -> CairoLineStyle +limitLineStyle color = line_width ^= lwidth + $ line_color ^= opaque color + -- $ line_dashes ^= [5,10] + $ defaultPlotLines ^. plot_lines_style + +plotLines :: [(x, y)] -> String-> AlphaColour Double-> PlotLines x y +plotLines p title color = plot_lines_style ^= lineStyle color + $ plot_lines_values ^= [[ (d, v) | (d,v) <- p]] + $ plot_lines_title ^= title + $ defaultPlotLines + +--limits :: (Ord a, Ord a2) =>t -> [Either (Plot a1 (a -> a -> a)) (Plot a3 (a2 -> a2 -> a2))] +--limits prices = [ Left $ hlinePlot "min/max" (limitLineStyle blue) min, +-- Left $ hlinePlot "" (limitLineStyle blue) max, +-- Right $ hlinePlot "min/max" (limitLineStyle green) min, +-- Right $ hlinePlot "" (limitLineStyle green) max ] + +bg :: AlphaColour Double +bg = opaque white -- $ sRGB 0 0 0.25 +fg :: AlphaColour Double +fg = opaque blue +fg1 :: AlphaColour Double +fg1 = opaque red-- $ sRGB 0.0 0.0 0.15 + +layoutStudy :: (PlotValue x, PlotValue y) => String -> [(x, y)] -> [(x, y)] -> Layout1 x y +layoutStudy title prices study = layout1_title ^=title + $ layout1_background ^= solidFillStyle bg + $ updateAllAxesStyles (axis_grid_style ^= solidLine 1 fg1) + $ layout1_left_axis ^: laxis_override ^= axisGridHide + $ layout1_right_axis ^: laxis_override ^= axisGridHide + $ layout1_bottom_axis ^: laxis_override ^= axisGridHide + $ layout1_plots ^= + ([ + Left (toPlot $plotLines prices "Price" fg), + Left (toPlot $plotLines study title fg1)] + ) + $ layout1_grid_last ^= False + $ setLayout1Foreground fg + $ defaultLayout1 + +layoutBuySells :: String -> [(LocalTime, Double)] -> [(LocalTime, Double)] -> [PlotPoint]-> [PlotPoint] -> Layout1 LocalTime Double +layoutBuySells title prices study buys sells = layout1_title ^="SPY" + $ layout1_background ^= solidFillStyle bg + $ updateAllAxesStyles (axis_grid_style ^= solidLine 1 fg1) + $ layout1_left_axis ^: laxis_override ^= axisGridHide + $ layout1_right_axis ^: laxis_override ^= axisGridHide + $ layout1_bottom_axis ^: laxis_override ^= axisGridHide + $ layout1_plots ^= + ([ + Left (toPlot $plotLines prices "Price" fg), + Left (toPlot $plotLines study title fg1)] + ++ map (\p -> Left $ hlinePlot "b" (limitLineStyle green) (plotPrice p)) buys + ++ map (\p -> Left $ vlinePlot "b" (limitLineStyle green) (fst$plotLocalTime p)) buys + ++ map (\p -> Left $ hlinePlot "s" (limitLineStyle red) (plotPrice p)) sells + ++ map (\p -> Left $ vlinePlot "s" (limitLineStyle red) (fst$plotLocalTime p)) sells + )-- ++ limits prices) + $ layout1_grid_last ^= False + $ setLayout1Foreground fg + $ defaultLayout1 + +chartStudy :: String -> [(LocalTime,Double)] -> [(LocalTime,Double)] -> Renderable () +chartStudy title prices study = toRenderable $ layoutStudy title prices study + +chartBuySells :: String -> [(LocalTime,Double)] -> [(LocalTime,Double)] -> [PlotPoint]-> [PlotPoint] -> Renderable () +chartBuySells title prices study buys sells = toRenderable $ layoutBuySells title prices study buys sells + +priceChartStudy :: String -> [(LocalTime,Double)] -> [(LocalTime,Double)] -> IO () +priceChartStudy title pr st = renderableToWindow (chartStudy title pr st ) 640 480 + +priceChartBuySells :: String -> [(LocalTime,Double)] -> [(LocalTime,Double)] -> [PlotPoint]-> [PlotPoint] -> IO () +priceChartBuySells title pr st bu se = renderableToWindow (chartBuySells title pr st bu se ) 640 480 hunk ./HQuant/FetchQuote.hs 3 -import Finance.Quote.Yahoo +import qualified Finance.Quote.Yahoo as Y hunk ./HQuant/FetchQuote.hs 5 -import Data.Time hunk ./HQuant/FetchQuote.hs 6 - -end :: Day -end = fromGregorian 2010 4 8 :: Day - -start :: Day -start = fromGregorian 2010 1 8 :: Day +import HQuant.History +import Data.Time +import Data.Time.Clock hunk ./HQuant/FetchQuote.hs 13 -toStringArray :: HistoricalQuote -> [String] -toStringArray (HistoricalQuote _ d o h l c a v) = [show d, show o, show c,show h, show l, show a, show v] +toStringArray :: HistoryLine -> [String] +toStringArray (HistoryLine (PDay d) o c h l a v) = [show d, show o, show c,show h, show l, show a, show v] +toStringArray (HistoryLine _ _ _ _ _ _ _) = error "not implimented" + +toHistory :: Y.HistoricalQuote -> HistoryLine +toHistory (Y.HistoricalQuote _ d o h l c a v) = HistoryLine (PDay d) (realToFrac o) (realToFrac c) (realToFrac h) (realToFrac l) (realToFrac a) v hunk ./HQuant/FetchQuote.hs 23 -writeHistory :: [Char] -> [HistoricalQuote] -> IO () +--writeHistory :: String -> [Y.HistoricalQuote] -> IO () +--writeHistory sym hist = +-- writeFile (sym++".csv") +-- $ map (show . toHistory) hist + + +writeHistory :: String -> [HistoryLine] -> IO () hunk ./HQuant/FetchQuote.hs 31 - writeFile (sym++".csv") - $ CSV.printCSV $ [headers] ++ map toStringArray hist + writeFile (sym++".csv") + $ CSV.printCSV $ [headers] ++ map toStringArray hist hunk ./HQuant/FetchQuote.hs 35 +loadYahoo :: Y.QuoteSymbol -> Day -> IO [HistoryLine] +loadYahoo sym start = do + t <- getCurrentTime + let end = utctDay t + h <- Y.getHistoricalQuote sym start end Y.Daily + case h of + Nothing -> error "getHistoricalQuote failed" + Just hist -> do + return $ map toHistory hist + hunk ./HQuant/History.hs 6 +import Data.Time + +data Order = + Order { + oDate :: UTCTime, + oShare :: Int, + oPrice :: Double + } deriving (Read, Show, Eq, Ord) + +data UnRealized = + UnRealized { + uOrders :: [Order], + uShares :: Int + } deriving (Read, Show, Eq, Ord) + +data GainLoss = + GainLoss { + gOrders :: [Order], + gProfit :: Double + } deriving (Read, Show, Eq, Ord) + +data Period = + PDay Day | + PHour Int | + PMinutes Int | + PTick Int + deriving (Read, Show, Eq, Ord) + +data PlotPoint = + PlotPoint { + plotPeriod :: Period, + plotPrice :: Double + } deriving (Read, Show, Eq, Ord) + +type TimePlot = [(PlotPoint)] + +data HistoryLine = + HistoryLine { +-- symbol :: String, + hperiod :: Period, + open :: Double, + close :: Double, + high :: Double, + low :: Double, + adjclose :: Double, + volume :: Int + } deriving (Read, Show, Eq, Ord) + +historyUTCTime :: HistoryLine -> UTCTime +historyUTCTime h = case (hperiod h) of + PDay d -> UTCTime d 0 + _ -> error "not implimented" hunk ./HQuant/History.hs 75 -data Period = - PDay Day | - PHour Int | - PTick Int - deriving Show +plotLocalTime :: PlotPoint -> (LocalTime, Double) +plotLocalTime (PlotPoint p d) = (periodLocalTime p, d) hunk ./HQuant/History.hs 79 -data HistoryLine = - HistoryLine { - symbol :: String, - hdate :: Day, - open :: Double, - close :: Double, - high :: Double, - low :: Double, - adjclose :: Double, - volume :: Int - } deriving Show +sortHistory :: HistoryLine -> HistoryLine -> Ordering +sortHistory a b | hdate a < hdate b = LT + | otherwise = GT + + +hdate :: HistoryLine -> Day +hdate h = case hperiod h of + PDay d -> d + _ -> error "not a day" hunk ./HQuant/History.hs 90 -strArrayToHistory s (d:o:c:h:l:a:v:_) = Just $HistoryLine s da op cl hi lo ad vo +strArrayToHistory _symbol (d:o:c:h:l:a:v:_) = Just $ HistoryLine da op cl hi lo ad vo hunk ./HQuant/History.hs 92 - da = fromJust $ parseTime defaultTimeLocale "%F" d + da = PDay $ fromJust $ parseTime defaultTimeLocale "%F" d hunk ./HQuant/LoadHistory.hs 7 +import Data.List addfile ./HQuant/Studies.hs hunk ./HQuant/Studies.hs 1 +module HQuant.Studies where + +import Data.List +--import Data.Time.Calendar (Day) +import HQuant.History +--import Data.Maybe + + +crossesBelow1 :: [PlotPoint] -> [PlotPoint] -> [PlotPoint] +crossesBelow1 [] _ = [] +crossesBelow1 _ [] = [] +crossesBelow1 (a:as) (b:bs) = crossesBelow a as b bs [] + +crossesBelow ::PlotPoint -> [PlotPoint] -> PlotPoint -> [PlotPoint] -> [PlotPoint] -> [PlotPoint] +crossesBelow _ [] _ _ r = r +crossesBelow _ _ _ [] r = r +crossesBelow l1 (n1:as) l2 (n2:bs) r = + if (d1 == d2) then + if (p1 < p2 && last1 >= last2) then -- && (last1 > last2) then + crossesBelow n1 as n2 bs (n2:r) + else crossesBelow n1 as n2 bs r + else + error $(show d1)++"<>"++(show d2) + where + d1 = plotPeriod n1 + d2 = plotPeriod n2 + p1 = plotPrice n1 + p2 = plotPrice n2 + last1 = plotPrice l1 + last2 = plotPrice l2 + + +crossesAbove1 :: [PlotPoint] -> [PlotPoint] -> [PlotPoint] +crossesAbove1 [] _ = [] +crossesAbove1 _ [] = [] +crossesAbove1 (a:as) (b:bs) = crossesAbove a as b bs [] + +crossesAbove ::PlotPoint -> [PlotPoint] -> PlotPoint -> [PlotPoint] -> [PlotPoint] -> [PlotPoint] +crossesAbove _ [] _ _ r = r +crossesAbove _ _ _ [] r = r +crossesAbove l1 (n1:as) l2 (n2:bs) r = + if (d1 == d2) then + if (p1 > p2 && last1 <= last2) then -- && (last1 > last2) then + crossesAbove n1 as n2 bs (n2:r) + else crossesAbove n1 as n2 bs r + else + error $(show d1)++"<>"++(show d2) + where + d1 = plotPeriod n1 + d2 = plotPeriod n2 + p1 = plotPrice n1 + p2 = plotPrice n2 + last1 = plotPrice l1 + last2 = plotPrice l2 hunk ./HQuant/Technical.hs 4 -import Data.Time.Calendar (Day) +--import Data.Time.Calendar (Day) hunk ./HQuant/Technical.hs 6 +import Data.Maybe hunk ./HQuant/Technical.hs 30 +assertForwardHistory :: [HistoryLine] -> [HistoryLine] +assertForwardHistory hs = hs +--assertForwardHistory hs = if +--assert False x = error "assertion failed!" hunk ./HQuant/Technical.hs 35 -type PlotPoint = (Period, Double) -plotPeriod :: PlotPoint -> Period -plotPeriod p = fst p +simpleMovingAverage :: Int -> [HistoryLine] -> [PlotPoint] +simpleMovingAverage nperiods hs = reverse $ catMaybes $ mapPlot (hsSma nperiods) $ reverse hs hunk ./HQuant/Technical.hs 38 -plotPrice :: (a,Double)-> Double -plotPrice p = snd p - - -sma :: Int -> [HistoryLine] -> PlotPoint -sma n hs = ave n (nclose n hs) +hsSma :: Int -> [HistoryLine] -> Maybe PlotPoint +hsSma n hs = if length hs >= n then Just $ averagePlotPoints n (hClosePlotN n hs) else Nothing hunk ./HQuant/Technical.hs 44 -mapPlot :: ([HistoryLine] -> PlotPoint) -> [HistoryLine] -> [PlotPoint] -mapPlot f [] = [] +mapPlot :: ([HistoryLine] -> Maybe PlotPoint) -> [HistoryLine] -> [Maybe PlotPoint] +mapPlot _ [] = [] hunk ./HQuant/Technical.hs 48 -foldPlot :: (Double -> Double -> Double) -> Double -> [(a,Double)] -> Double -foldPlot f z [] = z -- if the list is empty, the result is the initial value +mapPlot2 :: ([HistoryLine] -> Maybe PlotPoint) -> [HistoryLine] -> [Maybe PlotPoint] +mapPlot2 _ [] = [] +mapPlot2 f hs = f hs : mapPlot2 f (tail hs) + +foldPlot :: (Double -> Double -> Double) -> Double -> [PlotPoint] -> Double +foldPlot _ z [] = z -- if the list is empty, the result is the initial value hunk ./HQuant/Technical.hs 56 -ave :: Int -> [PlotPoint] -> PlotPoint -ave n fs = (plotPeriod $ head fs, (*) (1.0/(fromIntegral n)) ( foldPlot (+) 0 fs) ) +averagePlotPoints :: Int -> [PlotPoint] -> PlotPoint +averagePlotPoints n fs = PlotPoint (plotPeriod $ head fs) ((*) (1.0/(fromIntegral n)) ( foldPlot (+) 0 fs) ) hunk ./HQuant/Technical.hs 59 -nclose :: Int -> [HistoryLine] -> [PlotPoint] -nclose n hs = map (\h -> (historyPeriod h, close h)) $ take n hs +hClosePlotN :: Int -> [HistoryLine] -> [PlotPoint] +hClosePlotN n hs = map (\h -> PlotPoint (historyPeriod h) (close h)) $ take n hs hunk ./fetch.hs 1 +import HQuant.FetchQuote +import Data.Time +import Data.Time.Clock +import System.Environment +import qualified Finance.Quote.Yahoo as Yahoo + +start :: Day +start = fromGregorian 2010 1 1 :: Day hunk ./fetch.hs 12 - h <- getHistoricalQuote sym start end Daily - case h of - Nothing -> error "getHistoricalQuote failed" - Just hist -> do - writeHistory sym hist - return () + a <- getArgs + let sym = head a + hh <- loadYahoo sym start + writeHistory sym hh hunk ./hquant.hs 1 -module Test2 where +module Main where hunk ./hquant.hs 3 -import Graphics.Rendering.Chart -import Graphics.Rendering.Chart.Gtk hunk ./hquant.hs 4 -import Data.Colour -import Data.Colour.Names -import Data.Colour.SRGB -import Data.Accessor -import System.Environment(getArgs) ---import Prices(prices) -import HQuant.History +import HQuant.History hunk ./hquant.hs 7 +import HQuant.Studies hunk ./hquant.hs 9 +import Data.Maybe +import HQuant.Chart hunk ./hquant.hs 12 -lwidth = 1.0 +nperiods = 10 hunk ./hquant.hs 14 -lineStyle :: AlphaColour Double -> CairoLineStyle -lineStyle c = line_width ^= 3 * lwidth - $ line_color ^= c - $ defaultPlotLines ^. plot_lines_style hunk ./hquant.hs 15 -limitLineStyle :: Colour Double -> CairoLineStyle -limitLineStyle c = line_width ^= lwidth - $ line_color ^= opaque c - $ line_dashes ^= [5,10] - $ defaultPlotLines ^. plot_lines_style - ---plotLines :: [(x[asrq], y[asrr])]-> String-> AlphaColour Double-> PlotLines x[asrq] y[asrr] -plotLines prices title color = plot_lines_style ^= lineStyle color - $ plot_lines_values ^= [[ (d, v) | (d,v) <- prices]] - $ plot_lines_title ^= title - $ defaultPlotLines - -limits :: (Ord a, Ord a2) =>t -> [Either (Plot a1 (a -> a -> a)) (Plot a3 (a2 -> a2 -> a2))] -limits prices = [ Left $ hlinePlot "min/max" (limitLineStyle blue) min, - Left $ hlinePlot "" (limitLineStyle blue) max, - Right $ hlinePlot "min/max" (limitLineStyle green) min, - Right $ hlinePlot "" (limitLineStyle green) max ] - -bg :: AlphaColour Double -bg = opaque $ sRGB 0 0 0.25 -fg :: AlphaColour Double -fg = opaque white -fg1 :: AlphaColour Double -fg1 = opaque red-- $ sRGB 0.0 0.0 0.15 - - -layout :: (PlotValue x, PlotValue y) => [(x, y)] -> [(x, y)] -> Layout1 x y -layout prices study = layout1_title ^="Price History" - $ layout1_background ^= solidFillStyle bg - $ updateAllAxesStyles (axis_grid_style ^= solidLine 1 fg1) - $ layout1_left_axis ^: laxis_override ^= axisGridHide - $ layout1_right_axis ^: laxis_override ^= axisGridHide - $ layout1_bottom_axis ^: laxis_override ^= axisGridHide - $ layout1_plots ^= ([Left (toPlot $plotLines prices "Price" fg), Right (toPlot $plotLines study "study" fg1)])-- ++ limits prices) - $ layout1_grid_last ^= False - $ setLayout1Foreground fg - $ defaultLayout1 - -chart :: [(LocalTime,Double)] -> [(LocalTime,Double)] -> Renderable () -chart prices study = toRenderable $ layout prices study - -nperiods = 6 hunk ./hquant.hs 16 -sma20 = sma nperiods hunk ./hquant.hs 17 +buydate d (h:hs) = if hdate h == d then Just $ (PDay $hdate h, open h) else Nothing +selldate d (h:hs) = if hdate h == d then Just $ ( PDay $ hdate h, close h) else Nothing + +buyShares shares a b = a + b * shares +sellShares shares a b = a + b * shares hunk ./hquant.hs 23 ---main1 ["small"] = renderableToPNGFile (chart prices2 0.25) 320 240 "test2_small.png" ---main1 ["big"] = renderableToPNGFile (chart prices2 0.25) 800 600 "test2_big.png" hunk ./hquant.hs 25 - let hsplot = map (\h -> (historyLocalTime h, close h)) hs - let smaspy = drop nperiods $reverse $ mapPlot sma20 $ reverse hs - let sm = map (\(p,f) -> (periodLocalTime p, f)) smaspy - renderableToWindow (chart hsplot sm) 640 480 + let hsplot = map (\h -> PlotPoint (hperiod h) (close h)) hs :: [PlotPoint] + let smaspy = simpleMovingAverage nperiods hs :: [PlotPoint] + print smaspy + let start = head hsplot + let end = head $ reverse hsplot + let match = drop (nperiods-1) hsplot + print start + print end + let buys = reverse $crossesBelow1 smaspy match + let sells = reverse $crossesAbove1 smaspy match + --let profit = foldPlot (buyShares 100) 0 $ reverse $ drop 1 $ reverse buys + --let loss = foldPlot (buyShares 100) 0 sells + --print profit + --print loss + --print $ profit - loss + --buyAndHold start end 100 + priceChartBuySells ("SMA("++show nperiods++")") (map plotLocalTime match) (map plotLocalTime smaspy) buys sells + + --renderableToPNGFile (chart (map plotLocalTime match) (map plotLocalTime smaspy)) 640 480 "spysma.png" + --renderableToWindow (chart (map plotLocalTime match) (map plotLocalTime smaspy)) 640 480 + hunk ./load.hs 1 -import HQuant.Chart hunk ./load.hs 6 +import Data.Time.LocalTime +import Data.Time +import Data.Maybe (fromJust) +import System.Locale (defaultTimeLocale) +import Data.Time.Clock addfile ./pairs.hs hunk ./pairs.hs 1 + +import HQuant.LoadHistory +import HQuant.History +import Data.Time +import Data.Time.Clock +import qualified Finance.Quote.Yahoo as Yahoo + +start :: Day +start = fromGregorian 2010 1 1 :: Day + +buy h shares = Order (historyUTCTime h) shares (adjclose h) +sell h shares = Order (historyUTCTime h) (negate shares) (adjclose h) + +orderPrice (Order _ shares price) = negate$price * (fromIntegral shares) + +--buy price multiplier shares = price * multiplier * shares +--sell price multiplier shares = price * multiplier * (negate$shares) +profit o1 o2 = (orderPrice o1) + (orderPrice o2) + +main :: IO () +main = do + let longShares = 60 * 1 + let shotShared = 100 * 1 + gld <- readHistory "GLD" + gdx <- readHistory "GDX" + let o1 = buy ( head gld) longShares + let c1 = sell (head $reverse gld) longShares + let o2 = sell (head gdx) shotShared + let c2 = buy (head $reverse gdx) shotShared + print o1 + print c1 + print o2 + print c2 + + print $ orderPrice o1 + print $ orderPrice o2 + + let p1 =profit o1 c1 + let p2 =profit o2 c2 + print p1 + print p2 + print $p1+p2 + addfile ./spysma.hs hunk ./spysma.hs 1 +module Main where + +import HQuant.History +import HQuant.LoadHistory +import HQuant.Technical +import Data.List +import HQuant.Chart + +nperiods = 10 + + +spy = readHistory "SPY" + +main = do + hs <- spy + let hsplot = map (\h -> PlotPoint (hperiod h) (close h)) hs :: [PlotPoint] + let smaspy = simpleMovingAverage nperiods hs :: [PlotPoint] + print smaspy + let start = head hsplot + let end = head $ reverse hsplot + let match = drop (nperiods-1) hsplot + priceChartStudy ("SMA("++show nperiods++")") (map plotLocalTime match) (map plotLocalTime smaspy) + + +