{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE InstanceSigs #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE FlexibleInstances #-}

module Deal.DealMod (modDeal, ModifyType(..), AdjStrategy(..)
                     )                      
  where

import Data.Aeson
import Data.Aeson.Types
import Data.Aeson.TH
import Data.Aeson.Encode.Pretty (encodePretty)
import Servant.OpenApi
import Data.OpenApi hiding (Server,contentType,trace)

import qualified Accounts as A
import qualified Ledger as LD
import qualified Asset as Ast
import qualified Expense as F
import qualified Liability as L
import qualified CreditEnhancement as CE
import qualified Hedge as HE
import qualified Waterfall as W
import qualified Cashflow as CF
import qualified Assumptions as AP
import qualified AssetClass.AssetBase as ACM
import qualified Call as C
import qualified InterestRate as IR
import qualified Util as U
import qualified Deal.DealBase as DB
import Stmt
import Lib
import Util
import DateUtil
import Types
import Revolving
import Triggers

import qualified Data.Map as Map
import qualified Data.Time as T
import qualified Data.Set as S
import Data.List
import Data.Fixed
import Data.Maybe
import Data.Ratio
import Data.Aeson hiding (json)
import qualified Data.Aeson.Encode.Pretty as Pretty
import Language.Haskell.TH
import Data.Aeson.TH
import Data.Aeson.Types
import GHC.Generics
import Control.Lens hiding (element)
import Control.Lens.TH
import Data.IntMap (filterWithKey)
import qualified Data.Text as T
import Text.Read (readMaybe)
import qualified Pool as P
import qualified Types as CF

import Debug.Trace
import qualified Control.Lens as P
debug :: c -> String -> c
debug = (String -> c -> c) -> c -> String -> c
forall a b c. (a -> b -> c) -> b -> a -> c
flip String -> c -> c
forall a. String -> a -> a
trace


data AdjStrategy = ScaleBySpread
                 | ScaleByFactor
                 deriving (Int -> AdjStrategy -> ShowS
[AdjStrategy] -> ShowS
AdjStrategy -> String
(Int -> AdjStrategy -> ShowS)
-> (AdjStrategy -> String)
-> ([AdjStrategy] -> ShowS)
-> Show AdjStrategy
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> AdjStrategy -> ShowS
showsPrec :: Int -> AdjStrategy -> ShowS
$cshow :: AdjStrategy -> String
show :: AdjStrategy -> String
$cshowList :: [AdjStrategy] -> ShowS
showList :: [AdjStrategy] -> ShowS
Show,(forall x. AdjStrategy -> Rep AdjStrategy x)
-> (forall x. Rep AdjStrategy x -> AdjStrategy)
-> Generic AdjStrategy
forall x. Rep AdjStrategy x -> AdjStrategy
forall x. AdjStrategy -> Rep AdjStrategy x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. AdjStrategy -> Rep AdjStrategy x
from :: forall x. AdjStrategy -> Rep AdjStrategy x
$cto :: forall x. Rep AdjStrategy x -> AdjStrategy
to :: forall x. Rep AdjStrategy x -> AdjStrategy
Generic)

data ModifyType = AddSpreadToBonds BondName
                | SlideBalances BondName BondName
                deriving (Int -> ModifyType -> ShowS
[ModifyType] -> ShowS
ModifyType -> String
(Int -> ModifyType -> ShowS)
-> (ModifyType -> String)
-> ([ModifyType] -> ShowS)
-> Show ModifyType
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> ModifyType -> ShowS
showsPrec :: Int -> ModifyType -> ShowS
$cshow :: ModifyType -> String
show :: ModifyType -> String
$cshowList :: [ModifyType] -> ShowS
showList :: [ModifyType] -> ShowS
Show,(forall x. ModifyType -> Rep ModifyType x)
-> (forall x. Rep ModifyType x -> ModifyType) -> Generic ModifyType
forall x. Rep ModifyType x -> ModifyType
forall x. ModifyType -> Rep ModifyType x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. ModifyType -> Rep ModifyType x
from :: forall x. ModifyType -> Rep ModifyType x
$cto :: forall x. Rep ModifyType x -> ModifyType
to :: forall x. Rep ModifyType x -> ModifyType
Generic)

-- ^ Modify a deal by various type of recipes
modDeal :: Ast.Asset a => ModifyType -> Double -> DB.TestDeal a -> DB.TestDeal a
modDeal :: forall a.
Asset a =>
ModifyType -> Double -> TestDeal a -> TestDeal a
modDeal (AddSpreadToBonds String
bnd) Double
sprd TestDeal a
d 
  = let 
      sprd' :: Spread
sprd' = (Rational -> Spread
forall a. Fractional a => Rational -> a
fromRational (Rational -> Spread) -> (Double -> Rational) -> Double -> Spread
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Double -> Rational
forall a. Real a => a -> Rational
toRational) Double
sprd
      bndMap :: Map String Bond
