Skip to content

Commit

Permalink
feat: SSE implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
shafin-deriv committed Feb 4, 2025
1 parent acc9126 commit b42a7fa
Show file tree
Hide file tree
Showing 25 changed files with 2,607 additions and 303 deletions.
264 changes: 121 additions & 143 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,193 +1,171 @@
# champion-trader
# Champion Trader

A React TypeScript trading application built with modern technologies and best practices.
A React-based trading application for options trading.

## Technologies
## Features

- React 18
- TypeScript
- TailwindCSS for styling
- Zustand for state management
- Axios for API communication
- Jest and React Testing Library for testing
- Real-time market data streaming
- Contract price updates
- Position management
- Trade execution
- Responsive design
- TypeScript support

## Getting Started

> **Prerequisites:**
> The following steps require [NodeJS](https://nodejs.org/en/) to be installed on your system, so please
> install it beforehand if you haven't already.
### Prerequisites

To get started with your project, you'll first need to install the dependencies with:
- Node.js (v18 or higher)
- npm or yarn

### Installation

```bash
# Install dependencies
npm install
```

Then, you'll be able to run a development version of the project with:

```bash
# Start development server
npm run dev

# Build for production
npm run build

# Run tests
npm test
```

After a few seconds, your project should be accessible at the address
[http://localhost:4113/](http://localhost:4113/)
## Architecture

## Environment Configuration
### Real-time Data Streaming

The application supports different environments (development, staging, production) with environment-specific configurations. Create a `.env` file in the project root with the following variables:
The application uses Server-Sent Events (SSE) for real-time data streaming, providing efficient unidirectional communication for:

```bash
# WebSocket Configuration
RSBUILD_WS_URL=ws://options-trading-api.deriv.ai # WebSocket server URL
RSBUILD_WS_PUBLIC_PATH=/ws # Public WebSocket endpoint path
RSBUILD_WS_PROTECTED_PATH=/ws # Protected WebSocket endpoint path
- Market price updates
- Contract price streaming
- Position updates

# REST API Configuration
RSBUILD_REST_URL=http://options-trading-api.deriv.ai # REST API server URL
```
#### Why SSE over WebSocket?

Default configurations per environment:
1. **Simpler Protocol**: SSE is built on HTTP and is simpler to implement and maintain
2. **Automatic Reconnection**: Built-in reconnection handling
3. **Better Load Balancing**: Works well with HTTP/2 and standard load balancers
4. **Lower Overhead**: No need for ping/pong messages or connection heartbeats
5. **Firewall Friendly**: Uses standard HTTP port 80/443

### Development
```typescript
{
ws: {
baseUrl: 'ws://options-trading-api.deriv.ai',
publicPath: '/ws',
protectedPath: '/ws'
},
rest: {
baseUrl: 'http://options-trading-api.deriv.ai'
}
}
```
### Example Usage

### Staging
```typescript
{
ws: {
baseUrl: 'wss://options-trading-api.deriv.ai',
publicPath: '/ws',
protectedPath: '/ws'
},
rest: {
baseUrl: 'https://options-trading-api.deriv.ai'
}
// Market Data Streaming
import { useMarketSSE } from '@/hooks/sse';

function MarketPrice({ instrumentId }: { instrumentId: string }) {
const { price, isConnected } = useMarketSSE(instrumentId, {
onPrice: (price) => {
console.log('New price:', price);
}
});

return (
<div>
{isConnected ? (
<p>Current price: {price?.bid}</p>
) : (
<p>Connecting...</p>
)}
</div>
);
}
```

### Production
```typescript
{
ws: {
baseUrl: 'wss://options-trading-api.deriv.ai',
publicPath: '/ws',
protectedPath: '/ws'
},
rest: {
baseUrl: 'https://options-trading-api.deriv.ai'
}
// Contract Price Streaming
import { useContractSSE } from '@/hooks/sse';

function ContractPrice({ params, authToken }: { params: ContractPriceRequest; authToken: string }) {
const { price, isConnected } = useContractSSE(params, authToken, {
onPrice: (price) => {
console.log('Contract price:', price);
}
});

return (
<div>
{isConnected ? (
<p>Price: {price?.price}</p>
) : (
<p>Connecting...</p>
)}
</div>
);
}
```

## Testing
### State Management

Run all tests with:
The application uses Zustand for state management, providing:

```bash
npm test
```
- Centralized store for application state
- Simple and predictable state updates
- TypeScript support
- Minimal boilerplate

Run tests in watch mode during development:
### Project Structure

```bash
npm test -- --watch
```
src/
├── components/ # Reusable UI components
├── hooks/ # Custom React hooks
├── layouts/ # Page layouts
├── screens/ # Page components
├── services/ # API and service layer
│ └── api/
│ ├── rest/ # REST API services
│ └── sse/ # SSE services
├── stores/ # Zustand stores
└── types/ # TypeScript type definitions
```

### Testing Guidelines

- Follow Test-Driven Development (TDD) methodology
- Write tests before implementing functionality
- Maintain at least 90% test coverage
- Mock external dependencies (Axios, Zustand stores)
- Test edge cases explicitly

## Development Guidelines
## Development

### Component Design
### Code Style

- Follow Atomic Component Design principles
- Components should be self-contained and independent
- Follow TypeScript best practices
- Use functional components with hooks
- Implement proper error handling
- Write comprehensive tests
- Use TailwindCSS for styling
- Implement lazy loading for components

### State Management

- Use local state for component-specific logic
- Use Zustand for shared/global state
- Avoid prop drilling

### API Integration

#### REST API
The application uses Axios for REST API calls. Available endpoints:

##### Available Instruments
Fetches available trading instruments:
```typescript
import { getAvailableInstruments } from '@/services/api/rest/service';

const response = await getAvailableInstruments({
context: {
app_id: 1001,
account_type: 'real'
}
});
// Returns: { instruments: [{ id: string, name: string }] }
```
### Testing

General guidelines:
- Use Axios for HTTP requests
- Wrap API calls in service layers
- Handle errors gracefully
- Use environment-specific configurations from `src/config/api.ts`
The project uses Jest and React Testing Library for testing:

### Import Paths
```bash
# Run all tests
npm test

Use path aliases for better maintainability:
# Run tests with coverage
npm test -- --coverage

```typescript
// Instead of
import { TradeButton } from "../../components/TradeButton";

// Use
import { TradeButton } from "@/components/TradeButton";
# Run specific test file
npm test -- src/components/MyComponent.test.tsx
```

### Version Control
### Environment Variables

Commit messages should follow the pattern:
```
<type>: concise description
Create a `.env` file in the root directory:

- Detailed bullet points
- Additional context
```env
RSBUILD_REST_URL=https://api.example.com
RSBUILD_SSE_PUBLIC_PATH=/sse
RSBUILD_SSE_PROTECTED_PATH=/sse
```

Allowed types:
- feat: New features
- fix: Bug fixes
- refactor: Code changes that neither fix bugs nor add features
- docs: Documentation changes
- test: Test-related changes
- chore: Build process or auxiliary tool changes
## Contributing

## Building for Production
1. Fork the repository
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
4. Push to the branch (`git push origin feature/amazing-feature`)
5. Open a Pull Request

Build the project for release with:

```bash
npm run build
```
## License

This will create an optimized production build in the `dist` directory.
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
Loading

0 comments on commit b42a7fa

Please sign in to comment.