module OANDA.Rates
( InstrumentsArgs (..)
, instrumentsArgs
, Instrument (..)
, instruments
, Price (..)
, prices
, MidpointCandlestick (..)
, midpointCandles
, BidAskCandlestick (..)
, bidaskCandles
, CandlesArgs (..)
, candlesArgs
, CandlesCount (..)
, DayOfWeek (..)
, Granularity (..)
) where
import Data.Aeson
import Data.Char (toLower)
import Data.Decimal
import Data.Text (Text, pack)
import Data.Time
import qualified Data.Vector as V
import GHC.Generics (Generic)
import Network.Wreq (Options)
import OANDA.Util
import OANDA.Types
data InstrumentsArgs = InstrumentsArgs
{ instrumentsFields :: [Text]
, instrumentsInstruments :: [Text]
} deriving (Show)
instrumentsArgs :: InstrumentsArgs
instrumentsArgs = InstrumentsArgs ["displayName", "pip", "maxTradeUnits"] []
data Instrument = Instrument
{ instrumentInstrument :: String
, instrumentPip :: Maybe Decimal
, instrumentMaxTradeUnits :: Maybe Integer
, instrumentDisplayName :: Maybe String
, instrumentPrecision :: Maybe Decimal
, instrumentMaxTrailingStop :: Maybe Decimal
, instrumentMinTrailingStop :: Maybe Decimal
, instrumentMarginRate :: Maybe Decimal
, instrumentHalted :: Maybe String
, instrumentInterestRate :: Maybe Decimal
} deriving (Show, Generic)
instance FromJSON Instrument where
parseJSON = genericParseJSON $ jsonOpts "instrument"
instruments :: OandaEnv -> AccountID -> InstrumentsArgs -> IO (V.Vector Instrument)
instruments od (AccountID aid) (InstrumentsArgs fs is) = do
let url = baseURL od ++ "/v1/instruments"
opts = constructOpts od [ ("accountId", [pack $ show aid])
, ("instruments", is)
, ("fields", fs)
]
jsonResponseArray url opts "instruments"
prices :: OandaEnv -> [InstrumentText] -> Maybe ZonedTime -> IO (V.Vector Price)
prices od is zt =
do let url = baseURL od ++ "/v1/prices"
ztOpt = maybe [] (\zt' -> [("since", [pack $ formatTimeRFC3339 zt'])]) zt
opts = constructOpts od $ ("instruments", is) : ztOpt
jsonResponseArray url opts "prices"
data Price = Price
{ priceInstrument :: InstrumentText
, priceTime :: ZonedTime
, priceBid :: Decimal
, priceAsk :: Decimal
} deriving (Show, Generic)
instance FromJSON Price where
parseJSON = genericParseJSON $ jsonOpts "price"
midpointCandles :: OandaEnv -> InstrumentText -> CandlesArgs ->
IO (V.Vector MidpointCandlestick)
midpointCandles od i args =
do let (url, opts) = candleOpts od i args "midpoint"
response <- jsonResponse url opts :: IO MidpointCandlesResponse
return $ _midcandlesResponseCandles response
bidaskCandles :: OandaEnv -> InstrumentText -> CandlesArgs ->
IO (V.Vector BidAskCandlestick)
bidaskCandles od i args =
do let (url, opts) = candleOpts od i args "bidask"
response <- jsonResponse url opts :: IO BidAskCandlesResponse
return $ _bidaskResponseCandles response
candleOpts :: OandaEnv -> InstrumentText -> CandlesArgs -> String -> (String, Options)
candleOpts od i (CandlesArgs c g di atz wa) fmt = (url, opts)
where url = baseURL od ++ "/v1/candles"
opts = constructOpts od $ [ ("instrument", [i])
, ("granularity", [pack $ show g])
, ("candleFormat", [pack fmt])
, ("dailyAlignment", [pack $ show di])
, ("alignmentTimeZone", [pack atz])
, ("weeklyAlignment", [pack $ show wa])
] ++ countOpts c
countOpts (Count count) = [("count", [pack $ show count])]
countOpts (StartEnd st ed incf) = [ ("start", [pack $ formatTimeRFC3339 st])
, ("end", [pack $ formatTimeRFC3339 ed])
, ("includeFirst", [pack $ map toLower (show incf)])
]
data MidpointCandlestick = MidpointCandlestick
{ midpointCandlestickTime :: ZonedTime
, midpointCandlestickOpenMid :: Decimal
, midpointCandlestickHighMid :: Decimal
, midpointCandlestickLowMid :: Decimal
, midpointCandlestickCloseMid :: Decimal
, midpointCandlestickVolume :: Int
, midpointCandlestickComplete :: Bool
} deriving (Show, Generic)
instance FromJSON MidpointCandlestick where
parseJSON = genericParseJSON $ jsonOpts "midpointCandlestick"
data BidAskCandlestick = BidAskCandlestick
{ bidaskCandlestickTime :: ZonedTime
, bidaskCandlestickOpenBid :: Decimal
, bidaskCandlestickOpenAsk :: Decimal
, bidaskCandlestickHighBid :: Decimal
, bidaskCandlestickHighAsk :: Decimal
, bidaskCandlestickLowBid :: Decimal
, bidaskCandlestickLowAsk :: Decimal
, bidaskCandlestickCloseBid :: Decimal
, bidaskCandlestickCloseAsk :: Decimal
, bidaskCandlestickVolume :: Int
, bidaskCandlestickComplete :: Bool
} deriving (Show, Generic)
instance FromJSON BidAskCandlestick where
parseJSON = genericParseJSON $ jsonOpts "bidaskCandlestick"
data CandlesArgs = CandlesArgs
{ candlesCount :: CandlesCount
, candlesGranularity :: Granularity
, candlesDailyAlignment :: Int
, candlesAlignmentTZ :: String
, candlesWeeklyAlignment :: DayOfWeek
} deriving (Show)
candlesArgs :: CandlesArgs
candlesArgs = CandlesArgs (Count 500) S5 17 "America/New_York" Friday
data CandlesCount = Count Int
| StartEnd { start :: ZonedTime
, end :: ZonedTime
, includeFirst :: Bool
}
deriving (Show)
data DayOfWeek = Monday
| Tuesday
| Wednesday
| Thursday
| Friday
| Saturday
| Sunday
deriving (Show)
data Granularity = S5 | S10 | S15 | S30
| M1 | M2 | M3 | M4 | M5 | M10 | M15 | M30
| H1 | H2 | H3 | H4 | H6 | H8 | H12
| D
| W
| M
deriving (Show)
data MidpointCandlesResponse = MidpointCandlesResponse
{ _midcandlesResponseInstrument :: InstrumentText
, _midcandlesResponseGranularity :: String
, _midcandlesResponseCandles :: V.Vector MidpointCandlestick
} deriving (Show, Generic)
instance FromJSON MidpointCandlesResponse where
parseJSON = genericParseJSON $ jsonOpts "_midcandlesResponse"
data BidAskCandlesResponse = BidAskCandlesResponse
{ _bidaskResponseInstrument :: InstrumentText
, _bidaskResponseGranularity :: String
, _bidaskResponseCandles :: V.Vector BidAskCandlestick
} deriving (Show, Generic)
instance FromJSON BidAskCandlesResponse where
parseJSON = genericParseJSON $ jsonOpts "_bidaskResponse"