Browse Source

Types encode/decode

master
Denis Tereshkin 8 years ago
parent
commit
952e7fa113
  1. 5
      libatrade.cabal
  2. 29
      src/ATrade/Price.hs
  3. 49
      src/ATrade/Types.hs
  4. 4
      test/ArbitraryInstances.hs
  5. 1
      test/TestBrokerProtocol.hs
  6. 1
      test/TestTypes.hs

5
libatrade.cabal

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
name: libatrade
version: 0.2.0.0
version: 0.3.0.0
synopsis: ATrade infrastructure core library
description: Please see README.md
homepage: https://github.com/asakul/libatrade.git
@ -27,7 +27,6 @@ library @@ -27,7 +27,6 @@ library
, ATrade.Broker.TradeSinks.ZMQTradeSink
, ATrade.Util
build-depends: base >= 4.7 && < 5
, Decimal
, time
, datetime
, bytestring
@ -52,6 +51,7 @@ library @@ -52,6 +51,7 @@ library
, http-client
, http-client-tls
, utf8-string
, scientific
default-language: Haskell2010
executable libatrade-exe
@ -77,7 +77,6 @@ test-suite libatrade-test @@ -77,7 +77,6 @@ test-suite libatrade-test
, tasty-hspec
, quickcheck-text
, quickcheck-instances
, Decimal
, scientific
, tuple
, time

29
src/ATrade/Price.hs

