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.

186 lines
7.2 KiB

{-# LANGUAGE CPP #-}
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MultiParamTypeClasses #-}
3 years ago
module TXMLConnector
(
3 years ago
start
, TXMLConnector.stop
3 years ago
, TXMLConnectorHandle
, makeRequest
, makeBrokerBackend
3 years ago
) where
2 years ago
import ATrade.Broker.Backend (BrokerBackend (..),
BrokerBackendNotification (..))
2 years ago
import ATrade.Logging (Message, Severity (..),
3 years ago
logWith)
2 years ago
import ATrade.QuoteSource.Server (QuoteSourceServerData (..))
import ATrade.Types (Order, OrderId)
import Colog (HasLog (getLogAction, setLogAction),
LogAction (LogAction, unLogAction))
2 years ago
import Config (TransaqConnectorConfig (..))
import Control.Concurrent (ThreadId)
2 years ago
import Control.Concurrent.BoundedChan (BoundedChan)
2 years ago
import Control.Concurrent.STM (TVar, atomically,
3 years ago
newEmptyTMVar, newEmptyTMVarIO,
2 years ago
newTVarIO, putTMVar, takeTMVar,
writeTVar)
2 years ago
import Control.Concurrent.STM.TBQueue (TBQueue, newTBQueue)
2 years ago
import Control.Concurrent.STM.TMVar (TMVar)
2 years ago
import Control.Monad (void)
2 years ago
import Control.Monad.IO.Class (MonadIO (liftIO))
import Control.Monad.Reader (ReaderT (runReaderT))
import Control.Monad.Reader.Class (MonadReader)
import qualified Data.Bimap as BM
2 years ago
import qualified Data.Map.Strict as M
3 years ago
import qualified Data.Text as T
2 years ago
import Data.Time.Clock (UTCTime, getCurrentTime)
import GHC.Exts (IsList (..))
import Prelude hiding (log)
import SlaveThread (fork)
2 years ago
import TickerInfoServer (TickerInfoServerHandle)
2 years ago
import TickTable (TickTable)
2 years ago
import Transaq (TransaqResponse)
import TXML (LogLevel, MonadTXML,
2 years ago
initialize, sendCommand,
setCallback)
3 years ago
import qualified TXML
import TXMLConnector.Internal (BrokerState (..),
ConnectionStage (..), Env (..),
Request (..), Response (..),
workThread)
#if defined(mingw32_HOST_OS)
import qualified Win32.TXML as TXMLImpl
#else
import qualified Linux.TXML as TXMLImpl
#endif
3 years ago
2 years ago
3 years ago
data ConnectionParams =
ConnectionParams
2 years ago
{ cpLogin :: T.Text
3 years ago
, cpPassword :: T.Text
, cpHost :: T.Text
, cpPort :: Int
, cpLogPath :: T.Text
, cpLogLevel :: LogLevel
}
deriving (Show, Eq, Ord)
data TXMLConnectorHandle =
TXMLConnectorHandle
2 years ago
{ threadId :: ThreadId
, notificationQueue :: TBQueue TransaqResponse
, hRequestVar :: TMVar Request
, hResponseVar :: TMVar (TMVar Response)
, hRequestTimestamp :: TVar UTCTime
, hNotificationCallback :: TVar (Maybe (BrokerBackendNotification -> IO ()))
, hRunVar :: TMVar ()
3 years ago
}
newtype App a = App { unApp :: ReaderT Env IO a }
deriving (Monad, Applicative, Functor, MonadIO, MonadReader Env)
instance MonadTXML App where
initialize path loglevel = liftIO $ TXMLImpl.initialize path loglevel
uninitialize = liftIO TXMLImpl.uninitialize
sendCommand = liftIO . TXMLImpl.sendCommand
setCallback = liftIO . TXMLImpl.setCallback
instance HasLog Env Message App where
getLogAction env = LogAction { unLogAction = liftIO . (unLogAction . logger $ env) }
setLogAction _ env = env -- fuck it
2 years ago
3 years ago
start ::
LogAction IO Message
2 years ago
-> TickTable
3 years ago
-> TransaqConnectorConfig
-> BoundedChan QuoteSourceServerData
3 years ago
-> TickerInfoServerHandle
3 years ago
-> IO TXMLConnectorHandle
2 years ago
start logger' tickTable config' qssChannel' tisH = do
2 years ago
logWith logger' Info "TXMLConnector" "Starting"
notificationQueue' <- atomically $ newTBQueue 50000
requestVar' <- newEmptyTMVarIO
responseVar' <- newEmptyTMVarIO
currentCandles' <- newTVarIO []
serverConnected' <- liftIO $ newTVarIO StageConnection
candleKindMap' <- newTVarIO M.empty
requestTimestamp' <- getCurrentTime >>= newTVarIO
orderMap <- newTVarIO M.empty
notificationCallback <- newTVarIO Nothing
orderTransactionIdMap <- newTVarIO BM.empty
pendingOrders <- newTVarIO (fromList [])
2 years ago
runVar' <- newEmptyTMVarIO
timerVar' <- newEmptyTMVarIO
let brokerState' =
BrokerState
2 years ago
{ bsOrderTransactionIdMap = orderTransactionIdMap
, bsNotificationCallback = notificationCallback
, bsOrderMap = orderMap
, bsPendingOrders = pendingOrders
}
2 years ago
let env =
Env
2 years ago
{ qssChannel = qssChannel'
, tisHandle = tisH
2 years ago
, requestVar = requestVar'
, responseVar = responseVar'
, requestTimestamp = requestTimestamp'
, currentCandles = currentCandles'
, tickMap = tickTable
2 years ago
, transaqQueue = notificationQueue'
, logger = logger'
, config = config'
, serverConnected = serverConnected'
, candleKindMap = candleKindMap'
, brokerState = brokerState'
, runVar = runVar'
, timerVar = timerVar'
}
workThreadId <- fork $ (runReaderT . unApp) workThread env
return $ TXMLConnectorHandle
2 years ago
{ threadId = workThreadId
, notificationQueue = notificationQueue'
, hRequestVar = requestVar'
, hResponseVar = responseVar'
, hRequestTimestamp = requestTimestamp'
, hNotificationCallback = notificationCallback
2 years ago
, hRunVar = runVar'
}
3 years ago
stop :: TXMLConnectorHandle -> IO ()
stop h = atomically $ putTMVar (hRunVar h) ()
brSubmitOrder :: TXMLConnectorHandle -> Order -> IO ()
brSubmitOrder h order = void $ makeRequest h (RequestSubmitOrder order)
3 years ago
brCancelOrder :: TXMLConnectorHandle -> OrderId -> IO ()
brCancelOrder h oid = void $ makeRequest h (RequestCancelOrder oid)
3 years ago
brSetNotificationCallback :: TXMLConnectorHandle -> Maybe (BrokerBackendNotification -> IO ()) -> IO ()
brSetNotificationCallback h cb = atomically $ writeTVar (hNotificationCallback h) cb
makeBrokerBackend :: TXMLConnectorHandle -> T.Text -> BrokerBackend
2 years ago
makeBrokerBackend h accountId =
BrokerBackend [accountId] (brSetNotificationCallback h) (brSubmitOrder h) (brCancelOrder h) (TXMLConnector.stop h)
3 years ago
makeRequest :: TXMLConnectorHandle -> Request -> IO Response
makeRequest h request = do
now <- getCurrentTime
3 years ago
resp <- atomically $ do
resp <- newEmptyTMVar
writeTVar (hRequestTimestamp h) now
3 years ago
putTMVar (hResponseVar h) resp
putTMVar (hRequestVar h) request
pure resp
atomically $ do
void $ takeTMVar (hResponseVar h)
takeTMVar resp