Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions src/components/TradingHistoryExport.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { downloadCSV, filterTradesByDateRange, type TradeRecord } from '../utils/export-trading-history'

interface TradingHistoryExportProps {
trades: TradeRecord[]
}

export function TradingHistoryExport({ trades }: TradingHistoryExportProps) {
const handleExportAll = () => {
downloadCSV(trades)
}

const handleExportRange = () => {
const start = new Date()
start.setDate(start.getDate() - 30)
const end = new Date()
const filtered = filterTradesByDateRange(trades, start, end)
downloadCSV(filtered, `trades-last-30d-${end.toISOString().split('T')[0]}.csv`)
}

return (
<div className="flex items-center gap-2">
<button
onClick={handleExportAll}
className="px-3 py-1.5 text-sm bg-gray-100 dark:bg-gray-800 rounded hover:bg-gray-200 dark:hover:bg-gray-700 transition-colors"
>
📥 Export All (CSV)
</button>
<button
onClick={handleExportRange}
className="px-3 py-1.5 text-sm bg-gray-100 dark:bg-gray-800 rounded hover:bg-gray-200 dark:hover:bg-gray-700 transition-colors"
>
📥 Last 30 Days
</button>
</div>
)
}
67 changes: 67 additions & 0 deletions src/utils/export-trading-history.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/**
* Export trading history to CSV
* Handles date range filtering and CSV formatting
*/

interface TradeRecord {
id: string
timestamp: string | Date
type: 'long' | 'short'
side: 'open' | 'close'
asset: string
size: number
price: number
pnl?: number
fees?: number
}

function formatDate(date: string | Date): string {
const d = new Date(date)
return d.toISOString().split('T')[0]
}

function escapeCSV(value: string | number | undefined): string {
const str = String(value ?? '')
if (str.includes(',') || str.includes('"') || str.includes('\n')) {
return `"${str.replace(/"/g, '""')}"`
}
return str
}

export function generateCSV(trades: TradeRecord[]): string {
const headers = ['Date', 'Type', 'Side', 'Asset', 'Size', 'Price', 'PnL', 'Fees']
const rows = trades.map(t => [
formatDate(t.timestamp),
t.type.toUpperCase(),
t.side.toUpperCase(),
escapeCSV(t.asset),
t.size.toString(),
t.price.toString(),
(t.pnl ?? 0).toFixed(2),
(t.fees ?? 0).toFixed(4),
].map(escapeCSV).join(','))

return [headers.join(','), ...rows].join('\n')
}

export function downloadCSV(trades: TradeRecord[], filename?: string): void {
const csv = generateCSV(trades)
const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' })
const url = URL.createObjectURL(blob)
const link = document.createElement('a')
link.href = url
link.download = filename || `trading-history-${new Date().toISOString().split('T')[0]}.csv`
link.click()
URL.revokeObjectURL(url)
}

export function filterTradesByDateRange(
trades: TradeRecord[],
startDate: Date,
endDate: Date
): TradeRecord[] {
return trades.filter(t => {
const d = new Date(t.timestamp)
return d >= startDate && d <= endDate
})
}