funhi-chart 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +22 -0
- package/README.md +881 -0
- package/dist/dts/components/FunhiChart.d.ts +13 -0
- package/dist/dts/components/ProfessionalTradingChartRedux.d.ts +13 -0
- package/dist/dts/config/environment.d.ts +12 -0
- package/dist/dts/hooks/useOptimizedTokenAnalytics.d.ts +94 -0
- package/dist/dts/hooks/useSocket.d.ts +46 -0
- package/dist/dts/index.d.ts +18 -0
- package/dist/dts/services/candleStorage.d.ts +58 -0
- package/dist/dts/utils/candleAggregation.d.ts +67 -0
- package/dist/index.d.ts +295 -0
- package/dist/index.esm.js +8 -0
- package/dist/index.esm.js.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/package.json +68 -0
package/README.md
ADDED
|
@@ -0,0 +1,881 @@
|
|
|
1
|
+
# FunhiChart 📊
|
|
2
|
+
|
|
3
|
+
A **professional trading chart component** for React applications. Display beautiful, interactive candlestick charts with real-time updates, multiple timeframes, and live market data.
|
|
4
|
+
|
|
5
|
+
Built with TradingView's Lightweight Charts library and optimized for crypto trading platforms.
|
|
6
|
+
|
|
7
|
+
[](https://www.npmjs.com/package/funhi-chart)
|
|
8
|
+
[](https://opensource.org/licenses/MIT)
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## 🎯 What is FunhiChart?
|
|
13
|
+
|
|
14
|
+
FunhiChart is a **React component** that you can drop into **any React application** to display professional candlestick charts. It works everywhere:
|
|
15
|
+
|
|
16
|
+
- ✅ Create React App
|
|
17
|
+
- ✅ Next.js (App Router & Pages Router)
|
|
18
|
+
- ✅ Vite
|
|
19
|
+
- ✅ Remix
|
|
20
|
+
- ✅ Any React framework
|
|
21
|
+
|
|
22
|
+
**Two Ways to Use:**
|
|
23
|
+
|
|
24
|
+
1. **Standalone** - Just pass a token address, and it displays a chart (perfect for demos or testing)
|
|
25
|
+
2. **Connected** - Pass your own WebSocket connection and data for full real-time updates (production use)
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## ⚡ Quick Start (30 seconds)
|
|
30
|
+
|
|
31
|
+
### 1. Install
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npm install funhi-chart react react-dom lightweight-charts socket.io-client axios
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### 2. Use in Your App
|
|
38
|
+
|
|
39
|
+
```tsx
|
|
40
|
+
import { FunhiChart } from 'funhi-chart';
|
|
41
|
+
|
|
42
|
+
function App() {
|
|
43
|
+
return (
|
|
44
|
+
<FunhiChart
|
|
45
|
+
mint="YourTokenMintAddress"
|
|
46
|
+
ticker="SOL"
|
|
47
|
+
tokenName="Solana"
|
|
48
|
+
/>
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
**That's it!** 🎉 You now have a working chart.
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## 📚 Complete Examples
|
|
58
|
+
|
|
59
|
+
### Example 1: Basic Usage (Any React App)
|
|
60
|
+
|
|
61
|
+
Works in Create React App, Vite, or any React setup:
|
|
62
|
+
|
|
63
|
+
```tsx
|
|
64
|
+
import React from 'react';
|
|
65
|
+
import { FunhiChart } from 'funhi-chart';
|
|
66
|
+
|
|
67
|
+
function TradingPage() {
|
|
68
|
+
return (
|
|
69
|
+
<div style={{ width: '100%', height: '600px' }}>
|
|
70
|
+
<FunhiChart
|
|
71
|
+
mint="SolTokenMintAddress"
|
|
72
|
+
ticker="SOL"
|
|
73
|
+
tokenName="Solana"
|
|
74
|
+
/>
|
|
75
|
+
</div>
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export default TradingPage;
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Example 2: With Your Own WebSocket (Recommended)
|
|
83
|
+
|
|
84
|
+
Connect to your backend for real-time updates:
|
|
85
|
+
|
|
86
|
+
```tsx
|
|
87
|
+
import React, { useState, useEffect } from 'react';
|
|
88
|
+
import { FunhiChart } from 'funhi-chart';
|
|
89
|
+
import { io } from 'socket.io-client';
|
|
90
|
+
|
|
91
|
+
function LiveChart() {
|
|
92
|
+
const [socket, setSocket] = useState(null);
|
|
93
|
+
const [connected, setConnected] = useState(false);
|
|
94
|
+
const [marketCap, setMarketCap] = useState(0);
|
|
95
|
+
|
|
96
|
+
useEffect(() => {
|
|
97
|
+
// Connect to your backend
|
|
98
|
+
const newSocket = io('https://your-backend.com');
|
|
99
|
+
newSocket.on('connect', () => setConnected(true));
|
|
100
|
+
newSocket.on('marketCap', (data) => setMarketCap(data.value));
|
|
101
|
+
setSocket(newSocket);
|
|
102
|
+
|
|
103
|
+
return () => newSocket.close();
|
|
104
|
+
}, []);
|
|
105
|
+
|
|
106
|
+
return (
|
|
107
|
+
<FunhiChart
|
|
108
|
+
mint="TokenAddress"
|
|
109
|
+
ticker="TOKEN"
|
|
110
|
+
tokenName="My Token"
|
|
111
|
+
// Connect to your WebSocket
|
|
112
|
+
socket={socket}
|
|
113
|
+
isConnected={connected}
|
|
114
|
+
currentMarketCap={marketCap}
|
|
115
|
+
/>
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Example 3: Next.js (App Router)
|
|
121
|
+
|
|
122
|
+
For Next.js, use dynamic import to avoid SSR issues:
|
|
123
|
+
|
|
124
|
+
```tsx
|
|
125
|
+
'use client';
|
|
126
|
+
import dynamic from 'next/dynamic';
|
|
127
|
+
|
|
128
|
+
const FunhiChart = dynamic(
|
|
129
|
+
() => import('funhi-chart').then(mod => mod.FunhiChart),
|
|
130
|
+
{ ssr: false }
|
|
131
|
+
);
|
|
132
|
+
|
|
133
|
+
export default function ChartPage() {
|
|
134
|
+
return <FunhiChart mint="TokenAddress" ticker="SOL" />;
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Example 4: TypeScript
|
|
139
|
+
|
|
140
|
+
Full type safety with TypeScript:
|
|
141
|
+
|
|
142
|
+
```tsx
|
|
143
|
+
import React from 'react';
|
|
144
|
+
import { FunhiChart, ChartProps } from 'funhi-chart';
|
|
145
|
+
import { Socket } from 'socket.io-client';
|
|
146
|
+
|
|
147
|
+
interface MyChartProps {
|
|
148
|
+
tokenAddress: string;
|
|
149
|
+
symbol: string;
|
|
150
|
+
socket?: Socket;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const MyChart: React.FC<MyChartProps> = ({ tokenAddress, symbol, socket }) => {
|
|
154
|
+
return (
|
|
155
|
+
<FunhiChart
|
|
156
|
+
mint={tokenAddress}
|
|
157
|
+
ticker={symbol}
|
|
158
|
+
socket={socket}
|
|
159
|
+
/>
|
|
160
|
+
);
|
|
161
|
+
};
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
---
|
|
165
|
+
|
|
166
|
+
## 🎨 Features
|
|
167
|
+
|
|
168
|
+
- 🚀 **Real-time Updates** - Connect your WebSocket for live price updates
|
|
169
|
+
- 📊 **Multiple Timeframes** - 1m, 5m, 15m, 1h, 4h, 1d candlestick charts
|
|
170
|
+
- 🎨 **Beautiful UI** - Professional TradingView-style interface
|
|
171
|
+
- ⚡ **High Performance** - Handles thousands of data points smoothly
|
|
172
|
+
- 📱 **Responsive** - Works on mobile, tablet, and desktop
|
|
173
|
+
- 🎯 **TypeScript** - Full type definitions included
|
|
174
|
+
- 🔌 **Flexible** - Use standalone or with your own data
|
|
175
|
+
- 💾 **Data Persistence** - Automatic candle data caching
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
## 📖 API Reference
|
|
180
|
+
|
|
181
|
+
### Props
|
|
182
|
+
|
|
183
|
+
All available props for the `FunhiChart` component:
|
|
184
|
+
|
|
185
|
+
| Prop | Type | Required | Default | Description |
|
|
186
|
+
|------|------|----------|---------|-------------|
|
|
187
|
+
| `mint` | `string` | ✅ **Yes** | - | Token mint address (Solana address) |
|
|
188
|
+
| `ticker` | `string` | No | `""` | Token symbol (e.g., "SOL", "BTC") |
|
|
189
|
+
| `tokenName` | `string` | No | `""` | Full token name (e.g., "Solana") |
|
|
190
|
+
| `socket` | `Socket` | No | `null` | Your Socket.IO connection for live updates |
|
|
191
|
+
| `isConnected` | `boolean` | No | `false` | WebSocket connection status |
|
|
192
|
+
| `currentMarketCap` | `number` | No | `0` | Live market cap to display |
|
|
193
|
+
| `analyticsConnected` | `boolean` | No | `false` | Analytics connection status |
|
|
194
|
+
| `analyticsLoading` | `boolean` | No | `false` | Loading state for analytics |
|
|
195
|
+
|
|
196
|
+
### TypeScript Types
|
|
197
|
+
|
|
198
|
+
```typescript
|
|
199
|
+
import { Socket } from 'socket.io-client';
|
|
200
|
+
|
|
201
|
+
interface ChartProps {
|
|
202
|
+
// Required
|
|
203
|
+
mint: string;
|
|
204
|
+
|
|
205
|
+
// Optional - Display
|
|
206
|
+
ticker?: string;
|
|
207
|
+
tokenName?: string;
|
|
208
|
+
|
|
209
|
+
// Optional - Real-time Data
|
|
210
|
+
socket?: Socket | null;
|
|
211
|
+
isConnected?: boolean;
|
|
212
|
+
currentMarketCap?: number;
|
|
213
|
+
analyticsConnected?: boolean;
|
|
214
|
+
analyticsLoading?: boolean;
|
|
215
|
+
}
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
### Exports
|
|
219
|
+
|
|
220
|
+
```tsx
|
|
221
|
+
// Main component
|
|
222
|
+
import { FunhiChart } from 'funhi-chart';
|
|
223
|
+
|
|
224
|
+
// TypeScript types
|
|
225
|
+
import type { ChartProps } from 'funhi-chart';
|
|
226
|
+
|
|
227
|
+
// Utility services (if needed)
|
|
228
|
+
import { candleStorageService, candleAggregation } from 'funhi-chart';
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
## 🚀 Framework-Specific Guides
|
|
232
|
+
|
|
233
|
+
### Create React App / Vite
|
|
234
|
+
|
|
235
|
+
Standard import works perfectly:
|
|
236
|
+
|
|
237
|
+
```tsx
|
|
238
|
+
import { FunhiChart } from 'funhi-chart';
|
|
239
|
+
|
|
240
|
+
function App() {
|
|
241
|
+
return <FunhiChart mint="address" ticker="SOL" />;
|
|
242
|
+
}
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
### Next.js (Important!)
|
|
246
|
+
|
|
247
|
+
Next.js requires dynamic import with `ssr: false` because the chart uses browser APIs:
|
|
248
|
+
|
|
249
|
+
```tsx
|
|
250
|
+
'use client';
|
|
251
|
+
import dynamic from 'next/dynamic';
|
|
252
|
+
|
|
253
|
+
const FunhiChart = dynamic(
|
|
254
|
+
() => import('funhi-chart').then(mod => mod.FunhiChart),
|
|
255
|
+
{ ssr: false, loading: () => <div>Loading...</div> }
|
|
256
|
+
);
|
|
257
|
+
|
|
258
|
+
export default function Page() {
|
|
259
|
+
return <FunhiChart mint="address" ticker="SOL" />;
|
|
260
|
+
}
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
### Remix
|
|
264
|
+
|
|
265
|
+
Use client-side only rendering:
|
|
266
|
+
|
|
267
|
+
```tsx
|
|
268
|
+
import { ClientOnly } from 'remix-utils';
|
|
269
|
+
import { FunhiChart } from 'funhi-chart';
|
|
270
|
+
|
|
271
|
+
export default function Route() {
|
|
272
|
+
return (
|
|
273
|
+
<ClientOnly>
|
|
274
|
+
{() => <FunhiChart mint="address" ticker="SOL" />}
|
|
275
|
+
</ClientOnly>
|
|
276
|
+
);
|
|
277
|
+
}
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
### Gatsby
|
|
281
|
+
|
|
282
|
+
Use `loadable-components` or dynamic import in `useEffect`:
|
|
283
|
+
|
|
284
|
+
```tsx
|
|
285
|
+
import React, { useEffect, useState } from 'react';
|
|
286
|
+
|
|
287
|
+
function ChartPage() {
|
|
288
|
+
const [Chart, setChart] = useState(null);
|
|
289
|
+
|
|
290
|
+
useEffect(() => {
|
|
291
|
+
import('funhi-chart').then(mod => setChart(() => mod.FunhiChart));
|
|
292
|
+
}, []);
|
|
293
|
+
|
|
294
|
+
if (!Chart) return <div>Loading...</div>;
|
|
295
|
+
return <Chart mint="address" ticker="SOL" />;
|
|
296
|
+
}
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
## 💡 Common Use Cases
|
|
300
|
+
|
|
301
|
+
### 1. Quick Demo or Prototype
|
|
302
|
+
Just need a chart fast? One line does it:
|
|
303
|
+
|
|
304
|
+
```tsx
|
|
305
|
+
<FunhiChart mint="SolanaTokenAddress" ticker="SOL" />
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
### 2. Static Portfolio Tracker
|
|
309
|
+
Display charts for multiple tokens without live updates:
|
|
310
|
+
|
|
311
|
+
```tsx
|
|
312
|
+
{tokens.map(token => (
|
|
313
|
+
<FunhiChart
|
|
314
|
+
key={token.mint}
|
|
315
|
+
mint={token.mint}
|
|
316
|
+
ticker={token.symbol}
|
|
317
|
+
tokenName={token.name}
|
|
318
|
+
/>
|
|
319
|
+
))}
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
### 3. Live Trading Dashboard
|
|
323
|
+
Connect to your backend for real-time candle updates:
|
|
324
|
+
|
|
325
|
+
```tsx
|
|
326
|
+
const { socket, connected } = useYourSocket();
|
|
327
|
+
|
|
328
|
+
<FunhiChart
|
|
329
|
+
mint={selectedToken}
|
|
330
|
+
ticker="BTC"
|
|
331
|
+
socket={socket}
|
|
332
|
+
isConnected={connected}
|
|
333
|
+
/>
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
### 4. Full Analytics Platform
|
|
337
|
+
Pass all data for complete monitoring:
|
|
338
|
+
|
|
339
|
+
```tsx
|
|
340
|
+
<FunhiChart
|
|
341
|
+
mint={token.mint}
|
|
342
|
+
ticker={token.symbol}
|
|
343
|
+
tokenName={token.name}
|
|
344
|
+
socket={websocket}
|
|
345
|
+
isConnected={socketStatus}
|
|
346
|
+
currentMarketCap={liveMarketCap}
|
|
347
|
+
analyticsConnected={analyticsStatus}
|
|
348
|
+
analyticsLoading={isLoading}
|
|
349
|
+
/>
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
## 🔧 Advanced Features
|
|
353
|
+
|
|
354
|
+
### Timeframe Switching
|
|
355
|
+
|
|
356
|
+
The chart includes built-in buttons to switch between timeframes:
|
|
357
|
+
- **1m** - 1 minute candles
|
|
358
|
+
- **5m** - 5 minute candles
|
|
359
|
+
- **15m** - 15 minute candles
|
|
360
|
+
- **1h** - 1 hour candles
|
|
361
|
+
- **4h** - 4 hour candles
|
|
362
|
+
- **1d** - 1 day candles
|
|
363
|
+
|
|
364
|
+
Users can click to switch anytime - the chart automatically aggregates data.
|
|
365
|
+
|
|
366
|
+
### Data Persistence
|
|
367
|
+
|
|
368
|
+
Candle data is automatically saved to your backend database:
|
|
369
|
+
|
|
370
|
+
```typescript
|
|
371
|
+
import { candleStorageService } from 'funhi-chart';
|
|
372
|
+
|
|
373
|
+
// Manually save candles (usually handled automatically)
|
|
374
|
+
await candleStorageService.saveCandles({
|
|
375
|
+
mint: 'your-token-mint',
|
|
376
|
+
candles: candleData,
|
|
377
|
+
timeFrame: 60 // 1 minute
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
// Retrieve candles
|
|
381
|
+
const candles = await candleStorageService.getCandles({
|
|
382
|
+
mint: 'your-token-mint',
|
|
383
|
+
timeFrame: 60,
|
|
384
|
+
limit: 1000
|
|
385
|
+
});
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
### Custom Aggregation
|
|
389
|
+
|
|
390
|
+
The chart includes utilities for aggregating 1-minute candles to larger timeframes:
|
|
391
|
+
|
|
392
|
+
```typescript
|
|
393
|
+
import { candleAggregation, CandleData } from 'funhi-chart';
|
|
394
|
+
|
|
395
|
+
const oneMinuteCandles: CandleData[] = [...]; // Your 1m candle data
|
|
396
|
+
|
|
397
|
+
// Aggregate to 5-minute candles
|
|
398
|
+
const fiveMinuteCandles = candleAggregation.aggregateCandles(
|
|
399
|
+
oneMinuteCandles,
|
|
400
|
+
300 // 5 minutes in seconds
|
|
401
|
+
);
|
|
402
|
+
|
|
403
|
+
// Fill gaps in candle data
|
|
404
|
+
const filledCandles = candleAggregation.fillGaps(
|
|
405
|
+
fiveMinuteCandles,
|
|
406
|
+
300 // timeframe in seconds
|
|
407
|
+
);
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
## API Reference
|
|
411
|
+
|
|
412
|
+
### Components
|
|
413
|
+
|
|
414
|
+
#### FunhiChart
|
|
415
|
+
|
|
416
|
+
Main chart component that displays real-time candlestick data.
|
|
417
|
+
|
|
418
|
+
```tsx
|
|
419
|
+
<FunhiChart
|
|
420
|
+
mint="TokenMintAddress"
|
|
421
|
+
ticker="TOKEN"
|
|
422
|
+
tokenName="Token Name"
|
|
423
|
+
/>
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
### Hooks
|
|
427
|
+
|
|
428
|
+
#### useSocket
|
|
429
|
+
|
|
430
|
+
Hook for managing Socket.IO connections:
|
|
431
|
+
|
|
432
|
+
```tsx
|
|
433
|
+
import { useSocket } from 'funhi-chart';
|
|
434
|
+
|
|
435
|
+
function MyComponent() {
|
|
436
|
+
const { socket, isConnected } = useSocket(socketInstance);
|
|
437
|
+
|
|
438
|
+
// Use socket connection
|
|
439
|
+
}
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
#### useOptimizedTokenAnalytics
|
|
443
|
+
|
|
444
|
+
Hook for accessing token analytics data:
|
|
445
|
+
|
|
446
|
+
```tsx
|
|
447
|
+
import { useOptimizedTokenAnalytics } from 'funhi-chart';
|
|
448
|
+
|
|
449
|
+
function MyComponent() {
|
|
450
|
+
const analytics = useOptimizedTokenAnalytics('token-mint', analyticsData);
|
|
451
|
+
|
|
452
|
+
console.log(analytics.currentPrice);
|
|
453
|
+
console.log(analytics.currentMarketCap);
|
|
454
|
+
}
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
### Services
|
|
458
|
+
|
|
459
|
+
#### candleStorageService
|
|
460
|
+
|
|
461
|
+
Service for managing candle data persistence:
|
|
462
|
+
|
|
463
|
+
```typescript
|
|
464
|
+
import { candleStorageService } from 'funhi-chart';
|
|
465
|
+
|
|
466
|
+
// Save candles
|
|
467
|
+
await candleStorageService.saveCandles({
|
|
468
|
+
mint: 'token-mint',
|
|
469
|
+
candles: [...],
|
|
470
|
+
timeFrame: 60
|
|
471
|
+
});
|
|
472
|
+
|
|
473
|
+
// Get candles
|
|
474
|
+
const candles = await candleStorageService.getCandles({
|
|
475
|
+
mint: 'token-mint',
|
|
476
|
+
timeFrame: 60,
|
|
477
|
+
limit: 1000
|
|
478
|
+
});
|
|
479
|
+
```
|
|
480
|
+
|
|
481
|
+
### Utils
|
|
482
|
+
|
|
483
|
+
#### candleAggregation
|
|
484
|
+
|
|
485
|
+
Utility for aggregating candle data:
|
|
486
|
+
|
|
487
|
+
```typescript
|
|
488
|
+
import { candleAggregation } from 'funhi-chart';
|
|
489
|
+
|
|
490
|
+
// Aggregate candles
|
|
491
|
+
const aggregated = candleAggregation.aggregateCandles(
|
|
492
|
+
oneMinuteCandles,
|
|
493
|
+
300 // target timeframe in seconds
|
|
494
|
+
);
|
|
495
|
+
|
|
496
|
+
// Fill gaps
|
|
497
|
+
const filled = candleAggregation.fillGaps(
|
|
498
|
+
candles,
|
|
499
|
+
300 // timeframe in seconds
|
|
500
|
+
);
|
|
501
|
+
|
|
502
|
+
// Get required candle count
|
|
503
|
+
const required = candleAggregation.getRequiredOneMinuteCandles(
|
|
504
|
+
3600, // 1 hour
|
|
505
|
+
1000 // target 1000 candles
|
|
506
|
+
);
|
|
507
|
+
```
|
|
508
|
+
|
|
509
|
+
## Backend Requirements
|
|
510
|
+
|
|
511
|
+
The chart component expects a backend API with the following endpoints:
|
|
512
|
+
|
|
513
|
+
### Get Candles
|
|
514
|
+
|
|
515
|
+
```
|
|
516
|
+
GET /api/ohlcv/candles/:mint?timeFrame=60&limit=1000
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
Response:
|
|
520
|
+
```json
|
|
521
|
+
{
|
|
522
|
+
"success": true,
|
|
523
|
+
"data": {
|
|
524
|
+
"candles": [
|
|
525
|
+
{
|
|
526
|
+
"time": 1234567890,
|
|
527
|
+
"open": 100.5,
|
|
528
|
+
"high": 102.3,
|
|
529
|
+
"low": 99.8,
|
|
530
|
+
"close": 101.2,
|
|
531
|
+
"volume": 1500
|
|
532
|
+
}
|
|
533
|
+
]
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
```
|
|
537
|
+
|
|
538
|
+
### Save Candles
|
|
539
|
+
|
|
540
|
+
```
|
|
541
|
+
POST /api/ohlcv/candles/save
|
|
542
|
+
```
|
|
543
|
+
|
|
544
|
+
Request body:
|
|
545
|
+
```json
|
|
546
|
+
{
|
|
547
|
+
"mint": "token-mint-address",
|
|
548
|
+
"timeFrame": 60,
|
|
549
|
+
"candles": [...]
|
|
550
|
+
}
|
|
551
|
+
```
|
|
552
|
+
|
|
553
|
+
### WebSocket Events
|
|
554
|
+
|
|
555
|
+
The backend should support these Socket.IO events:
|
|
556
|
+
|
|
557
|
+
- `ohlcv:subscribe` - Subscribe to OHLCV updates
|
|
558
|
+
- `ohlcv:update` - Receive candle updates
|
|
559
|
+
- `heartbeat` - Receive periodic updates
|
|
560
|
+
- `chartUpdate` - Receive chart data updates
|
|
561
|
+
|
|
562
|
+
## Styling
|
|
563
|
+
|
|
564
|
+
The chart uses Tailwind CSS classes. Make sure you have Tailwind CSS configured in your project, or provide custom CSS:
|
|
565
|
+
|
|
566
|
+
```css
|
|
567
|
+
/* Custom styling example */
|
|
568
|
+
.chart-container {
|
|
569
|
+
width: 100%;
|
|
570
|
+
height: 600px;
|
|
571
|
+
border-radius: 12px;
|
|
572
|
+
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
|
573
|
+
}
|
|
574
|
+
```
|
|
575
|
+
|
|
576
|
+
## Examples
|
|
577
|
+
|
|
578
|
+
### Example 1: Basic Integration
|
|
579
|
+
|
|
580
|
+
```tsx
|
|
581
|
+
import React from 'react';
|
|
582
|
+
import { FunhiChart } from 'funhi-chart';
|
|
583
|
+
|
|
584
|
+
export default function TradingPage() {
|
|
585
|
+
return (
|
|
586
|
+
<div className="container mx-auto p-4">
|
|
587
|
+
<h1 className="text-2xl font-bold mb-4">Live Trading Chart</h1>
|
|
588
|
+
<FunhiChart
|
|
589
|
+
mint="YOUR_TOKEN_MINT_ADDRESS"
|
|
590
|
+
ticker="TOKEN"
|
|
591
|
+
tokenName="Your Token Name"
|
|
592
|
+
/>
|
|
593
|
+
</div>
|
|
594
|
+
);
|
|
595
|
+
}
|
|
596
|
+
```
|
|
597
|
+
|
|
598
|
+
### Example 2: With Custom Analytics
|
|
599
|
+
|
|
600
|
+
```tsx
|
|
601
|
+
import React, { useState, useEffect } from 'react';
|
|
602
|
+
import { FunhiChart } from 'funhi-chart';
|
|
603
|
+
import axios from 'axios';
|
|
604
|
+
|
|
605
|
+
export default function AdvancedChart() {
|
|
606
|
+
const [analyticsData, setAnalyticsData] = useState(null);
|
|
607
|
+
|
|
608
|
+
useEffect(() => {
|
|
609
|
+
// Fetch analytics data from your API
|
|
610
|
+
async function fetchAnalytics() {
|
|
611
|
+
const response = await axios.get('/api/token/analytics');
|
|
612
|
+
setAnalyticsData(response.data);
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
fetchAnalytics();
|
|
616
|
+
}, []);
|
|
617
|
+
|
|
618
|
+
return (
|
|
619
|
+
<div className="w-full">
|
|
620
|
+
<FunhiChart
|
|
621
|
+
mint="YOUR_TOKEN_MINT_ADDRESS"
|
|
622
|
+
ticker="TOKEN"
|
|
623
|
+
tokenName="Your Token Name"
|
|
624
|
+
/>
|
|
625
|
+
|
|
626
|
+
{analyticsData && (
|
|
627
|
+
<div className="mt-4">
|
|
628
|
+
<h2>Token Analytics</h2>
|
|
629
|
+
{/* Display analytics data */}
|
|
630
|
+
</div>
|
|
631
|
+
)}
|
|
632
|
+
</div>
|
|
633
|
+
);
|
|
634
|
+
}
|
|
635
|
+
```
|
|
636
|
+
|
|
637
|
+
### Example 3: Multiple Charts
|
|
638
|
+
|
|
639
|
+
```tsx
|
|
640
|
+
import React from 'react';
|
|
641
|
+
import { FunhiChart } from 'funhi-chart';
|
|
642
|
+
|
|
643
|
+
const tokens = [
|
|
644
|
+
{ mint: 'TOKEN1_MINT', ticker: 'TK1', name: 'Token 1' },
|
|
645
|
+
{ mint: 'TOKEN2_MINT', ticker: 'TK2', name: 'Token 2' },
|
|
646
|
+
{ mint: 'TOKEN3_MINT', ticker: 'TK3', name: 'Token 3' },
|
|
647
|
+
];
|
|
648
|
+
|
|
649
|
+
export default function MultiChart() {
|
|
650
|
+
return (
|
|
651
|
+
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 p-4">
|
|
652
|
+
{tokens.map(token => (
|
|
653
|
+
<div key={token.mint} className="border rounded-lg p-4">
|
|
654
|
+
<h3 className="text-lg font-bold mb-2">{token.name}</h3>
|
|
655
|
+
<FunhiChart
|
|
656
|
+
mint={token.mint}
|
|
657
|
+
ticker={token.ticker}
|
|
658
|
+
tokenName={token.name}
|
|
659
|
+
/>
|
|
660
|
+
</div>
|
|
661
|
+
))}
|
|
662
|
+
</div>
|
|
663
|
+
);
|
|
664
|
+
}
|
|
665
|
+
```
|
|
666
|
+
|
|
667
|
+
## TypeScript Support
|
|
668
|
+
|
|
669
|
+
This package is written in TypeScript and includes type definitions:
|
|
670
|
+
|
|
671
|
+
```typescript
|
|
672
|
+
import { FunhiChart, CandleData, TimeFrame } from 'funhi-chart';
|
|
673
|
+
|
|
674
|
+
const candle: CandleData = {
|
|
675
|
+
time: 1234567890,
|
|
676
|
+
open: 100,
|
|
677
|
+
high: 102,
|
|
678
|
+
low: 99,
|
|
679
|
+
close: 101,
|
|
680
|
+
volume: 1000
|
|
681
|
+
};
|
|
682
|
+
|
|
683
|
+
const timeFrame: TimeFrame = {
|
|
684
|
+
label: '1m',
|
|
685
|
+
value: '1m',
|
|
686
|
+
seconds: 60
|
|
687
|
+
};
|
|
688
|
+
```
|
|
689
|
+
|
|
690
|
+
## Performance Optimization
|
|
691
|
+
|
|
692
|
+
### Tips for Optimal Performance
|
|
693
|
+
|
|
694
|
+
1. **Limit Data**: Use the `limit` parameter when fetching candles:
|
|
695
|
+
```typescript
|
|
696
|
+
const candles = await candleStorageService.getCandles({
|
|
697
|
+
mint: 'token-mint',
|
|
698
|
+
timeFrame: 60,
|
|
699
|
+
limit: 500 // Limit to last 500 candles
|
|
700
|
+
});
|
|
701
|
+
```
|
|
702
|
+
|
|
703
|
+
2. **Debounce Updates**: The chart automatically debounces real-time updates to prevent excessive re-renders.
|
|
704
|
+
|
|
705
|
+
3. **Use Memoization**: When passing data to the chart, use React.memo() or useMemo():
|
|
706
|
+
```tsx
|
|
707
|
+
const ChartComponent = React.memo(() => (
|
|
708
|
+
<FunhiChart mint={mint} ticker={ticker} tokenName={tokenName} />
|
|
709
|
+
));
|
|
710
|
+
```
|
|
711
|
+
|
|
712
|
+
## ❓ Frequently Asked Questions
|
|
713
|
+
|
|
714
|
+
### Can I use this without Next.js?
|
|
715
|
+
|
|
716
|
+
**Yes!** FunhiChart works with any React application:
|
|
717
|
+
- Create React App ✅
|
|
718
|
+
- Vite ✅
|
|
719
|
+
- Remix ✅
|
|
720
|
+
- Gatsby ✅
|
|
721
|
+
- Plain React ✅
|
|
722
|
+
|
|
723
|
+
Only Next.js requires special handling (dynamic import with `ssr: false`).
|
|
724
|
+
|
|
725
|
+
### Do I need a backend?
|
|
726
|
+
|
|
727
|
+
**For basic use, no.** The chart can work standalone with just a `mint` address.
|
|
728
|
+
|
|
729
|
+
**For real-time updates, yes.** You need:
|
|
730
|
+
- A WebSocket server (Socket.IO)
|
|
731
|
+
- An API that provides candle data
|
|
732
|
+
|
|
733
|
+
### Can I use my own WebSocket connection?
|
|
734
|
+
|
|
735
|
+
**Yes!** Pass your socket as a prop:
|
|
736
|
+
|
|
737
|
+
```tsx
|
|
738
|
+
<FunhiChart mint="address" socket={yourSocket} isConnected={true} />
|
|
739
|
+
```
|
|
740
|
+
|
|
741
|
+
This is the recommended approach for production apps.
|
|
742
|
+
|
|
743
|
+
### Does it work with non-Solana tokens?
|
|
744
|
+
|
|
745
|
+
The `mint` prop is designed for Solana token addresses, but you can pass any unique identifier. The chart itself is blockchain-agnostic - it just displays candlestick data.
|
|
746
|
+
|
|
747
|
+
### Can I customize the appearance?
|
|
748
|
+
|
|
749
|
+
The chart has a professional design out of the box. The component itself doesn't expose styling props currently, but you can wrap it in a container with custom dimensions:
|
|
750
|
+
|
|
751
|
+
```tsx
|
|
752
|
+
<div style={{ width: '100%', height: '600px', background: '#000' }}>
|
|
753
|
+
<FunhiChart mint="address" />
|
|
754
|
+
</div>
|
|
755
|
+
```
|
|
756
|
+
|
|
757
|
+
### How do I show real-time market cap?
|
|
758
|
+
|
|
759
|
+
Pass the `currentMarketCap` prop:
|
|
760
|
+
|
|
761
|
+
```tsx
|
|
762
|
+
<FunhiChart
|
|
763
|
+
mint="address"
|
|
764
|
+
currentMarketCap={123456789}
|
|
765
|
+
analyticsConnected={true}
|
|
766
|
+
/>
|
|
767
|
+
```
|
|
768
|
+
|
|
769
|
+
### What's the difference between standalone and connected mode?
|
|
770
|
+
|
|
771
|
+
| Feature | Standalone | Connected |
|
|
772
|
+
|---------|-----------|-----------|
|
|
773
|
+
| **Setup** | Just pass `mint` | Pass `socket` and data props |
|
|
774
|
+
| **Real-time updates** | ❌ No | ✅ Yes |
|
|
775
|
+
| **Live market cap** | ❌ No | ✅ Yes |
|
|
776
|
+
| **Connection badge** | Shows "Disconnected" | Shows "Connected" |
|
|
777
|
+
| **Best for** | Demos, testing | Production apps |
|
|
778
|
+
|
|
779
|
+
### Can I display multiple charts on one page?
|
|
780
|
+
|
|
781
|
+
**Yes!** Just render multiple components:
|
|
782
|
+
|
|
783
|
+
```tsx
|
|
784
|
+
<FunhiChart mint="token1" ticker="SOL" />
|
|
785
|
+
<FunhiChart mint="token2" ticker="BTC" />
|
|
786
|
+
<FunhiChart mint="token3" ticker="ETH" />
|
|
787
|
+
```
|
|
788
|
+
|
|
789
|
+
Each chart is independent.
|
|
790
|
+
|
|
791
|
+
### Is TypeScript required?
|
|
792
|
+
|
|
793
|
+
**No.** The package works with JavaScript. TypeScript types are included as a bonus if you use TypeScript.
|
|
794
|
+
|
|
795
|
+
### What license is this?
|
|
796
|
+
|
|
797
|
+
MIT License - free to use in commercial projects!
|
|
798
|
+
|
|
799
|
+
---
|
|
800
|
+
|
|
801
|
+
## 🐛 Troubleshooting
|
|
802
|
+
|
|
803
|
+
### Chart shows "Disconnected" badge
|
|
804
|
+
|
|
805
|
+
This means no WebSocket is connected. Either:
|
|
806
|
+
1. You're using standalone mode (expected behavior)
|
|
807
|
+
2. Pass `socket` and `isConnected` props for real-time mode
|
|
808
|
+
|
|
809
|
+
### Next.js: "window is not defined" error
|
|
810
|
+
|
|
811
|
+
You forgot to use dynamic import! See the [Next.js section](#nextjs-important).
|
|
812
|
+
|
|
813
|
+
### Chart not displaying data
|
|
814
|
+
|
|
815
|
+
1. Verify the `mint` address is correct
|
|
816
|
+
2. Check browser console for API errors
|
|
817
|
+
3. Ensure your backend API is running
|
|
818
|
+
4. Check the API URL is configured correctly
|
|
819
|
+
|
|
820
|
+
### Performance issues with multiple charts
|
|
821
|
+
|
|
822
|
+
Use virtualization or lazy loading:
|
|
823
|
+
|
|
824
|
+
```tsx
|
|
825
|
+
import { lazy, Suspense } from 'react';
|
|
826
|
+
|
|
827
|
+
const FunhiChart = lazy(() => import('funhi-chart').then(m => ({ default: m.FunhiChart })));
|
|
828
|
+
|
|
829
|
+
<Suspense fallback={<Loading />}>
|
|
830
|
+
<FunhiChart mint="address" />
|
|
831
|
+
</Suspense>
|
|
832
|
+
```
|
|
833
|
+
|
|
834
|
+
## Contributing
|
|
835
|
+
|
|
836
|
+
Contributions are welcome! Please follow these steps:
|
|
837
|
+
|
|
838
|
+
1. Fork the repository
|
|
839
|
+
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
|
|
840
|
+
3. Commit your changes (`git commit -m 'Add amazing feature'`)
|
|
841
|
+
4. Push to the branch (`git push origin feature/amazing-feature`)
|
|
842
|
+
5. Open a Pull Request
|
|
843
|
+
|
|
844
|
+
## License
|
|
845
|
+
|
|
846
|
+
MIT © Funhi Team
|
|
847
|
+
|
|
848
|
+
## Support
|
|
849
|
+
|
|
850
|
+
- **Issues**: [GitHub Issues](https://github.com/funhi/funhi-chart/issues)
|
|
851
|
+
- **Email**: support@funhi.com
|
|
852
|
+
- **Documentation**: [Full Documentation](https://github.com/funhi/funhi-chart#readme)
|
|
853
|
+
|
|
854
|
+
## 📝 Changelog
|
|
855
|
+
|
|
856
|
+
### Version 1.0.0 (Current)
|
|
857
|
+
|
|
858
|
+
**New Features:**
|
|
859
|
+
- ✨ Component renamed to `FunhiChart` (with backward compatibility)
|
|
860
|
+
- 🔌 External socket prop support for seamless integration
|
|
861
|
+
- 📊 Live analytics props (market cap, connection status)
|
|
862
|
+
- 🎯 Works with any React framework
|
|
863
|
+
- ⚡ Production-ready with real-time updates
|
|
864
|
+
- 📱 Fully responsive design
|
|
865
|
+
- 🎨 Multiple timeframes (1m, 5m, 15m, 1h, 4h, 1d)
|
|
866
|
+
- 💾 Automatic data persistence
|
|
867
|
+
- 🎯 Full TypeScript support
|
|
868
|
+
|
|
869
|
+
**Breaking Changes:**
|
|
870
|
+
- None! Fully backward compatible with `ProfessionalTradingChartRedux`
|
|
871
|
+
|
|
872
|
+
---
|
|
873
|
+
|
|
874
|
+
## 🙏 Credits
|
|
875
|
+
|
|
876
|
+
Built with:
|
|
877
|
+
- [Lightweight Charts](https://github.com/tradingview/lightweight-charts) by TradingView
|
|
878
|
+
- [Socket.IO](https://socket.io/) for real-time communication
|
|
879
|
+
- [React](https://react.dev/) for UI
|
|
880
|
+
- Love ❤️ by the Funhi Team
|
|
881
|
+
|