|
|
|
@ -38,12 +38,21 @@ import ATrade.Driver.Junction.Types (StrategyDescriptor |
|
|
|
confStrategy, |
|
|
|
confStrategy, |
|
|
|
strategyState, |
|
|
|
strategyState, |
|
|
|
strategyTimers) |
|
|
|
strategyTimers) |
|
|
|
|
|
|
|
import ATrade.Logging (Message, |
|
|
|
|
|
|
|
Severity (Info), |
|
|
|
|
|
|
|
fmtMessage, |
|
|
|
|
|
|
|
logWarning, |
|
|
|
|
|
|
|
logWith) |
|
|
|
import ATrade.Quotes.QHP (mkQHPHandle) |
|
|
|
import ATrade.Quotes.QHP (mkQHPHandle) |
|
|
|
import ATrade.RoboCom.ConfigStorage (ConfigStorage (loadConfig)) |
|
|
|
import ATrade.RoboCom.ConfigStorage (ConfigStorage (loadConfig)) |
|
|
|
import ATrade.RoboCom.Persistence (MonadPersistence (loadState, saveState)) |
|
|
|
import ATrade.RoboCom.Persistence (MonadPersistence (loadState, saveState)) |
|
|
|
import ATrade.Types (ClientSecurityParams (ClientSecurityParams), |
|
|
|
import ATrade.Types (ClientSecurityParams (ClientSecurityParams), |
|
|
|
OrderId, |
|
|
|
OrderId, |
|
|
|
Trade (tradeOrderId)) |
|
|
|
Trade (tradeOrderId)) |
|
|
|
|
|
|
|
import Colog (HasLog (getLogAction, setLogAction), |
|
|
|
|
|
|
|
LogAction, |
|
|
|
|
|
|
|
logTextStdout, |
|
|
|
|
|
|
|
(>$<)) |
|
|
|
import Control.Concurrent (threadDelay) |
|
|
|
import Control.Concurrent (threadDelay) |
|
|
|
import Control.Exception.Safe (MonadThrow, |
|
|
|
import Control.Exception.Safe (MonadThrow, |
|
|
|
bracket) |
|
|
|
bracket) |
|
|
|
@ -84,8 +93,8 @@ import Options.Applicative (Parser, |
|
|
|
metavar, progDesc, |
|
|
|
metavar, progDesc, |
|
|
|
short, strOption, |
|
|
|
short, strOption, |
|
|
|
(<**>)) |
|
|
|
(<**>)) |
|
|
|
import Prelude hiding (readFile) |
|
|
|
import Prelude hiding (log, |
|
|
|
import System.Log.Logger (warningM) |
|
|
|
readFile) |
|
|
|
import System.ZMQ4 (withContext) |
|
|
|
import System.ZMQ4 (withContext) |
|
|
|
import System.ZMQ4.ZAP (loadCertificateFromFile) |
|
|
|
import System.ZMQ4.ZAP (loadCertificateFromFile) |
|
|
|
|
|
|
|
|
|
|
|
@ -96,12 +105,17 @@ data JunctionEnv = |
|
|
|
peConfigPath :: FilePath, |
|
|
|
peConfigPath :: FilePath, |
|
|
|
peQuoteThread :: QuoteThreadHandle, |
|
|
|
peQuoteThread :: QuoteThreadHandle, |
|
|
|
peBroker :: BrokerClientHandle, |
|
|
|
peBroker :: BrokerClientHandle, |
|
|
|
peRobots :: IORef (M.Map T.Text RobotDriverHandle) |
|
|
|
peRobots :: IORef (M.Map T.Text RobotDriverHandle), |
|
|
|
|
|
|
|
peLogAction :: LogAction JunctionM Message |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
newtype JunctionM a = JunctionM { unJunctionM :: ReaderT JunctionEnv IO a } |
|
|
|
newtype JunctionM a = JunctionM { unJunctionM :: ReaderT JunctionEnv IO a } |
|
|
|
deriving (Functor, Applicative, Monad, MonadReader JunctionEnv, MonadIO, MonadThrow) |
|
|
|
deriving (Functor, Applicative, Monad, MonadReader JunctionEnv, MonadIO, MonadThrow) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
instance HasLog JunctionEnv Message JunctionM where |
|
|
|
|
|
|
|
getLogAction = peLogAction |
|
|
|
|
|
|
|
setLogAction a e = e { peLogAction = a } |
|
|
|
|
|
|
|
|
|
|
|
instance ConfigStorage JunctionM where |
|
|
|
instance ConfigStorage JunctionM where |
|
|
|
loadConfig key = do |
|
|
|
loadConfig key = do |
|
|
|
basePath <- asks peConfigPath |
|
|
|
basePath <- asks peConfigPath |
|
|
|
@ -115,7 +129,7 @@ instance MonadPersistence JunctionM where |
|
|
|
res <- liftIO $ runRedis conn $ mset [(encodeUtf8 key, BL.toStrict $ encode newState), |
|
|
|
res <- liftIO $ runRedis conn $ mset [(encodeUtf8 key, BL.toStrict $ encode newState), |
|
|
|
(encodeUtf8 (key <> ":last_store") , encodeUtf8 . T.pack . show $ now)] |
|
|
|
(encodeUtf8 (key <> ":last_store") , encodeUtf8 . T.pack . show $ now)] |
|
|
|
case res of |
|
|
|
case res of |
|
|
|
Left _ -> liftIO $ warningM "main" "Unable to save state" |
|
|
|
Left _ -> logWarning "Junction " "Unable to save state" |
|
|
|
Right _ -> return () |
|
|
|
Right _ -> return () |
|
|
|
|
|
|
|
|
|
|
|
loadState key = do |
|
|
|
loadState key = do |
|
|
|
@ -124,17 +138,17 @@ instance MonadPersistence JunctionM where |
|
|
|
-- TODO: just chain eithers |
|
|
|
-- TODO: just chain eithers |
|
|
|
case res of |
|
|
|
case res of |
|
|
|
Left _ -> do |
|
|
|
Left _ -> do |
|
|
|
liftIO $ warningM "main" "Unable to load state" |
|
|
|
logWarning "Junction" "Unable to load state" |
|
|
|
return def |
|
|
|
return def |
|
|
|
Right maybeRawState -> |
|
|
|
Right maybeRawState -> |
|
|
|
case maybeRawState of |
|
|
|
case maybeRawState of |
|
|
|
Just rawState -> case eitherDecode $ BL.fromStrict rawState of |
|
|
|
Just rawState -> case eitherDecode $ BL.fromStrict rawState of |
|
|
|
Left _ -> do |
|
|
|
Left _ -> do |
|
|
|
liftIO $ warningM "main" "Unable to decode state" |
|
|
|
logWarning "Junction" "Unable to decode state" |
|
|
|
return def |
|
|
|
return def |
|
|
|
Right decodedState -> return decodedState |
|
|
|
Right decodedState -> return decodedState |
|
|
|
Nothing -> do |
|
|
|
Nothing -> do |
|
|
|
liftIO $ warningM "main" "Unable to decode state" |
|
|
|
logWarning "Junction" "Unable to decode state" |
|
|
|
return def |
|
|
|
return def |
|
|
|
|
|
|
|
|
|
|
|
instance QuoteStream JunctionM where |
|
|
|
instance QuoteStream JunctionM where |
|
|
|
@ -148,18 +162,25 @@ junctionMain :: M.Map T.Text StrategyDescriptorE -> IO () |
|
|
|
junctionMain descriptors = do |
|
|
|
junctionMain descriptors = do |
|
|
|
opts <- parseOptions |
|
|
|
opts <- parseOptions |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let bootstrapLogAction = fmtMessage >$< logTextStdout |
|
|
|
|
|
|
|
let log = logWith bootstrapLogAction |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
log Info "Junction" $ "Reading config from: " <> (T.pack . show) (configPath opts) |
|
|
|
|
|
|
|
|
|
|
|
cfg <- readFile (configPath opts) >>= input auto |
|
|
|
cfg <- readFile (configPath opts) >>= input auto |
|
|
|
|
|
|
|
|
|
|
|
barsMap <- newIORef M.empty |
|
|
|
barsMap <- newIORef M.empty |
|
|
|
|
|
|
|
|
|
|
|
redis <- checkedConnect (defaultConnectInfo { connectPort = UnixSocket (T.unpack $ redisSocket cfg) }) |
|
|
|
redis <- checkedConnect (defaultConnectInfo { connectPort = UnixSocket (T.unpack $ redisSocket cfg) }) |
|
|
|
withContext $ \ctx -> do |
|
|
|
withContext $ \ctx -> do |
|
|
|
let downloaderEnv = DownloaderEnv (mkQHPHandle ctx (qhpEndpoint cfg)) ctx (qtisEndpoint cfg) |
|
|
|
let downloaderLogAction = fmtMessage >$< logTextStdout |
|
|
|
|
|
|
|
let downloaderEnv = DownloaderEnv (mkQHPHandle ctx (qhpEndpoint cfg)) ctx (qtisEndpoint cfg) downloaderLogAction |
|
|
|
robotsMap <- newIORef M.empty |
|
|
|
robotsMap <- newIORef M.empty |
|
|
|
ordersMap <- newIORef M.empty |
|
|
|
ordersMap <- newIORef M.empty |
|
|
|
handledNotifications <- newIORef S.empty |
|
|
|
handledNotifications <- newIORef S.empty |
|
|
|
withBroker cfg ctx robotsMap ordersMap handledNotifications $ \bro -> |
|
|
|
withBroker cfg ctx robotsMap ordersMap handledNotifications $ \bro -> |
|
|
|
withQThread downloaderEnv barsMap cfg ctx $ \qt -> do |
|
|
|
withQThread downloaderEnv barsMap cfg ctx $ \qt -> do |
|
|
|
|
|
|
|
let junctionLogAction = fmtMessage >$< logTextStdout |
|
|
|
let env = |
|
|
|
let env = |
|
|
|
JunctionEnv |
|
|
|
JunctionEnv |
|
|
|
{ |
|
|
|
{ |
|
|
|
@ -167,7 +188,8 @@ junctionMain descriptors = do |
|
|
|
peConfigPath = robotsConfigsPath cfg, |
|
|
|
peConfigPath = robotsConfigsPath cfg, |
|
|
|
peQuoteThread = qt, |
|
|
|
peQuoteThread = qt, |
|
|
|
peBroker = bro, |
|
|
|
peBroker = bro, |
|
|
|
peRobots = robotsMap |
|
|
|
peRobots = robotsMap, |
|
|
|
|
|
|
|
peLogAction = junctionLogAction |
|
|
|
} |
|
|
|
} |
|
|
|
withJunction env $ do |
|
|
|
withJunction env $ do |
|
|
|
startRobots cfg bro barsMap |
|
|
|
startRobots cfg bro barsMap |
|
|
|
@ -194,7 +216,8 @@ junctionMain descriptors = do |
|
|
|
rConf <- liftIO $ newIORef (confStrategy bigConf) |
|
|
|
rConf <- liftIO $ newIORef (confStrategy bigConf) |
|
|
|
rState <- loadState (stateKey inst) >>= liftIO . newIORef |
|
|
|
rState <- loadState (stateKey inst) >>= liftIO . newIORef |
|
|
|
rTimers <- loadState (stateKey inst <> ":timers") >>= liftIO . newIORef |
|
|
|
rTimers <- loadState (stateKey inst <> ":timers") >>= liftIO . newIORef |
|
|
|
let robotEnv = RobotEnv rState rConf rTimers bro barsMap |
|
|
|
let robotLogAction = fmtMessage >$< logTextStdout |
|
|
|
|
|
|
|
let robotEnv = RobotEnv rState rConf rTimers bro barsMap robotLogAction |
|
|
|
robot <- createRobotDriverThread inst desc (flip runReaderT robotEnv . unRobotM) bigConf rConf rState rTimers |
|
|
|
robot <- createRobotDriverThread inst desc (flip runReaderT robotEnv . unRobotM) bigConf rConf rState rTimers |
|
|
|
robotsMap' <- asks peRobots |
|
|
|
robotsMap' <- asks peRobots |
|
|
|
liftIO $ atomicModifyIORef' robotsMap' (\s -> (M.insert (strategyId inst) robot s, ())) |
|
|
|
liftIO $ atomicModifyIORef' robotsMap' (\s -> (M.insert (strategyId inst) robot s, ())) |
|
|
|
@ -215,7 +238,7 @@ junctionMain descriptors = do |
|
|
|
|
|
|
|
|
|
|
|
case getNotificationTarget robotsMap ordersMap notification of |
|
|
|
case getNotificationTarget robotsMap ordersMap notification of |
|
|
|
Just robot -> postNotificationEvent robot notification |
|
|
|
Just robot -> postNotificationEvent robot notification |
|
|
|
Nothing -> warningM "Junction" "Unknown order" |
|
|
|
Nothing -> return () --logWarning "Junction" "Unknown order" -- TODO log |
|
|
|
|
|
|
|
|
|
|
|
atomicModifyIORef' handled (\s -> (S.insert (getNotificationSqnum notification) s, ())) |
|
|
|
atomicModifyIORef' handled (\s -> (S.insert (getNotificationSqnum notification) s, ())) |
|
|
|
|
|
|
|
|
|
|
|
|