@ -5,10 +5,16 @@ module ATrade.Price ( @@ -5,10 +5,16 @@ module ATrade.Price (
fromDouble,
toDouble,
decompose,
compose
compose,
fromScientific,
toScientific
) where
import Data.Int
import Data.Ratio
import Data.Aeson
import Data.Scientific
data Price = Price {
priceQuants :: !Int64
@ -41,9 +47,30 @@ toDouble p = fromIntegral (priceQuants p) / fromIntegral mega @@ -41,9 +47,30 @@ toDouble p = fromIntegral (priceQuants p) / fromIntegral mega
fromDouble :: Double -> Price
fromDouble d = Price { priceQuants = truncate (d * fromIntegral mega) }
toScientific :: Price -> Scientific
toScientific p = normalize $ scientific (toInteger $ priceQuants p) (-6)
fromScientific :: Scientific -> Price
fromScientific d = Price { priceQuants = if base10Exponent nd >= -6 then fromInteger $ coefficient nd * (10 ^ (base10Exponent nd + 6)) else 0 }
where
nd = normalize d
decompose :: Price -> (Int64, Int32)
decompose Price{priceQuants = p} = (p `div` mega, (fromInteger . toInteger) $ p `mod` mega)
compose :: (Int64, Int32) -> Price
compose (int, frac) = Price { priceQuants = int * mega + (fromInteger . toInteger) frac }
instance FromJSON Price where
parseJSON = withScientific "number" (\x -> let nx = normalize x in
return Price { priceQuants = if base10Exponent nx >= -6 then fromInteger $ coefficient nx * (10 ^ (base10Exponent nx + 6)) else 0 })
instance ToJSON Price where
toJSON x = Number (normalize $ scientific (toInteger $ priceQuants x) (-6))
instance Real Price where
toRational a = (toInteger . priceQuants $ a) % toInteger mega
instance Fractional Price where
fromRational a = fromInteger (numerator a) / fromInteger (denominator a)
a / b = fromDouble $ toDouble a / toDouble b

49
src/ATrade/Types.hs

@ -36,7 +36,6 @@ import Data.Binary.Builder @@ -36,7 +36,6 @@ import Data.Binary.Builder
import Data.Binary.Get
import Data.ByteString.Lazy as B
import Data.DateTime
import Data.Decimal
import Data.Int
import Data.List as L
import Data.Maybe
@ -138,14 +137,6 @@ parseTick = do @@ -138,14 +137,6 @@ parseTick = do
makeTimestamp :: Word64 -> Word32 -> UTCTime
makeTimestamp sec usec = addUTCTime (fromRational $ toInteger usec % 1000000) (fromSeconds . toInteger $ sec)
makeValue :: Int64 -> Int32 -> Decimal
makeValue intpart nanopart = case eitherFromRational r of
Right v -> v + convertedIntPart
Left _ -> convertedIntPart
where
convertedIntPart = realFracToDecimal 10 (fromIntegral intpart)
r = toInteger nanopart % 1000000000
deserializeTick :: [ByteString] -> Maybe Tick
deserializeTick (header:rawData:_) = case runGetOrFail parseTick rawData of
Left (_, _, _) -> Nothing
@ -161,10 +152,10 @@ deserializeTickBody bs = case runGetOrFail parseTick bs of @@ -161,10 +152,10 @@ deserializeTickBody bs = case runGetOrFail parseTick bs of
data Bar = Bar {
barSecurity :: !TickerId,
barTimestamp :: !UTCTime,
barOpen :: !Decimal,
barHigh :: !Decimal,
barLow :: !Decimal,
barClose :: !Decimal,
barOpen :: !Price,
barHigh :: !Price,
barLow :: !Price,
barClose :: !Price,
barVolume :: !Integer
} deriving (Show, Eq, Generic)
@ -186,29 +177,27 @@ instance ToJSON SignalId where @@ -186,29 +177,27 @@ instance ToJSON SignalId where
"signal-name" .= signalName sid,
"comment" .= comment sid ]
instance FromJSON Decimal where
parseJSON = withScientific "number" (return . realFracToDecimal 10 . toRational)
instance ToJSON Decimal where
toJSON = Number . fromRational . toRational
data OrderPrice = Market | Limit Decimal | Stop Decimal Decimal | StopMarket Decimal
data OrderPrice = Market | Limit Price | Stop Price Price | StopMarket Price
deriving (Show, Eq)
decimal :: (RealFrac r) => r -> Decimal
decimal = realFracToDecimal 10
instance FromJSON OrderPrice where
parseJSON (String s) = when (s /= "market") (fail "If string, then should be 'market'") >>
return Market
parseJSON (Number n) = return $ Limit $ decimal n
parseJSON a@(Number n) = do
price <- parseJSON a
return $ Limit price
parseJSON (Object v) = do
triggerPrice <- v .: "trigger" :: Parser Double
triggerPrice <- v .: "trigger"
case triggerPrice of
a@(Number trpr) -> do
trprice <- parseJSON a
execPrice <- v .: "execution"
case execPrice of
(String s) -> when (s /= "market") (fail "If string, then should be 'market'") >> return $ StopMarket (decimal triggerPrice)
(Number n) -> return $ Stop (decimal triggerPrice) (decimal n)
(String s) -> if s /= "market"
then (fail "If string, then should be 'market'")
else return $ StopMarket trprice
(Number n) -> return $ Stop trprice (fromScientific n)
_ -> fail "Should be either number or 'market'"
parseJSON _ = fail "OrderPrice"
@ -321,9 +310,9 @@ instance ToJSON Order where @@ -321,9 +310,9 @@ instance ToJSON Order where
data Trade = Trade {
tradeOrderId :: OrderId,
tradePrice :: Decimal,
tradePrice :: Price,
tradeQuantity :: Integer,
tradeVolume :: Decimal,
tradeVolume :: Price,
tradeVolumeCurrency :: T.Text,
tradeOperation :: Operation,
tradeAccount :: T.Text,
@ -384,6 +373,6 @@ data TickerInfo = TickerInfo { @@ -384,6 +373,6 @@ data TickerInfo = TickerInfo {
tiClass :: T.Text,
tiBase :: Maybe TickerId,
tiLotSize :: Integer,
tiTickSize :: Decimal
tiTickSize :: Price
} deriving (Show, Eq)

4
test/ArbitraryInstances.hs

@ -15,7 +15,6 @@ import ATrade.Price as P @@ -15,7 +15,6 @@ import ATrade.Price as P
import ATrade.Broker.Protocol
import Data.Int
import Data.Decimal
import Data.Scientific
import Data.Time.Clock
import Data.Time.Calendar
@ -42,9 +41,6 @@ instance Arbitrary Tick where @@ -42,9 +41,6 @@ instance Arbitrary Tick where
instance Arbitrary DataType where
arbitrary = toEnum <$> choose (1, 10)
instance Arbitrary Decimal where
arbitrary = realFracToDecimal 10 <$> (arbitrary :: Gen Scientific)
instance Arbitrary SignalId where
arbitrary = SignalId <$> arbitrary <*> arbitrary <*> arbitrary

1
test/TestBrokerProtocol.hs

@ -15,7 +15,6 @@ import ATrade.Broker.Protocol @@ -15,7 +15,6 @@ import ATrade.Broker.Protocol
import ArbitraryInstances
import Data.Aeson
import Data.Decimal
import Data.Scientific
properties = testGroup "Broker.Protocol" [

1
test/TestTypes.hs

@ -16,7 +16,6 @@ import ArbitraryInstances @@ -16,7 +16,6 @@ import ArbitraryInstances
import Data.Aeson
import Data.Aeson.Types
import Data.Decimal
import Data.Scientific
import Data.Text
import Data.Time.Calendar

Loading…
Cancel
Save