bndMap = TestDeal a -> Map String Bond
forall a. TestDeal a -> Map String Bond
DB.bonds TestDeal a
d
      bndMap' :: Map String Bond
bndMap' = (Bond -> Bond) -> [String] -> Map String Bond -> Map String Bond
forall k a. Ord k => (a -> a) -> [k] -> Map k a -> Map k a
U.mapWithinMap 
                  (\Bond
b -> Bond
b Bond -> (Bond -> Bond) -> Bond
forall a b. a -> (a -> b) -> b
& (InterestInfo -> Identity InterestInfo) -> Bond -> Identity Bond
Traversal' Bond InterestInfo
L.interestInfoTraversal ((InterestInfo -> Identity InterestInfo) -> Bond -> Identity Bond)
-> (InterestInfo -> InterestInfo) -> Bond -> Bond
forall s t a b. ASetter s t a b -> (a -> b) -> s -> t
%~ Spread -> InterestInfo -> InterestInfo
L.adjInterestInfoBySpread Spread
sprd'
                           Bond -> (Bond -> Bond) -> Bond
forall a b. a -> (a -> b) -> b
& (Spread -> Identity Spread) -> Bond -> Identity Bond
Traversal' Bond Spread
L.curRatesTraversal ((Spread -> Identity Spread) -> Bond -> Identity Bond)
-> (Spread -> Spread) -> Bond -> Bond
forall s t a b. ASetter s t a b -> (a -> b) -> s -> t
%~ (Spread -> Spread -> Spread
forall a. Num a => a -> a -> a
+ Spread
sprd')) 
                  [String
bnd]
                  Map String Bond
bndMap
    in 
      TestDeal a
d {DB.bonds = bndMap'}

modDeal (SlideBalances String
bn1 String
bn2) Double
r d :: TestDeal a
d@DB.TestDeal {bonds :: forall a. TestDeal a -> Map String Bond
DB.bonds = Map String Bond
bndMap}
  = let 
      totalBalance :: Balance
totalBalance = [Balance] -> Balance
forall a. Num a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum ([Balance] -> Balance) -> [Balance] -> Balance
forall a b. (a -> b) -> a -> b
$ OriginalInfo -> Balance
L.originBalance (OriginalInfo -> Balance)
-> (Bond -> OriginalInfo) -> Bond -> Balance
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Bond -> OriginalInfo
L.bndOriginInfo (Bond -> Balance) -> [Bond] -> [Balance]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> TestDeal a -> [String] -> [Bond]
forall a. Asset a => TestDeal a -> [String] -> [Bond]
DB.viewDealBondsByNames TestDeal a
d [String
bn1, String
bn2]
      leftBal :: Balance
leftBal = Balance -> Rational -> Balance
mulBR Balance
totalBalance (Double -> Rational
forall a. Real a => a -> Rational
toRational Double
r) -- `debug` ("split ratio" ++ show r)
      rightBal :: Balance
rightBal = Balance
totalBalance Balance -> Balance -> Balance
forall a. Num a => a -> a -> a
- Balance
leftBal 
      bndMap' :: Map String Bond
bndMap' = String -> (Bond -> Bond) -> Map String Bond -> Map String Bond
DB.updateBondInMap String
bn1 (Balance -> Bond -> Bond
L.adjustBalance Balance
leftBal) (Map String Bond -> Map String Bond)
-> Map String Bond -> Map String Bond
forall a b. (a -> b) -> a -> b
$
                 String -> (Bond -> Bond) -> Map String Bond -> Map String Bond
DB.updateBondInMap String
bn2 (Balance -> Bond -> Bond
L.adjustBalance Balance
rightBal) Map String Bond
bndMap -- `debug` ("leftBal: " ++ show leftBal ++ ", rightBal: " ++ show rightBal )
    in 
      TestDeal a
d {DB.bonds = bndMap'}

modDeal ModifyType
x Double
_ TestDeal a
_ = String -> TestDeal a
forall a. HasCallStack => String -> a
error (String -> TestDeal a) -> String -> TestDeal a
forall a b. (a -> b) -> a -> b
$ String
"modify deal: not implemented"String -> ShowS
forall a. [a] -> [a] -> [a]
++ ModifyType -> String
forall a. Show a => a -> String
show ModifyType
x


$(deriveJSON defaultOptions ''AdjStrategy)
instance ToSchema AdjStrategy

$(deriveJSON defaultOptions ''ModifyType)
instance ToSchema ModifyType