\n \n\n setShowAddBlock(false)}\n />\n \n );\n};\n","import React, { useCallback, useEffect, useRef } from 'react';\nimport { useStateSelector, blocksSelectors } from '../../data/global/dataSelectors';\nimport { DashboardContent, IDashboardContentProps } from '@tradingblock/components';\nimport { useDispatcher } from '../../data/global/hooks';\nimport { autoScrollToEnhanced } from './DashboardNavigation';\n\nexport const DashboardContentWrapper: React.FunctionComponent> = ({ children, ...props }) => {\n const locked = useStateSelector(s => s.blocks.locked);\n const linking = useStateSelector(s => s.blocks.linking);\n\n const highlightBlockIds = useStateSelector(blocksSelectors.highlightBlockIds);\n const highlightedAt = useStateSelector(blocksSelectors.highlightedAt);\n const timeoutMs = useStateSelector(blocksSelectors.highlightTimeoutMs);\n\n const { dispatcher } = useDispatcher();\n const clearHighlightedBlocks = useCallback(() => dispatcher.block.clearHighlightedBlocks(), [dispatcher.block]);\n\n const timeoutId = useRef();\n useEffect(() => {\n // if highlight set, restart timeout to clear highlight\n if (highlightBlockIds && highlightedAt) {\n const blockReference = document.querySelector(`div[id*=block-${highlightBlockIds[0]}]`);\n autoScrollToEnhanced(blockReference);\n window.clearTimeout(timeoutId.current);\n timeoutId.current = window.setTimeout(clearHighlightedBlocks, timeoutMs || 4000);\n }\n return () => {\n window.clearTimeout(timeoutId.current);\n };\n }, [timeoutId, highlightBlockIds, highlightedAt, timeoutMs, clearHighlightedBlocks]);\n\n return (\n \n {children}\n \n );\n};\n","import React, { useState, useRef, useEffect } from 'react';\nimport _ from 'lodash';\nimport { SizeType } from '@tradingblock/types';\nimport { useWhyDidYouUpdate, useWindowSizeContext } from '@tradingblock/components';\nimport { BlockDimensions } from '../../types';\n\nfunction useBbox(timeout?: number): [{ width: number; height: number } | undefined, React.MutableRefObject] {\n const ref = useRef(null);\n // const [bbox, setBbox] = useState();\n const [bbox, setBbox] = useState<{ width: number; height: number }>();\n\n useEffect(() => {\n const set = () => {\n if (ref.current) {\n const currBbox = ref.current.getBoundingClientRect();\n if (!_.isEqual(bbox, currBbox)) {\n return setBbox(ref && ref.current ? { width: currBbox.width, height: currBbox.height } : undefined);\n }\n }\n };\n set();\n let updateTimeout: NodeJS.Timeout | undefined = undefined;\n if (ref && ref.current) {\n const resizeObs = _.get(window, 'ResizeObserver', undefined);\n if (typeof resizeObs === 'function') {\n let resizeObserver: ResizeObserver | null = new resizeObs(() => {\n if (updateTimeout) {\n clearTimeout(updateTimeout);\n }\n updateTimeout = setTimeout(() => set(), timeout || 250);\n });\n resizeObserver.observe(ref.current);\n return () => {\n if (updateTimeout) {\n clearTimeout(updateTimeout);\n }\n if (!resizeObserver) {\n return;\n }\n\n resizeObserver.disconnect();\n resizeObserver = null;\n };\n }\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [timeout]);\n\n return [bbox, ref];\n}\n\nconst defaultDimensions: BlockDimensions = {\n width: SizeType.lg,\n height: SizeType.lg,\n widthClassName: `block-width-lg`,\n heightClassName: `block-height-lg`,\n};\nexport function useBboxDimensions(timeout?: number): [BlockDimensions, React.MutableRefObject] {\n const [bbox, ref] = useBbox(timeout);\n // even though window size not used for dim calculation, still need to use as dep so we update size when window size changes\n const windowSize = useWindowSizeContext();\n const [dimensions, setDimensions] = useState(defaultDimensions);\n useEffect(() => {\n let width: SizeType = dimensions.width;\n let height: SizeType = dimensions.width;\n if (bbox && windowSize) {\n if (bbox.width && bbox.width < 670) {\n width = SizeType.sm;\n } else if (bbox.width && bbox.width < 850) {\n width = SizeType.md;\n } else {\n width = SizeType.lg;\n }\n if (bbox.height && bbox.height < 200) {\n height = SizeType.sm;\n } else if (bbox.width && bbox.height < 500) {\n height = SizeType.md;\n } else {\n height = SizeType.lg;\n }\n }\n const newDimensions = {\n width,\n height,\n bboxWidth: bbox && bbox.width,\n bboxHeight: bbox && bbox.height,\n widthClassName: `block-width-${width}`,\n heightClassName: `block-height-${height}`,\n };\n if (!_.isEqual(dimensions, newDimensions)) {\n setDimensions(newDimensions);\n }\n }, [bbox, dimensions, windowSize]);\n\n useWhyDidYouUpdate('useBboxDimensions', { bbox, windowSize, dimensions, ref });\n return [dimensions, ref];\n}\n\nexport function useBlockSize(dimensions: BlockDimensions, widthOrHeight: 'width' | 'height', values: [T, T, T]) {\n if (dimensions[widthOrHeight] === SizeType.sm) {\n return values[0];\n } else if (dimensions[widthOrHeight] === SizeType.md) {\n return values[1];\n } else {\n return values[2];\n }\n}\n","import { useBaseBlockActionDispatch, BlockStateContext } from '../../../components/blocks/BlockState';\nimport { IBlockDataState, IBlockState } from '@tradingblock/types';\nimport { BlockAndTableActions, BlockTableActions } from '../../../components/blocks/state/blockTable/BlockTableActions';\nimport { WithTables } from '../../../components/blocks/state/blockTable/BlockTableState';\nimport createCachedSelector from 're-reselect';\nimport _ from 'lodash';\nimport { useCallback, useContext } from 'react';\nimport { DataTableState } from '@tradingblock/components';\n\nconst defaultDataTableState: DataTableState = { sortBy: [], pageSize: 50, pageIndex: 0, columnOrder: [] };\nconst defaultAdminAccountManagementState: DataTableState = { sortBy: [], pageSize: 10, pageIndex: 0, columnOrder: [] };\nconst isAdminAccountManagementTable = (key: string) => {\n const adminTableKeys = [\n 'adminAccountManagmentTable',\n 'adminApplicationsTable',\n 'admin-entitlements-table',\n 'releaseNotes',\n 'adminAlertsTemplateTable',\n ];\n\n return adminTableKeys.includes(key);\n};\n\nconst blockTableStateSelector = createCachedSelector(\n (s: IBlockState>, key: string) => (s.data.tables ? s.data.tables[key] : undefined),\n (s: IBlockState>, key: string) => key,\n (tablesState, key): DataTableState => {\n if (_.isNil(tablesState) && !isAdminAccountManagementTable(key)) {\n return defaultDataTableState;\n }\n if (_.isNil(tablesState) && isAdminAccountManagementTable(key)) {\n return defaultAdminAccountManagementState;\n }\n\n if (!isAdminAccountManagementTable(key)) {\n return { ...defaultDataTableState, ...tablesState };\n } else {\n return { ...defaultAdminAccountManagementState, ...tablesState };\n }\n }\n)((s, key: string) => `block-table-${s.blockId}-${key}`);\n\nexport const useBlockTableActions = () => useBaseBlockActionDispatch();\n\nexport const useBlockTable = (key: string) => {\n const state: IBlockState> = useContext(BlockStateContext);\n const initialState = blockTableStateSelector(state, key);\n const dispatch = useBaseBlockActionDispatch();\n const setTable = useCallback(\n (table: Partial) => {\n dispatch(BlockTableActions.setTableState({ key: key, table }, { persist: true }));\n },\n [dispatch]\n );\n return { state: initialState, setTable };\n};\n","import React, { useEffect, useCallback, useMemo } from 'react';\nimport { SortingRule, Table, useWhyDidYouUpdate, useParentSizeContext, DataTableState } from '@tradingblock/components';\nimport { useBboxDimensions } from '../useBboxDimensions';\nimport { useBlockId } from '../../../components/blocks/BlockState';\nimport { useBlockTableSize } from './useBlockTableSize';\nimport { useBlockTable } from './useBlockTableActions';\nimport { BlockTableProps } from './BlockTableTypes';\nimport { useStateSelector } from '../../../data/global/dataSelectors';\n\nexport const BlockTableContent: React.FunctionComponent = ({\n onSizeChanged,\n onSort,\n tableKey,\n onPage,\n onPageSize,\n pageCount,\n getColumnOrder,\n expandRows,\n ...props\n}) => {\n const b = useParentSizeContext();\n const [{ width }, ref] = useBboxDimensions(250);\n const size = useBlockTableSize(width);\n const blockTableState = useBlockTable(tableKey);\n const handleonSort = useCallback(\n (sorts: SortingRule[]) => {\n if (onSort) {\n onSort(sorts);\n }\n blockTableState.setTable({ sortBy: sorts });\n },\n [onSort, blockTableState.setTable]\n );\n const handleOnColumnOrderChanged = useCallback(\n (columnOrder: string[]) => {\n blockTableState.setTable({ columnOrder });\n },\n [blockTableState.setTable]\n );\n useEffect(() => {\n if (onSizeChanged) {\n onSizeChanged(size);\n }\n }, [size, onSizeChanged]);\n\n const blockId = useBlockId();\n useWhyDidYouUpdate(`${blockId}:BlockTable`, { size, ref, blockId, ...props });\n const initialState = useMemo((): DataTableState => {\n const tableState = blockTableState.state;\n return {\n ...(tableState || {}),\n ...(props.initialState || {}),\n columnOrder: tableState.columnOrder || (props.initialState && props.initialState.columnOrder),\n sortBy: tableState.sortBy || (props.initialState && props.initialState.sortBy),\n };\n }, [props.initialState, blockTableState.state]);\n\n useEffect(() => {\n if (getColumnOrder) {\n getColumnOrder(blockTableState.state.columnOrder);\n }\n }, [getColumnOrder, blockTableState.state.columnOrder]);\n\n // use the blockTableState to set the page index and page size if they differ from the initial state\n // this is to ensure that the table state is always in sync with the blockTableState\n // currently the activities block is not set up to persist tab or timeframe selections, so we cannot use the blockTableState to set the page index and page size\n // TODO: refactor the activities block to persist tab and timeframe selections\n useEffect(() => {\n if (\n initialState.pageIndex !== blockTableState.state.pageIndex &&\n onPage &&\n tableKey !== 'orders' &&\n tableKey !== 'accountsTable'\n ) {\n onPage(blockTableState.state.pageIndex);\n }\n if (\n initialState.pageSize !== blockTableState.state.pageSize &&\n onPageSize &&\n tableKey !== 'orders' &&\n tableKey !== 'accountsTable'\n ) {\n onPageSize(blockTableState.state.pageSize);\n }\n }, [blockTableState.state.pageIndex, blockTableState.state.pageSize]);\n\n const handleOnPage = useCallback(\n (pageIndex: number) => {\n if (onPage) {\n onPage(pageIndex);\n }\n blockTableState.setTable({ pageIndex });\n },\n [onPage, blockTableState.setTable]\n );\n\n const handleOnPageSize = useCallback(\n (pageSize: number) => {\n if (onPageSize) {\n onPageSize(pageSize);\n }\n blockTableState.setTable({ pageSize });\n },\n [onPageSize, blockTableState.setTable]\n );\n const isDashboardLocked = useStateSelector(s => s.ui.dashboard.isLocked);\n return (\n
\n
\n
\n );\n};\n","import { useMemo } from 'react';\nimport { SizeType } from '@tradingblock/types';\nimport { getTableSize, useWindowSizeContext } from '@tradingblock/components';\nexport function useBlockTableSize(tableWidth: SizeType): SizeType {\n const { width } = useWindowSizeContext();\n const size = useMemo(() => getTableSize(tableWidth, width), [width, tableWidth]);\n return size;\n}\n","import React from 'react';\nimport { TableProps, useParentSizeContext } from '@tradingblock/components';\nimport { BlockTableContent } from './table/BlockTableContent';\nimport { BlockTableProps } from './table/BlockTableTypes';\n\nexport const BlockTable: React.FunctionComponent = props => {\n return (\n \n \n \n );\n};\n","/* eslint-disable react-hooks/exhaustive-deps */\nimport { useStateSelector } from '../../../data/global/dataSelectors';\nimport { blockSettings } from '../../../data/global/selectors/settingSelectors';\nimport { useBlockId } from '../../../components/blocks/BlockState';\n\nexport const useOrderBlockSettings = (blockId?: string) => {\n return useStateSelector(s => blockSettings.order(s, blockId));\n};\nexport const useOrderSettings = () => {\n const blockId = useBlockId();\n return useOrderBlockSettings(blockId);\n};\n","import { useOrderData, OrderState } from './OrderState';\nimport { useGroupState } from '../../useGroupState';\n\ntype fieldOf = keyof T;\ntype selectorOf = (val: T) => TT;\n\nexport function useOrderState(field: K) {\n // const blockId = useBlockId();\n // const selector = createCachedSelector((s: OrderState, blockId: string) => s[field], (val: OrderState[K]) => val)((_: OrderState, blockId: string) => blockId);\n // const value = useOrderData(s => selector(s, blockId));\n const value = useOrderData(s => s[field]);\n return value;\n}\nexport function useOrderStateAs(field: K, transform: (val: OrderState[K]) => T) {\n const value = useOrderData(s => s[field]);\n return transform(value);\n}\n\nexport const useOrderSymbol = () => {\n const [symbol] = useGroupState('symbol');\n return symbol ? symbol.symbol : '';\n //return useOrderStateAs('symbol', s => (s ? s.symbol : ''));\n};\nexport const useOrderSymbolOrUndefined = () => {\n const [symbol] = useGroupState('symbol');\n return symbol ? symbol.symbol : undefined;\n};\n\nexport const useOrderAssetSymbolOrUndefined = () => {\n const [symbol] = useGroupState('symbol');\n return symbol ? symbol : undefined;\n};\n","import _ from 'lodash';\nimport createCachedSelector from 're-reselect';\nimport { Legs, OrderAction } from '@tradingblock/types';\nimport { calculateOrderPrice, orderLegOccSymbol } from '@tradingblock/api';\nimport { OrderSelectors } from '../state/OrderSelector';\nimport { OrderState } from '../state/OrderState';\nimport { createDeepSelector, createDeepArraySelector } from '../../../data/selectors';\nimport { GCD } from '../../../utilities/data';\nimport { LegQuoteState, Quotebidask } from './orderTypes';\n\nexport const getOrderLegPrices = createCachedSelector(\n (state: LegQuoteState) => state.legs,\n (state: LegQuoteState) => state.quotes,\n ({ orderAction, strategy, legs }: LegQuoteState) =>\n OrderSelectors.actionForPrice({ strategy, action: orderAction, legs }),\n (state: LegQuoteState) => GCD(_.map(state.legs, l => l.SpreadRatio || 1)) || 1,\n (state: LegQuoteState) => state.strategy,\n (legs: Legs, quotes: Quotebidask, action: OrderAction, gcd: number, strategy) => {\n return calculateOrderPrice(legs, quotes, action, gcd, strategy);\n }\n)((s: LegQuoteState, blockId: string) => blockId || 'UNKNOWN', { selectorCreator: createDeepSelector });\n// export const orderLegPrices = getOrderLegPrices({ legs, quotes: quotes, orderType, orderAction, strategy });\n\nexport const getOrderQuotes = createCachedSelector(\n (s: OrderState, blockId: string) => _.values(s.quotes),\n quotes => quotes\n)((_, blockId: string) => `orderquotes-${blockId}`);\n\nconst orderLegSymbolSelector = createDeepArraySelector(\n (s: OrderState) => s.legs,\n (s: OrderState) => s.symbol,\n (legs, symbol) => {\n if (symbol === undefined) {\n return [];\n }\n\n const legSymbols = legs\n ? _.reduce(\n legs,\n (acc: string[], l) => {\n const legSymbol = orderLegOccSymbol(symbol, l);\n if (legSymbol === undefined) {\n return acc;\n }\n return _.uniq([...acc, legSymbol]).sort();\n },\n []\n )\n : [];\n return legSymbols;\n }\n);\n\nexport const orderBlockSymbols = createCachedSelector(\n (s: OrderState, blockId: string) => (s.symbol ? s.symbol.symbol : undefined),\n (s: OrderState) => (s.symbol ? s.symbol.underlyingSymbol : undefined),\n orderLegSymbolSelector,\n (symbol, underlyingSymbol, legSymbols) => {\n let symbolValues: string[] = [];\n if (symbol) {\n symbolValues = [...symbolValues, symbol];\n }\n if (underlyingSymbol) {\n symbolValues = [...symbolValues, underlyingSymbol];\n }\n if (legSymbols && legSymbols.length > 0) {\n symbolValues = [...symbolValues, ...legSymbols];\n }\n\n return _.uniq(symbolValues);\n }\n)((s, blockId: string) => `${blockId}-symbols`);\n","import { useMemo } from 'react';\nimport _ from 'lodash';\nimport createCachedSelector from 're-reselect';\nimport { useWhyDidYouUpdate } from '@tradingblock/components';\nimport { useOrderData, useOrderDataSelector, OrderQuote, useOrderBlockData, OrderState } from '../state/OrderState';\nimport { LegSelector, OrderSymbolListValues } from '../state/OrderLegSelector';\nimport { OrderPriceData } from '../data/orderTypes';\nimport { getOrderLegPrices, getOrderQuotes } from '../data/orderSelectors';\nimport { useQuoteBidAskMetadata } from '../../../hooks/useFeedQuote';\nimport { areArraysEqual } from '../../../utilities/data';\nimport { useBlockId } from '../../../components/blocks/BlockState';\nimport { Strategies, getKnownStrategy } from '@tradingblock/api';\nimport { account } from '../../../data/global/selectors/accountSelectors';\nimport { useSelector } from 'react-redux';\nimport { AssetType, OptionType, OrderAction, OrderType } from '@tradingblock/types';\nimport { ClassificationOrderLeg, classifyStrategy } from '../../../data/global/utilities/strategyClassification';\n\nconst orderDataSelector = createCachedSelector(\n (s: OrderState, blockId: string) => s.strategy,\n (s: OrderState) => s.orderType,\n (s: OrderState) => s.action,\n (strategy, orderType, orderAction) => ({ strategy, orderType, orderAction })\n)((s: OrderState, blockId: string) => `orderDateSelector-${blockId}`);\n\nconst useOrderPriceRawValues = (quotes: OrderQuote[], isBuy?: boolean): OrderPriceData => {\n const blockId = useBlockId();\n const { price } = useOrderDataSelector(s => ({\n price: s.price,\n }));\n const isLimitOrder = useOrderDataSelector(s => s.orderType === OrderType.Limit);\n const isIRA = useSelector(account.accountIsIRA);\n const legs = useOrderData(s => LegSelector.LegsByOCC(s, blockId));\n const { strategy, orderType, orderAction } = useOrderData(s => orderDataSelector(s, blockId));\n const match = useOrderData(s => s.validation && s.validation.match);\n\n // const classifyOrderLegs: ClassificationOrderLeg[] = Object.values(legs).reduce((acc, leg) => {\n // if (leg.AssetType === AssetType.Equity) {\n // acc.push({\n // type: \"Shares\",\n // action: leg.Action === OrderAction.Buy ? \"BUY\" : \"SELL\",\n // strike: 0,\n // expiration: new Date(),\n // spreadRatio: leg.SpreadRatio ? leg.SpreadRatio : 0,\n // });\n // return acc;\n // }\n // if (leg.Strike === undefined || leg.Expiration === undefined || leg.SpreadRatio === undefined) {\n // return acc;\n // }\n\n // acc.push({\n // type: leg.OptionType === OptionType.Call ? \"CALL\" : \"PUT\",\n // action: leg.Action === OrderAction.Buy ? \"BUY\" : \"SELL\",\n // strike: leg.Strike,\n // expiration: typeof leg.Expiration.date === \"string\" ? new Date(leg.Expiration.date) : leg.Expiration.date,\n // spreadRatio: leg.SpreadRatio ? leg.SpreadRatio : 0,\n // });\n // return acc;\n // }, [] as ClassificationOrderLeg[]);\n\n // const classifiedStrategy = classifyStrategy(classifyOrderLegs.length === Object.values(legs).length ? classifyOrderLegs : []);\n // const match = Strategies.find(s => s.info.Name === classifiedStrategy.name);\n\n // if the strategy is custom but match is a call or put calendar, then we need to assign order action based on the action of the latest expiring option leg\n const isCustomStrategy = strategy === 'Custom';\n const isCallVerticalMatch = match && match.info.Name === 'Call Vertical';\n const isPutVerticalMatch = match && match.info.Name === 'Put Vertical';\n const isCoveredCallMatch = match && match.info.Name === 'Covered Call';\n const isCallButterflyMatch = match && match.info.Name === 'Call Butterfly';\n const isPutButterflyMatch = match && match.info.Name === 'Put Butterfly';\n const isIronButterflyMatch = match && match.info.Name === 'Iron Butterfly';\n const isIronCondorMatch = match && match.info.Name === 'Iron Condor';\n const isCallCondorMatch = match && match.info.Name === 'Call Condor';\n const isPutCondorMatch = match && match.info.Name === 'Put Condor';\n\n let orderActionValue = orderAction;\n\n if (isCustomStrategy && isCallVerticalMatch) {\n // for a call vertical spread the order is considered a buy if you are buying the lower strike and selling the higher strike\n\n // find the leg with the lower strike\n const lowerStrikeLeg = _.minBy(Object.values(legs), l => l.Strike);\n if (lowerStrikeLeg) {\n if (lowerStrikeLeg.Action === OrderAction.Buy) {\n orderActionValue = OrderAction.Buy;\n } else {\n orderActionValue = OrderAction.Sell;\n }\n }\n }\n\n if (isCustomStrategy && isPutVerticalMatch) {\n // for a put vertical spread the order is considered a buy if you are selling the lower strike and buying the higher strike\n\n // find the leg with the lower strike\n const lowerStrikeLeg = _.minBy(Object.values(legs), l => l.Strike);\n if (lowerStrikeLeg) {\n if (lowerStrikeLeg.Action === OrderAction.Buy) {\n orderActionValue = OrderAction.Sell;\n } else {\n orderActionValue = OrderAction.Buy;\n }\n }\n }\n\n if (isCustomStrategy && isCoveredCallMatch) {\n // covered call is considered a buy (bullish) if you are buying the stock and selling the call\n // covered call is considered a sell (bearish) if you are selling the stock and buying the call\n const shareLeg = Object.values(legs).find(l => l.AssetType === AssetType.Equity);\n if (shareLeg) {\n if (shareLeg.Action === OrderAction.Buy) {\n orderActionValue = OrderAction.Buy;\n } else {\n orderActionValue = OrderAction.Sell;\n }\n }\n }\n\n if (isCustomStrategy && isCallButterflyMatch) {\n // for a call butterfly the order is considered a buy if you are buying the lower strike and higher strike and selling the middle strike\n\n // find the leg with the lower strike\n const lowerStrikeLeg = _.minBy(Object.values(legs), l => l.Strike);\n if (lowerStrikeLeg) {\n if (lowerStrikeLeg.Action === OrderAction.Buy) {\n orderActionValue = OrderAction.Buy;\n } else {\n orderActionValue = OrderAction.Sell;\n }\n }\n }\n\n if (isCustomStrategy && isPutButterflyMatch) {\n // for a put butterfly the order is considered a buy if you are selling the lower strike and higher strike and buying the middle strike\n\n // find the leg with the lower strike\n const lowerStrikeLeg = _.minBy(Object.values(legs), l => l.Strike);\n if (lowerStrikeLeg) {\n if (lowerStrikeLeg.Action === OrderAction.Buy) {\n orderActionValue = OrderAction.Buy;\n } else {\n orderActionValue = OrderAction.Sell;\n }\n }\n }\n\n if (isCustomStrategy && isIronButterflyMatch) {\n // for an iron butterfly the order is considered a buy if you are buying the lower strike and higher strike and selling the middle strike\n\n // find the leg with the lower strike\n const lowerStrikeLeg = _.minBy(Object.values(legs), l => l.Strike);\n if (lowerStrikeLeg) {\n if (lowerStrikeLeg.Action === OrderAction.Buy) {\n orderActionValue = OrderAction.Sell;\n } else {\n orderActionValue = OrderAction.Buy;\n }\n }\n }\n\n if (isCustomStrategy && isIronCondorMatch) {\n // for an iron condor the order is considered a buy if you are selling the lower strike and higher strike and buying the middle strike\n // find the leg with the lower strike\n const lowerStrikeLeg = _.minBy(Object.values(legs), l => l.Strike);\n if (lowerStrikeLeg) {\n if (lowerStrikeLeg.Action === OrderAction.Buy) {\n orderActionValue = OrderAction.Sell;\n } else {\n orderActionValue = OrderAction.Buy;\n }\n }\n }\n\n if (isCustomStrategy && isCallCondorMatch) {\n // for a call condor the order is considered a buy if you are buying the lower strike and higher strike and selling the middle strike\n // find the leg with the lower strike\n const lowerStrikeLeg = _.minBy(Object.values(legs), l => l.Strike);\n if (lowerStrikeLeg) {\n if (lowerStrikeLeg.Action === OrderAction.Buy) {\n orderActionValue = OrderAction.Buy;\n } else {\n orderActionValue = OrderAction.Sell;\n }\n }\n }\n\n if (isCustomStrategy && isPutCondorMatch) {\n // for a put condor the order is considered a buy if you are selling the lower strike and higher strike and buying the middle strike\n // find the leg with the lower strike\n const lowerStrikeLeg = _.minBy(Object.values(legs), l => l.Strike);\n if (lowerStrikeLeg) {\n if (lowerStrikeLeg.Action === OrderAction.Buy) {\n orderActionValue = OrderAction.Buy;\n } else {\n orderActionValue = OrderAction.Sell;\n }\n }\n }\n\n const orderLegPrices = getOrderLegPrices({\n legs,\n quotes: quotes,\n orderType,\n orderAction: orderActionValue,\n strategy,\n });\n let marginCost = 0;\n\n if (strategy !== undefined && strategy !== 'Custom' && getKnownStrategy(strategy)) {\n const tradingStrategy = getKnownStrategy(strategy);\n if (tradingStrategy && tradingStrategy.profile.MarginRequirements) {\n //TODO: When upgrading typescript then can simplify type check into if statement\n const marginCostFormula = tradingStrategy.profile.MarginRequirements[orderAction];\n\n if (marginCostFormula && Object.values(legs).length > 0 && quotes.length > 0) {\n //TODO: Need to think if 0 is really correct here for price if pice is not set...\n marginCost = marginCostFormula(legs, quotes, isLimitOrder, price ? price : 0, isIRA);\n }\n }\n }\n\n if (strategy !== undefined && strategy === 'Custom' && match && match.profile && match.profile.MarginRequirements) {\n const actionValue = isBuy ? OrderAction.Buy : OrderAction.Sell;\n const tradingStrategy = getKnownStrategy(match.info.Name);\n if (tradingStrategy && tradingStrategy.profile.MarginRequirements) {\n const marginCostFormula = tradingStrategy.profile.MarginRequirements[actionValue];\n\n if (marginCostFormula && Object.values(legs).length > 0 && quotes.length > 0) {\n marginCost = marginCostFormula(legs, quotes, isLimitOrder, price ? price : 0, isIRA);\n }\n }\n }\n\n if (orderLegPrices === undefined) {\n return {\n bid: 0,\n ask: 0,\n mid: 0,\n totalMultiple: 0,\n gcd: 0,\n marginCost: 0,\n };\n }\n const { bid, ask, mid, ...marketPrices } = orderLegPrices;\n return {\n ...marketPrices,\n mid,\n ask,\n bid,\n marginCost,\n };\n};\n\nexport const useOrderPrice = (isBuy?: boolean): OrderPriceData & { includesAllSymbols: boolean } => {\n const blockId = useBlockId();\n const orderSymbols = useOrderBlockData(OrderSymbolListValues);\n const quotes = useOrderData((s: OrderState) => getOrderQuotes(s, blockId));\n const uniqueQuoteSymbols = _.uniq(quotes.map(q => q.Symbol));\n const includesAllSymbols = areArraysEqual(uniqueQuoteSymbols, orderSymbols);\n const { bid, ask, mid, totalMultiple, gcd, marginCost } = useOrderPriceRawValues(quotes, isBuy);\n return { bid, ask, mid, totalMultiple, includesAllSymbols, gcd, marginCost };\n};\n\nexport const useOrderPriceValue = (field: keyof ReturnType) => {\n const quotes = useQuoteBidAskMetadata();\n useWhyDidYouUpdate('useOrderPriceValue', { field, quotes });\n const value = useOrderPriceRawValues(quotes)[field];\n return useMemo(() => value, [value]);\n};\n// export const useSymbolBidAsk = (occSymbol: string) => {\n// const quote = useStateSelector(s => getQuoteMetadata(s, occSymbol || ''));\n// const symbolQuote = useMemo(() => (quote ? { bid: quote.BidPrice, ask: quote.AskPrice } : { bid: undefined, ask: undefined }), [quote]);\n// return symbolQuote;\n// };\n","import { useCallback, useMemo } from 'react';\nimport _ from 'lodash';\nimport { getType } from 'typesafe-actions';\nimport {\n AssetSymbol,\n SaveOptions,\n Legs,\n OrderLegDTO,\n TradingStrategyOrCustom,\n OrderAction,\n TradingStrategy,\n OptionType,\n PositionInfo,\n DebitOrCredit,\n BlockGroupOrderInfo,\n AssetSymbolInfo,\n Expiration,\n Order,\n OrderLeg,\n} from '@tradingblock/types';\nimport { useDispatcher } from '../../../data/global/hooks';\nimport { useOrderBlockSettings } from '../hooks/useOrderSettings';\nimport { useBlockState, useBlockActionDispatchAndGenericActions } from '../../../components/blocks/BlockState';\nimport { DefaultLegs, useOrderDebug } from '../OrderUtilities';\nimport { OrderState, useOrderData } from './OrderState';\nimport { OrderActions, Actions } from './OrderActions';\nimport { useOrderSymbol } from './useOrderState';\nimport { useGroupAssetSymbol } from '../../useGroupState';\nimport { useOrderPrice } from '../hooks/useOrderPrice';\n\nexport function useOrderActions() {\n const log = useOrderDebug('useOrderSymbolData');\n // const assetSymbol = useOrderData(s => s.symbol);\n const assetSymbol = useGroupAssetSymbol();\n const symbol = useOrderSymbol();\n const { dispatcher } = useDispatcher();\n const blockId = useBlockState('blockId');\n const settings = useOrderBlockSettings(blockId);\n const legs = useOrderData((s: OrderState) => s.legs || {});\n\n const { mid } = useOrderPrice();\n\n // const action = useOrderData((s: OrderState) => s.action);\n const [{ updateData, setField }, dispatch] = useBlockActionDispatchAndGenericActions();\n const clearOrder = useCallback(() => {\n return dispatch(Actions.clear({ options: { persist: true } }, { persist: true }));\n }, [dispatch]);\n const setStrike = useCallback(\n (legId: string, strike: number) => {\n return dispatch(Actions.setStrike({ legId, strike, options: { persist: true } }, { persist: true }));\n },\n [dispatch]\n );\n const setSymbol = useCallback(\n (symbol?: AssetSymbol, defaultToEmptyCustomIfSymbolChanges?: boolean, options?: SaveOptions) => {\n return dispatch(\n Actions.setSymbol(\n { symbol, options: { defaultToEmptyCustomIfSymbolChanges, settings } },\n options || { persist: true }\n )\n );\n },\n [dispatch, settings]\n );\n // const addOrderLeg = useCallback(\n // (leg: GroupOrderLeg, strategy: TradingStrategyOrCustom) => {\n // const strat: TradingStrategyNameOrCustom = strategy.info.Name;\n // return dispatch(Actions.addOrderLeg({ leg, strategy: strat }, { persist: true }));\n // },\n // [dispatch]\n // );\n\n const handleOrderGroupChange = useCallback(\n (symbol: AssetSymbol, orderInfo: BlockGroupOrderInfo) => {\n return dispatch(Actions.handleOrderGroupChange({ ...orderInfo, symbol, options: { persist: true }, settings }));\n },\n [dispatch, settings]\n );\n const setLegAction = useCallback(\n (legId: string, action?: OrderAction, options?: SaveOptions) => {\n return dispatch(Actions.setLegAction({ legId, action, options }, { persist: true }));\n },\n [dispatch]\n );\n const setExpiration = useCallback(\n (legId: string, expiration?: Expiration) => {\n return dispatch(Actions.setExpiration({ legId, expiration }, { persist: true }));\n },\n [dispatch]\n );\n const setOptionType = useCallback(\n (legId: string, optionType: OptionType) => {\n return dispatch(Actions.setOptionType({ legId, optionType }, { persist: true }));\n },\n [dispatch]\n );\n const setLegQuantity = useCallback(\n (legId: string, quantity: number) => {\n return dispatch(Actions.setLegQuantity({ legId, quantity }, { persist: true }));\n },\n [dispatch]\n );\n const setIsDirty = useCallback(\n (dirty: boolean) => {\n updateData({ isDirty: dirty });\n },\n [updateData]\n );\n const setOrderAction = useCallback(\n (action: OrderAction) => {\n return dispatch(Actions.setOrderAction({ action }, { persist: true }));\n },\n [dispatch]\n );\n const updateStateData = useMemo(\n () => (value: Partial, options?: SaveOptions | undefined) => {\n log('updateState %o', value);\n return updateData({ ...value }, options);\n },\n [updateData, log]\n );\n\n const setStrategy = useCallback(\n (\n strat: TradingStrategyOrCustom,\n options?: SaveOptions & { action?: OrderAction; reverseLegs?: boolean; isDirty?: boolean }\n ) => {\n const { action, reverseLegs, isDirty } = options || {\n action: undefined,\n reverseLegs: undefined,\n isDirty: undefined,\n };\n // allow missing symbol for 'Custom' strategy\n if (assetSymbol || strat.info.Name === 'Custom') {\n dispatch(\n Actions.setStrategy(\n { action, reverseLegs, isDirty, strategy: strat, symbol: assetSymbol, settings },\n { persist: true }\n )\n );\n } else {\n console.error('asset symbol is empty!');\n }\n dispatch({ type: getType(Actions.setPrice), payload: { price: undefined, updateCreditOrDebit: true, mid: mid } });\n dispatch({ type: getType(Actions.setStopPrice), payload: { price: undefined, updateCreditOrDebit: false } });\n },\n [assetSymbol, dispatch, settings] // , updateStateData, symbol, legs\n );\n const setMatchingStrategies = useCallback(\n (strat: TradingStrategy[], options?: SaveOptions) => {\n if (symbol) {\n updateStateData({ matchingStrategy: strat }, options);\n }\n },\n [updateStateData, symbol]\n );\n const setAction = useCallback(\n (actionVal: OrderAction, options?: SaveOptions) => {\n const updatedLegs: Legs = _.reduce(\n legs,\n (acc: Legs, val: OrderLegDTO, key: string): Legs => ({\n ...acc,\n [val.Id || key]: { ...val, Action: val.Action === OrderAction.Buy ? OrderAction.Sell : OrderAction.Buy },\n }),\n {}\n );\n updateStateData({ action: actionVal, legs: updatedLegs }, options);\n },\n [updateStateData, legs]\n );\n const startValidation = useCallback(\n (strategy?: TradingStrategy) => {\n dispatch({ type: 'startValidation', payload: { strategy } });\n },\n [dispatch]\n );\n const setPositionInfo = useCallback((info: PositionInfo) => dispatch(Actions.setPositionInfo({ info })), [dispatch]);\n\n const changeSymbol = useCallback(\n (symbol: AssetSymbolInfo, symbolValue: AssetSymbol, options?: SaveOptions, symbolMismatch?: boolean) => {\n const baseLegs = _.keys(legs).length > 0 ? legs : DefaultLegs({}, symbol);\n\n dispatcher.block.setQuoteSubscription(blockId, [symbolValue.symbol]);\n\n const updatedData = {\n price: undefined,\n symbol: symbolValue,\n legs: !symbolMismatch\n ? _.reduce(\n baseLegs,\n (acc: Legs, leg: OrderLegDTO, id: string) => {\n return {\n ...acc,\n [id]: {\n ...leg,\n SymbolName: symbolValue.symbol,\n Symbol: symbolValue.symbol,\n UnderlyingSymbol: symbolValue.symbol,\n },\n };\n },\n {}\n )\n : {},\n };\n updateStateData(updatedData, options);\n },\n [blockId, legs, updateStateData, dispatcher]\n );\n const updateField: typeof setField = useCallback(\n (field: K, value: OrderState[K], options?: SaveOptions) =>\n setField(field, value, options),\n [setField]\n );\n const setQuantity = useCallback(\n (quantity: number, options?: SaveOptions) => {\n return dispatch(Actions.setQuantity({ quantity }, { persist: true }));\n },\n [dispatch]\n );\n const orderPlaced = useCallback(() => dispatch({ type: getType(Actions.orderPlaced), payload: {} }), [dispatch]);\n const setPrice = useCallback(\n (price: number | undefined, updateCreditOrDebit: boolean, negativePrice?: boolean) =>\n dispatch({ type: getType(Actions.setPrice), payload: { price, updateCreditOrDebit, negativePrice } }),\n [dispatch]\n );\n const setStopPrice = useCallback(\n (price?: number) => dispatch({ type: getType(Actions.setStopPrice), payload: { price } }),\n [dispatch]\n );\n const setDebitCredit = useCallback(\n (debitCredit?: DebitOrCredit) => dispatch(Actions.setDebitCredit({ debitCredit }, { persist: true })),\n [dispatch]\n );\n\n const removeQuote = useCallback((key: string) => dispatch({ type: getType(Actions.removeQuote), payload: key }), [\n dispatch,\n ]);\n\n const setSubaccountId = useCallback((subAccountId) => {\n dispatch(Actions.setSubaccountId({ subaccountId: subAccountId }));\n }, [dispatch])\n\n const setOrder = useCallback((order: Order) => {\n dispatch(Actions.setOrder({ order }));\n }, [dispatch]);\n\n return {\n handleOrderGroupChange,\n removeQuote,\n setDebitCredit,\n setSubaccountId,\n setPrice,\n setStopPrice,\n orderPlaced,\n setQuantity,\n setPositionInfo,\n setOrderAction,\n clearOrder,\n startValidation,\n setSymbol,\n setOptionType,\n setLegQuantity,\n setExpiration,\n setStrike,\n setStrategy,\n updateField,\n setAction,\n changeSymbol,\n setIsDirty,\n setMatchingStrategies,\n setLegAction,\n setOrder,\n };\n}\n","import createCachedSelector from 're-reselect';\nimport { DataState } from '../state';\nimport _ from 'lodash';\n\nexport const IsWarningSymbol = createCachedSelector(\n (s: DataState, underlyingSymbol?: string) => s.symbols.warningSymbols,\n (s: DataState, underlyingSymbol?: string) => underlyingSymbol,\n (warningSymbols, symbol) => {\n if (symbol === undefined) {\n return false;\n }\n if (!warningSymbols) {\n return false;\n }\n return warningSymbols.map(s => s.toLocaleLowerCase()).find(s => s === symbol.toLocaleLowerCase()) ? true : false;\n }\n)((s, underlyingSymbol) => underlyingSymbol || 'UNKNOWN');\n","import useAudio from 'react-use/lib/useAudio';\n\nexport const audioSrc = {\n success: require('../assets/sounds/ok.mp3'),\n error: require('../assets/sounds/error.mp3'),\n updates: require('../assets/sounds/updates.mp3'),\n};\n\nexport const useSounds = () => {\n const [successAudio, , successControls] = useAudio({\n src: audioSrc.success,\n });\n const [errorAudio, , errorControls] = useAudio({\n src: audioSrc.error,\n });\n return {\n successAudio,\n successControls,\n errorAudio,\n errorControls,\n };\n};\n","import { useMemo } from 'react';\nimport _ from 'lodash';\nimport { OrderType, OrderAction, TradingStrategyNameOrCustom, DebitOrCredit, AssetType } from '@tradingblock/types';\nimport { useOrderDataSelector } from '../state/OrderState';\nimport { useOrderPrice } from './useOrderPrice';\n\nconst calculateStrategyTotal = (\n isLimitOrder: boolean,\n orderType: OrderType,\n orderAction: OrderAction,\n ask: number,\n bid: number,\n quantity: number,\n totalMultiple: number,\n gcd: number,\n limitPrice: number | undefined,\n stopPrice: number | undefined,\n strategy: TradingStrategyNameOrCustom | undefined,\n debitOrCredit: DebitOrCredit,\n isBuy: boolean | undefined\n) => {\n let orderPrice: number | undefined = 0;\n let execDebitOrCredit: DebitOrCredit | undefined = undefined;\n\n if (orderType === OrderType.Stop_Market) {\n orderPrice = stopPrice;\n } else if (orderType === OrderType.Stop_Limit) {\n orderPrice = limitPrice;\n } else if (isLimitOrder && limitPrice !== undefined) {\n if (isBuy || isBuy === undefined) {\n if (debitOrCredit === DebitOrCredit.Debit) {\n orderPrice = Math.min(ask, limitPrice);\n } else {\n orderPrice = Math.min(ask, -limitPrice);\n }\n if (orderPrice >= 0.0) {\n execDebitOrCredit = DebitOrCredit.Debit;\n } else {\n execDebitOrCredit = DebitOrCredit.Credit;\n }\n } else {\n if (debitOrCredit === DebitOrCredit.Credit) {\n orderPrice = Math.max(bid, limitPrice);\n } else {\n orderPrice = Math.max(bid, -limitPrice);\n }\n if (orderPrice >= 0.0) {\n execDebitOrCredit = DebitOrCredit.Credit;\n } else {\n execDebitOrCredit = DebitOrCredit.Debit;\n }\n }\n } else if (isLimitOrder) {\n orderPrice = undefined;\n } else {\n orderPrice = isBuy ? ask : bid;\n }\n\n const total = orderPrice && _.isFinite(orderPrice) ? quantity * orderPrice * totalMultiple * gcd : 0;\n return {\n total: Math.abs(total),\n execDebitOrCredit,\n };\n};\n\nexport const useOrderTotal = () => {\n const orderAction = useOrderDataSelector(s => s.action);\n const orderType = useOrderDataSelector(s => s.orderType);\n const isLimitOrder = useOrderDataSelector(s => s.orderType === OrderType.Limit);\n const strategy = useOrderDataSelector(s => s.strategy);\n const match = useOrderDataSelector(s => s.validation && s.validation.match);\n const legs = useOrderDataSelector(s => s.legs);\n const isCustom = strategy === 'Custom';\n const isMatchCalendarStrategy =\n isCustom && match && (match.info.Name === 'Call Calendar' || match.info.Name === 'Put Calendar');\n const isCallVerticalMatch = isCustom && match && match.info.Name === 'Call Vertical';\n const isPutVerticalMatch = isCustom && match && match.info.Name === 'Put Vertical';\n const isCoveredCallMatch = isCustom && match && match.info.Name === 'Covered Call';\n const isCallButterflyMatch = match && match.info.Name === 'Call Butterfly';\n const isPutButterflyMatch = match && match.info.Name === 'Put Butterfly';\n const isIronButterflyMatch = match && match.info.Name === 'Iron Butterfly';\n const isIronCondorMatch = match && match.info.Name === 'Iron Condor';\n const isCallCondorMatch = match && match.info.Name === 'Call Condor';\n const isPutCondorMatch = match && match.info.Name === 'Put Condor';\n\n const latestExpiringOptionLeg = useMemo(() => {\n if (isMatchCalendarStrategy && legs) {\n return _.maxBy(Object.values(legs), l => l.Expiration && l.Expiration.date);\n }\n return undefined;\n }, [isMatchCalendarStrategy, legs]);\n\n const lowerStrikeLeg = useMemo(() => {\n if (\n (isCallVerticalMatch ||\n isPutVerticalMatch ||\n isCallButterflyMatch ||\n isPutButterflyMatch ||\n isIronButterflyMatch ||\n isIronCondorMatch ||\n isCallCondorMatch ||\n isPutCondorMatch) &&\n legs\n ) {\n return _.minBy(Object.values(legs), l => l.Strike);\n }\n return undefined;\n }, [\n isCallVerticalMatch,\n isPutVerticalMatch,\n isCallButterflyMatch,\n isPutButterflyMatch,\n isIronButterflyMatch,\n isIronCondorMatch,\n isCallCondorMatch,\n isPutCondorMatch,\n legs,\n ]);\n\n const shareLeg = useMemo(() => {\n if (isCoveredCallMatch && legs) {\n return _.find(Object.values(legs), l => l.AssetType === AssetType.Equity);\n }\n return undefined;\n }, [isCoveredCallMatch, legs]);\n const { quantity, debitCredit, price, stopPrice } = useOrderDataSelector(s => ({\n price: s.price,\n stopPrice: s.stopPrice,\n quantity: _.isFinite(s.quantity) ? s.quantity : 1,\n debitCredit: s.debitCredit,\n }));\n const isBuy = useMemo(() => {\n return !isCustom\n ? orderAction === OrderAction.Buy\n : isMatchCalendarStrategy\n ? orderAction === OrderAction.Buy\n : isCallVerticalMatch\n ? lowerStrikeLeg && lowerStrikeLeg.Action === OrderAction.Buy\n : isPutVerticalMatch\n ? lowerStrikeLeg && lowerStrikeLeg.Action === OrderAction.Sell\n : isCoveredCallMatch\n ? shareLeg && shareLeg.Action === OrderAction.Buy\n : isCallButterflyMatch\n ? lowerStrikeLeg && lowerStrikeLeg.Action === OrderAction.Buy\n : isPutButterflyMatch\n ? lowerStrikeLeg && lowerStrikeLeg.Action === OrderAction.Buy\n : isIronButterflyMatch\n ? lowerStrikeLeg && lowerStrikeLeg.Action === OrderAction.Buy\n : isIronCondorMatch\n ? lowerStrikeLeg && lowerStrikeLeg.Action === OrderAction.Sell\n : isCallCondorMatch\n ? lowerStrikeLeg && lowerStrikeLeg.Action === OrderAction.Buy\n : isPutCondorMatch\n ? lowerStrikeLeg && lowerStrikeLeg.Action === OrderAction.Buy\n : _.every(legs, l => l.Action === OrderAction.Buy) || _.some(legs, l => l.Action === OrderAction.Buy);\n }, [\n isCustom,\n orderAction,\n latestExpiringOptionLeg,\n lowerStrikeLeg,\n shareLeg,\n legs,\n isCallVerticalMatch,\n isPutVerticalMatch,\n isCoveredCallMatch,\n isCallButterflyMatch,\n isPutButterflyMatch,\n isIronButterflyMatch,\n isIronCondorMatch,\n ]);\n\n const { ask, bid, totalMultiple, gcd, marginCost } = useOrderPrice(isBuy);\n\n return useMemo(() => {\n const totalResults = calculateStrategyTotal(\n isLimitOrder,\n orderType,\n orderAction,\n ask,\n bid,\n quantity,\n totalMultiple,\n gcd,\n price !== undefined ? Math.abs(price) : price,\n stopPrice !== undefined ? Math.abs(stopPrice) : stopPrice,\n strategy,\n debitCredit === undefined ? DebitOrCredit.Debit : debitCredit,\n isBuy\n );\n\n return { ...totalResults, debitCredit, marginCost: marginCost * quantity * totalMultiple * gcd };\n }, [\n isLimitOrder,\n orderAction,\n ask,\n bid,\n quantity,\n totalMultiple,\n gcd,\n price,\n isCustom,\n debitCredit,\n stopPrice,\n isBuy,\n legs,\n strategy,\n ]);\n};\n","import { useState, useCallback, useMemo, useEffect } from 'react';\r\nimport _ from 'lodash';\r\nimport constate from 'constate';\r\nimport useAudio from 'react-use/lib/useAudio';\r\nimport {\r\n TradingblockOrder,\r\n DebitOrCredit,\r\n Order,\r\n OrderLeg,\r\n OrderClass,\r\n OrderType,\r\n Durations,\r\n UserLevelTypes,\r\n UserProfileLevel,\r\n OrderStrategyType,\r\n AssetType,\r\n} from '@tradingblock/types';\r\nimport { orderToReplaceOrder } from '@tradingblock/api';\r\nimport { useOrderActions } from '../../state/useOrderActions';\r\nimport { useStateSelector } from '../../../../data/global/dataSelectors';\r\nimport { IsWarningSymbol } from '../../../../data/global/selectors/symbolSelector';\r\nimport { useDispatcher } from '../../../../data/global/hooks';\r\nimport { OrderActions } from '../../../../data/global/actions';\r\nimport { useOrderSettings } from '../../hooks/useOrderSettings';\r\nimport { useSounds } from '../../../../hooks/useSounds';\r\nimport { useOrderTotal } from '../../hooks/useOrderTotal';\r\nimport { PreviewResult } from './PreviewPopup';\r\nimport { legToDto } from '../../OrderUtilities';\r\nimport { useDashboardSettings } from '../../../../hooks/useDashboardSettings';\r\nimport { OrderState, useOrderBlockData } from '../../state/OrderState';\r\nimport { OrderSelectors } from '../../state/OrderSelector';\r\nimport { set } from 'numeral';\r\nimport { useBlockActions, useBlockId } from '../../../../components/blocks/BlockState';\r\n\r\nexport type PreviewActions = 'execute' | 'replace' | 'error';\r\n\r\nexport const useOrderPreview = () => {\r\n const [isPreview, setIsPreview] = useState(false);\r\n\r\n const { successControls, errorControls, successAudio, errorAudio } = useSounds();\r\n const { disableSounds } = useOrderSettings();\r\n const { orderPlaced } = useOrderActions();\r\n const { muteAllSounds } = useDashboardSettings();\r\n const togglePreview = useCallback(() => setIsPreview(!isPreview), [isPreview]);\r\n\r\n const previewClosed = useCallback(\r\n (result: PreviewResult) => {\r\n setIsPreview(false);\r\n if (disableSounds !== true && result.action === 'order-placed') {\r\n !muteAllSounds &&\r\n (() => {\r\n const play = successControls.play();\r\n if (play !== undefined) {\r\n play.catch(() => {\r\n // Do nothing\r\n //TODO: Determine if we want to warn the user that the sound failed to play\r\n });\r\n }\r\n })();\r\n orderPlaced();\r\n } else if (disableSounds !== true && result.action === 'error') {\r\n !muteAllSounds &&\r\n (() => {\r\n const play = errorControls.play();\r\n if (play !== undefined) {\r\n play.catch(() => {\r\n // Do nothing\r\n //TODO: Determine if we want to warn the user that the sound failed to play\r\n });\r\n }\r\n })();\r\n } else {\r\n //do nothing if popup is just closed\r\n }\r\n },\r\n [setIsPreview, successControls, errorControls, disableSounds]\r\n );\r\n\r\n return useMemo(() => ({ isPreview, togglePreview, previewClosed, audio: { successAudio, errorAudio } }), [\r\n isPreview,\r\n togglePreview,\r\n previewClosed,\r\n successAudio,\r\n errorAudio,\r\n ]);\r\n};\r\n\r\nexport const getOrderPreviewLegs = (order: TradingblockOrder | Order) => {\r\n const hasMultipleLegs = order.Legs && order.Legs.length > 1;\r\n\r\n return _(order.Legs)\r\n .filter(l => {\r\n if (_.isNil(l.Symbol)) {\r\n return false;\r\n }\r\n if (hasMultipleLegs) {\r\n return l.Symbol && l.SpreadRatio ? true : false;\r\n } else if (l.Symbol) {\r\n return true;\r\n }\r\n return false;\r\n })\r\n .map(legToDto)\r\n .value();\r\n};\r\n\r\nconst adjustOrderQuantitiesAndRatios = (order: Order) => {\r\n if (!order) {\r\n return [0, []];\r\n }\r\n // function to find greatest common divisor\r\n const gcd = (a: number, b: number): number => {\r\n return b === 0 ? a : gcd(b, a % b);\r\n };\r\n\r\n // function to find highest common factor\r\n const findHCF = (arr: number[]): number => {\r\n return arr.reduce((a, b) => gcd(a, b));\r\n };\r\n\r\n const hcf = findHCF(order.Legs.map(l => l.SpreadRatio || 1));\r\n\r\n const adjustedOverallQuantity = order.Quantity * hcf;\r\n\r\n const adjustedRatios = order.Legs.map(l => {\r\n const ratio = l.SpreadRatio || 1;\r\n const adjustedRatio = ratio / hcf;\r\n return {\r\n ...l,\r\n SpreadRatio: adjustedRatio,\r\n Quantity: adjustedOverallQuantity * adjustedRatio,\r\n };\r\n });\r\n\r\n return [adjustedOverallQuantity, adjustedRatios];\r\n};\r\n\r\nfunction finalizeOrder(\r\n order: T,\r\n accountId?: number,\r\n debitOrCredit?: DebitOrCredit,\r\n subaccountId?: number\r\n): T {\r\n // determine the strategy of the order\r\n const isCustom = order.StrategyType === 'Undefined';\r\n // determine if all legs are option legs\r\n const allOptionLegs = order.Legs.every(l => l.AssetType === AssetType.Option);\r\n if (isCustom && allOptionLegs && order && order.Legs && order.Legs.length > 1) {\r\n const [adjustedOverallQuantity, adjustedRatios] = adjustOrderQuantitiesAndRatios(order);\r\n\r\n return {\r\n ...order,\r\n AccountId: accountId,\r\n DebitCredit: debitOrCredit,\r\n SubaccountId: subaccountId,\r\n Quantity: adjustedOverallQuantity,\r\n Legs: adjustedRatios,\r\n };\r\n }\r\n\r\n return {\r\n ...order,\r\n AccountId: accountId,\r\n DebitCredit: debitOrCredit,\r\n SubaccountId: subaccountId,\r\n };\r\n}\r\n\r\nexport const useOrderPreviewOrder = (action: PreviewActions) => {\r\n const order = useOrderBlockData(OrderSelectors.order);\r\n const [initialPrice, setInitialPrice] = useState();\r\n const [orderId, setOrderId] = useState();\r\n const { setStopPrice, setPrice, setDebitCredit, setSubaccountId, setOrder: setOrderCallback } = useOrderActions();\r\n const accountId = useStateSelector(state => state.account.accountId);\r\n const profile = useStateSelector(state => state.account.profile);\r\n const userLevel = profile && profile.current && profile.current.level;\r\n const isAboveAccountLevel = userLevel && userLevel !== UserProfileLevel.Account;\r\n\r\n useEffect(() => {\r\n const orderPrice = order ? order.Price : undefined;\r\n const currId = order ? order.OrderId : undefined;\r\n if (order && (initialPrice === undefined || orderId !== currId) && orderPrice) {\r\n setInitialPrice(orderPrice);\r\n setOrderId(currId);\r\n }\r\n }, [order, initialPrice]);\r\n\r\n // const orderlegs = useOrderData(orderLegsSelector);\r\n const legs = useMemo(() => {\r\n if (order) {\r\n return getOrderPreviewLegs(order);\r\n }\r\n return [];\r\n }, [order]);\r\n\r\n const totalResults = useOrderTotal();\r\n const isWarningSymbol = useStateSelector(s => IsWarningSymbol(s, order ? order.UnderlyingSymbol : ''));\r\n\r\n const isTradingblockOrder = useMemo(() => {\r\n if (order) {\r\n return (order as TradingblockOrder).kind === 'order';\r\n }\r\n return false;\r\n }, [order]);\r\n\r\n const finalOrder = useMemo(() => {\r\n if (_.isNil(order)) {\r\n return undefined;\r\n }\r\n const debitOrCredit = order.DebitCredit || totalResults.debitCredit;\r\n // if the order strategy type contains vertical, calendar, butterfly, or condor we need to set the strategy type accordingly\r\n // currently the backend does not differentiate between call and put verticals/calendars/butterflies/condors so we need to do it here\r\n return finalizeOrder(\r\n {\r\n ...order,\r\n BypassWarnings: isWarningSymbol,\r\n StrategyType:\r\n order.StrategyType && _.includes(order.StrategyType, 'Vertical')\r\n ? OrderStrategyType.Vertical\r\n : order.StrategyType && _.includes(order.StrategyType, 'Calendar')\r\n ? OrderStrategyType.Calendar\r\n : order.StrategyType && order.StrategyType === OrderStrategyType.Call\r\n ? OrderStrategyType.Single\r\n : order.StrategyType && order.StrategyType === OrderStrategyType.Put\r\n ? OrderStrategyType.Single\r\n : order.StrategyType && _.includes(order.StrategyType, 'Butterfly')\r\n ? OrderStrategyType.Butterfly\r\n : order.StrategyType && _.includes(order.StrategyType, 'Condor')\r\n ? OrderStrategyType.Condor\r\n : order.StrategyType,\r\n },\r\n order.AccountId || accountId,\r\n debitOrCredit,\r\n order.SubaccountId\r\n );\r\n }, [order]);\r\n\r\n const changeSubaccountId = useCallback(\r\n (id?: number) => {\r\n if (order === undefined) {\r\n return;\r\n }\r\n setSubaccountId(id);\r\n },\r\n [setSubaccountId, order]\r\n );\r\n\r\n const changeLimitPrice = useCallback(\r\n (price: number | null) => {\r\n if (order === undefined) {\r\n return;\r\n }\r\n if (price !== null) {\r\n setPrice(price, false);\r\n }\r\n },\r\n [order]\r\n );\r\n\r\n const changeStopPrice = useCallback(\r\n (price: number | null) => {\r\n if (order === undefined) {\r\n return;\r\n }\r\n if (price !== null) {\r\n setStopPrice(price);\r\n }\r\n },\r\n [order]\r\n );\r\n\r\n const changeDebitCredit = useCallback(\r\n (val: DebitOrCredit | undefined) => {\r\n if (order === undefined) {\r\n return;\r\n }\r\n setDebitCredit(val);\r\n },\r\n [order]\r\n );\r\n\r\n const { dispatch } = useDispatcher();\r\n const onSave = useCallback(() => {\r\n if (finalOrder) {\r\n // If the user is an admin, representative, or advisor we can bypass warnings by default\r\n if (isAboveAccountLevel) {\r\n finalOrder.BypassWarnings = true;\r\n }\r\n // need to remove SpreadRatio from order leg of single legged orders prior to sending to the backend\r\n if (finalOrder.Legs && finalOrder.Legs.length === 1) {\r\n finalOrder.Legs[0].SpreadRatio = undefined;\r\n }\r\n if (action === 'execute' || action === undefined) {\r\n dispatch(OrderActions.requestPlaceOrder(finalOrder));\r\n } else if (action === 'replace') {\r\n dispatch(OrderActions.requestChange(orderToReplaceOrder(finalOrder)));\r\n }\r\n if (finalOrder.Price) {\r\n setInitialPrice(finalOrder.Price);\r\n }\r\n }\r\n }, [order, action, isWarningSymbol, totalResults, accountId, dispatch]);\r\n\r\n const setOrder = useCallback(\r\n (order: Order) => {\r\n setOrderCallback(order);\r\n },\r\n [order]\r\n );\r\n\r\n return {\r\n order,\r\n legs,\r\n action,\r\n initialPrice,\r\n isWarningSymbol,\r\n isTradingblockOrder,\r\n setOrder,\r\n changeSubaccountId,\r\n changeDebitCredit,\r\n changeLimitPrice,\r\n changeStopPrice,\r\n onSave,\r\n };\r\n};\r\n","import { createSelector } from 'reselect';\nimport createCachedSelector from 're-reselect';\nimport _ from 'lodash';\nimport { expirationValue } from '../../../utilities/date';\nimport { StrikeByExpirationSymbolMap, ExpirationStrike } from '../../../types';\nimport { DataState } from '../state';\nimport { Expiration } from '@tradingblock/types';\nexport const getExpirations = createCachedSelector(\n (state: DataState) => state.expirations,\n (_state: DataState, symbol: string) => symbol,\n (state, symbol) => {\n const symbolExp = state[symbol] || {\n isFetching: false,\n expirations: undefined,\n };\n return symbolExp;\n }\n)((_, symbol) => symbol);\nexport const ExpirationSelectors = {\n expirations: createCachedSelector(\n (state: DataState) => state.expirations,\n (_state: DataState, symbol: string) => symbol,\n (state, symbol) => {\n const symbolExp = state[symbol] || {\n isFetching: false,\n expirations: undefined,\n };\n return symbolExp.expirations ? symbolExp.expirations : undefined;\n }\n )((_, symbol) => symbol),\n isFetching: createCachedSelector(\n (state: DataState) => state.expirations,\n (_state: DataState, symbol: string) => symbol,\n (state, symbol) => {\n const symbolExp = state[symbol] || {\n isFetching: false,\n expirations: undefined,\n };\n return symbolExp.isFetching;\n }\n )((_, symbol) => symbol),\n};\nconst getStrikeState = (\n state: {\n [symbol: string]: StrikeByExpirationSymbolMap;\n },\n symbol: string,\n expiration: Expiration\n) => {\n const expKey = expirationValue(expiration);\n const symbolState = state[symbol] || {};\n return symbolState[expKey] || { isFetching: false, strikes: undefined, symbol, expiration };\n};\n\nexport const StrikeSelectors = {\n expirationsBySymbol: createSelector(\n (state: DataState) => state,\n (_state: DataState, symbol: string) => symbol,\n (state: DataState, symbol: string) => {\n const symbolStrikes: ExpirationStrike[] =\n state.strikes && state.strikes[symbol] ? _.values(state.strikes[symbol]) : [];\n return _.map(symbolStrikes, ss => ss.expiration);\n }\n ),\n strikesBySymbol: createCachedSelector(\n (state: DataState) => state.strikes,\n (_state: DataState, symbol: string) => symbol,\n (state: { [symbol: string]: StrikeByExpirationSymbolMap }, symbol: string): ExpirationStrike[] => {\n const symbolStrikes: ExpirationStrike[] = state && state[symbol] ? _.values(state[symbol]) : [];\n return symbolStrikes;\n }\n )((_, symbol) => symbol),\n strikes: createCachedSelector(\n (state: DataState) => state.strikes,\n (_state: DataState, symbolExp: { symbol: string; expiration: Expiration }) => symbolExp,\n (state, symbolExp) => {\n const { expiration, symbol } = symbolExp;\n return getStrikeState(state, symbol, expiration).strikes;\n }\n )((_, { symbol, expiration }) => `${symbol}-${expirationValue(expiration)}`),\n isFetching: createCachedSelector(\n (state: DataState) => state.strikes,\n (_state: DataState, symbolExp: { symbol: string; expiration: Expiration }) => symbolExp,\n (state, symbolExp) => {\n const { expiration, symbol } = symbolExp;\n return getStrikeState(state, symbol, expiration).isFetching;\n }\n )((_, { symbol, expiration }) => `${symbol}-${expirationValue(expiration)}`),\n anyFetching: createCachedSelector(\n (state: DataState) => state.strikes,\n (state: DataState, symbol: string) => symbol,\n (\n strState: {\n [symbol: string]: StrikeByExpirationSymbolMap;\n },\n symbol: string\n ) => {\n const strikeValues = strState[symbol] || {};\n return _.some(strikeValues, (v, k) => v.isFetching === true);\n }\n )((_, symbol) => symbol),\n};\n","import { useOrderData } from '../state/OrderState';\nimport { OrderSelectors } from '../state/OrderSelector';\nimport { useOrderSymbol } from '../state/useOrderState';\nimport { useStateSelector } from '../../../data/global/dataSelectors';\nimport { ExpirationSelectors, StrikeSelectors } from '../../../data/global/selectors/expirationStrikeSelector';\nimport { DataState } from '../../../data/global/state';\n\nexport const useOrderStatus = () => {\n const isComplete = useOrderData(OrderSelectors.isComplete);\n const symbol = useOrderSymbol();\n const areFetchingExpirations = useStateSelector(state => ExpirationSelectors.isFetching(state, symbol || ''));\n const areStrikesFetching = useStateSelector((state: DataState) => StrikeSelectors.anyFetching(state, symbol || ''));\n const isLoading = areStrikesFetching || areFetchingExpirations;\n return {\n complete: isComplete,\n loading: isLoading,\n };\n};\n","import React, { useEffect, useRef, useState } from 'react';\nimport InputNumber, { InputNumberProps } from 'rc-input-number';\nimport { useOrderData } from '../state/OrderState';\nimport { useOrderStatus } from '../data/useOrderStatus';\n\nexport interface DEPRECATED_PriceComponentProps\n extends Omit, 'formatter' | 'parser' | 'precision' | 'step'> {\n isCustomStrategyOrCalendar?: boolean;\n}\n\nexport function DEPRECATED_PriceComponent({ isCustomStrategyOrCalendar, ...props }: PriceComponentProps) {\n const priceInputNumberRef = useRef(null);\n\n // Odd hack, but basically InputNumber takes control over the input, and does not listen to reference updates as it\n // Alters it according to the source code. The issue is that when we clear the value, it does not update the input\n // So we have to manually update the input when the value changes\n useEffect(() => {\n if (priceInputNumberRef.current && props.value === undefined) {\n priceInputNumberRef.current.value = '';\n }\n }, [priceInputNumberRef, props.value]);\n\n const { price } = useOrderData(s => ({ price: s.price }));\n\n return (\n
\n = 0 ? 0.01 : -0.01) : 0.01}\n formatter={(value: number | string | undefined, { userTyping, input }): string | undefined | null => {\n // Handle value and input slippage when the user is entering a value and the input is slipping behind\n if (value === '' && (input === '' || input === '$' || input === '0')) {\n return '';\n }\n\n // Handles when the user is typing and the input is slipping behind on deletion\n if (value === '' && userTyping !== true) {\n if (input === '$0.01') {\n return '$0.00';\n }\n return '';\n }\n\n // Handle when the user is entering input as it can be handled different\n if (userTyping) {\n // If the user is typing, return the value with a dollar sign and 2 decimal places\n return `${input !== '' &&\n input !== '$' &&\n input !== '.' &&\n input !== '0.' &&\n input !== '0' &&\n input !== '$0.00' &&\n input !== '-'\n ? input\n : value !== '0' && value !== ''\n ? isCustomStrategyOrCalendar // if isCustomStrategyOrCalendar is true, we allow negative\n ? typeof value === 'number'\n ? value\n : parseFloat(value === undefined || value === '' ? '0' : value)\n : Math.abs(\n typeof value === 'number' ? value : parseFloat(value === undefined || value === '' ? '0' : value)\n )\n : '$0.00'\n }`;\n }\n\n // If the user is not inputting anything\n if (value === undefined) {\n return '';\n }\n // Output the value of the value passed in with a dollar sign and 2 decimal places and removes ending two 00 if they exist on 4th decimal place\n // log the output prior to returning to see what is being returned\n return `$${Math.abs(typeof value === 'number' ? value : parseFloat(value === '' ? '0' : value))\n .toFixed(4)\n .replace(/(\\.\\d{2})(0*)$/, '$1')}`;\n }}\n parser={(displayValue: string | undefined): number => {\n return displayValue ? Number(displayValue.replace(/[$\\s,]/g, '')) : 0;\n }}\n {...props}\n />\n
\n );\n}\n\n\n/**\n * Props for the PriceComponent.\n * @typedef {Object} PriceComponentProps\n * @property {string} [placeholder] - The placeholder text for the input field.\n * @property {(value: number | null) => void} onChange - Callback function that is called when the input value changes.\n * @property {boolean} [isCustomStrategyOrCalendar] - Flag indicating if custom strategy or calendar logic is applied.\n * @property {boolean} [disabled] - Flag indicating if the input should be disabled.\n * @property {number | null} [value] - The initial value of the input.\n */\nexport interface PriceComponentProps {\n placeholder?: string;\n onChange: (value: number | null) => void;\n isCustomStrategyOrCalendar?: boolean;\n disabled?: boolean;\n value?: number | null;\n}\n\n/**\n * A component for inputting price values.\n * @param {PriceComponentProps} props - The props for the component.\n */\nexport default function PriceComponent({\n placeholder,\n isCustomStrategyOrCalendar,\n onChange: valueFinalized,\n disabled,\n value,\n}: PriceComponentProps) {\n const [displayValue, setDisplayValue] = useState('');\n const [priceValue, setPriceValue] = useState(value || 0);\n const priceInputNumberRef = useRef(null);\n const { complete } = useOrderStatus();\n\n // When the value prop changes, format it and update state.\n useEffect(() => {\n if (value === null) {\n setDisplayValue('$0.00'); // Clear display if value is null or undefined\n setPriceValue(0);\n valueFinalized(0)\n } else if (value === undefined) {\n setDisplayValue(''); // Clear display if value is null or undefined\n setPriceValue(0);\n } else {\n // Format value for display, removing trailing \"00\" if present\n let formattedDisplayValue = `$${Math.abs(value).toFixed(4)}`;\n if (formattedDisplayValue.endsWith(\"00\")) {\n formattedDisplayValue = formattedDisplayValue.slice(0, -2);\n }\n setDisplayValue(formattedDisplayValue);\n setPriceValue(value); // Store the actual numeric value\n }\n }, [value]);\n\n /**\n * Handle input change events.\n * @param {React.ChangeEvent} e - The change event.\n */\n const onInputChanged = (e: React.ChangeEvent) => {\n const inputValue = e.target.value;\n // Define regex based on whether custom strategy or calendar is enabled\n const regex = new RegExp(/^\\$?\\d*(\\.\\d{0,4})?$/);\n \n // Check for multiple leading zeros and replace them with a single zero\n let sanitizedInputValue = inputValue.replace(/^\\$?0+/, (match) => match === '$0' || match === '$00' ? '$0' : '0');\n\n if (sanitizedInputValue.length > 20) {\n return;\n }\n\n // Update state if input value matches allowed format\n if (sanitizedInputValue === '$' || regex.test(sanitizedInputValue)) {\n const numericValue = parseFloat(inputValue.replace(/[^\\d.-]/g, '')) || 0;\n setDisplayValue(sanitizedInputValue);\n setPriceValue(numericValue);\n }\n };\n\n /**\n * Format the input value when the input field loses focus.\n * @param {React.FocusEvent} e - The focus event.\n */\n const formatOnBlur = (e: React.FocusEvent) => {\n let inputValue = e.target.value.replace(/[^\\d.-]/g, '');\n let numericValue = parseFloat(inputValue) || 0;\n\n // Format the numeric value for display, removing trailing \"00\" if present\n let formattedDisplayValue = `$${Math.abs(numericValue).toFixed(4)}`;\n if (formattedDisplayValue.endsWith(\"00\")) {\n formattedDisplayValue = formattedDisplayValue.slice(0, -2);\n }\n setDisplayValue(formattedDisplayValue);\n setPriceValue(numericValue);\n valueFinalized(numericValue); // Invoke the callback with the numeric value\n };\n\n /**\n * Adjust the current price value by a given amount.\n * @param {number} adjustment - The amount to adjust the price by.\n */\n const adjustPenny = (adjustment: number) => {\n if (priceValue === 0 && adjustment < 0) {\n return\n }\n // If the price is negative, then we need to invert the logic of the + and = button so that + still technically increase the value.\n if(priceValue < 0) {\n adjustment = adjustment * -1;\n }\n \n // Math.round is to handle precision, hate it but until we use a decimal format for USD it is what it is...\n let numericValue = Math.round((priceValue + adjustment) * 10000) / 10000;\n setPriceValue(numericValue); // Update the numeric value\n\n // Format the new price value for display, removing trailing \"00\" if present\n let formattedDisplayValue = `$${Math.abs(numericValue).toFixed(4)}`;\n if (formattedDisplayValue.endsWith(\"00\")) {\n formattedDisplayValue = formattedDisplayValue.slice(0, -2);\n }\n setDisplayValue(formattedDisplayValue);\n valueFinalized(numericValue); // Invoke the callback with the new numeric value\n };\n\n /**\n * Increase the price value by one penny (0.01).\n */\n const addPenny = () => adjustPenny(0.01);\n\n /**\n * Decrease the price value by one penny (0.01).\n */\n const subtractPenny = () => adjustPenny(-0.01);\n \n /**\n * Handle the 'Enter' key press event to blur the input field.\n * @param {React.KeyboardEvent} e - The keyboard event.\n */\n const handleKeyDown = (e: React.KeyboardEvent) => {\n if (e.key === 'Enter' && priceInputNumberRef.current) {\n priceInputNumberRef.current.blur();\n }\n };\n\n // Render the component UI\n return (\n
\n Quote was updated at the time displayed. Some or all intraday quotes may be delayed up to 20 minutes, and\n may not reflect current bid, ask or last sale.\n