This is Implementation of Forex Trading backend system using Nestjs.
- 1. Prerequisites
- 2. Project Setup
- 3. Install Dependencies
- 4. Run the PostgreSQL and Redis Server using Docker
- 5. Generate Prisma Client
- 6. Apply Database Migrations
- 6. Run the Project
- Run each apps separately (Optional)
- Important Note
- To Unlock Full Currency Support
- How to Enable Full Currency Support (if you have a premium API key)
-
Live FX Exchange Rates: Stay ahead of the market with live foreign exchange rates that are updated every 30 seconds, ensuring you have access to the most up-to-date pricing information for informed trading decisions.
-
Secure Authentication and Authorization: Robust authentication and authorization mechanisms are in place, employing industry-standard access and refresh token protocols. This ensures that your trading activities and sensitive data remain secure and accessible only to authorized users.
-
User Wallet Management: Users can easily topup their wallet account and check the balances in nearly all currencies.
-
Real-Time Currency Conversions: Leveraging the live exchange rates, users can convert amounts between different currencies with precision and accuracy.
- Node.js >=v20.10.0 and Docker: Install the latest versions from their respective official websites: Nodejs and Docker.
- Clone the project repository using Git.
- Navigate to the project directory using the
cd
command in your terminal. - Create a file named
.env
in the project's root directory. - Copy and paste the contents of the
.env.example
file into the newly created .env file. Replace the placeholder values with your own credentials (e.g., database connection details, API keys).
Run the following command in your terminal to install the project's dependencies:
npm install
Run the following command to apply database migrations, ensuring your database schema is up-to-date:
docker-compose -f docker-compose.dev.yaml up -d
Run the following command to generate the Prisma client, which facilitates interaction with your database:
npm run prisma:generate
Run the following command to apply database migrations, ensuring your database schema is up-to-date:
npm run prisma:migrate:dev
- Run the Project (In one command)
npm run dev
- Run Workers
npm run workers
- Run Cron
npm run cron
- Run Backend
npm run backend
This project utilizes the Alphavantage.co API (s://www.alphavantage.co/) for retrieving live exchange rates. However, the free tier has a strict rate limit of 25 requests per day.
The project is configured using the demo API key, fetching only the USD to JPY exchange rate every 30 seconds.
You'll need a premium API key from Alphavantage.co, granting access to exchange rates for all currencies and a higher request limit (i.e 300+ request per minute).
- In the
forex.service.ts
file, uncomment the following two functions
async fxConversion(body: FxConversionDto) {
const {
forex_exchange_rates_id,
from_currency_code,
to_currency_code,
amount,
} = body;
const redisData = await this._redisService.getForexExchangeRate(
ForexExchangeRatesLastestRedisKey
);
const dbData = forex_exchange_rates_id
? await this._forexExchangeRatesService.getForexExchangeRatesById({
forex_exchange_rates_id,
})
: (
await this._forexExchangeRatesService.getLatestForexExchangeRates()
)[0];
const exchangeRates = this.getExchangeRates(
redisData,
dbData,
from_currency_code,
to_currency_code
);
if (!exchangeRates) {
throw new Error('Exchange rates not found');
}
const { fromCurrencyExchangeRate, toCurrencyExchangeRate } = exchangeRates;
const result = CurrencyConverterService.convert({
fromCurrencyCode: from_currency_code,
fromCurrencyExchangeRateFromBaseCurrency:
fromCurrencyExchangeRate.exchange_rate,
toCurrencyCode: to_currency_code,
toCurrencyExchangeRateFromBaseCurrency:
toCurrencyExchangeRate.exchange_rate,
amount,
});
return {
convertedAmount: result,
currency: to_currency_code,
};
}
private getExchangeRates(
redisData: ForexExchangeRatesRedisData | null,
dbData: ForexExchangeRatesDbData | null,
fromCurrencyCode: CurrencyCode,
toCurrencyCode: CurrencyCode
): {
fromCurrencyExchangeRate: CurrencyExchangeRate;
toCurrencyExchangeRate: CurrencyExchangeRate;
} | null {
const data =
redisData?.currency_exchange_rates ||
dbData?.currency_exchange_rates ||
[];
const fromCurrencyExchangeRate = data.find(
(rate) => rate.to_currency_code === fromCurrencyCode
);
const toCurrencyExchangeRate = data.find(
(rate) => rate.to_currency_code === toCurrencyCode
);
if (!fromCurrencyExchangeRate || !toCurrencyExchangeRate) {
return null;
}
return { fromCurrencyExchangeRate, toCurrencyExchangeRate };
}
- Code Modification
Forex.controller.ts
const res = await this._forexService.fxConversionFormBaseCurrency(body);
to
const res = await this._forexService.fxConversion(body);
Uncomment the cron scheduler in the file to enable fetching of exchange rates for all currencies every 30 seconds (recommended only if you have a premium API key).
@Cron(CronExpression.EVERY_30_SECONDS)
async syncForexRatesEvery30Seconds() {
const forex_exchange_rates_expires_at_milliseconds = 1000 * 30;
const forex_exchange_rates_id = uuidV4();
const forex_exchange_rates_expires_at = generateTimestamp(
forex_exchange_rates_expires_at_milliseconds
);
currencyCodesWithName.map(async (currency: CurrencyCodeInterface) => {
const params: ForexExchangeRateUrlProps = {
to_currency: currency.code,
apiKey: this._configService.ALPHA_VANTAGE_API_KEYS,
};
const url = getForexExchangeRateUrl(params);
const eventData: SyncForexExchangeRateJob['data'] = {
url,
forex_exchange_rates_id,
forex_exchange_rates_expires_at,
};
console.log('adding job :', forex_exchange_rates_id);
this._forexExchangeRatesQueue.add(
ForexJobPattern.SYNC_FOREX_EXCHANGE_RATES,
{ ...eventData }
);
});
}
and comment :
// THIS CRON WILL ONLY ADD THE USD TO INR FETCHING URL
// DUE TO ALPHA VANTAGE API HARD RATE LIMIT (i.e 25 requests a day only)
@Cron(CronExpression.EVERY_30_SECONDS)
async syncForexExchangeRatesEvery30SecondsWithDemoKey() {
const forex_exchange_rates_expires_at_milliseconds = 1000 * 30;
const forex_exchange_rates_id = uuidV4();
const forex_exchange_rates_expires_at = generateTimestamp(
forex_exchange_rates_expires_at_milliseconds
);
const params: ForexExchangeRateUrlProps = {
to_currency: 'JPY',
apiKey: this._configService.ALPHA_VANTAGE_API_KEYS,
};
const url = getForexExchangeRateUrl(params);
const eventData: SyncForexExchangeRateJob['data'] = {
url,
forex_exchange_rates_id,
forex_exchange_rates_expires_at,
};
this._forexExchangeRatesQueue.add(
ForexJobPattern.SYNC_FOREX_EXCHANGE_RATES,
{ ...eventData }
);
console.log('Adding jobs to queue :', forex_exchange_rates_id);
}
http://localhost:9000/
http://localhost:9000/api/v1/docs
https://forex-trading-system-assignment-production.up.railway.app/api/v1/docs
POST /api/v1/auth/register
Parameter | Type | Description |
---|---|---|
email |
string |
Required. |
password |
string |
Required. |
firstName |
string |
Required. |
lastName |
string |
Required. (Optional) |
POST /api/v1/auth/login
Parameter | Type | Description |
---|---|---|
email |
string |
Required. |
password |
string |
Required. |
GET /api/v1/auth/refresh-token
π NOTE: This Api Endpoint required Authorization in cookie need to be pass refresh_token".
Cookie: refresh_token=<your_refresh_token>
1. This API endpoint allows users to top up their account with a specified amount in a given currency.
π NOTE: Currently, this API endpoint only supports the JPY currency.
π NOTE: This Api Endpoint required Authorization header "Bearer token".
POST /api/v1/accounts/topup
Parameter | Type | Description |
---|---|---|
currency |
string |
Required. |
amount |
string |
Required. |
π NOTE: Currently, this API endpoint only supports the JPY currency.
π NOTE: This Api Endpoint required Authorization header "Bearer token".
GET /api/v1/accounts/balance
1.This API performs an FX conversion using the provided forex_exchange_rates_id
and converts the specified amount from one currency to another.
π NOTE: Currently, this endpoint is only working for the USD->JPY currency conversion.
POST /api/v1/fx-conversion
Parameter | Type | Description |
---|---|---|
forex_exchange_rates_id |
string |
Required. |
from_currency_code |
string |
Required. |
to_currency_code |
string |
Required. |
amount |
string |
Required. |
π NOTE: Currently, this endpoint is only working for the USD->JPY currency conversion.
GET /api/v1/fx-rates
If you encounter any issues or have questions while setting up this application, please don't hesitate to reach out! We're here to help!
Contact:
- Email:
anmolgangwar64+forex@gmail.com