redesign fully scaffolded and web login works
This commit is contained in:
@@ -0,0 +1,227 @@
|
||||
# Trading Strategy Best Practices
|
||||
|
||||
## Code Organization
|
||||
|
||||
### Separation of Concerns
|
||||
```typescript
|
||||
// Good: Clear separation
|
||||
class Strategy {
|
||||
async analyze(data: MarketData): Promise<Signal> { }
|
||||
}
|
||||
|
||||
class RiskManager {
|
||||
validateSignal(signal: Signal): boolean { }
|
||||
}
|
||||
|
||||
class ExecutionEngine {
|
||||
async execute(signal: Signal): Promise<Order> { }
|
||||
}
|
||||
|
||||
// Bad: Everything in one function
|
||||
async function trade() {
|
||||
// Analysis, risk, execution all mixed
|
||||
}
|
||||
```
|
||||
|
||||
### Configuration Management
|
||||
```typescript
|
||||
// Good: External configuration
|
||||
interface StrategyConfig {
|
||||
stopLossPercent: number;
|
||||
takeProfitPercent: number;
|
||||
maxPositionSize: number;
|
||||
riskPerTrade: number;
|
||||
}
|
||||
|
||||
const config = loadConfig('strategy.yaml');
|
||||
|
||||
// Bad: Hardcoded values scattered throughout
|
||||
const stopLoss = price * 0.95; // What if you want to change this?
|
||||
```
|
||||
|
||||
## Testing Considerations
|
||||
|
||||
### Testable Code
|
||||
```typescript
|
||||
// Good: Pure functions, easy to test
|
||||
function calculateRSI(prices: number[], period: number = 14): number {
|
||||
// Pure calculation, no side effects
|
||||
return rsi;
|
||||
}
|
||||
|
||||
// Bad: Hard to test
|
||||
async function strategy() {
|
||||
const data = await fetchLiveData(); // Can't control in tests
|
||||
const signal = analyze(data);
|
||||
await executeTrade(signal); // Side effects
|
||||
}
|
||||
```
|
||||
|
||||
### Mock-Friendly Design
|
||||
```typescript
|
||||
// Good: Dependency injection
|
||||
class Strategy {
|
||||
constructor(
|
||||
private dataProvider: DataProvider,
|
||||
private executor: OrderExecutor
|
||||
) {}
|
||||
|
||||
async run() {
|
||||
const data = await this.dataProvider.getData();
|
||||
// ...
|
||||
}
|
||||
}
|
||||
|
||||
// In tests: inject mocks
|
||||
const strategy = new Strategy(mockDataProvider, mockExecutor);
|
||||
```
|
||||
|
||||
## Performance Optimization
|
||||
|
||||
### Avoid Recalculation
|
||||
```typescript
|
||||
// Good: Cache indicator results
|
||||
class IndicatorCache {
|
||||
private cache = new Map<string, { value: number, timestamp: number }>();
|
||||
|
||||
get(key: string, ttl: number, calculator: () => number): number {
|
||||
const cached = this.cache.get(key);
|
||||
if (cached && Date.now() - cached.timestamp < ttl) {
|
||||
return cached.value;
|
||||
}
|
||||
|
||||
const value = calculator();
|
||||
this.cache.set(key, { value, timestamp: Date.now() });
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
// Bad: Recalculate every time
|
||||
for (const ticker of tickers) {
|
||||
const rsi = calculateRSI(await getData(ticker)); // Slow
|
||||
}
|
||||
```
|
||||
|
||||
### Batch Operations
|
||||
```typescript
|
||||
// Good: Batch API calls
|
||||
const results = await Promise.all(
|
||||
tickers.map(ticker => dataProvider.getOHLC(ticker))
|
||||
);
|
||||
|
||||
// Bad: Sequential API calls
|
||||
const results = [];
|
||||
for (const ticker of tickers) {
|
||||
results.push(await dataProvider.getOHLC(ticker)); // Slow
|
||||
}
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
### Graceful Degradation
|
||||
```typescript
|
||||
// Good: Fallback behavior
|
||||
async function getMarketData(ticker: string): Promise<OHLC[]> {
|
||||
try {
|
||||
return await primarySource.fetch(ticker);
|
||||
} catch (error) {
|
||||
logger.warn('Primary source failed, trying backup');
|
||||
try {
|
||||
return await backupSource.fetch(ticker);
|
||||
} catch (backupError) {
|
||||
logger.error('All sources failed');
|
||||
return getCachedData(ticker); // Last resort
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Bad: Let it crash
|
||||
async function getMarketData(ticker: string) {
|
||||
return await api.fetch(ticker); // Uncaught errors
|
||||
}
|
||||
```
|
||||
|
||||
### Detailed Logging
|
||||
```typescript
|
||||
// Good: Structured logging with context
|
||||
logger.info({
|
||||
action: 'order_placed',
|
||||
ticker: 'BTC/USDT',
|
||||
side: 'buy',
|
||||
size: 0.1,
|
||||
price: 50000,
|
||||
orderId: 'abc123',
|
||||
strategy: 'mean-reversion'
|
||||
});
|
||||
|
||||
// Bad: String concatenation
|
||||
console.log('Placed order'); // No context
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
||||
### Self-Documenting Code
|
||||
```typescript
|
||||
// Good: Clear naming and JSDoc
|
||||
/**
|
||||
* Calculate position size using Kelly Criterion
|
||||
* @param winRate Probability of winning (0-1)
|
||||
* @param avgWin Average win amount
|
||||
* @param avgLoss Average loss amount
|
||||
* @param capital Total available capital
|
||||
* @returns Optimal position size in base currency
|
||||
*/
|
||||
function calculateKellyPosition(
|
||||
winRate: number,
|
||||
avgWin: number,
|
||||
avgLoss: number,
|
||||
capital: number
|
||||
): number {
|
||||
const kellyPercent = (winRate * avgWin - (1 - winRate) * avgLoss) / avgWin;
|
||||
return Math.max(0, Math.min(kellyPercent * capital, capital * 0.25)); // Cap at 25%
|
||||
}
|
||||
|
||||
// Bad: Cryptic names
|
||||
function calc(w: number, a: number, b: number, c: number) {
|
||||
return (w * a - (1 - w) * b) / a * c;
|
||||
}
|
||||
```
|
||||
|
||||
## Security
|
||||
|
||||
### Input Validation
|
||||
```typescript
|
||||
// Good: Validate all external inputs
|
||||
function validateTicker(ticker: string): boolean {
|
||||
return /^[A-Z]+:[A-Z]+\/[A-Z]+$/.test(ticker);
|
||||
}
|
||||
|
||||
function validatePeriod(period: string): boolean {
|
||||
return ['1m', '5m', '15m', '1h', '4h', '1d', '1w'].includes(period);
|
||||
}
|
||||
|
||||
// Bad: Trust user input
|
||||
function getOHLC(ticker: string, period: string) {
|
||||
return db.query(`SELECT * FROM ohlc WHERE ticker='${ticker}'`); // SQL injection!
|
||||
}
|
||||
```
|
||||
|
||||
### Rate Limiting
|
||||
```typescript
|
||||
// Good: Prevent API abuse
|
||||
class RateLimiter {
|
||||
private calls: number[] = [];
|
||||
|
||||
async throttle(maxCallsPerMinute: number): Promise<void> {
|
||||
const now = Date.now();
|
||||
this.calls = this.calls.filter(t => now - t < 60000);
|
||||
|
||||
if (this.calls.length >= maxCallsPerMinute) {
|
||||
const wait = 60000 - (now - this.calls[0]);
|
||||
await sleep(wait);
|
||||
}
|
||||
|
||||
this.calls.push(now);
|
||||
}
|
||||
}
|
||||
```
|
||||
Reference in New Issue
Block a user