import Decimal from 'decimal.js' ; import { StreamAction , CapitalState } from '../types' ; import { INITIALIZED , ORDER_PLACED , ORDER_FILLED , ORDER_CANCELLED } from '../constants' ; const initialState = { cash : new Decimal ( 0 ) , commission : new Decimal ( 0 ) , reservedCash : new Decimal ( 0 ) , total : new Decimal ( 0 ) } ; private param { CapitalState = initialState param { StreamAction } action return { CapitalState } export function capitalReducer ( state = initialState , action ) { state = { ... state } ; switch ( action . type ) { case INITIALIZED : { if ( typeof action . payload . startCapital !== 'undefined' ) { state . cash = new Decimal ( action . payload . startCapital ) ; state . total = new Decimal ( action . payload . startCapital ) ; } if ( action . payload . initialStates . capital ) { const initial = action . payload . initialStates . capital ; if ( typeof initial . cash !== 'undefined' ) { state . cash = new Decimal ( initial . cash ) ; } if ( typeof initial . commission !== 'undefined' ) { state . commission = new Decimal ( initial . commission ) ; } if ( typeof initial . reservedCash !== 'undefined' ) { state . reservedCash = new Decimal ( initial . reservedCash ) ; } if ( typeof initial . total !== 'undefined' ) { state . total = new Decimal ( initial . total ) ; } } break ; } case ORDER_PLACED : { const order = action . payload ; const direction = Decimal . sign ( order . quantity ) ; let cash ; let reservedCash ; if ( direction === 1 ) { const cost = new Decimal ( order . price ) . mul ( order . quantity ) . abs ( ) ; reservedCash = new Decimal ( state . reservedCash ) . add ( cost ) . add ( order . commission ) ; cash = new Decimal ( state . cash ) . sub ( cost ) . sub ( order . commission ) ; } else { reservedCash = new Decimal ( state . reservedCash ) . add ( order . commission ) ; cash = new Decimal ( state . cash ) . sub ( order . commission ) ; } state . reservedCash = reservedCash ; state . cash = cash ; state . total = Decimal . add ( state . cash , state . reservedCash ) ; break ; } case ORDER_FILLED : { const placedOrder = action . payload . placedOrder ; const filledOrder = action . payload . filledOrder ; const direction = Decimal . sign ( filledOrder . quantity ) ; const adjustedCommission = new Decimal ( placedOrder . commission ) . mul ( filledOrder . quantity ) . div ( placedOrder . quantity ) ; if ( direction === 1 ) { const cost = new Decimal ( filledOrder . quantity ) . mul ( placedOrder . price ) . add ( adjustedCommission ) ; const reservedCash = Decimal . sub ( state . reservedCash , cost ) ; state . reservedCash = reservedCash ; } else { const extraCommission = Decimal . max ( 0 , Decimal . sub ( filledOrder . commission , placedOrder . commission ) . mul ( filledOrder . commission ) ) ; const receivedCash = Decimal . mul ( filledOrder . quantity , filledOrder . price ) . abs ( ) . sub ( extraCommission ) ; const cash = Decimal . add ( state . cash , receivedCash ) ; const reservedCash = Decimal . sub ( state . reservedCash , adjustedCommission ) ; state . cash = cash ; state . reservedCash = reservedCash ; } state . commission = Decimal . add ( state . commission , filledOrder . commission ) ; state . total = Decimal . add ( state . cash , state . reservedCash ) ; break ; } case ORDER_CANCELLED : { const cancelledOrder = action . payload ; const direction = Decimal . sign ( cancelledOrder . quantity ) ; if ( direction === 1 ) { const cost = Decimal . mul ( cancelledOrder . price , cancelledOrder . quantity ) . abs ( ) ; const reservedCash = Decimal . sub ( state . reservedCash , cost ) . sub ( cancelledOrder . commission ) ; const cash = Decimal . add ( state . cash , cost ) . add ( cancelledOrder . commission ) ; state . reservedCash = reservedCash ; state . cash = cash ; } break ; } default : { break ; } } return { ... state } ; }