UNPKG

@copytrade/broker-fyers

Version:
324 lines 12.7 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.FyersService = void 0; const { fyersModel } = require('fyers-api-v3'); class FyersService { constructor() { this.accessToken = null; this.refreshToken = null; this.appId = ''; this.secretKey = ''; // Initialize the official Fyers API client this.fyers = new fyersModel({ path: process.cwd() + '/logs', enableLogging: true }); } // Generate auth URL for user to visit - Fixed to use actual login page generateAuthUrl(credentials) { this.appId = credentials.clientId; this.fyers.setAppId(credentials.clientId); this.fyers.setRedirectUrl(credentials.redirectUri); // Use the correct Fyers login URL instead of API endpoint const authUrl = `https://api-t1.fyers.in/api/v3/generate-authcode?client_id=${credentials.clientId}&redirect_uri=${encodeURIComponent(credentials.redirectUri)}&response_type=code&state=sample_state`; console.log('🔗 Fixed Auth URL generated:', authUrl); return authUrl; } // Generate access token from auth code async generateAccessToken(authCode, credentials) { try { // Set App ID and secret key before generating access token this.fyers.setAppId(credentials.clientId); this.appId = credentials.clientId; this.secretKey = credentials.secretKey; const response = await this.fyers.generate_access_token({ client_id: credentials.clientId, secret_key: credentials.secretKey, auth_code: authCode }); if (response.s === 'ok') { this.accessToken = response.access_token; this.refreshToken = response.refresh_token; // Store refresh token this.fyers.setAccessToken(response.access_token); console.log('✅ Fyers access token and refresh token generated successfully'); // Get user profile to extract actual account ID try { const profileResponse = await this.fyers.get_profile(); if (profileResponse.s === 'ok' && profileResponse.data) { const accountId = profileResponse.data.fy_id || profileResponse.data.id || profileResponse.data.user_id; console.log(`✅ Fyers profile fetched, account ID: ${accountId}`); return { success: true, accessToken: response.access_token, refreshToken: response.refresh_token, accountId: accountId, // Return actual Fyers account ID message: 'Access token generated successfully', }; } else { console.log('⚠️ Profile fetch failed, using client ID as fallback'); } } catch (profileError) { console.log('⚠️ Profile fetch error:', profileError.message); } // Fallback: return without account ID return { success: true, accessToken: response.access_token, refreshToken: response.refresh_token, message: 'Access token generated successfully', }; } else { throw new Error(response.message || 'Failed to generate access token'); } } catch (error) { console.error('🚨 Failed to generate access token:', error); return { success: false, message: error.message || 'Access token generation failed', }; } } // Complete login flow - returns auth URL for user to visit async login(credentials) { try { const authUrl = this.generateAuthUrl(credentials); // For OAuth flows, return success: false with authUrl // This indicates that authentication is required return { success: false, authUrl, message: 'OAuth authentication required', }; } catch (error) { console.error('🚨 Fyers login failed:', error); return { success: false, message: error.message || 'Login failed', }; } } // Place order using official API async placeOrder(orderData) { if (!this.accessToken) { throw new Error('Not authenticated. Please login first.'); } try { const payload = { symbol: orderData.symbol, qty: orderData.qty, type: orderData.type === 'MARKET' ? 2 : 1, // 1=LIMIT, 2=MARKET side: orderData.side === 'BUY' ? 1 : -1, // 1=BUY, -1=SELL productType: this.getProductTypeCode(orderData.productType), // Fyers API expects camelCase limitPrice: orderData.limitPrice || 0, // Fyers API expects camelCase stopPrice: orderData.stopPrice || 0, // Fyers API expects camelCase disclosedQty: orderData.disclosedQty || 0, // Fyers API expects camelCase validity: orderData.validity === 'DAY' ? 'DAY' : 'IOC', offlineOrder: orderData.offlineOrder || false, // Fyers API expects camelCase stopLoss: orderData.stopLoss || 0, // Fyers API expects camelCase takeProfit: orderData.takeProfit || 0, // Fyers API expects camelCase }; const response = await this.fyers.place_order(payload); console.log('✅ Order placed successfully:', response); return response; } catch (error) { console.error('🚨 Failed to place order:', error); throw new Error(error.message || 'Order placement failed'); } } // Get order book using official API async getOrderBook() { if (!this.accessToken) { throw new Error('Not authenticated. Please login first.'); } try { const response = await this.fyers.orderbook(); return response.orderBook || []; } catch (error) { console.error('🚨 Failed to get order book:', error); throw new Error(error.message || 'Failed to get order book'); } } // Get positions using official API async getPositions() { if (!this.accessToken) { throw new Error('Not authenticated. Please login first.'); } try { const response = await this.fyers.get_positions(); return response.netPositions || []; } catch (error) { console.error('🚨 Failed to get positions:', error); throw new Error(error.message || 'Failed to get positions'); } } // Search symbols using official API async searchScrip(exchange, symbol) { try { const response = await this.fyers.search_scrips({ symbol: `${exchange}:${symbol}` }); return response.symbols || []; } catch (error) { console.error('🚨 Failed to search symbols:', error); throw new Error(error.message || 'Symbol search failed'); } } // Get quotes using official API async getQuotes(symbols) { if (!this.accessToken) { throw new Error('Not authenticated. Please login first.'); } try { const response = await this.fyers.getQuotes(symbols); return response.d || []; } catch (error) { console.error('🚨 Failed to get quotes:', error); throw new Error(error.message || 'Failed to get quotes'); } } // Get profile using official API async getProfile() { if (!this.accessToken) { throw new Error('Not authenticated. Please login first.'); } try { const response = await this.fyers.get_profile(); return response; } catch (error) { console.error('🚨 Failed to get profile:', error); throw new Error(error.message || 'Failed to get profile'); } } // Helper method to convert product type to code getProductTypeCode(productType) { const productMap = { 'CNC': 'CNC', 'INTRADAY': 'INTRADAY', 'MARGIN': 'MARGIN', 'CO': 'CO', 'BO': 'BO', }; return productMap[productType] || 'CNC'; } // Check if authenticated isAuthenticated() { return !!this.accessToken; } // Get access token getAccessToken() { return this.accessToken; } // Set access token (for existing sessions) setAccessToken(token) { this.accessToken = token; this.fyers.setAccessToken(token); } // Set refresh token setRefreshToken(token) { this.refreshToken = token; } // Get refresh token getRefreshToken() { return this.refreshToken; } // Refresh access token using refresh token async refreshAccessToken() { if (!this.refreshToken) { return { success: false, message: 'No refresh token available', }; } if (!this.appId || !this.secretKey) { return { success: false, message: 'App ID or Secret Key not set', }; } try { console.log('🔄 Refreshing Fyers access token using refresh token...'); const response = await this.fyers.refresh_access_token({ client_id: this.appId, secret_key: this.secretKey, refresh_token: this.refreshToken }); if (response.s === 'ok') { this.accessToken = response.access_token; this.refreshToken = response.refresh_token; // Update refresh token if provided this.fyers.setAccessToken(response.access_token); console.log('✅ Fyers access token refreshed successfully'); return { success: true, accessToken: response.access_token, refreshToken: response.refresh_token, message: 'Access token refreshed successfully', }; } else { console.error('❌ Failed to refresh access token:', response.message); return { success: false, message: response.message || 'Failed to refresh access token', }; } } catch (error) { console.error('🚨 Failed to refresh access token:', error); return { success: false, message: error.message || 'Access token refresh failed', }; } } // Validate if the current session is still active async validateSession() { if (!this.accessToken) { return false; } try { // Use a lightweight API call to check if session is still valid // getProfile is a simple endpoint that requires authentication const response = await this.fyers.get_profile(); // If the call succeeds, session is valid return response.s === 'ok'; } catch (error) { console.log('⚠️ Session validation failed for Fyers:', error.message); // If API call fails, session is likely expired this.accessToken = null; return false; } } // Logout async logout() { try { this.accessToken = null; this.appId = ''; console.log('✅ Fyers logout successful'); return { success: true, message: 'Logout successful', }; } catch (error) { console.error('🚨 Fyers logout failed:', error); return { success: false, message: error.message || 'Logout failed', }; } } } exports.FyersService = FyersService; //# sourceMappingURL=fyersService.js.map