|
|
|
@ -15,6 +15,7 @@ module TXMLConnector |
|
|
|
, HistoryResponse(..) |
|
|
|
, HistoryResponse(..) |
|
|
|
, makeRequest |
|
|
|
, makeRequest |
|
|
|
, TXMLConnectorHandle |
|
|
|
, TXMLConnectorHandle |
|
|
|
|
|
|
|
, makeBrokerBackend |
|
|
|
) where |
|
|
|
) where |
|
|
|
|
|
|
|
|
|
|
|
import ATrade.Logging (Message, Severity (..), log, |
|
|
|
import ATrade.Logging (Message, Severity (..), log, |
|
|
|
@ -36,14 +37,16 @@ import Control.Concurrent.STM (TVar, atomically, modifyTVar', |
|
|
|
import Control.Concurrent.STM.TBQueue (TBQueue, newTBQueue, |
|
|
|
import Control.Concurrent.STM.TBQueue (TBQueue, newTBQueue, |
|
|
|
readTBQueue, writeTBQueue) |
|
|
|
readTBQueue, writeTBQueue) |
|
|
|
import Control.Monad (forever, void, when) |
|
|
|
import Control.Monad (forever, void, when) |
|
|
|
|
|
|
|
import qualified Data.Bimap as BM |
|
|
|
import Data.Maybe (mapMaybe) |
|
|
|
import Data.Maybe (mapMaybe) |
|
|
|
import qualified Data.Text as T |
|
|
|
import qualified Data.Text as T |
|
|
|
|
|
|
|
import qualified Deque.Strict as D |
|
|
|
import Text.XML.Light.Input (parseXML) |
|
|
|
import Text.XML.Light.Input (parseXML) |
|
|
|
import Text.XML.Light.Types (Content (Elem), |
|
|
|
import Text.XML.Light.Types (Content (Elem), |
|
|
|
Element (elName), |
|
|
|
Element (elName), |
|
|
|
QName (qName)) |
|
|
|
QName (qName)) |
|
|
|
import Transaq (AllTradesTrade (..), |
|
|
|
import Transaq (AllTradesTrade (..), |
|
|
|
Candle (..), |
|
|
|
Candle (..), ClientData (..), |
|
|
|
CommandConnect (..), |
|
|
|
CommandConnect (..), |
|
|
|
CommandDisconnect (CommandDisconnect), |
|
|
|
CommandDisconnect (CommandDisconnect), |
|
|
|
CommandGetHistoryData (CommandGetHistoryData), |
|
|
|
CommandGetHistoryData (CommandGetHistoryData), |
|
|
|
@ -51,32 +54,45 @@ import Transaq (AllTradesTrade (..), |
|
|
|
ConnectionState (Disconnected), |
|
|
|
ConnectionState (Disconnected), |
|
|
|
Language (LanguageEn), |
|
|
|
Language (LanguageEn), |
|
|
|
MarketInfo (..), |
|
|
|
MarketInfo (..), |
|
|
|
|
|
|
|
OrderNotification (..), |
|
|
|
|
|
|
|
OrderStatus (..), |
|
|
|
Quotation (..), |
|
|
|
Quotation (..), |
|
|
|
ResponseAllTrades (ResponseAllTrades), |
|
|
|
ResponseAllTrades (ResponseAllTrades), |
|
|
|
ResponseCandleKinds (ResponseCandleKinds), |
|
|
|
ResponseCandleKinds (ResponseCandleKinds), |
|
|
|
ResponseCandles (..), |
|
|
|
ResponseCandles (..), |
|
|
|
ResponseCandlesStatus (StatusPending), |
|
|
|
ResponseCandlesStatus (StatusPending), |
|
|
|
|
|
|
|
ResponseClient (ResponseClient), |
|
|
|
ResponseMarkets (ResponseMarkets), |
|
|
|
ResponseMarkets (ResponseMarkets), |
|
|
|
|
|
|
|
ResponseOrders (ResponseOrders), |
|
|
|
ResponseQuotations (ResponseQuotations), |
|
|
|
ResponseQuotations (ResponseQuotations), |
|
|
|
ResponseQuotes (ResponseQuotes), |
|
|
|
ResponseQuotes (ResponseQuotes), |
|
|
|
|
|
|
|
ResponseResult (..), |
|
|
|
ResponseSecurities (ResponseSecurities), |
|
|
|
ResponseSecurities (ResponseSecurities), |
|
|
|
|
|
|
|
ResponseTrades (ResponseTrades), |
|
|
|
Security (..), SecurityId (..), |
|
|
|
Security (..), SecurityId (..), |
|
|
|
|
|
|
|
TradeNotification (..), |
|
|
|
TransaqCommand (toXml), |
|
|
|
TransaqCommand (toXml), |
|
|
|
TransaqResponse (..), |
|
|
|
TransaqResponse (..), |
|
|
|
TransaqResponse (..), |
|
|
|
TransaqResponse (..), |
|
|
|
TransaqResponseC (fromXml), |
|
|
|
TransaqResponseC (fromXml), |
|
|
|
kCandleKindId, kPeriod, state, |
|
|
|
UnfilledAction (..), |
|
|
|
status) |
|
|
|
kCandleKindId, kPeriod, state) |
|
|
|
import TXML (LogLevel, freeCallback, |
|
|
|
import TXML (LogLevel, freeCallback, |
|
|
|
initialize, sendCommand, |
|
|
|
initialize, sendCommand, |
|
|
|
setCallback) |
|
|
|
setCallback) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import ATrade.Broker.Backend (BrokerBackend (..), |
|
|
|
|
|
|
|
BrokerBackendNotification (..)) |
|
|
|
import ATrade.QuoteSource.Server (QuoteSourceServerData (..)) |
|
|
|
import ATrade.QuoteSource.Server (QuoteSourceServerData (..)) |
|
|
|
import ATrade.Types (Bar (..), |
|
|
|
import ATrade.Types (Bar (..), |
|
|
|
BarTimeframe (unBarTimeframe), |
|
|
|
BarTimeframe (unBarTimeframe), |
|
|
|
DataType (BestBid, BestOffer, LastTradePrice), |
|
|
|
DataType (BestBid, BestOffer, LastTradePrice), |
|
|
|
Tick (..), TickerId, |
|
|
|
Order (..), OrderId, |
|
|
|
fromDouble) |
|
|
|
OrderPrice (..), |
|
|
|
|
|
|
|
OrderState (..), Tick (..), |
|
|
|
|
|
|
|
TickerId, Trade (..), |
|
|
|
|
|
|
|
fromDouble, toDouble) |
|
|
|
|
|
|
|
import qualified ATrade.Types as AT |
|
|
|
import Colog.Monad (WithLog) |
|
|
|
import Colog.Monad (WithLog) |
|
|
|
import Control.Concurrent.BoundedChan (BoundedChan, writeChan) |
|
|
|
import Control.Concurrent.BoundedChan (BoundedChan, writeChan) |
|
|
|
import Control.Concurrent.STM.TMVar (TMVar) |
|
|
|
import Control.Concurrent.STM.TMVar (TMVar) |
|
|
|
@ -84,9 +100,11 @@ import Control.Monad (forM_) |
|
|
|
import Control.Monad.IO.Class (MonadIO (liftIO)) |
|
|
|
import Control.Monad.IO.Class (MonadIO (liftIO)) |
|
|
|
import Control.Monad.Reader (ReaderT (runReaderT)) |
|
|
|
import Control.Monad.Reader (ReaderT (runReaderT)) |
|
|
|
import Control.Monad.Reader.Class (MonadReader, asks) |
|
|
|
import Control.Monad.Reader.Class (MonadReader, asks) |
|
|
|
|
|
|
|
import Data.Int (Int64) |
|
|
|
import qualified Data.Map.Strict as M |
|
|
|
import qualified Data.Map.Strict as M |
|
|
|
import Data.Time.Clock (UTCTime, diffUTCTime, |
|
|
|
import Data.Time.Clock (UTCTime, diffUTCTime, |
|
|
|
getCurrentTime) |
|
|
|
getCurrentTime) |
|
|
|
|
|
|
|
import GHC.Exts (IsList (..)) |
|
|
|
import Prelude hiding (log) |
|
|
|
import Prelude hiding (log) |
|
|
|
import TickerInfoServer (TickerInfo (..), |
|
|
|
import TickerInfoServer (TickerInfo (..), |
|
|
|
TickerInfoServerHandle, |
|
|
|
TickerInfoServerHandle, |
|
|
|
@ -115,12 +133,16 @@ data HistoryRequest = |
|
|
|
, hrReset :: Bool |
|
|
|
, hrReset :: Bool |
|
|
|
} deriving (Show, Eq, Ord) |
|
|
|
} deriving (Show, Eq, Ord) |
|
|
|
|
|
|
|
|
|
|
|
newtype Request = |
|
|
|
data Request = |
|
|
|
Request HistoryRequest |
|
|
|
RequestHistory HistoryRequest |
|
|
|
deriving (Show, Eq, Ord) |
|
|
|
| RequestSubmitOrder Order |
|
|
|
|
|
|
|
| RequestCancelOrder OrderId |
|
|
|
|
|
|
|
deriving (Show, Eq) |
|
|
|
|
|
|
|
|
|
|
|
data Response = |
|
|
|
data Response = |
|
|
|
ResponseHistory HistoryResponse |
|
|
|
ResponseHistory HistoryResponse |
|
|
|
|
|
|
|
| ResponseOrderSubmitted |
|
|
|
|
|
|
|
| ResponseOrderCancelled |
|
|
|
| ResponseTimeout |
|
|
|
| ResponseTimeout |
|
|
|
|
|
|
|
|
|
|
|
data HistoryResponse = |
|
|
|
data HistoryResponse = |
|
|
|
@ -134,11 +156,12 @@ data HistoryResponse = |
|
|
|
data TXMLConnectorHandle = |
|
|
|
data TXMLConnectorHandle = |
|
|
|
TXMLConnectorHandle |
|
|
|
TXMLConnectorHandle |
|
|
|
{ |
|
|
|
{ |
|
|
|
threadId :: ThreadId |
|
|
|
threadId :: ThreadId |
|
|
|
, notificationQueue :: TBQueue TransaqResponse |
|
|
|
, notificationQueue :: TBQueue TransaqResponse |
|
|
|
, hRequestVar :: TMVar Request |
|
|
|
, hRequestVar :: TMVar Request |
|
|
|
, hResponseVar :: TMVar (TMVar Response) |
|
|
|
, hResponseVar :: TMVar (TMVar Response) |
|
|
|
, hRequestTimestamp :: TVar UTCTime |
|
|
|
, hRequestTimestamp :: TVar UTCTime |
|
|
|
|
|
|
|
, hNotificationCallback :: TVar (Maybe (BrokerBackendNotification -> IO ())) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
data ConnectionStage = StageConnection | StageGetInfo | StageConnected |
|
|
|
data ConnectionStage = StageConnection | StageGetInfo | StageConnected |
|
|
|
@ -147,11 +170,25 @@ data ConnectionStage = StageConnection | StageGetInfo | StageConnected |
|
|
|
data MainQueueData = |
|
|
|
data MainQueueData = |
|
|
|
MainQueueTransaqData TransaqResponse |
|
|
|
MainQueueTransaqData TransaqResponse |
|
|
|
| MainQueueRequest Request |
|
|
|
| MainQueueRequest Request |
|
|
|
deriving (Eq, Show, Ord) |
|
|
|
deriving (Eq, Show) |
|
|
|
|
|
|
|
|
|
|
|
data TickKey = TickKey TickerId DataType |
|
|
|
data TickKey = TickKey TickerId DataType |
|
|
|
deriving (Show, Ord, Eq) |
|
|
|
deriving (Show, Ord, Eq) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
data TransactionId = |
|
|
|
|
|
|
|
TransactionId Int64 |
|
|
|
|
|
|
|
| ExchangeOrderId Int64 |
|
|
|
|
|
|
|
deriving (Show, Ord, Eq) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
data BrokerState = |
|
|
|
|
|
|
|
BrokerState |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
bsOrderTransactionIdMap :: TVar (BM.Bimap OrderId TransactionId) |
|
|
|
|
|
|
|
, bsNotificationCallback :: TVar (Maybe (BrokerBackendNotification -> IO ())) |
|
|
|
|
|
|
|
, bsOrderMap :: TVar (M.Map OrderId Order) |
|
|
|
|
|
|
|
, bsPendingOrders :: TVar (D.Deque Order) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
data Env = |
|
|
|
data Env = |
|
|
|
Env |
|
|
|
Env |
|
|
|
{ |
|
|
|
{ |
|
|
|
@ -167,6 +204,7 @@ data Env = |
|
|
|
, config :: TransaqConnectorConfig |
|
|
|
, config :: TransaqConnectorConfig |
|
|
|
, serverConnected :: TVar ConnectionStage |
|
|
|
, serverConnected :: TVar ConnectionStage |
|
|
|
, candleKindMap :: TVar (M.Map Int Int) |
|
|
|
, candleKindMap :: TVar (M.Map Int Int) |
|
|
|
|
|
|
|
, brokerState :: BrokerState |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
newtype App a = App { unApp :: ReaderT Env IO a } |
|
|
|
newtype App a = App { unApp :: ReaderT Env IO a } |
|
|
|
@ -192,6 +230,18 @@ start logger config qssChannel tisH = do |
|
|
|
serverConnected <- liftIO $ newTVarIO StageConnection |
|
|
|
serverConnected <- liftIO $ newTVarIO StageConnection |
|
|
|
candleKindMap <- newTVarIO M.empty |
|
|
|
candleKindMap <- newTVarIO M.empty |
|
|
|
requestTimestamp <- getCurrentTime >>= newTVarIO |
|
|
|
requestTimestamp <- getCurrentTime >>= newTVarIO |
|
|
|
|
|
|
|
orderMap <- newTVarIO M.empty |
|
|
|
|
|
|
|
notificationCallback <- newTVarIO Nothing |
|
|
|
|
|
|
|
orderTransactionIdMap <- newTVarIO BM.empty |
|
|
|
|
|
|
|
pendingOrders <- newTVarIO (fromList []) |
|
|
|
|
|
|
|
let brokerState = |
|
|
|
|
|
|
|
BrokerState |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
bsOrderTransactionIdMap = orderTransactionIdMap |
|
|
|
|
|
|
|
, bsNotificationCallback = notificationCallback |
|
|
|
|
|
|
|
, bsOrderMap = orderMap |
|
|
|
|
|
|
|
, bsPendingOrders = pendingOrders |
|
|
|
|
|
|
|
} |
|
|
|
let env = |
|
|
|
let env = |
|
|
|
Env |
|
|
|
Env |
|
|
|
{ |
|
|
|
{ |
|
|
|
@ -207,6 +257,7 @@ start logger config qssChannel tisH = do |
|
|
|
, config = config |
|
|
|
, config = config |
|
|
|
, serverConnected = serverConnected |
|
|
|
, serverConnected = serverConnected |
|
|
|
, candleKindMap = candleKindMap |
|
|
|
, candleKindMap = candleKindMap |
|
|
|
|
|
|
|
, brokerState = brokerState |
|
|
|
} |
|
|
|
} |
|
|
|
threadId <- forkIO $ (runReaderT . unApp) workThread env |
|
|
|
threadId <- forkIO $ (runReaderT . unApp) workThread env |
|
|
|
return $ TXMLConnectorHandle |
|
|
|
return $ TXMLConnectorHandle |
|
|
|
@ -215,6 +266,8 @@ start logger config qssChannel tisH = do |
|
|
|
, notificationQueue = notificationQueue |
|
|
|
, notificationQueue = notificationQueue |
|
|
|
, hRequestVar = requestVar |
|
|
|
, hRequestVar = requestVar |
|
|
|
, hResponseVar = responseVar |
|
|
|
, hResponseVar = responseVar |
|
|
|
|
|
|
|
, hRequestTimestamp = requestTimestamp |
|
|
|
|
|
|
|
, hNotificationCallback = notificationCallback |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
workThread :: App () |
|
|
|
workThread :: App () |
|
|
|
@ -299,8 +352,19 @@ workThread = do |
|
|
|
, hrMoreData = False |
|
|
|
, hrMoreData = False |
|
|
|
} |
|
|
|
} |
|
|
|
_ -> log Warning "TXMLConnector.WorkThread" "Incoming candles without response var" |
|
|
|
_ -> log Warning "TXMLConnector.WorkThread" "Incoming candles without response var" |
|
|
|
|
|
|
|
TransaqResponseOrders (ResponseOrders orders) -> forM_ orders handleOrder |
|
|
|
|
|
|
|
TransaqResponseTrades (ResponseTrades trades) -> forM_ trades handleTrade |
|
|
|
|
|
|
|
TransaqResponseResult (ResponseSuccess (Just transactionId)) -> do |
|
|
|
|
|
|
|
brState <- asks brokerState |
|
|
|
|
|
|
|
liftIO $ atomically $ do |
|
|
|
|
|
|
|
deque <- readTVar (bsPendingOrders brState) |
|
|
|
|
|
|
|
case D.uncons deque of |
|
|
|
|
|
|
|
Just (order, deque') -> do |
|
|
|
|
|
|
|
writeTVar (bsPendingOrders brState) deque' |
|
|
|
|
|
|
|
modifyTVar' (bsOrderTransactionIdMap brState) (BM.insert (orderId order) (TransactionId transactionId)) |
|
|
|
|
|
|
|
Nothing -> pure () |
|
|
|
_ -> pure () |
|
|
|
_ -> pure () |
|
|
|
MainQueueRequest (Request request) -> do |
|
|
|
MainQueueRequest (RequestHistory request) -> do |
|
|
|
cur <- asks currentCandles |
|
|
|
cur <- asks currentCandles |
|
|
|
liftIO $ atomically $ writeTVar cur [] |
|
|
|
liftIO $ atomically $ writeTVar cur [] |
|
|
|
maybeCk <- M.lookup (unBarTimeframe . hrTimeframe $ request) <$> (asks candleKindMap >>= liftIO . readTVarIO) |
|
|
|
maybeCk <- M.lookup (unBarTimeframe . hrTimeframe $ request) <$> (asks candleKindMap >>= liftIO . readTVarIO) |
|
|
|
@ -317,10 +381,83 @@ workThread = do |
|
|
|
} |
|
|
|
} |
|
|
|
_ -> log Warning "TXMLConnector.WorkThread" $ "Unable to parse security ID: " <> hrTickerId request |
|
|
|
_ -> log Warning "TXMLConnector.WorkThread" $ "Unable to parse security ID: " <> hrTickerId request |
|
|
|
_ -> log Warning "TXMLConnector.WorkThread" $ "Invalid candlekind requested" <> (T.pack . show . unBarTimeframe . hrTimeframe $ request) |
|
|
|
_ -> log Warning "TXMLConnector.WorkThread" $ "Invalid candlekind requested" <> (T.pack . show . unBarTimeframe . hrTimeframe $ request) |
|
|
|
|
|
|
|
MainQueueRequest (RequestSubmitOrder order) -> do |
|
|
|
|
|
|
|
case mkNewOrderCommand order of |
|
|
|
|
|
|
|
Just cmd -> do |
|
|
|
|
|
|
|
v <- liftIO . sendCommand . toXml $ cmd |
|
|
|
|
|
|
|
case v of |
|
|
|
|
|
|
|
Left err -> log Warning "TXMLConnector.WorkThread" $ "Unable to send request: [" <> err <> "]" |
|
|
|
|
|
|
|
Right _ -> do |
|
|
|
|
|
|
|
brState <- asks brokerState |
|
|
|
|
|
|
|
liftIO $ atomically $ do |
|
|
|
|
|
|
|
modifyTVar' (bsPendingOrders brState) (order `D.snoc`) |
|
|
|
|
|
|
|
modifyTVar' (bsOrderMap brState) (M.insert (orderId order) order) |
|
|
|
|
|
|
|
_ -> pure () |
|
|
|
|
|
|
|
_ -> pure () |
|
|
|
|
|
|
|
|
|
|
|
checkRequestTimeout |
|
|
|
checkRequestTimeout |
|
|
|
|
|
|
|
|
|
|
|
requestTimeout = 10 |
|
|
|
requestTimeout = 10 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
handleTrade transaqTrade = do |
|
|
|
|
|
|
|
brState <- asks brokerState |
|
|
|
|
|
|
|
trIdMap <- liftIO $ readTVarIO (bsOrderTransactionIdMap brState) |
|
|
|
|
|
|
|
maybeCb <- liftIO $ readTVarIO (bsNotificationCallback brState) |
|
|
|
|
|
|
|
orderMap <- liftIO $ readTVarIO (bsOrderMap brState) |
|
|
|
|
|
|
|
case maybeCb of |
|
|
|
|
|
|
|
Just cb -> case BM.lookupR (ExchangeOrderId (tOrderNo transaqTrade)) trIdMap of |
|
|
|
|
|
|
|
Just oid -> case M.lookup oid orderMap of |
|
|
|
|
|
|
|
Just order -> liftIO $ cb (BackendTradeNotification (fromTransaqTrade transaqTrade order)) |
|
|
|
|
|
|
|
_ -> pure () |
|
|
|
|
|
|
|
_ -> pure () |
|
|
|
|
|
|
|
Nothing -> pure () |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fromTransaqTrade transaqTrade order = |
|
|
|
|
|
|
|
Trade |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
tradeOrderId = orderId order |
|
|
|
|
|
|
|
, tradePrice = fromDouble (tPrice transaqTrade) |
|
|
|
|
|
|
|
, tradeQuantity = fromIntegral $ tQuantity transaqTrade |
|
|
|
|
|
|
|
, tradeVolume = fromDouble $ tValue transaqTrade |
|
|
|
|
|
|
|
, tradeVolumeCurrency = "" |
|
|
|
|
|
|
|
, tradeOperation = fromDirection (tBuysell transaqTrade) |
|
|
|
|
|
|
|
, tradeAccount = tClient transaqTrade <> "#" <> tUnion transaqTrade |
|
|
|
|
|
|
|
, tradeSecurity = tBoard transaqTrade <> "#" <> tSecCode transaqTrade |
|
|
|
|
|
|
|
, tradeTimestamp = tTimestamp transaqTrade |
|
|
|
|
|
|
|
, tradeCommission = fromDouble $ tComission transaqTrade |
|
|
|
|
|
|
|
, tradeSignalId = orderSignalId order |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fromDirection Transaq.Buy = AT.Buy |
|
|
|
|
|
|
|
fromDirection Transaq.Sell = AT.Sell |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
handleOrder orderUpdate = do |
|
|
|
|
|
|
|
brState <- asks brokerState |
|
|
|
|
|
|
|
trIdMap <- liftIO $ readTVarIO (bsOrderTransactionIdMap brState) |
|
|
|
|
|
|
|
maybeCb <- liftIO $ readTVarIO (bsNotificationCallback brState) |
|
|
|
|
|
|
|
case maybeCb of |
|
|
|
|
|
|
|
Just cb -> case BM.lookupR (TransactionId (fromIntegral $ oTransactionId orderUpdate)) trIdMap of |
|
|
|
|
|
|
|
Just oid -> liftIO $ cb (BackendOrderNotification oid (orderStateFromTransaq orderUpdate)) |
|
|
|
|
|
|
|
_ -> pure () |
|
|
|
|
|
|
|
Nothing -> pure () |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
orderStateFromTransaq orderUpdate = |
|
|
|
|
|
|
|
case oStatus orderUpdate of |
|
|
|
|
|
|
|
OrderActive -> Submitted |
|
|
|
|
|
|
|
OrderCancelled -> Cancelled |
|
|
|
|
|
|
|
OrderDenied -> Rejected |
|
|
|
|
|
|
|
OrderDisabled -> Rejected |
|
|
|
|
|
|
|
OrderExpired -> Cancelled |
|
|
|
|
|
|
|
OrderFailed -> Rejected |
|
|
|
|
|
|
|
OrderForwarding -> Unsubmitted |
|
|
|
|
|
|
|
OrderInactive -> OrderError |
|
|
|
|
|
|
|
OrderMatched -> Executed |
|
|
|
|
|
|
|
OrderRefused -> Rejected |
|
|
|
|
|
|
|
OrderRemoved -> Rejected |
|
|
|
|
|
|
|
OrderWait -> Unsubmitted |
|
|
|
|
|
|
|
OrderWatching -> Unsubmitted |
|
|
|
|
|
|
|
_ -> OrderError |
|
|
|
|
|
|
|
|
|
|
|
checkRequestTimeout = do |
|
|
|
checkRequestTimeout = do |
|
|
|
now <- liftIO getCurrentTime |
|
|
|
now <- liftIO getCurrentTime |
|
|
|
tsVar <- asks requestTimestamp |
|
|
|
tsVar <- asks requestTimestamp |
|
|
|
@ -381,6 +518,9 @@ workThread = do |
|
|
|
TransaqResponseSecInfo secInfo -> |
|
|
|
TransaqResponseSecInfo secInfo -> |
|
|
|
log Debug "TXMLConnector.WorkThread" $ "Incoming secinfo:" <> (T.pack . show) secInfo |
|
|
|
log Debug "TXMLConnector.WorkThread" $ "Incoming secinfo:" <> (T.pack . show) secInfo |
|
|
|
-- TODO: Pass to qtis |
|
|
|
-- TODO: Pass to qtis |
|
|
|
|
|
|
|
TransaqResponseClient (ResponseClient clientData) -> do |
|
|
|
|
|
|
|
log Debug "TXMLConnector.WorkThread" $ |
|
|
|
|
|
|
|
"Incoming client data: " <> (T.pack . show) (cClientId clientData) <> "#" <> (T.pack . show) (cUnion clientData) |
|
|
|
_ -> pure () |
|
|
|
_ -> pure () |
|
|
|
handleUnconnected :: App () |
|
|
|
handleUnconnected :: App () |
|
|
|
handleUnconnected = do |
|
|
|
handleUnconnected = do |
|
|
|
@ -494,6 +634,12 @@ parseSecurityId tickerId = case T.findIndex (== '#') tickerId of |
|
|
|
makeTickerId :: SecurityId -> TickerId |
|
|
|
makeTickerId :: SecurityId -> TickerId |
|
|
|
makeTickerId sec = board sec <> "#" <> seccode sec |
|
|
|
makeTickerId sec = board sec <> "#" <> seccode sec |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
parseAccountId :: T.Text -> Maybe (T.Text, T.Text) |
|
|
|
|
|
|
|
parseAccountId accId = case T.findIndex (== '#') accId of |
|
|
|
|
|
|
|
Just ix -> Just (T.take ix accId, T.drop (ix + 1) accId) |
|
|
|
|
|
|
|
Nothing -> Nothing |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
makeRequest :: TXMLConnectorHandle -> Request -> IO Response |
|
|
|
makeRequest :: TXMLConnectorHandle -> Request -> IO Response |
|
|
|
makeRequest h request = do |
|
|
|
makeRequest h request = do |
|
|
|
now <- getCurrentTime |
|
|
|
now <- getCurrentTime |
|
|
|
@ -507,6 +653,46 @@ makeRequest h request = do |
|
|
|
void $ takeTMVar (hResponseVar h) |
|
|
|
void $ takeTMVar (hResponseVar h) |
|
|
|
takeTMVar resp |
|
|
|
takeTMVar resp |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
mkNewOrderCommand :: Order -> Maybe Transaq.CommandNewOrder |
|
|
|
|
|
|
|
mkNewOrderCommand order = |
|
|
|
|
|
|
|
case parseSecurityId (orderSecurity order) of |
|
|
|
|
|
|
|
Just secId -> |
|
|
|
|
|
|
|
case parseAccountId (orderAccountId order) of |
|
|
|
|
|
|
|
Just (client, union) -> do |
|
|
|
|
|
|
|
case orderPrice order of |
|
|
|
|
|
|
|
Market -> Just $ Transaq.CommandNewOrder |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
security = secId |
|
|
|
|
|
|
|
, client = client |
|
|
|
|
|
|
|
, unionCode = union |
|
|
|
|
|
|
|
, price = 0 |
|
|
|
|
|
|
|
, quantity = fromInteger $ orderQuantity order |
|
|
|
|
|
|
|
, buysell = toDirection $ orderOperation order |
|
|
|
|
|
|
|
, bymarket = True |
|
|
|
|
|
|
|
, brokerRef = T.empty |
|
|
|
|
|
|
|
, unfilled = UnfilledPutInQueue |
|
|
|
|
|
|
|
, usecredit = False |
|
|
|
|
|
|
|
, nosplit = False |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
Limit price -> Just $ Transaq.CommandNewOrder |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
security = secId |
|
|
|
|
|
|
|
, client = client |
|
|
|
|
|
|
|
, unionCode = union |
|
|
|
|
|
|
|
, price = toDouble price |
|
|
|
|
|
|
|
, quantity = fromInteger $ orderQuantity order |
|
|
|
|
|
|
|
, buysell = toDirection $ orderOperation order |
|
|
|
|
|
|
|
, bymarket = False |
|
|
|
|
|
|
|
, brokerRef = T.empty |
|
|
|
|
|
|
|
, unfilled = UnfilledPutInQueue |
|
|
|
|
|
|
|
, usecredit = False |
|
|
|
|
|
|
|
, nosplit = False |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
_ -> Nothing |
|
|
|
|
|
|
|
where |
|
|
|
|
|
|
|
toDirection AT.Buy = Transaq.Buy |
|
|
|
|
|
|
|
toDirection AT.Sell = Transaq.Sell |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
candleToBar :: SecurityId -> Candle -> Bar |
|
|
|
candleToBar :: SecurityId -> Candle -> Bar |
|
|
|
candleToBar sec candle = |
|
|
|
candleToBar sec candle = |
|
|
|
@ -520,3 +706,17 @@ candleToBar sec candle = |
|
|
|
, barClose = fromDouble (cClose candle) |
|
|
|
, barClose = fromDouble (cClose candle) |
|
|
|
, barVolume = fromIntegral $ cVolume candle |
|
|
|
, barVolume = fromIntegral $ cVolume candle |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
brSubmitOrder :: TXMLConnectorHandle -> Order -> IO () |
|
|
|
|
|
|
|
brSubmitOrder h order = void $ makeRequest h (RequestSubmitOrder order) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
brCancelOrder :: TXMLConnectorHandle -> OrderId -> IO () |
|
|
|
|
|
|
|
brCancelOrder h oid = void $ makeRequest h (RequestCancelOrder oid) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
brSetNotificationCallback :: TXMLConnectorHandle -> Maybe (BrokerBackendNotification -> IO ()) -> IO () |
|
|
|
|
|
|
|
brSetNotificationCallback h cb = atomically $ writeTVar (hNotificationCallback h) cb |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
makeBrokerBackend :: TXMLConnectorHandle -> T.Text -> BrokerBackend |
|
|
|
|
|
|
|
makeBrokerBackend h account = |
|
|
|
|
|
|
|
BrokerBackend [account] (brSetNotificationCallback h) (brSubmitOrder h) (brCancelOrder h) (pure ()) |
|
|
|
|
|
|
|
|
|
|
|
|