|
|
|
@ -1,51 +1,51 @@ |
|
|
|
{-# LANGUAGE OverloadedStrings #-} |
|
|
|
{-# LANGUAGE OverloadedStrings #-} |
|
|
|
{-# LANGUAGE BangPatterns #-} |
|
|
|
{-# LANGUAGE Strict #-} |
|
|
|
{-# LANGUAGE Strict #-} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
module Broker.PaperBroker ( |
|
|
|
module Broker.PaperBroker ( |
|
|
|
PaperBrokerState, |
|
|
|
PaperBrokerState, |
|
|
|
mkPaperBroker |
|
|
|
mkPaperBroker |
|
|
|
) where |
|
|
|
) where |
|
|
|
|
|
|
|
|
|
|
|
import Data.Hashable |
|
|
|
import ATrade.Broker.Protocol |
|
|
|
import Data.Bits |
|
|
|
import ATrade.Broker.Server |
|
|
|
import ATrade.Types |
|
|
|
import ATrade.Quotes.QTIS |
|
|
|
import Data.IORef |
|
|
|
import ATrade.Types |
|
|
|
import qualified Data.List as L |
|
|
|
import Control.Concurrent hiding (readChan, writeChan) |
|
|
|
import qualified Data.Map.Strict as M |
|
|
|
import Control.Concurrent.BoundedChan |
|
|
|
import qualified Data.Text as T |
|
|
|
import Control.Monad |
|
|
|
import ATrade.Broker.Protocol |
|
|
|
import Data.Bits |
|
|
|
import ATrade.Broker.Server |
|
|
|
import Data.Hashable |
|
|
|
import Data.Time.Clock |
|
|
|
import Data.IORef |
|
|
|
import Data.Maybe |
|
|
|
import qualified Data.List as L |
|
|
|
import Control.Monad |
|
|
|
import qualified Data.Map.Strict as M |
|
|
|
import Control.Concurrent.BoundedChan |
|
|
|
import Data.Maybe |
|
|
|
import Control.Concurrent hiding (readChan, writeChan) |
|
|
|
import qualified Data.Text as T |
|
|
|
import System.Log.Logger |
|
|
|
import Data.Time.Clock |
|
|
|
import ATrade.Quotes.QTIS |
|
|
|
import System.Log.Logger |
|
|
|
import System.ZMQ4 |
|
|
|
import System.ZMQ4 |
|
|
|
|
|
|
|
|
|
|
|
import Commissions (CommissionConfig(..)) |
|
|
|
import Commissions (CommissionConfig (..)) |
|
|
|
import TickTable (TickTableH, TickKey(..), getTick, getTickerInfo) |
|
|
|
import TickTable (TickKey (..), TickTableH, |
|
|
|
|
|
|
|
getTick, getTickerInfo) |
|
|
|
|
|
|
|
|
|
|
|
data PaperBrokerState = PaperBrokerState { |
|
|
|
data PaperBrokerState = PaperBrokerState { |
|
|
|
pbTid :: Maybe ThreadId, |
|
|
|
pbTid :: Maybe ThreadId, |
|
|
|
tickTable :: TickTableH, |
|
|
|
tickTable :: TickTableH, |
|
|
|
orders :: M.Map OrderId Order, |
|
|
|
orders :: M.Map OrderId Order, |
|
|
|
cash :: !Price, |
|
|
|
cash :: !Price, |
|
|
|
notificationCallback :: Maybe (Notification -> IO ()), |
|
|
|
notificationCallback :: Maybe (Notification -> IO ()), |
|
|
|
pendingOrders :: [Order], |
|
|
|
pendingOrders :: [Order], |
|
|
|
|
|
|
|
|
|
|
|
fortsClassCodes :: [T.Text], |
|
|
|
fortsClassCodes :: [T.Text], |
|
|
|
fortsOpenTimeIntervals :: [(DiffTime, DiffTime)], |
|
|
|
fortsOpenTimeIntervals :: [(DiffTime, DiffTime)], |
|
|
|
|
|
|
|
|
|
|
|
auctionableClassCodes :: [T.Text], |
|
|
|
auctionableClassCodes :: [T.Text], |
|
|
|
premarketStartTime :: DiffTime, |
|
|
|
premarketStartTime :: DiffTime, |
|
|
|
marketOpenTime :: DiffTime, |
|
|
|
marketOpenTime :: DiffTime, |
|
|
|
postMarketStartTime :: DiffTime, |
|
|
|
postMarketStartTime :: DiffTime, |
|
|
|
postMarketFixTime :: DiffTime, |
|
|
|
postMarketFixTime :: DiffTime, |
|
|
|
postMarketCloseTime :: DiffTime, |
|
|
|
postMarketCloseTime :: DiffTime, |
|
|
|
commissions :: [CommissionConfig] |
|
|
|
commissions :: [CommissionConfig] |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
hourMin :: Integer -> Integer -> DiffTime |
|
|
|
hourMin :: Integer -> Integer -> DiffTime |
|
|
|
@ -90,9 +90,11 @@ brokerThread chan state = forever $ do |
|
|
|
executePendingOrders tick state |
|
|
|
executePendingOrders tick state |
|
|
|
|
|
|
|
|
|
|
|
executePendingOrders tick state = do |
|
|
|
executePendingOrders tick state = do |
|
|
|
|
|
|
|
marketOpenTime' <- marketOpenTime <$> readIORef state |
|
|
|
po <- pendingOrders <$> readIORef state |
|
|
|
po <- pendingOrders <$> readIORef state |
|
|
|
executedIds <- catMaybes <$> mapM execute po |
|
|
|
when (utctDayTime (timestamp tick) >= marketOpenTime') $ do |
|
|
|
atomicModifyIORef' state (\s -> (s { pendingOrders = L.filter (\order -> orderId order `L.notElem` executedIds) (pendingOrders s)}, ())) |
|
|
|
executedIds <- catMaybes <$> mapM execute po |
|
|
|
|
|
|
|
atomicModifyIORef' state (\s -> (s { pendingOrders = L.filter (\order -> orderId order `L.notElem` executedIds) (pendingOrders s)}, ())) |
|
|
|
where |
|
|
|
where |
|
|
|
execute order = |
|
|
|
execute order = |
|
|
|
if security tick == orderSecurity order |
|
|
|
if security tick == orderSecurity order |
|
|
|
@ -147,7 +149,7 @@ maybeCall proj state arg = do |
|
|
|
cb <- proj <$> readIORef state |
|
|
|
cb <- proj <$> readIORef state |
|
|
|
case cb of |
|
|
|
case cb of |
|
|
|
Just callback -> callback arg |
|
|
|
Just callback -> callback arg |
|
|
|
Nothing -> return () |
|
|
|
Nothing -> return () |
|
|
|
|
|
|
|
|
|
|
|
executeAtTick state order tick = do |
|
|
|
executeAtTick state order tick = do |
|
|
|
let newOrder = order { orderState = Executed } |
|
|
|
let newOrder = order { orderState = Executed } |
|
|
|
@ -179,8 +181,8 @@ pbSubmitOrder :: IORef PaperBrokerState -> Order -> IO () |
|
|
|
pbSubmitOrder state order = do |
|
|
|
pbSubmitOrder state order = do |
|
|
|
infoM "PaperBroker" $ "Submitted order: " ++ show order |
|
|
|
infoM "PaperBroker" $ "Submitted order: " ++ show order |
|
|
|
case orderPrice order of |
|
|
|
case orderPrice order of |
|
|
|
Market -> executeMarketOrder state order |
|
|
|
Market -> executeMarketOrder state order |
|
|
|
Limit price -> submitLimitOrder price state order |
|
|
|
Limit price -> submitLimitOrder price state order |
|
|
|
Stop price trigger -> submitStopOrder state order |
|
|
|
Stop price trigger -> submitStopOrder state order |
|
|
|
StopMarket trigger -> submitStopMarketOrder state order |
|
|
|
StopMarket trigger -> submitStopMarketOrder state order |
|
|
|
|
|
|
|
|
|
|
|
@ -204,8 +206,9 @@ pbSubmitOrder state order = do |
|
|
|
let newOrder = order { orderState = Submitted } |
|
|
|
let newOrder = order { orderState = Submitted } |
|
|
|
atomicModifyIORef' state (\s -> (s { orders = M.insert (orderId order) newOrder $ orders s }, ())) |
|
|
|
atomicModifyIORef' state (\s -> (s { orders = M.insert (orderId order) newOrder $ orders s }, ())) |
|
|
|
maybeCall notificationCallback state $ OrderNotification (orderId order) Submitted |
|
|
|
maybeCall notificationCallback state $ OrderNotification (orderId order) Submitted |
|
|
|
Just tick -> |
|
|
|
Just tick -> do |
|
|
|
if ((orderOperation order == Buy) && (value tick < price)) || ((orderOperation order == Sell) && (value tick > price)) |
|
|
|
marketOpenTime' <- marketOpenTime <$> readIORef state |
|
|
|
|
|
|
|
if (((orderOperation order == Buy) && (value tick < price)) || ((orderOperation order == Sell) && (value tick > price)) && (utctDayTime (timestamp tick) >= marketOpenTime')) |
|
|
|
then do |
|
|
|
then do |
|
|
|
maybeCall notificationCallback state $ OrderNotification (orderId order) Submitted |
|
|
|
maybeCall notificationCallback state $ OrderNotification (orderId order) Submitted |
|
|
|
executeAtTick state order tick |
|
|
|
executeAtTick state order tick |
|
|
|
@ -218,7 +221,7 @@ pbSubmitOrder state order = do |
|
|
|
submitStopMarketOrder _ _ = warningM "PaperBroker" $ "Not implemented: Submitted order: " ++ show order |
|
|
|
submitStopMarketOrder _ _ = warningM "PaperBroker" $ "Not implemented: Submitted order: " ++ show order |
|
|
|
|
|
|
|
|
|
|
|
orderDatatype = case orderOperation order of |
|
|
|
orderDatatype = case orderOperation order of |
|
|
|
Buy -> BestOffer |
|
|
|
Buy -> BestOffer |
|
|
|
Sell -> BestBid |
|
|
|
Sell -> BestBid |
|
|
|
|
|
|
|
|
|
|
|
key = TickKey (orderSecurity order) orderDatatype |
|
|
|
key = TickKey (orderSecurity order) orderDatatype |
|
|
|
@ -235,7 +238,7 @@ pbDestroyBroker state = do |
|
|
|
maybeTid <- pbTid <$> readIORef state |
|
|
|
maybeTid <- pbTid <$> readIORef state |
|
|
|
case maybeTid of |
|
|
|
case maybeTid of |
|
|
|
Just tid -> killThread tid |
|
|
|
Just tid -> killThread tid |
|
|
|
Nothing -> return () |
|
|
|
Nothing -> return () |
|
|
|
|
|
|
|
|
|
|
|
{- |
|
|
|
{- |
|
|
|
pbGetOrder :: IORef PaperBrokerState -> OrderId -> IO (Maybe Order) |
|
|
|
pbGetOrder :: IORef PaperBrokerState -> OrderId -> IO (Maybe Order) |
|
|
|
|