import Decimal from 'decimal.js' ; import { StreamAction , Bar , PositionsState , Position } from '../types' ; import { INITIALIZED , ORDER_FILLED } from '../constants' ; const initialState = { instruments : { } , total : new Decimal ( 0 ) } ; param { any } maybeBar export function parseBar ( maybeBar ) { const bar = { } as Bar ; if ( maybeBar . identifier ) { bar . identifier = maybeBar . identifier ; } else { throw new TypeError ( 'Invalid argument' ) ; } for ( const key of [ 'open' , 'high' , 'low' , 'close' ] ) { if ( typeof maybeBar [ key ] === 'undefined' ) { throw new TypeError ( 'Invalid argument' ) ; } else { bar [ key ] = new Decimal ( maybeBar [ key ] ) ; } } return bar ; } private param { PositionsState = initialState param { StreamAction } action return { PositionsState } export function positionsReducer ( state = initialState , action ) { state = { ... state , instruments : Object . assign ( { } , state . instruments ) } ; switch ( action . type ) { case INITIALIZED : { if ( action . payload . initialStates . positions ) { const initial = action . payload . initialStates . positions ; state = { ... state , ... initial } ; } break ; } case ORDER_FILLED : { const filledOrder = action . payload . filledOrder ; const { identifier } = filledOrder ; const direction = Decimal . sign ( filledOrder . quantity ) ; if ( ! state . instruments [ identifier ] ) { const value = Decimal . mul ( filledOrder . quantity , filledOrder . price ) ; state . instruments [ identifier ] = { quantity : new Decimal ( filledOrder . quantity ) , value , price : new Decimal ( filledOrder . price ) } ; state . total = Decimal . add ( state . total , value ) ; break ; } let instrument = state . instruments [ identifier ] ; if ( direction === 1 ) { const price = Decimal . mul ( filledOrder . price , filledOrder . quantity ) . add ( Decimal . mul ( instrument . quantity , instrument . price ) ) . div ( Decimal . add ( instrument . quantity , filledOrder . quantity ) ) ; instrument . price = price ; } const quantity = Decimal . add ( instrument . quantity , filledOrder . quantity ) ; const value = Decimal . mul ( filledOrder . price , Decimal . add ( instrument . quantity , filledOrder . quantity ) ) ; const oldValue = instrument . value ; instrument = { ... instrument , quantity , value } ; if ( instrument . quantity . eq ( 0 ) ) { delete state . instruments [ identifier ] ; state . total = Decimal . sub ( state . total , oldValue ) ; break ; } state . instruments [ identifier ] = instrument ; state . total = Decimal . add ( state . total , Decimal . sub ( value , oldValue ) ) ; break ; } default : { try { const bar = parseBar ( action . payload ) ; const { identifier } = bar ; if ( state . instruments [ identifier ] ) { const quantity = state . instruments [ identifier ] . quantity ; const marketPrice = bar . close ; const oldValue = state . instruments [ identifier ] . value ; const value = Decimal . mul ( quantity , marketPrice ) ; state . instruments [ identifier ] . value = value ; state . total = Decimal . add ( state . total , Decimal . sub ( value , oldValue ) ) ; } } catch ( e ) { } break ; } } return { ... state } ; }