You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
881 lines
28 KiB
881 lines
28 KiB
|
3 years ago
|
{-# LANGUAGE DuplicateRecordFields #-}
|
||
|
|
{-# LANGUAGE RecordWildCards #-}
|
||
|
|
|
||
|
|
module Transaq
|
||
|
|
(
|
||
|
|
CommandConnect(..),
|
||
|
|
Language(..),
|
||
|
|
TransaqCommand(..),
|
||
|
|
TransaqResponseC(..),
|
||
|
|
TransaqResponse(..),
|
||
|
|
SecurityId(..),
|
||
|
|
CommandDisconnect(..),
|
||
|
|
CommandSubscribe(..),
|
||
|
|
CommandNewOrder(..),
|
||
|
|
CommandCancelOrder(..),
|
||
|
|
CommandGetSecuritiesInfo(..),
|
||
|
|
ResponseResult(..),
|
||
|
|
ResponseCandles(..),
|
||
|
|
ResponseServerStatus(..),
|
||
|
|
ResponseCandleKinds(..),
|
||
|
|
ResponseMarkets(..),
|
||
|
|
ResponseSecurities(..),
|
||
|
|
ResponseSecInfo(..),
|
||
|
|
ResponseQuotations(..),
|
||
|
|
ResponseAllTrades(..),
|
||
|
|
ResponseTrades(..),
|
||
|
|
ResponseQuotes(..),
|
||
|
|
Quotation(..),
|
||
|
|
Quote(..),
|
||
|
|
TradeNotification(..),
|
||
|
|
OrderNotification(..),
|
||
|
|
AllTradesTrade(..),
|
||
|
|
Tick(..),
|
||
|
|
ConnectionState(..),
|
||
|
|
MarketInfo(..)
|
||
|
|
) where
|
||
|
|
|
||
|
|
import Control.Applicative ((<|>))
|
||
|
|
import Control.Error.Util (hush)
|
||
|
|
import Control.Monad (void)
|
||
|
|
import Data.Attoparsec.Text (Parser, char, decimal, many',
|
||
|
|
maybeResult, parse, parseOnly,
|
||
|
|
skipSpace)
|
||
|
|
import Data.Decimal (DecimalRaw (..))
|
||
|
|
import Data.Int (Int64)
|
||
|
|
import Data.Maybe (catMaybes, fromMaybe, mapMaybe,
|
||
|
|
maybeToList)
|
||
|
|
import qualified Data.Text as T
|
||
|
|
import Data.Time (fromGregorian)
|
||
|
|
import Data.Time.Clock (UTCTime (UTCTime))
|
||
|
|
import Debug.Trace
|
||
|
|
import Text.Read (readMaybe)
|
||
|
|
import Text.XML.Light (Attr (..), CData (cdData),
|
||
|
|
Element (elName), Node (..), QName (..),
|
||
|
|
elChildren, findAttr, findChild,
|
||
|
|
onlyText, strContent, unode)
|
||
|
|
import Text.XML.Light.Output (showElement)
|
||
|
|
import Text.XML.Light.Types (Element (elContent), blank_name)
|
||
|
|
|
||
|
|
data Language = LanguageRu | LanguageEn
|
||
|
|
deriving (Show, Eq, Ord)
|
||
|
|
|
||
|
|
instance Node Language where
|
||
|
|
node n LanguageRu = node n ("ru" :: String)
|
||
|
|
node n LanguageEn = node n ("en" :: String)
|
||
|
|
|
||
|
|
type TransaqPrice = DecimalRaw Int
|
||
|
|
|
||
|
|
strAttr :: String -> String -> Attr
|
||
|
|
strAttr key val = Attr { attrKey = blank_name { qName = key}, attrVal = val}
|
||
|
|
|
||
|
|
fromBool :: Bool -> String
|
||
|
|
fromBool True = "true"
|
||
|
|
fromBool False = "false"
|
||
|
|
|
||
|
|
parseTimestamp :: T.Text -> Maybe UTCTime
|
||
|
|
parseTimestamp = hush . parseOnly parser
|
||
|
|
where
|
||
|
|
parser = parseWithDate <|> (UTCTime epoch <$> parseTime)
|
||
|
|
parseWithDate = do
|
||
|
|
date <- parseDate
|
||
|
|
skipSpace
|
||
|
|
time <- parseTime
|
||
|
|
pure $ UTCTime date time
|
||
|
|
parseDate = do
|
||
|
|
day <- decimal
|
||
|
|
void $ char '.'
|
||
|
|
month <- decimal
|
||
|
|
void $ char '.'
|
||
|
|
year <- decimal
|
||
|
|
pure $ fromGregorian year month day
|
||
|
|
|
||
|
|
parseTime = do
|
||
|
|
hour <- (decimal :: Parser Int)
|
||
|
|
void $ char ':'
|
||
|
|
minute <- decimal
|
||
|
|
void $ char ':'
|
||
|
|
second <- decimal
|
||
|
|
msecs <- many' $ do
|
||
|
|
void $ char '.'
|
||
|
|
(decimal :: Parser Int)
|
||
|
|
let secofday = hour * 3600 + minute * 60 + second
|
||
|
|
case msecs of
|
||
|
|
[ms] -> pure $ fromIntegral secofday + fromIntegral ms / 1000.0
|
||
|
|
_ -> pure $ fromIntegral secofday
|
||
|
|
epoch = fromGregorian 1970 1 1
|
||
|
|
|
||
|
|
|
||
|
|
class TransaqCommand t where
|
||
|
|
toXml :: t -> T.Text
|
||
|
|
|
||
|
|
class TransaqResponseC t where
|
||
|
|
fromXml :: Element -> Maybe t
|
||
|
|
|
||
|
|
data CommandConnect =
|
||
|
|
CommandConnect
|
||
|
|
{
|
||
|
|
login :: T.Text,
|
||
|
|
password :: T.Text,
|
||
|
|
host :: T.Text,
|
||
|
|
port :: Int,
|
||
|
|
language :: Language,
|
||
|
|
autopos :: Bool,
|
||
|
|
micexRegisters :: Bool,
|
||
|
|
milliseconds :: Bool,
|
||
|
|
utcTime :: Bool,
|
||
|
|
proxy :: (), -- not supported
|
||
|
|
rqDelay :: Maybe Int,
|
||
|
|
sessionTimeout :: Maybe Int,
|
||
|
|
requestTimeout :: Maybe Int,
|
||
|
|
pushULimits :: Maybe Int,
|
||
|
|
pushPosEquity :: Maybe Int
|
||
|
|
} deriving (Show, Eq, Ord)
|
||
|
|
|
||
|
|
instance Node CommandConnect where
|
||
|
|
node n CommandConnect {..} = node n (attrs, subnodes)
|
||
|
|
where
|
||
|
|
attrs = [strAttr "id" "connect"]
|
||
|
|
subnodes =
|
||
|
|
[ unode "login" (T.unpack login)
|
||
|
|
, unode "password" (T.unpack password)
|
||
|
|
, unode "host" (T.unpack host)
|
||
|
|
, unode "port" (show port)
|
||
|
|
, unode "language" language
|
||
|
|
, unode "autopos" (fromBool autopos)
|
||
|
|
, unode "micex_registers" (fromBool micexRegisters)
|
||
|
|
, unode "milliseconds" (fromBool milliseconds)
|
||
|
|
, unode "utc_time" (fromBool utcTime)
|
||
|
|
]
|
||
|
|
++ maybeToList (unode "rqdelay" . show <$> rqDelay)
|
||
|
|
++ maybeToList (unode "session_timeout" . show <$> sessionTimeout)
|
||
|
|
++ maybeToList (unode "request_timeout" . show <$> requestTimeout)
|
||
|
|
++ maybeToList (unode "push_u_limits" . show <$> pushULimits)
|
||
|
|
++ maybeToList (unode "push_pos_limits" . show <$> pushPosEquity)
|
||
|
|
|
||
|
|
instance TransaqCommand CommandConnect where
|
||
|
|
toXml = T.pack . showElement . unode "command"
|
||
|
|
|
||
|
|
data CommandDisconnect = CommandDisconnect
|
||
|
|
deriving (Show, Eq, Ord)
|
||
|
|
|
||
|
|
instance TransaqCommand CommandDisconnect where
|
||
|
|
toXml CommandDisconnect = T.pack . showElement $ unode "command" [strAttr "id" "disconnect"]
|
||
|
|
|
||
|
|
data SecurityId =
|
||
|
|
SecurityId
|
||
|
|
{
|
||
|
|
board :: T.Text
|
||
|
|
, seccode :: T.Text
|
||
|
|
} deriving (Show, Eq, Ord)
|
||
|
|
|
||
|
|
instance Node SecurityId where
|
||
|
|
node n SecurityId {..} = node n
|
||
|
|
[ unode "board" (T.unpack board)
|
||
|
|
, unode "seccode" (T.unpack seccode)
|
||
|
|
]
|
||
|
|
|
||
|
|
data CommandSubscribe =
|
||
|
|
CommandSubscribe
|
||
|
|
{
|
||
|
|
alltrades :: [SecurityId]
|
||
|
|
, quotations :: [SecurityId]
|
||
|
|
, quotes :: [SecurityId]
|
||
|
|
} deriving (Show, Eq, Ord)
|
||
|
|
|
||
|
|
instance TransaqCommand CommandSubscribe where
|
||
|
|
toXml CommandSubscribe {..} =
|
||
|
|
T.pack . showElement $ unode "command" ([strAttr "id" "subscribe"],
|
||
|
|
[ unode "alltrades" $ fmap (unode "security") alltrades
|
||
|
|
, unode "quotations" $ fmap (unode "security") quotations
|
||
|
|
, unode "quotes" $ fmap (unode "security") quotes
|
||
|
|
])
|
||
|
|
|
||
|
|
data CommandUnsubscribe =
|
||
|
|
CommandUnsubscribe
|
||
|
|
{
|
||
|
|
alltrades :: [SecurityId]
|
||
|
|
, quotations :: [SecurityId]
|
||
|
|
, quotes :: [SecurityId]
|
||
|
|
} deriving (Show, Eq, Ord)
|
||
|
|
|
||
|
|
instance TransaqCommand CommandUnsubscribe where
|
||
|
|
toXml CommandUnsubscribe {..} =
|
||
|
|
T.pack . showElement $ unode "command" ([strAttr "id" "unsubscribe"],
|
||
|
|
[ unode "alltrades" $ fmap (unode "security") alltrades
|
||
|
|
, unode "quotations" $ fmap (unode "security") quotations
|
||
|
|
, unode "quotes" $ fmap (unode "security") quotes
|
||
|
|
])
|
||
|
|
|
||
|
|
data CommandGetHistoryData =
|
||
|
|
CommandGetHistoryData
|
||
|
|
{
|
||
|
|
security :: SecurityId
|
||
|
|
, periodId :: Int
|
||
|
|
, count :: Int
|
||
|
|
, reset :: Bool
|
||
|
|
} deriving (Show, Eq, Ord)
|
||
|
|
|
||
|
|
instance TransaqCommand CommandGetHistoryData where
|
||
|
|
toXml CommandGetHistoryData {..} =
|
||
|
|
T.pack . showElement $ unode "command" ([strAttr "id" "gethistorydata"],
|
||
|
|
[ unode "security" security
|
||
|
|
, unode "period" (show periodId)
|
||
|
|
, unode "count" (show count)
|
||
|
|
, unode "reset" (fromBool reset)
|
||
|
|
])
|
||
|
|
|
||
|
|
data TradeDirection = Buy | Sell
|
||
|
|
deriving (Show, Eq, Ord)
|
||
|
|
|
||
|
|
instance Node TradeDirection where
|
||
|
|
node n Buy = node n ("B" :: String)
|
||
|
|
node n Sell = node n ("S" :: String)
|
||
|
|
|
||
|
|
data UnfilledAction =
|
||
|
|
UnfilledPutInQueue
|
||
|
|
| UnfilledFOK
|
||
|
|
| UnfilledIOC
|
||
|
|
deriving (Show, Eq, Ord)
|
||
|
|
|
||
|
|
instance Node UnfilledAction where
|
||
|
|
node n UnfilledPutInQueue = node n ("PutInQueue" :: String)
|
||
|
|
node n UnfilledFOK = node n ("FOK" :: String)
|
||
|
|
node n UnfilledIOC = node n ("IOC" :: String)
|
||
|
|
|
||
|
|
data CommandNewOrder =
|
||
|
|
CommandNewOrder
|
||
|
|
{
|
||
|
|
security :: SecurityId
|
||
|
|
, client :: T.Text
|
||
|
|
, unionCode :: T.Text
|
||
|
|
, price :: TransaqPrice
|
||
|
|
, quantity :: Int
|
||
|
|
, buysell :: TradeDirection
|
||
|
|
, bymarket :: Bool
|
||
|
|
, brokerRef :: T.Text
|
||
|
|
, unfilled :: UnfilledAction
|
||
|
|
, usecredit :: Bool
|
||
|
|
, nosplit :: Bool
|
||
|
|
} deriving (Show, Eq, Ord)
|
||
|
|
|
||
|
|
instance TransaqCommand CommandNewOrder where
|
||
|
|
toXml CommandNewOrder {..} =
|
||
|
|
T.pack . showElement $ unode "command" ([strAttr "id" "neworder"],
|
||
|
|
[ unode "security" security
|
||
|
|
, unode "client" $ T.unpack client
|
||
|
|
, unode "union" $ T.unpack unionCode
|
||
|
|
, unode "price" $ show price
|
||
|
|
, unode "quantity" $ show quantity
|
||
|
|
, unode "buysell" buysell
|
||
|
|
, unode "brokerref" $ T.unpack brokerRef
|
||
|
|
, unode "unfillled" unfilled
|
||
|
|
]
|
||
|
|
++ boolToList "bymarket" bymarket
|
||
|
|
++ boolToList "usecredit" usecredit
|
||
|
|
++ boolToList "nosplit" nosplit)
|
||
|
|
where
|
||
|
|
boolToList n True = [unode n ("" :: String)]
|
||
|
|
boolToList _ False = []
|
||
|
|
|
||
|
|
newtype CommandCancelOrder =
|
||
|
|
CommandCancelOrder
|
||
|
|
{
|
||
|
|
transactionId :: Integer
|
||
|
|
} deriving (Show, Eq, Ord)
|
||
|
|
|
||
|
|
instance TransaqCommand CommandCancelOrder where
|
||
|
|
toXml CommandCancelOrder{..} =
|
||
|
|
T.pack . showElement $ unode "command" ([strAttr "id" "cancelOrder"],
|
||
|
|
[ unode "transactionid" (show transactionId)])
|
||
|
|
|
||
|
|
newtype CommandGetSecuritiesInfo =
|
||
|
|
CommandGetSecuritiesInfo
|
||
|
|
{
|
||
|
|
securities :: [SecurityId]
|
||
|
|
} deriving (Show, Eq, Ord)
|
||
|
|
|
||
|
|
instance TransaqCommand CommandGetSecuritiesInfo where
|
||
|
|
toXml CommandGetSecuritiesInfo{..} =
|
||
|
|
T.pack . showElement $ unode "command" ([strAttr "id" "get_securities_info"],
|
||
|
|
fmap (unode "security") securities)
|
||
|
|
|
||
|
|
data ResponseResult =
|
||
|
|
ResponseSuccess
|
||
|
|
| ResponseFailure T.Text
|
||
|
|
deriving (Show, Eq, Ord)
|
||
|
|
|
||
|
|
instance TransaqResponseC ResponseResult where
|
||
|
|
fromXml root =
|
||
|
|
if qName (elName root) == "result"
|
||
|
|
then
|
||
|
|
if findAttr (blank_name {qName = "success"}) root == Just "true"
|
||
|
|
then Just ResponseSuccess
|
||
|
|
else Just . ResponseFailure . T.pack . concatMap cdData . onlyText . elContent $ root
|
||
|
|
else Nothing
|
||
|
|
|
||
|
|
|
||
|
|
data Candle =
|
||
|
|
Candle
|
||
|
|
{
|
||
|
|
cTimestamp :: UTCTime
|
||
|
|
, cOpen :: TransaqPrice
|
||
|
|
, cHigh :: TransaqPrice
|
||
|
|
, cLow :: TransaqPrice
|
||
|
|
, cClose :: TransaqPrice
|
||
|
|
, cVolume :: Int
|
||
|
|
, cOpenInterest :: Int
|
||
|
|
} deriving (Show, Eq, Ord)
|
||
|
|
|
||
|
|
data ResponseCandlesStatus =
|
||
|
|
StatusEndOfHistory
|
||
|
|
| StatusDone
|
||
|
|
| StatusPending
|
||
|
|
| StatusUnavaliable
|
||
|
|
deriving (Show, Eq, Ord)
|
||
|
|
|
||
|
|
data ResponseCandles =
|
||
|
|
ResponseCandles
|
||
|
|
{
|
||
|
|
periodId :: Int
|
||
|
|
, status :: ResponseCandlesStatus
|
||
|
|
, security :: SecurityId
|
||
|
|
, candles :: [Candle]
|
||
|
|
} deriving (Show, Eq, Ord)
|
||
|
|
|
||
|
|
uname :: String -> QName
|
||
|
|
uname x = blank_name {qName = x}
|
||
|
|
|
||
|
|
childContent :: String -> Element -> Maybe String
|
||
|
|
childContent tag el = strContent <$> findChild (uname tag) el
|
||
|
|
|
||
|
|
instance TransaqResponseC ResponseCandles where
|
||
|
|
fromXml root = do
|
||
|
|
periodId <- findAttr (uname "period") root >>= readMaybe
|
||
|
|
status <- findAttr (uname "status") root >>= readMaybe >>= parseStatus
|
||
|
|
board <- T.pack <$> findAttr (uname "board") root
|
||
|
|
seccode <- T.pack <$> findAttr (uname "seccode") root
|
||
|
|
let candles = mapMaybe parseCandle . elChildren $ root
|
||
|
|
return ResponseCandles
|
||
|
|
{
|
||
|
|
periodId = periodId
|
||
|
|
, status = status
|
||
|
|
, security = SecurityId board seccode
|
||
|
|
, candles = candles
|
||
|
|
}
|
||
|
|
where
|
||
|
|
parseStatus :: Int -> Maybe ResponseCandlesStatus
|
||
|
|
parseStatus intStatus =
|
||
|
|
case intStatus of
|
||
|
|
0 -> Just StatusEndOfHistory
|
||
|
|
1 -> Just StatusDone
|
||
|
|
2 -> Just StatusPending
|
||
|
|
3 -> Just StatusUnavaliable
|
||
|
|
_ -> Nothing
|
||
|
|
parseCandle element = do
|
||
|
|
timestamp <- findAttr (uname "open") element >>= parseTimestamp . T.pack
|
||
|
|
open <- findAttr (uname "open") element >>= readMaybe
|
||
|
|
high <- findAttr (uname "high") element >>= readMaybe
|
||
|
|
low <- findAttr (uname "low") element >>= readMaybe
|
||
|
|
close <- findAttr (uname "close") element >>= readMaybe
|
||
|
|
volume <- findAttr (uname "volume") element >>= readMaybe
|
||
|
|
openInterest <- findAttr (uname "oi") element >>= readMaybe
|
||
|
|
return Candle
|
||
|
|
{
|
||
|
|
cTimestamp = timestamp
|
||
|
|
, cOpen = open
|
||
|
|
, cHigh = high
|
||
|
|
, cLow = low
|
||
|
|
, cClose = close
|
||
|
|
, cVolume = volume
|
||
|
|
, cOpenInterest = openInterest
|
||
|
|
}
|
||
|
|
|
||
|
|
data ConnectionState =
|
||
|
|
Connected
|
||
|
|
| Disconnected
|
||
|
|
| Error T.Text
|
||
|
|
deriving (Show, Eq, Ord)
|
||
|
|
|
||
|
|
data ResponseServerStatus =
|
||
|
|
ResponseServerStatus
|
||
|
|
{
|
||
|
|
serverId :: Maybe Int
|
||
|
|
, state :: ConnectionState
|
||
|
|
, recover :: Maybe Bool
|
||
|
|
, serverTimezone :: Maybe T.Text
|
||
|
|
, systemVersion :: Maybe Int
|
||
|
|
, build :: Maybe Int
|
||
|
|
} deriving (Show, Eq, Ord)
|
||
|
|
|
||
|
|
instance TransaqResponseC ResponseServerStatus where
|
||
|
|
fromXml root = do
|
||
|
|
let serverId = findAttr (uname "id") root >>= readMaybe
|
||
|
|
connectedStr <- findAttr (uname "connected") root
|
||
|
|
state <- case connectedStr of
|
||
|
|
"true" -> pure Connected
|
||
|
|
"false" -> pure Disconnected
|
||
|
|
"error" -> pure $ Error (T.pack $ strContent root)
|
||
|
|
_ -> pure Disconnected
|
||
|
|
let recover =
|
||
|
|
case findAttr (uname "recover") root of
|
||
|
|
Just "true" -> pure True
|
||
|
|
_ -> pure False
|
||
|
|
let serverTimezone = T.pack <$> findAttr (uname "server_tz") root
|
||
|
|
let systemVersion = findAttr (uname "sys_ver") root >>= readMaybe
|
||
|
|
let build = findAttr (uname "build") root >>= readMaybe
|
||
|
|
pure $ ResponseServerStatus {..}
|
||
|
|
|
||
|
|
data MarketInfo =
|
||
|
|
MarketInfo
|
||
|
|
{ marketId :: Int
|
||
|
|
, marketName :: T.Text
|
||
|
|
} deriving (Show, Eq, Ord)
|
||
|
|
|
||
|
|
newtype ResponseMarkets = ResponseMarkets [MarketInfo]
|
||
|
|
deriving (Show, Eq, Ord)
|
||
|
|
|
||
|
|
instance TransaqResponseC ResponseMarkets where
|
||
|
|
fromXml root = do
|
||
|
|
markets <- mapM parseMarketInfo $ elChildren root
|
||
|
|
pure . ResponseMarkets . catMaybes $ markets
|
||
|
|
where
|
||
|
|
parseMarketInfo tag =
|
||
|
|
if (qName . elName) tag == "market"
|
||
|
|
then do
|
||
|
|
marketId <- findAttr (uname "id") tag >>= readMaybe
|
||
|
|
let marketName = T.pack $ strContent tag
|
||
|
|
pure $ Just $ MarketInfo {..}
|
||
|
|
else pure Nothing
|
||
|
|
|
||
|
|
data CandleKind =
|
||
|
|
CandleKind
|
||
|
|
{
|
||
|
|
kCandleKindId :: Int
|
||
|
|
, kPeriod :: Int
|
||
|
|
, kName :: T.Text
|
||
|
|
} deriving (Show, Eq, Ord)
|
||
|
|
|
||
|
|
newtype ResponseCandleKinds = ResponseCandleKinds [CandleKind]
|
||
|
|
deriving (Show, Eq, Ord)
|
||
|
|
|
||
|
|
|
||
|
|
instance TransaqResponseC ResponseCandleKinds where
|
||
|
|
fromXml root = do
|
||
|
|
kinds <- mapM parseCandleKind $ elChildren root
|
||
|
|
pure . ResponseCandleKinds . catMaybes $ kinds
|
||
|
|
where
|
||
|
|
parseCandleKind tag =
|
||
|
|
if (qName . elName) tag == "kind"
|
||
|
|
then do
|
||
|
|
kCandleKindId <- childContent "id" tag >>= readMaybe
|
||
|
|
kPeriod <- childContent "period" tag >>= readMaybe
|
||
|
|
kName <- T.pack <$> childContent "name" tag
|
||
|
|
pure . Just $ CandleKind {..}
|
||
|
|
else pure Nothing
|
||
|
|
|
||
|
|
data Security =
|
||
|
|
Security
|
||
|
|
{
|
||
|
|
secId :: Int
|
||
|
|
, active :: Bool
|
||
|
|
, seccode :: T.Text
|
||
|
|
, instrClass :: T.Text
|
||
|
|
, board :: T.Text
|
||
|
|
, market :: T.Text
|
||
|
|
, currency :: T.Text
|
||
|
|
, shortName :: T.Text
|
||
|
|
, decimals :: Int
|
||
|
|
, minStep :: Double
|
||
|
|
, lotSize :: Int
|
||
|
|
, lotDivider :: Int
|
||
|
|
, pointCost :: Double
|
||
|
|
, secType :: T.Text
|
||
|
|
} deriving (Show, Eq, Ord)
|
||
|
|
|
||
|
|
newtype ResponseSecurities =
|
||
|
|
ResponseSecurities [Security]
|
||
|
|
deriving (Show, Eq, Ord)
|
||
|
|
|
||
|
|
instance TransaqResponseC ResponseSecurities where
|
||
|
|
fromXml root = do
|
||
|
|
securities <- mapM parseSecurity $ elChildren root
|
||
|
|
pure . ResponseSecurities . catMaybes $ securities
|
||
|
|
where
|
||
|
|
parseSecurity tag =
|
||
|
|
if (qName . elName) tag == "security"
|
||
|
|
then do
|
||
|
|
secId <- findAttr (uname "secid") tag >>= readMaybe
|
||
|
|
active <- findAttr (uname "active") tag >>= parseBool
|
||
|
|
seccode <- T.pack <$> childContent "seccode" tag
|
||
|
|
instrClass <- T.pack <$> childContent "instrclass" tag
|
||
|
|
board <- T.pack <$> childContent "instrclass" tag
|
||
|
|
market <- T.pack <$> childContent "market" tag
|
||
|
|
currency <- T.pack <$> childContent "currency" tag
|
||
|
|
shortName <- T.pack <$> childContent "shortname" tag
|
||
|
|
decimals <- childContent "decimals" tag >>= readMaybe
|
||
|
|
minStep <- childContent "minstep" tag >>= readMaybe
|
||
|
|
lotSize <- childContent "lotsize" tag >>= readMaybe
|
||
|
|
lotDivider <- childContent "lotdivider" tag >>= readMaybe
|
||
|
|
pointCost <- childContent "point_cost" tag >>= readMaybe
|
||
|
|
secType <- T.pack <$> childContent "sectype" tag
|
||
|
|
pure . Just $ Security {..}
|
||
|
|
else
|
||
|
|
pure Nothing
|
||
|
|
|
||
|
|
parseBool "true" = Just True
|
||
|
|
parseBool "false" = Just False
|
||
|
|
parseBool _ = Nothing
|
||
|
|
|
||
|
|
|
||
|
|
data ResponseSecInfo =
|
||
|
|
ResponseSecInfo
|
||
|
|
{
|
||
|
|
secId :: Int
|
||
|
|
, secName :: T.Text
|
||
|
|
, secCode :: T.Text
|
||
|
|
, market :: Int
|
||
|
|
, pname :: T.Text
|
||
|
|
, clearingPrice :: Double
|
||
|
|
, minprice :: Double
|
||
|
|
, maxprice :: Double
|
||
|
|
, pointCost :: Double
|
||
|
|
} deriving (Show, Eq, Ord)
|
||
|
|
|
||
|
|
|
||
|
|
instance TransaqResponseC ResponseSecInfo where
|
||
|
|
fromXml tag = do
|
||
|
|
secId <- findAttr (uname "secid") tag >>= readMaybe
|
||
|
|
secName <- T.pack <$> childContent "secname" tag
|
||
|
|
secCode <- T.pack <$> childContent "seccode" tag
|
||
|
|
market <- childContent "market" tag >>= readMaybe
|
||
|
|
pname <- T.pack <$> childContent "pname" tag
|
||
|
|
clearingPrice <- childContent "clearing_price" tag >>= readMaybe
|
||
|
|
minprice <- childContent "minprice" tag >>= readMaybe
|
||
|
|
maxprice <- childContent "maxprice" tag >>= readMaybe
|
||
|
|
pointCost <- childContent "point_cost" tag >>= readMaybe
|
||
|
|
pure ResponseSecInfo {..}
|
||
|
|
|
||
|
|
data Quotation =
|
||
|
|
Quotation
|
||
|
|
{
|
||
|
|
qSecId :: Int
|
||
|
|
, qBoard :: T.Text
|
||
|
|
, qSeccode :: T.Text
|
||
|
|
, qOpen :: Double
|
||
|
|
, qWaprice :: Double
|
||
|
|
, qBidDepth :: Int
|
||
|
|
, qBidDepthT :: Int
|
||
|
|
, qNumBids :: Int
|
||
|
|
, qOfferDepth :: Int
|
||
|
|
, qOfferDepthT :: Int
|
||
|
|
, qBid :: Double
|
||
|
|
, qOffer :: Double
|
||
|
|
, qNumOffers :: Int
|
||
|
|
, qNumTrades :: Int
|
||
|
|
, qVolToday :: Int
|
||
|
|
, qOpenPositions :: Int
|
||
|
|
, qLastPrice :: Double
|
||
|
|
, qQuantity :: Int
|
||
|
|
, qTimestamp :: UTCTime
|
||
|
|
, qValToday :: Double
|
||
|
|
} deriving (Show, Eq, Ord)
|
||
|
|
|
||
|
|
newtype ResponseQuotations =
|
||
|
|
ResponseQuotations [Quotation]
|
||
|
|
deriving (Show, Eq, Ord)
|
||
|
|
|
||
|
|
instance TransaqResponseC ResponseQuotations where
|
||
|
|
fromXml root = do
|
||
|
|
quotations <- mapM parseQuotation $ elChildren root
|
||
|
|
pure . ResponseQuotations . catMaybes $ quotations
|
||
|
|
where
|
||
|
|
parseQuotation tag = do
|
||
|
|
qSecId <- findAttr (uname "secid") tag >>= readMaybe
|
||
|
|
qBoard <- T.pack <$> childContent "board" tag
|
||
|
|
qSeccode <- T.pack <$> childContent "seccode" tag
|
||
|
|
qOpen <- childContent "open" tag >>= readMaybe
|
||
|
|
qWaprice <- childContent "waprice" tag >>= readMaybe
|
||
|
|
qBidDepth <- childContent "biddepth" tag >>= readMaybe
|
||
|
|
qBidDepthT <- childContent "biddeptht" tag >>= readMaybe
|
||
|
|
qNumBids <- childContent "numbids" tag >>= readMaybe
|
||
|
|
qBid <- childContent "bid" tag >>= readMaybe
|
||
|
|
qOfferDepth <- childContent "offerdepth" tag >>= readMaybe
|
||
|
|
qOfferDepthT <- childContent "offerdeptht" tag >>= readMaybe
|
||
|
|
qNumOffers <- childContent "numoffers" tag >>= readMaybe
|
||
|
|
qOffer <- childContent "offer" tag >>= readMaybe
|
||
|
|
qNumTrades <- childContent "numtrades" tag >>= readMaybe
|
||
|
|
qVolToday <- childContent "voltoday" tag >>= readMaybe
|
||
|
|
qOpenPositions <- childContent "openpositions" tag >>= readMaybe
|
||
|
|
qLastPrice <- childContent "last" tag >>= readMaybe
|
||
|
|
qQuantity <- childContent "quantity" tag >>= readMaybe
|
||
|
|
qTimestamp <- childContent "time" tag >>= (parseTimestamp . T.pack)
|
||
|
|
qValToday <- childContent "valToday" tag >>= readMaybe
|
||
|
|
pure $ Just Quotation {..}
|
||
|
|
|
||
|
|
data TradingPeriod =
|
||
|
|
PeriodOpen
|
||
|
|
| PeriodNormal
|
||
|
|
| PeriodClose
|
||
|
|
| PeriodUnknown
|
||
|
|
deriving (Show, Eq, Ord)
|
||
|
|
|
||
|
|
data AllTradesTrade =
|
||
|
|
AllTradesTrade
|
||
|
|
{
|
||
|
|
attSecId :: Int
|
||
|
|
, attSecCode :: T.Text
|
||
|
|
, attTradeNo :: Int64
|
||
|
|
, attTimestamp :: UTCTime
|
||
|
|
, attBoard :: T.Text
|
||
|
|
, attPrice :: Double
|
||
|
|
, attQuantity :: Int
|
||
|
|
, attBuysell :: TradeDirection
|
||
|
|
, attOpenInterest :: Int
|
||
|
|
, attPeriod :: TradingPeriod
|
||
|
|
} deriving (Show, Eq, Ord)
|
||
|
|
|
||
|
|
newtype ResponseAllTrades =
|
||
|
|
ResponseAllTrades [AllTradesTrade]
|
||
|
|
deriving (Show, Eq, Ord)
|
||
|
|
|
||
|
|
parseTradeDirection :: T.Text -> Maybe TradeDirection
|
||
|
|
parseTradeDirection t =
|
||
|
|
case t of
|
||
|
|
"B" -> Just Buy
|
||
|
|
"S" -> Just Sell
|
||
|
|
_ -> Nothing
|
||
|
|
|
||
|
|
instance TransaqResponseC ResponseAllTrades where
|
||
|
|
fromXml root = do
|
||
|
|
alltrades <- mapM parseAllTrade $ elChildren root
|
||
|
|
pure . ResponseAllTrades . catMaybes $ alltrades
|
||
|
|
where
|
||
|
|
parseAllTrade tag = do
|
||
|
|
attSecId <- findAttr (uname "secid") tag >>= readMaybe
|
||
|
|
attSecCode <- T.pack <$> childContent "seccode" tag
|
||
|
|
attTradeNo <- childContent "tradeno" tag >>= readMaybe
|
||
|
|
attTimestamp <- T.pack <$> childContent "time" tag >>= parseTimestamp
|
||
|
|
attBoard <- T.pack <$> childContent "board" tag
|
||
|
|
attPrice <- childContent "price" tag >>= readMaybe
|
||
|
|
attQuantity <- childContent "quantity" tag >>= readMaybe
|
||
|
|
attBuysell <- T.pack <$> childContent "buysell" tag >>= parseTradeDirection
|
||
|
|
let attOpenInterest = fromMaybe 0 $ childContent "openinterest" tag >>= readMaybe
|
||
|
|
let attPeriod = fromMaybe PeriodUnknown $ childContent "period" tag >>= parseTradingPeriod
|
||
|
|
pure . Just $ AllTradesTrade {..}
|
||
|
|
|
||
|
|
parseTradingPeriod :: String -> Maybe TradingPeriod
|
||
|
|
parseTradingPeriod "O" = Just PeriodOpen
|
||
|
|
parseTradingPeriod "N" = Just PeriodNormal
|
||
|
|
parseTradingPeriod "C" = Just PeriodClose
|
||
|
|
parseTradingPeriod _ = Nothing
|
||
|
|
|
||
|
|
|
||
|
|
data Quote =
|
||
|
|
Quote
|
||
|
|
{
|
||
|
|
secId :: Int
|
||
|
|
, board :: T.Text
|
||
|
|
, secCode :: T.Text
|
||
|
|
, price :: Double
|
||
|
|
, source :: T.Text
|
||
|
|
, yield :: Int
|
||
|
|
, buy :: Int
|
||
|
|
, sell :: Int
|
||
|
|
} deriving (Show, Eq, Ord)
|
||
|
|
|
||
|
|
newtype ResponseQuotes =
|
||
|
|
ResponseQuotes [Quote]
|
||
|
|
deriving (Show, Eq, Ord)
|
||
|
|
|
||
|
|
instance TransaqResponseC ResponseQuotes where
|
||
|
|
fromXml root = do
|
||
|
|
quotes <- mapM parseQuote $ elChildren root
|
||
|
|
pure . ResponseQuotes . catMaybes $ quotes
|
||
|
|
where
|
||
|
|
parseQuote tag = do
|
||
|
|
secId <- findAttr (uname "secid") tag >>= readMaybe
|
||
|
|
secCode <- T.pack <$> childContent "seccode" tag
|
||
|
|
board <- T.pack <$> childContent "board" tag
|
||
|
|
price <- childContent "price" tag >>= readMaybe
|
||
|
|
source <- T.pack <$> childContent "source" tag
|
||
|
|
yield <- childContent "yield" tag >>= readMaybe
|
||
|
|
buy <- childContent "buy" tag >>= readMaybe
|
||
|
|
sell <- childContent "sell" tag >>= readMaybe
|
||
|
|
return . Just $ Quote {..}
|
||
|
|
|
||
|
|
data OrderStatus =
|
||
|
|
OrderCancelled
|
||
|
|
| OrderDenied
|
||
|
|
| OrderDisabled
|
||
|
|
| OrderExpired
|
||
|
|
| OrderFailed
|
||
|
|
| OrderLinkWait
|
||
|
|
| OrderRejected
|
||
|
|
| OrderSLExecuted
|
||
|
|
| OrderSLForwarding
|
||
|
|
| OrderSLGuardTime
|
||
|
|
| OrderTPCorrection
|
||
|
|
| OrderTPCorrectionGuardTime
|
||
|
|
| OrderTPExecuted
|
||
|
|
| OrderTPForwarding
|
||
|
|
| OrderTPGuardTime
|
||
|
|
| OrderWatching
|
||
|
|
deriving (Show, Eq, Ord)
|
||
|
|
|
||
|
|
data OrderNotification =
|
||
|
|
OrderNotification
|
||
|
|
{
|
||
|
|
transactionId :: Int
|
||
|
|
, orderNo :: Int64
|
||
|
|
, secId :: Int
|
||
|
|
, board :: T.Text
|
||
|
|
, secCode :: T.Text
|
||
|
|
, client :: T.Text
|
||
|
|
, union :: T.Text
|
||
|
|
, status :: OrderStatus
|
||
|
|
, buysell :: TradeDirection
|
||
|
|
, timestamp :: UTCTime
|
||
|
|
, brokerRef :: T.Text
|
||
|
|
, balance :: Int
|
||
|
|
, price :: Double
|
||
|
|
, quantity :: Int
|
||
|
|
, result :: T.Text
|
||
|
|
} deriving (Show, Eq, Ord)
|
||
|
|
|
||
|
|
newtype ResponseOrders =
|
||
|
|
ResponseOrders [OrderNotification]
|
||
|
|
deriving (Show, Eq, Ord)
|
||
|
|
|
||
|
|
instance TransaqResponseC ResponseOrders where
|
||
|
|
fromXml root = do
|
||
|
|
quotes <- mapM parseOrder $ elChildren root
|
||
|
|
pure . ResponseOrders . catMaybes $ quotes
|
||
|
|
where
|
||
|
|
parseOrder tag = do
|
||
|
|
transactionId <- findAttr (uname "transactionid") tag >>= readMaybe
|
||
|
|
orderNo <- childContent "orderno" tag >>= readMaybe
|
||
|
|
secId <- childContent "secid" tag >>= readMaybe
|
||
|
|
board <- T.pack <$> childContent "board" tag
|
||
|
|
secCode <- T.pack <$> childContent "seccode" tag
|
||
|
|
client <- T.pack <$> childContent "client" tag
|
||
|
|
union <- T.pack <$> childContent "union" tag
|
||
|
|
status <- childContent "status" tag >>= parseStatus
|
||
|
|
buysell <- childContent "buysell" tag >>= parseTradeDirection . T.pack
|
||
|
|
timestamp <- childContent "time" tag >>= parseTimestamp . T.pack
|
||
|
|
brokerRef <- T.pack <$> childContent "brokerref" tag
|
||
|
|
balance <- childContent "balance" tag >>= readMaybe
|
||
|
|
price <- childContent "price" tag >>= readMaybe
|
||
|
|
quantity <- childContent "quantity" tag >>= readMaybe
|
||
|
|
result <- T.pack <$> childContent "result" tag
|
||
|
|
return . Just $ OrderNotification {..}
|
||
|
|
parseStatus "cancelled" = Just OrderCancelled
|
||
|
|
parseStatus "denied" = Just OrderDenied
|
||
|
|
parseStatus "disabled" = Just OrderDisabled
|
||
|
|
parseStatus "expired" = Just OrderExpired
|
||
|
|
parseStatus "failed" = Just OrderFailed
|
||
|
|
parseStatus "linkwait" = Just OrderLinkWait
|
||
|
|
parseStatus "rejected" = Just OrderRejected
|
||
|
|
parseStatus "sl_executed" = Just OrderSLExecuted
|
||
|
|
parseStatus "sl_forwarding" = Just OrderSLForwarding
|
||
|
|
parseStatus "sl_guardtime" = Just OrderSLGuardTime
|
||
|
|
parseStatus "tp_correction" = Just OrderTPCorrection
|
||
|
|
parseStatus "tp_correction_guardtime" = Just OrderTPCorrectionGuardTime
|
||
|
|
parseStatus "tp_executed" = Just OrderTPExecuted
|
||
|
|
parseStatus "tp_forwarding" = Just OrderTPForwarding
|
||
|
|
parseStatus "tp_guardtime" = Just OrderTPGuardTime
|
||
|
|
parseStatus "watching" = Just OrderWatching
|
||
|
|
parseStatus _ = Nothing
|
||
|
|
|
||
|
|
data TradeNotification =
|
||
|
|
TradeNotification
|
||
|
|
{
|
||
|
|
secId :: Int
|
||
|
|
, tradeNo :: Int64
|
||
|
|
, orderNo :: Int64
|
||
|
|
, board :: T.Text
|
||
|
|
, secCode :: T.Text
|
||
|
|
, client :: T.Text
|
||
|
|
, union :: T.Text
|
||
|
|
, buysell :: TradeDirection
|
||
|
|
, timestamp :: UTCTime
|
||
|
|
, value :: Double
|
||
|
|
, comission :: Double
|
||
|
|
, price :: Double
|
||
|
|
} deriving (Show, Eq, Ord)
|
||
|
|
|
||
|
|
newtype ResponseTrades =
|
||
|
|
ResponseTrades [TradeNotification]
|
||
|
|
deriving (Show, Eq, Ord)
|
||
|
|
|
||
|
|
instance TransaqResponseC ResponseTrades where
|
||
|
|
fromXml root = do
|
||
|
|
quotes <- mapM parseTrade $ elChildren root
|
||
|
|
pure . ResponseTrades . catMaybes $ quotes
|
||
|
|
where
|
||
|
|
parseTrade tag = do
|
||
|
|
secId <- childContent "secid" tag >>= readMaybe
|
||
|
|
tradeNo <- childContent "tradeno" tag >>= readMaybe
|
||
|
|
orderNo <- childContent "orderno" tag >>= readMaybe
|
||
|
|
board <- T.pack <$> childContent "board" tag
|
||
|
|
secCode <- T.pack <$> childContent "seccode" tag
|
||
|
|
client <- T.pack <$> childContent "client" tag
|
||
|
|
union <- T.pack <$> childContent "union" tag
|
||
|
|
buysell <- childContent "buysell" tag >>= parseTradeDirection . T.pack
|
||
|
|
timestamp <- childContent "time" tag >>= parseTimestamp . T.pack
|
||
|
|
value <- childContent "value" tag >>= readMaybe
|
||
|
|
comission <- childContent "comission" tag >>= readMaybe
|
||
|
|
price <- childContent "price" tag >>= readMaybe
|
||
|
|
pure . Just $ TradeNotification {..}
|
||
|
|
|
||
|
|
data Tick =
|
||
|
|
Tick
|
||
|
|
{
|
||
|
|
secId :: Int
|
||
|
|
, tradeNo :: Int64
|
||
|
|
, timestamp :: UTCTime
|
||
|
|
, price :: Double
|
||
|
|
, quantity :: Int
|
||
|
|
, period :: TradingPeriod
|
||
|
|
, buySell :: TradeDirection
|
||
|
|
, openInterest :: Int
|
||
|
|
, board :: T.Text
|
||
|
|
, secCode :: T.Text
|
||
|
|
} deriving (Show, Eq, Ord)
|
||
|
|
|
||
|
|
newtype ResponseTicks =
|
||
|
|
ResponseTicks [Tick]
|
||
|
|
deriving (Show, Eq, Ord)
|
||
|
|
|
||
|
|
data TransaqResponse =
|
||
|
|
TransaqResponseResult ResponseResult
|
||
|
|
| TransaqResponseCandles ResponseCandles
|
||
|
|
| TransaqResponseServerStatus ResponseServerStatus
|
||
|
|
| TransaqResponseMarkets ResponseMarkets
|
||
|
|
| TransaqResponseCandleKinds ResponseCandleKinds
|
||
|
|
| TransaqResponseSecurities ResponseSecurities
|
||
|
|
| TransaqResponseSecInfo ResponseSecInfo
|
||
|
|
| TransaqResponseQuotations ResponseQuotations
|
||
|
|
| TransaqResponseAllTrades ResponseAllTrades
|
||
|
|
| TransaqResponseQuotes ResponseQuotes
|
||
|
|
| TransaqResponseOrders ResponseOrders
|
||
|
|
| TransaqResponseTrades ResponseTrades
|
||
|
|
deriving (Show, Eq, Ord)
|
||
|
|
|
||
|
|
instance TransaqResponseC TransaqResponse where
|
||
|
|
fromXml root = case qName . elName $ root of
|
||
|
|
"result" -> TransaqResponseResult <$> fromXml root
|
||
|
|
"error" -> TransaqResponseResult <$> fromXml root
|
||
|
|
"candles" -> TransaqResponseCandles <$> fromXml root
|
||
|
|
"server_status" -> TransaqResponseServerStatus <$> fromXml root
|
||
|
|
"markets" -> TransaqResponseMarkets <$> fromXml root
|
||
|
|
"candlekinds" -> TransaqResponseCandleKinds <$> fromXml root
|
||
|
|
"securities" -> TransaqResponseSecurities <$> fromXml root
|
||
|
|
"sec_info" -> TransaqResponseSecInfo <$> fromXml root
|
||
|
|
"quotations" -> TransaqResponseQuotations <$> fromXml root
|
||
|
|
"alltrades" -> TransaqResponseAllTrades <$> fromXml root
|
||
|
|
"quotes" -> TransaqResponseQuotes <$> fromXml root
|
||
|
|
"orders" -> TransaqResponseOrders <$> fromXml root
|
||
|
|
"trades" -> TransaqResponseTrades <$> fromXml root
|
||
|
|
_ -> Nothing
|