diff --git a/src/pages/nse-options/index.tsx b/src/pages/nse-options/index.tsx index 0d372f8..9f4fc44 100644 --- a/src/pages/nse-options/index.tsx +++ b/src/pages/nse-options/index.tsx @@ -61,14 +61,30 @@ const NseFlatDataOptions = observer( const [symbolStore, setSymbolStore] = useState<{ symbolStore: SymbolStore; } | null>(null); - const onUserSelectDate = (newDate: string) => { + + const onUserSelectDate = async (newDate: string) => { console.log(`Expiry date changed to: ${newDate}`); // Log the new expiry date - // Update expiryDate in the store + + // Update the selected expiry date in the store store?.nseFetchStore.setExpiryDate(newDate); - + // Fetch new data based on the updated expiryDate and the currently selected stock - store?.nseFetchStore.fetchData(userSelectedStock, newDate); + const selectedStock = userSelectedStock || 'NIFTY'; // Use a default stock if not selected + + // Check if the expiry dates are available in the expiryDateStore + if (expiryDateStore && expiryDateStore.expiryDates.length > 0) { + // Set the expiryDate to the first expiry date from the list + const firstExpiryDate = expiryDateStore.expiryDates[0]; + store?.nseFetchStore.setExpiryDate(firstExpiryDate); + + // Fetch data for the first expiry date and selected stock + await store?.nseFetchStore.fetchData(selectedStock, firstExpiryDate); + } else { + console.warn('No expiry dates available for the selected symbol'); + } }; + + useEffect(() => { const symbolStoreInstance = initializeSymbolStore(); @@ -308,8 +324,11 @@ const NseFlatDataOptions = observer( return (
- {rowData[`${type}_totalTradedVolume`].toLocaleString()} -
+ {rowData[`${type}_totalTradedVolume`] && isFinite(rowData[`${type}_totalTradedVolume`]) + ? rowData[`${type}_totalTradedVolume`].toLocaleString() + : 'N/A' // Or any other fallback or default value + } +
Gamma: {rowData[`${type}_gamma`]}
@@ -340,10 +359,11 @@ const NseFlatDataOptions = observer( // const oi = isDividedByLotSize && lot_size && lot_size !== 0 ? rowData['CE_openInterest'] / lot_size : rowData['CE_openInterest']; //const changeInOI = isDividedByLotSize && lot_size && lot_size !== 0 ? rowData['CE_changeinOpenInterest'] / lot_size : rowData['CE_changeinOpenInterest']; - const ce_oi = - isDividedByLotSize && lot_size && lot_size !== 0 + const ce_oi = rowData["CE_openInterest"] && isFinite(rowData["CE_openInterest"]) + ? (isDividedByLotSize && lot_size && lot_size !== 0 ? Math.abs(rowData["CE_openInterest"] / lot_size) - : rowData["CE_openInterest"]; + : rowData["CE_openInterest"]) + : 0; // or some other default value or handling const CE_changeInOI = isDividedByLotSize && lot_size && lot_size !== 0 @@ -359,7 +379,11 @@ const NseFlatDataOptions = observer( marginRight: `${100 - size}%`, borderRadius: "0px 25px 25px 0px", }; - + console.log('CE_changeInOI:', CE_changeInOI); + console.log('lot_size:', lot_size); + console.log('isDividedByLotSize:', isDividedByLotSize); + console.log('maxSize:', maxSize); + console.log('size:', size); return (
@@ -391,10 +415,11 @@ const NseFlatDataOptions = observer( // const oi = isDividedByLotSize && lot_size && lot_size !== 0 ? rowData['CE_openInterest'] / lot_size : rowData['CE_openInterest']; //const changeInOI = isDividedByLotSize && lot_size && lot_size !== 0 ? rowData['CE_changeinOpenInterest'] / lot_size : rowData['CE_changeinOpenInterest']; - const pe_oi = - isDividedByLotSize && lot_size && lot_size !== 0 + const pe_oi = rowData["PE_openInterest"] && isFinite(rowData["PE_openInterest"]) + ? (isDividedByLotSize && lot_size && lot_size !== 0 ? Math.abs(rowData["PE_openInterest"] / lot_size) - : rowData["PE_openInterest"]; + : rowData["PE_openInterest"]) + : 0; // or some other default value or handling const PE_changeInOI = isDividedByLotSize && lot_size && lot_size !== 0 @@ -435,18 +460,16 @@ const NseFlatDataOptions = observer( ); }; - const calculateFairPrice = (data: any) => { - const atmStrikePrice = store?.nseFetchStore.atmStrike || 0; // Changed this line to fetch atmStrike directly from the store - const ceLastPrice = data?.[0]?.CE_lastPrice || 0; - const peLastPrice = data?.[0]?.PE_lastPrice || 0; - - // Log the values - console.log("ATM Strike Price: ", atmStrikePrice); - console.log("CE Last Price: ", ceLastPrice); - console.log("PE Last Price: ", peLastPrice); - - return atmStrikePrice + ceLastPrice - peLastPrice; + const calculateFairPrice = (data: any, atmStrikePrice: number) => { + const ceLastPrice = data?.find((row: any) => row.strikePrice === atmStrikePrice)?.CE_lastPrice || 0; + const peLastPrice = data?.find((row: any) => row.strikePrice === atmStrikePrice)?.PE_lastPrice || 0; + + // Calculate the fair price based on CE and PE last prices + const fairPrice = atmStrikePrice + ceLastPrice - peLastPrice; + + return fairPrice; }; + // helper function to round a value to the nearest half up function roundHalfUp(niftyValue: number, base: number) { @@ -503,8 +526,12 @@ const NseFlatDataOptions = observer(
{(() => { - const data = store?.nseFetchStore?.data; - const fairPrice = calculateFairPrice(data); + // Inside your component, after obtaining the ATM strike price + const atmStrikePrice = store?.nseFetchStore.atmStrike || 0; + + // Call calculateFairPrice with the ATM strike price + const fairPrice = calculateFairPrice(store?.nseFetchStore.data, atmStrikePrice); + return
Fair Price: {fairPrice.toFixed(2)}
; })()} @@ -566,15 +593,15 @@ const NseFlatDataOptions = observer(
- { - const selectedExpiryDate = e.value as string; - onUserSelectDate(selectedExpiryDate); // Call onUserSelectDate when a new date is selected - }} - /> + { + const selectedExpiryDate = e.value as string; + onUserSelectDate(selectedExpiryDate); // Call onUserSelectDate when a new date is selected + }} +/>
{isFetchingExpiryDates ? ( diff --git a/src/stores/NseFetchStore.ts b/src/stores/NseFetchStore.ts index e1e233b..040d34a 100644 --- a/src/stores/NseFetchStore.ts +++ b/src/stores/NseFetchStore.ts @@ -1,6 +1,13 @@ -import { makeObservable, observable, action, reaction, runInAction, autorun } from 'mobx'; +import { + makeObservable, + observable, + action, + autorun, + computed, + runInAction +} from 'mobx'; import axios from 'axios'; -import { NseOptionData, NseApiResponse} from '../types'; +import { NseOptionData, NseApiResponse } from '../types'; import { ExpiryDateStore } from './ExpiryDateStore'; import { DefaultStore } from './DefaultStore'; @@ -18,40 +25,18 @@ export class NseFetchStore { defaultStore: DefaultStore; lot_size: number | null = null; // Added a new observable property for lot size fairPrice: number | null = null; - - - - setSymbol = async (symbol: string): Promise => { - console.log('setSymbol called with symbol:', symbol); - this.symbol = symbol || 'NIFTY'; - - // Fetch expiry dates for the new symbol - await this.expiryDateStore.fetchExpiryDatesForSymbol(symbol); - - runInAction(() => { - // Set expiryDate to the first available expiry date - this.expiryDate = this.expiryDateStore.expiryDates[0] || null; - }); - - // Set expiryDate in defaultStore to the first available expiry date - if (this.expiryDate) { - runInAction(() => { - this.defaultStore.setExpiryDate(this.expiryDate!); - }); - } else { - console.warn('expiryDate is null, not calling setExpiryDate'); - } - console.log('expiryDate after fetchExpiryDatesForSymbol:', this.expiryDate); - - // Return the expiryDate - return this.expiryDate || ''; - }; - - - constructor(defaultStore: DefaultStore,expiryDateStore: ExpiryDateStore,initialNseData?: NseOptionData[]) { + ceLastPriceForATM: number | null = null; + peLastPriceForATM: number | null = null; + + constructor( + defaultStore: DefaultStore, + expiryDateStore: ExpiryDateStore, + initialNseData?: NseOptionData[] + ) { console.log('NseFetchStore constructor called'); this.defaultStore = defaultStore; this.expiryDateStore = expiryDateStore; + makeObservable(this, { atmStrike: observable, atmStrikeIndex: observable, @@ -65,51 +50,45 @@ export class NseFetchStore { calculateAtmStrike: action, setExpiryDate: action, setExpiryDates: action, - setSymbol: action, - fetchPutCallRatioData: action, - lot_size: observable // Added this line + lot_size: observable, // Added this line + setSymbol: action, // Explicitly specify setSymbol as an action }); - - // Use autorun instead of reaction + + // Use autorun to fetch data when expiryDate changes autorun(() => { if (this.expiryDate) { this.fetchData(); } }); - - // Call setSymbol function and wait for it to complete - this.setSymbol(this.symbol).then(() => { - if (initialNseData) { - this.data.replace(initialNseData); - // Set lot_size when initializing the store with data if available - this.lot_size = initialNseData[0]?.lot_size || null; - } - - if (typeof window !== 'undefined') { - this.intervalId = window.setInterval(() => { - // Use the current symbol and expiry date in the fetchData call - if (this.expiryDate) { - this.fetchData(); - } - }, 18000); - } - }); + + // Initialize with default symbol and fetch data + this.setSymbol(this.symbol); + + // Set up an interval for periodic data fetch + if (typeof window !== 'undefined') { + this.intervalId = window.setInterval(() => { + this.checkAndFetchData(); + }, 18000); + } } + setIsLoading(loading: boolean) { this.isLoading = loading; } setData(data: NseOptionData[]) { - - this.data.splice(0, this.data.length, ...data);this.data.replace(data); + this.data.replace(data); + if (data.length > 0) { console.log('Setting underlyingValue to:', data[0].CE_underlyingValue || data[0].PE_underlyingValue); this.underlyingValue = data[0].CE_underlyingValue || data[0].PE_underlyingValue; // Extract and set lot_size from the fetched data this.lot_size = data[0].lot_size || null; - } else { - this.underlyingValue = null; - } + } + + + + this.calculateAtmStrike(); } @@ -122,6 +101,7 @@ export class NseFetchStore { let closestDiff = Number.MAX_VALUE; let closestIndex = -1; + this.data.forEach((option, index) => { const diff = Math.abs(this.underlyingValue! - option.strikePrice); if (diff < closestDiff) { @@ -148,14 +128,50 @@ export class NseFetchStore { setExpiryDate(expiryDate: string): void { this.expiryDate = expiryDate; + // Clear or update other observables/state variables + this.data.clear(); + this.checkAndFetchData(); } setExpiryDates(dates: string[]): void { this.expiryDates = dates; } - - fetchData = async (userSelectedStock: string = this.symbol || 'NIFTY', firstExpiryDate: string | null = this.expiryDate) => { + setSymbol(symbol: string): void { + console.log('setSymbol called with symbol:', symbol); + this.symbol = symbol || 'NIFTY'; + + // Fetch expiry dates for the new symbol and wait for it to complete + this.expiryDateStore.fetchExpiryDatesForSymbol(symbol); + + if (this.expiryDateStore.expiryDates.length > 0) { + runInAction(() => { + // Set expiryDate to the first available expiry date + this.expiryDate = this.expiryDateStore.expiryDates[0]; + this.defaultStore.setExpiryDate(this.expiryDate); + }); + + console.log('expiryDate after fetchExpiryDatesForSymbol:', this.expiryDate); + + // Since expiry date is now set, fetch data if it hasn't been fetched before + if (!this.data.length) { + this.fetchData(); + } + } else { + console.warn('No expiry dates available for the selected symbol'); + } + } + + checkAndFetchData() { + if (this.expiryDate) { + this.fetchData(); + } + } + + async fetchData( + userSelectedStock: string = this.symbol || 'NIFTY', + firstExpiryDate: string | null = this.expiryDate + ) { if (!firstExpiryDate) { console.log('Expiry date is not set, cannot fetch data'); throw new Error('Expiry date is not set, cannot fetch data'); @@ -164,67 +180,36 @@ export class NseFetchStore { try { const response = await axios.get(`https://tradepodapisrv.azurewebsites.net/api/paytm/?symbol=${encodeURIComponent(this.symbol)}&expiry_date=${encodeURIComponent(firstExpiryDate)}`); - console.log("API Response: ", response.data); // Add this line to log the API response + console.log("API Response: ", response.data); const data = response.data as NseApiResponse; if (data && data.nse_options_data) { - this.setData(data.nse_options_data); console.log('underlyingValue after setData:', this.underlyingValue); - return data.nse_options_data; // Return the fetched data + return data.nse_options_data; } else { throw new Error('Data or data.nse_option_data is undefined'); } } catch (error) { console.error('Error fetching data:', error); - return []; // Return an empty array in case of an error + return []; } finally { this.isLoading = false; } - }; + } dispose() { if (this.intervalId) { window.clearInterval(this.intervalId); } } - - - - fetchPutCallRatioData = async (symbol: string, expiryDate: string) => { - // Fetch the data for the given symbol and expiry date - const data = await this.fetchData(symbol, expiryDate); - - // Calculate the Put/Call ratio for each strike price - const putCallRatioData = data.map(option => { - if (option.CE_totalTradedVolume && option.PE_totalTradedVolume) { - return { - strikePrice: option.strikePrice, - putCallRatio: option.PE_totalTradedVolume / option.CE_totalTradedVolume - }; - } else { - return null; - } - }).filter(item => item !== null); - - // Format the data for the chart - const formattedData = putCallRatioData.map(item => { - if (item) { - const time = new Date(item.strikePrice).getTime() / 1000; // Convert the strike price to a UNIX timestamp - - return { - time, - value: item.putCallRatio - }; - } - return null; - }).filter(item => item !== null); - - return formattedData; - }; - } -export const initializeNseFetchStore = (defaultStore: DefaultStore, expiryDateStore: ExpiryDateStore, initialNseData?: NseOptionData[]): NseFetchStore => { +export const initializeNseFetchStore = ( + defaultStore: DefaultStore, + expiryDateStore: ExpiryDateStore, + initialNseData?: NseOptionData[] +): NseFetchStore => { return new NseFetchStore(defaultStore, expiryDateStore, initialNseData); -}; \ No newline at end of file +}; +