mirror of
https://github.com/NoFxAiOS/nofx.git
synced 2026-07-03 11:00:58 +08:00
Merge pull request #235 from Icyoung/beta
Beta Beta mode support、UI design optimize
This commit is contained in:
93
.github/ISSUE_TEMPLATE/bounty_claim.md
vendored
Normal file
93
.github/ISSUE_TEMPLATE/bounty_claim.md
vendored
Normal file
@@ -0,0 +1,93 @@
|
||||
---
|
||||
name: Bounty Claim
|
||||
about: Claim a bounty task or propose a new bounty
|
||||
title: '[BOUNTY CLAIM] '
|
||||
labels: bounty
|
||||
assignees: ''
|
||||
---
|
||||
|
||||
## 💰 Bounty Information
|
||||
|
||||
**Claiming existing bounty?**
|
||||
- Issue #: <!-- Link to existing bounty issue -->
|
||||
- Bounty amount: <!-- If specified -->
|
||||
|
||||
**OR proposing new bounty?**
|
||||
- Proposed feature/fix: <!-- Brief description -->
|
||||
- Estimated effort: [Small / Medium / Large]
|
||||
|
||||
---
|
||||
|
||||
## 👤 About You
|
||||
|
||||
**Name/Username:** <!-- Your name or GitHub username -->
|
||||
|
||||
**Contact:**
|
||||
- GitHub: @your_username
|
||||
- Telegram: @your_telegram (optional)
|
||||
- Email: your@email.com (optional)
|
||||
|
||||
**Relevant Experience:**
|
||||
- <!-- Link to your GitHub profile -->
|
||||
- <!-- Previous contributions or similar projects -->
|
||||
- <!-- Relevant skills (Go, React, trading systems, etc.) -->
|
||||
|
||||
---
|
||||
|
||||
## 📋 Implementation Plan
|
||||
|
||||
### 1. Approach
|
||||
<!-- Describe your technical approach -->
|
||||
- How will you implement this?
|
||||
- What components will be affected?
|
||||
- Any dependencies or libraries needed?
|
||||
|
||||
### 2. Timeline
|
||||
- **Start date:** <!-- When you plan to start -->
|
||||
- **Estimated completion:** <!-- How long will it take? -->
|
||||
- **Milestones:**
|
||||
- [ ] Week 1: ...
|
||||
- [ ] Week 2: ...
|
||||
- [ ] Week 3: ...
|
||||
|
||||
### 3. Deliverables
|
||||
- [ ] Working code (merged PR)
|
||||
- [ ] Unit tests (if applicable)
|
||||
- [ ] Documentation updates
|
||||
- [ ] Demo video/screenshots
|
||||
|
||||
---
|
||||
|
||||
## 🔍 Questions for Maintainers
|
||||
|
||||
<!-- Any questions you have about the requirements? -->
|
||||
|
||||
1.
|
||||
2.
|
||||
3.
|
||||
|
||||
---
|
||||
|
||||
## 📚 References
|
||||
|
||||
<!-- Any relevant links, documentation, or examples -->
|
||||
|
||||
-
|
||||
|
||||
---
|
||||
|
||||
## ✅ Acknowledgment
|
||||
|
||||
By claiming this bounty, I acknowledge that:
|
||||
- [ ] I have read the [Contributing Guide](../../CONTRIBUTING.md)
|
||||
- [ ] I will follow the [Code of Conduct](../../CODE_OF_CONDUCT.md)
|
||||
- [ ] I understand the acceptance criteria
|
||||
- [ ] My contribution will be licensed under MIT License
|
||||
- [ ] Payment is subject to successful PR merge
|
||||
|
||||
---
|
||||
|
||||
**For maintainers:**
|
||||
- [ ] Bounty claim approved
|
||||
- [ ] Issue assigned to claimant
|
||||
- [ ] Timeline agreed upon
|
||||
47
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
47
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
---
|
||||
name: Bug Report
|
||||
about: Report a bug to help us improve NOFX
|
||||
title: '[BUG] '
|
||||
labels: bug
|
||||
assignees: ''
|
||||
---
|
||||
|
||||
## 🐛 Bug Description
|
||||
<!-- A clear and concise description of what the bug is -->
|
||||
|
||||
## 📋 Steps to Reproduce
|
||||
1. Go to '...'
|
||||
2. Click on '...'
|
||||
3. Run command '...'
|
||||
4. See error
|
||||
|
||||
## ✅ Expected Behavior
|
||||
<!-- What you expected to happen -->
|
||||
|
||||
## ❌ Actual Behavior
|
||||
<!-- What actually happened -->
|
||||
|
||||
## 📸 Screenshots / Logs
|
||||
<!-- If applicable, add screenshots or error logs to help explain your problem -->
|
||||
|
||||
```
|
||||
Paste logs here
|
||||
```
|
||||
|
||||
## 💻 Environment
|
||||
- **OS:** [e.g. macOS 13, Ubuntu 22.04, Windows 11]
|
||||
- **Go Version:** [e.g. 1.21.5]
|
||||
- **Node.js Version:** [e.g. 18.17.0]
|
||||
- **NOFX Version/Commit:** [e.g. v3.0.0 or commit hash]
|
||||
- **Deployment Method:** [Docker / Manual / PM2]
|
||||
- **Exchange:** [Binance / Hyperliquid / Aster]
|
||||
|
||||
## 🔧 Additional Context
|
||||
<!-- Add any other context about the problem here -->
|
||||
|
||||
- Does this happen consistently or intermittently?
|
||||
- Did it work before? When did it break?
|
||||
- Any recent configuration changes?
|
||||
|
||||
## ✋ Possible Solution
|
||||
<!-- Optional: If you have ideas on how to fix this -->
|
||||
153
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
153
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,153 @@
|
||||
# Pull Request
|
||||
|
||||
## 📝 Description
|
||||
|
||||
<!-- Provide a brief summary of your changes -->
|
||||
|
||||
## 🎯 Type of Change
|
||||
|
||||
<!-- Mark the relevant option with an "x" -->
|
||||
|
||||
- [ ] 🐛 Bug fix (non-breaking change which fixes an issue)
|
||||
- [ ] ✨ New feature (non-breaking change which adds functionality)
|
||||
- [ ] 💥 Breaking change (fix or feature that would cause existing functionality to not work as expected)
|
||||
- [ ] 📝 Documentation update
|
||||
- [ ] 🎨 Code style update (formatting, renaming)
|
||||
- [ ] ♻️ Refactoring (no functional changes)
|
||||
- [ ] ⚡ Performance improvement
|
||||
- [ ] ✅ Test update
|
||||
- [ ] 🔧 Build/config change
|
||||
|
||||
## 🔗 Related Issues
|
||||
|
||||
<!-- Link related issues below. Use "Closes #123" to auto-close issues when PR is merged -->
|
||||
|
||||
- Closes #
|
||||
- Related to #
|
||||
|
||||
## 📋 Changes Made
|
||||
|
||||
<!-- List the specific changes you made -->
|
||||
|
||||
- Change 1
|
||||
- Change 2
|
||||
- Change 3
|
||||
|
||||
## 🧪 Testing
|
||||
|
||||
### Manual Testing
|
||||
|
||||
<!-- Describe how you tested your changes -->
|
||||
|
||||
- [ ] Tested locally (manual verification)
|
||||
- [ ] Tested on testnet (for exchange integrations)
|
||||
- [ ] Tested with different configurations
|
||||
- [ ] Verified no existing functionality broke
|
||||
|
||||
### Test Environment
|
||||
|
||||
- **OS:** [e.g. macOS, Ubuntu]
|
||||
- **Go Version:** [e.g. 1.21.5]
|
||||
- **Exchange:** [if applicable]
|
||||
|
||||
### Test Results
|
||||
|
||||
<!-- Paste relevant test output or describe results -->
|
||||
|
||||
```
|
||||
Test output here
|
||||
```
|
||||
|
||||
## 📸 Screenshots / Demo
|
||||
|
||||
<!-- If applicable, add screenshots or video demo -->
|
||||
|
||||
<!-- For UI changes, include before/after screenshots -->
|
||||
|
||||
**Before:**
|
||||
|
||||
|
||||
**After:**
|
||||
|
||||
|
||||
## ✅ Checklist
|
||||
|
||||
<!-- Mark completed items with an "x" -->
|
||||
|
||||
### Code Quality
|
||||
|
||||
- [ ] My code follows the project's code style ([Contributing Guide](../CONTRIBUTING.md))
|
||||
- [ ] I have performed a self-review of my code
|
||||
- [ ] I have commented my code, particularly in hard-to-understand areas
|
||||
- [ ] My changes generate no new warnings or errors
|
||||
- [ ] Code compiles successfully (`go build` / `npm run build`)
|
||||
- [ ] I have run `go fmt` (for Go code)
|
||||
|
||||
### Testing
|
||||
|
||||
- [ ] I have added tests that prove my fix is effective or that my feature works
|
||||
- [ ] New and existing unit tests pass locally
|
||||
- [ ] I have tested on testnet (for trading/exchange changes)
|
||||
|
||||
### Documentation
|
||||
|
||||
- [ ] I have updated the documentation accordingly
|
||||
- [ ] I have updated the README if needed
|
||||
- [ ] I have added inline code comments where necessary
|
||||
- [ ] I have updated type definitions (for TypeScript changes)
|
||||
|
||||
### Git
|
||||
|
||||
- [ ] My commits follow the conventional commits format (`feat:`, `fix:`, etc.)
|
||||
- [ ] I have rebased my branch on the latest `dev` branch
|
||||
- [ ] There are no merge conflicts
|
||||
|
||||
## 🔒 Security Considerations
|
||||
|
||||
<!-- Answer these questions for security-sensitive changes -->
|
||||
|
||||
- [ ] No API keys or secrets are hardcoded
|
||||
- [ ] User inputs are properly validated
|
||||
- [ ] No SQL injection vulnerabilities introduced
|
||||
- [ ] Authentication/authorization properly handled
|
||||
- [ ] N/A (not security-related)
|
||||
|
||||
## ⚡ Performance Impact
|
||||
|
||||
<!-- Describe any performance implications -->
|
||||
|
||||
- [ ] No significant performance impact
|
||||
- [ ] Performance improved
|
||||
- [ ] Performance may be impacted (explain below)
|
||||
|
||||
<!-- If performance impacted, explain: -->
|
||||
|
||||
## 📚 Additional Notes
|
||||
|
||||
<!-- Any additional information for reviewers -->
|
||||
|
||||
---
|
||||
|
||||
## For Bounty Claims
|
||||
|
||||
<!-- Fill this section only if claiming a bounty -->
|
||||
|
||||
- [ ] This PR is for bounty issue #
|
||||
- [ ] All acceptance criteria from the bounty issue are met
|
||||
- [ ] I have included a demo video/screenshots
|
||||
- [ ] I am ready for payment upon merge
|
||||
|
||||
**Payment Details:** <!-- Discuss privately with maintainers -->
|
||||
|
||||
---
|
||||
|
||||
## 🙏 Reviewer Notes
|
||||
|
||||
<!-- Optional: anything specific you want reviewers to focus on? -->
|
||||
|
||||
---
|
||||
|
||||
**By submitting this PR, I confirm that:**
|
||||
- [ ] I have read the [Contributing Guidelines](../CONTRIBUTING.md)
|
||||
- [ ] I agree to the [Code of Conduct](../CODE_OF_CONDUCT.md)
|
||||
- [ ] My contribution is licensed under the MIT License
|
||||
127
.github/labeler.yml
vendored
Normal file
127
.github/labeler.yml
vendored
Normal file
@@ -0,0 +1,127 @@
|
||||
# Auto-labeler configuration
|
||||
# Automatically adds labels based on changed files
|
||||
|
||||
# Area: Frontend
|
||||
'area: frontend':
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- 'web/**/*'
|
||||
- '*.tsx'
|
||||
- '*.ts'
|
||||
- '*.jsx'
|
||||
- '*.js'
|
||||
- '*.css'
|
||||
|
||||
# Area: Backend
|
||||
'area: backend':
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- '**/*.go'
|
||||
- 'go.mod'
|
||||
- 'go.sum'
|
||||
- 'cmd/**/*'
|
||||
- 'internal/**/*'
|
||||
- 'pkg/**/*'
|
||||
|
||||
# Area: Exchange
|
||||
'area: exchange':
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- 'internal/exchange/**/*'
|
||||
- 'pkg/exchange/**/*'
|
||||
- '**/binance*.go'
|
||||
- '**/hyperliquid*.go'
|
||||
- '**/aster*.go'
|
||||
- '**/okx*.go'
|
||||
- '**/bybit*.go'
|
||||
|
||||
# Area: AI
|
||||
'area: ai':
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- 'internal/ai/**/*'
|
||||
- 'pkg/ai/**/*'
|
||||
- '**/deepseek*.go'
|
||||
- '**/qwen*.go'
|
||||
- '**/openai*.go'
|
||||
- '**/claude*.go'
|
||||
|
||||
# Area: API
|
||||
'area: api':
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- 'internal/api/**/*'
|
||||
- 'pkg/api/**/*'
|
||||
- '**/handler*.go'
|
||||
- '**/router*.go'
|
||||
|
||||
# Area: Security
|
||||
'area: security':
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- '**/auth*.go'
|
||||
- '**/jwt*.go'
|
||||
- '**/encryption*.go'
|
||||
- '**/crypto*.go'
|
||||
- 'SECURITY.md'
|
||||
|
||||
# Area: Database
|
||||
'area: database':
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- 'internal/database/**/*'
|
||||
- 'internal/db/**/*'
|
||||
- '**/migration*.go'
|
||||
- '**/*.sql'
|
||||
- '**/schema*.go'
|
||||
|
||||
# Area: UI/UX
|
||||
'area: ui/ux':
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- 'web/src/components/**/*'
|
||||
- 'web/src/pages/**/*'
|
||||
- '**/*.css'
|
||||
- '**/style*.ts'
|
||||
|
||||
# Area: Deployment
|
||||
'area: deployment':
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- 'Dockerfile'
|
||||
- 'docker-compose*.yml'
|
||||
- '.github/workflows/**/*'
|
||||
- 'start.sh'
|
||||
- '**/*deploy*.md'
|
||||
|
||||
# Type: Documentation
|
||||
'type: documentation':
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- 'docs/**/*'
|
||||
- '*.md'
|
||||
- 'README*'
|
||||
- 'CHANGELOG*'
|
||||
- 'CONTRIBUTING.md'
|
||||
- 'CODE_OF_CONDUCT.md'
|
||||
|
||||
# Type: Test
|
||||
'type: test':
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- '**/*_test.go'
|
||||
- 'test/**/*'
|
||||
- '**/*.test.ts'
|
||||
- '**/*.test.tsx'
|
||||
- '**/*.spec.ts'
|
||||
|
||||
# Dependencies
|
||||
'dependencies':
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- 'go.mod'
|
||||
- 'go.sum'
|
||||
- 'package.json'
|
||||
- 'package-lock.json'
|
||||
- 'web/package.json'
|
||||
- 'web/package-lock.json'
|
||||
180
.github/labels.yml
vendored
Normal file
180
.github/labels.yml
vendored
Normal file
@@ -0,0 +1,180 @@
|
||||
# GitHub Labels Configuration
|
||||
# Use https://github.com/crazy-max/ghaction-github-labeler to sync labels
|
||||
|
||||
# Priority Labels
|
||||
- name: "priority: critical"
|
||||
color: "d73a4a"
|
||||
description: "Critical priority - requires immediate attention"
|
||||
|
||||
- name: "priority: high"
|
||||
color: "ff6b6b"
|
||||
description: "High priority - should be addressed soon"
|
||||
|
||||
- name: "priority: medium"
|
||||
color: "fbca04"
|
||||
description: "Medium priority - normal queue"
|
||||
|
||||
- name: "priority: low"
|
||||
color: "0e8a16"
|
||||
description: "Low priority - nice to have"
|
||||
|
||||
# Type Labels
|
||||
- name: "type: bug"
|
||||
color: "d73a4a"
|
||||
description: "Something isn't working"
|
||||
|
||||
- name: "type: feature"
|
||||
color: "a2eeef"
|
||||
description: "New feature or request"
|
||||
|
||||
- name: "type: enhancement"
|
||||
color: "84b6eb"
|
||||
description: "Improvement to existing feature"
|
||||
|
||||
- name: "type: documentation"
|
||||
color: "0075ca"
|
||||
description: "Documentation improvements"
|
||||
|
||||
- name: "type: security"
|
||||
color: "ee0701"
|
||||
description: "Security-related changes"
|
||||
|
||||
- name: "type: performance"
|
||||
color: "f9d0c4"
|
||||
description: "Performance improvements"
|
||||
|
||||
- name: "type: refactor"
|
||||
color: "fbca04"
|
||||
description: "Code refactoring"
|
||||
|
||||
- name: "type: test"
|
||||
color: "c5def5"
|
||||
description: "Test-related changes"
|
||||
|
||||
# Status Labels
|
||||
- name: "status: needs review"
|
||||
color: "fbca04"
|
||||
description: "PR is ready for review"
|
||||
|
||||
- name: "status: needs changes"
|
||||
color: "d93f0b"
|
||||
description: "PR needs changes based on review"
|
||||
|
||||
- name: "status: on hold"
|
||||
color: "fef2c0"
|
||||
description: "PR/issue is on hold"
|
||||
|
||||
- name: "status: in progress"
|
||||
color: "0e8a16"
|
||||
description: "Currently being worked on"
|
||||
|
||||
- name: "status: blocked"
|
||||
color: "d93f0b"
|
||||
description: "Blocked by another issue/PR"
|
||||
|
||||
# Area Labels (aligned with roadmap)
|
||||
- name: "area: security"
|
||||
color: "ee0701"
|
||||
description: "Security enhancements (Phase 1.1)"
|
||||
|
||||
- name: "area: ai"
|
||||
color: "7057ff"
|
||||
description: "AI capabilities and models (Phase 1.2)"
|
||||
|
||||
- name: "area: exchange"
|
||||
color: "0075ca"
|
||||
description: "Exchange integrations (Phase 1.3)"
|
||||
|
||||
- name: "area: architecture"
|
||||
color: "d4c5f9"
|
||||
description: "Project structure refactoring (Phase 1.4)"
|
||||
|
||||
- name: "area: ui/ux"
|
||||
color: "c2e0c6"
|
||||
description: "User experience improvements (Phase 1.5)"
|
||||
|
||||
- name: "area: frontend"
|
||||
color: "bfdadc"
|
||||
description: "Frontend (React/TypeScript)"
|
||||
|
||||
- name: "area: backend"
|
||||
color: "c5def5"
|
||||
description: "Backend (Go)"
|
||||
|
||||
- name: "area: api"
|
||||
color: "0e8a16"
|
||||
description: "API endpoints"
|
||||
|
||||
- name: "area: database"
|
||||
color: "f9d0c4"
|
||||
description: "Database changes"
|
||||
|
||||
- name: "area: deployment"
|
||||
color: "fbca04"
|
||||
description: "Deployment and CI/CD"
|
||||
|
||||
# Special Labels
|
||||
- name: "good first issue"
|
||||
color: "7057ff"
|
||||
description: "Good for newcomers"
|
||||
|
||||
- name: "help wanted"
|
||||
color: "008672"
|
||||
description: "Extra attention is needed"
|
||||
|
||||
- name: "bounty"
|
||||
color: "1d76db"
|
||||
description: "Bounty available for this issue"
|
||||
|
||||
- name: "bounty: claimed"
|
||||
color: "5319e7"
|
||||
description: "Bounty has been claimed"
|
||||
|
||||
- name: "bounty: paid"
|
||||
color: "0e8a16"
|
||||
description: "Bounty has been paid"
|
||||
|
||||
- name: "RFC"
|
||||
color: "d4c5f9"
|
||||
description: "Request for Comments - needs discussion"
|
||||
|
||||
- name: "breaking change"
|
||||
color: "d73a4a"
|
||||
description: "Includes breaking changes"
|
||||
|
||||
- name: "duplicate"
|
||||
color: "cfd3d7"
|
||||
description: "This issue or pull request already exists"
|
||||
|
||||
- name: "invalid"
|
||||
color: "e4e669"
|
||||
description: "This doesn't seem right"
|
||||
|
||||
- name: "wontfix"
|
||||
color: "ffffff"
|
||||
description: "This will not be worked on"
|
||||
|
||||
- name: "dependencies"
|
||||
color: "0366d6"
|
||||
description: "Dependency updates"
|
||||
|
||||
# Roadmap Phases
|
||||
- name: "roadmap: phase-1"
|
||||
color: "0e8a16"
|
||||
description: "Core Infrastructure Enhancement"
|
||||
|
||||
- name: "roadmap: phase-2"
|
||||
color: "fbca04"
|
||||
description: "Testing & Stability"
|
||||
|
||||
- name: "roadmap: phase-3"
|
||||
color: "0075ca"
|
||||
description: "Universal Market Expansion"
|
||||
|
||||
- name: "roadmap: phase-4"
|
||||
color: "7057ff"
|
||||
description: "Advanced AI & Automation"
|
||||
|
||||
- name: "roadmap: phase-5"
|
||||
color: "d73a4a"
|
||||
description: "Enterprise & Scaling"
|
||||
331
.github/workflows/pr-checks-advisory.yml
vendored
Normal file
331
.github/workflows/pr-checks-advisory.yml
vendored
Normal file
@@ -0,0 +1,331 @@
|
||||
name: PR Checks (Advisory)
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened]
|
||||
branches: [main, dev]
|
||||
|
||||
# These checks are advisory only - they won't block PR merging
|
||||
# Results will be posted as comments to help contributors improve their PRs
|
||||
|
||||
jobs:
|
||||
pr-info:
|
||||
name: PR Information
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
pull-requests: write
|
||||
steps:
|
||||
- name: Check PR title format
|
||||
id: check-title
|
||||
run: |
|
||||
PR_TITLE="${{ github.event.pull_request.title }}"
|
||||
|
||||
# Check if title follows conventional commits
|
||||
if echo "$PR_TITLE" | grep -qE "^(feat|fix|docs|style|refactor|perf|test|chore|ci|security)(\(.+\))?: .+"; then
|
||||
echo "status=✅ Good" >> $GITHUB_OUTPUT
|
||||
echo "message=PR title follows Conventional Commits format" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "status=⚠️ Suggestion" >> $GITHUB_OUTPUT
|
||||
echo "message=Consider using Conventional Commits format: type(scope): description" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- name: Calculate PR size
|
||||
id: pr-size
|
||||
run: |
|
||||
ADDITIONS=${{ github.event.pull_request.additions }}
|
||||
DELETIONS=${{ github.event.pull_request.deletions }}
|
||||
TOTAL=$((ADDITIONS + DELETIONS))
|
||||
|
||||
if [ $TOTAL -lt 100 ]; then
|
||||
echo "size=🟢 Small" >> $GITHUB_OUTPUT
|
||||
echo "label=size: small" >> $GITHUB_OUTPUT
|
||||
elif [ $TOTAL -lt 500 ]; then
|
||||
echo "size=🟡 Medium" >> $GITHUB_OUTPUT
|
||||
echo "label=size: medium" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "size=🔴 Large" >> $GITHUB_OUTPUT
|
||||
echo "label=size: large" >> $GITHUB_OUTPUT
|
||||
echo "suggestion=Consider breaking this into smaller PRs for easier review" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
echo "lines=$TOTAL" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Post advisory comment
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const titleStatus = '${{ steps.check-title.outputs.status }}';
|
||||
const titleMessage = '${{ steps.check-title.outputs.message }}';
|
||||
const prSize = '${{ steps.pr-size.outputs.size }}';
|
||||
const prLines = '${{ steps.pr-size.outputs.lines }}';
|
||||
const sizeSuggestion = '${{ steps.pr-size.outputs.suggestion }}' || '';
|
||||
|
||||
let comment = '## 🤖 PR Advisory Feedback\n\n';
|
||||
comment += 'Thank you for your contribution! Here\'s some automated feedback to help improve your PR:\n\n';
|
||||
comment += '### PR Title\n';
|
||||
comment += titleStatus + ' ' + titleMessage + '\n\n';
|
||||
comment += '### PR Size\n';
|
||||
comment += prSize + ' (' + prLines + ' lines changed)\n';
|
||||
if (sizeSuggestion) {
|
||||
comment += '\n💡 **Suggestion:** ' + sizeSuggestion + '\n';
|
||||
}
|
||||
comment += '\n---\n\n';
|
||||
comment += '### 📖 New PR Management System\n\n';
|
||||
comment += 'We\'re introducing a new PR management system! These checks are **advisory only** and won\'t block your PR.\n\n';
|
||||
comment += '**Want to check your PR against new standards?**\n';
|
||||
comment += '```bash\n';
|
||||
comment += '# Run the PR health check tool\n';
|
||||
comment += './scripts/pr-check.sh\n';
|
||||
comment += '```\n\n';
|
||||
comment += 'This tool will:\n';
|
||||
comment += '- 🔍 Analyze your PR (doesn\'t modify anything)\n';
|
||||
comment += '- ✅ Show what\'s already good\n';
|
||||
comment += '- ⚠️ Point out issues\n';
|
||||
comment += '- 💡 Give specific suggestions on how to fix\n\n';
|
||||
comment += '**Learn more:**\n';
|
||||
comment += '- [Migration Guide](https://github.com/tinkle-community/nofx/blob/dev/docs/community/MIGRATION_ANNOUNCEMENT.md)\n';
|
||||
comment += '- [Contributing Guidelines](https://github.com/tinkle-community/nofx/blob/dev/CONTRIBUTING.md)\n\n';
|
||||
comment += '**Questions?** Just ask in the comments! We\'re here to help. 🙏\n\n';
|
||||
comment += '---\n\n';
|
||||
comment += '*This is an automated message. It won\'t affect your PR being merged.*';
|
||||
|
||||
github.rest.issues.createComment({
|
||||
issue_number: context.issue.number,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
body: comment
|
||||
});
|
||||
|
||||
backend-checks:
|
||||
name: Backend Checks (Advisory)
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
pull-requests: write
|
||||
continue-on-error: true
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.21'
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y libta-lib-dev || true
|
||||
go mod download || true
|
||||
|
||||
- name: Check Go formatting
|
||||
id: go-fmt
|
||||
continue-on-error: true
|
||||
run: |
|
||||
UNFORMATTED=$(gofmt -l . 2>/dev/null || echo "")
|
||||
if [ -n "$UNFORMATTED" ]; then
|
||||
echo "status=⚠️ Needs formatting" >> $GITHUB_OUTPUT
|
||||
echo "files<<EOF" >> $GITHUB_OUTPUT
|
||||
echo "$UNFORMATTED" | head -10 >> $GITHUB_OUTPUT
|
||||
echo "EOF" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "status=✅ Good" >> $GITHUB_OUTPUT
|
||||
echo "files=" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- name: Run go vet
|
||||
id: go-vet
|
||||
continue-on-error: true
|
||||
run: |
|
||||
if go vet ./... 2>&1 | tee vet-output.txt; then
|
||||
echo "status=✅ Good" >> $GITHUB_OUTPUT
|
||||
echo "output=" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "status=⚠️ Issues found" >> $GITHUB_OUTPUT
|
||||
echo "output<<EOF" >> $GITHUB_OUTPUT
|
||||
cat vet-output.txt | head -20 >> $GITHUB_OUTPUT
|
||||
echo "EOF" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- name: Run tests
|
||||
id: go-test
|
||||
continue-on-error: true
|
||||
run: |
|
||||
if go test ./... -v 2>&1 | tee test-output.txt; then
|
||||
echo "status=✅ Passed" >> $GITHUB_OUTPUT
|
||||
echo "output=" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "status=⚠️ Failed" >> $GITHUB_OUTPUT
|
||||
echo "output<<EOF" >> $GITHUB_OUTPUT
|
||||
cat test-output.txt | tail -30 >> $GITHUB_OUTPUT
|
||||
echo "EOF" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- name: Post backend feedback
|
||||
if: always()
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const fmtStatus = '${{ steps.go-fmt.outputs.status }}' || '⚠️ Skipped';
|
||||
const vetStatus = '${{ steps.go-vet.outputs.status }}' || '⚠️ Skipped';
|
||||
const testStatus = '${{ steps.go-test.outputs.status }}' || '⚠️ Skipped';
|
||||
const fmtFiles = `${{ steps.go-fmt.outputs.files }}`;
|
||||
const vetOutput = `${{ steps.go-vet.outputs.output }}`;
|
||||
const testOutput = `${{ steps.go-test.outputs.output }}`;
|
||||
|
||||
let comment = '## 🔧 Backend Checks (Advisory)\n\n';
|
||||
comment += '### Go Formatting\n';
|
||||
comment += fmtStatus + '\n';
|
||||
if (fmtFiles) {
|
||||
comment += '\nFiles needing formatting:\n```\n' + fmtFiles + '\n```\n';
|
||||
}
|
||||
comment += '\n### Go Vet\n';
|
||||
comment += vetStatus + '\n';
|
||||
if (vetOutput) {
|
||||
comment += '\n```\n' + vetOutput.substring(0, 500) + '\n```\n';
|
||||
}
|
||||
comment += '\n### Tests\n';
|
||||
comment += testStatus + '\n';
|
||||
if (testOutput) {
|
||||
comment += '\n```\n' + testOutput.substring(0, 1000) + '\n```\n';
|
||||
}
|
||||
comment += '\n---\n\n';
|
||||
comment += '💡 **To fix locally:**\n';
|
||||
comment += '```bash\n';
|
||||
comment += '# Format code\n';
|
||||
comment += 'go fmt ./...\n\n';
|
||||
comment += '# Check for issues\n';
|
||||
comment += 'go vet ./...\n\n';
|
||||
comment += '# Run tests\n';
|
||||
comment += 'go test ./...\n';
|
||||
comment += '```\n\n';
|
||||
comment += '*These checks are advisory and won\'t block merging. Need help? Just ask!*';
|
||||
|
||||
github.rest.issues.createComment({
|
||||
issue_number: context.issue.number,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
body: comment
|
||||
});
|
||||
|
||||
frontend-checks:
|
||||
name: Frontend Checks (Advisory)
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
pull-requests: write
|
||||
continue-on-error: true
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '18'
|
||||
|
||||
- name: Check if web directory exists
|
||||
id: check-web
|
||||
run: |
|
||||
if [ -d "web" ]; then
|
||||
echo "exists=true" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "exists=false" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- name: Install dependencies
|
||||
if: steps.check-web.outputs.exists == 'true'
|
||||
working-directory: ./web
|
||||
continue-on-error: true
|
||||
run: npm ci
|
||||
|
||||
- name: Run linter
|
||||
if: steps.check-web.outputs.exists == 'true'
|
||||
id: lint
|
||||
working-directory: ./web
|
||||
continue-on-error: true
|
||||
run: |
|
||||
if npm run lint 2>&1 | tee lint-output.txt; then
|
||||
echo "status=✅ Good" >> $GITHUB_OUTPUT
|
||||
echo "output=" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "status=⚠️ Issues found" >> $GITHUB_OUTPUT
|
||||
echo "output<<EOF" >> $GITHUB_OUTPUT
|
||||
cat lint-output.txt | head -20 >> $GITHUB_OUTPUT
|
||||
echo "EOF" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- name: Type check
|
||||
if: steps.check-web.outputs.exists == 'true'
|
||||
id: typecheck
|
||||
working-directory: ./web
|
||||
continue-on-error: true
|
||||
run: |
|
||||
if npm run type-check 2>&1 | tee typecheck-output.txt; then
|
||||
echo "status=✅ Good" >> $GITHUB_OUTPUT
|
||||
echo "output=" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "status=⚠️ Issues found" >> $GITHUB_OUTPUT
|
||||
echo "output<<EOF" >> $GITHUB_OUTPUT
|
||||
cat typecheck-output.txt | head -20 >> $GITHUB_OUTPUT
|
||||
echo "EOF" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- name: Build
|
||||
if: steps.check-web.outputs.exists == 'true'
|
||||
id: build
|
||||
working-directory: ./web
|
||||
continue-on-error: true
|
||||
run: |
|
||||
if npm run build 2>&1 | tee build-output.txt; then
|
||||
echo "status=✅ Success" >> $GITHUB_OUTPUT
|
||||
echo "output=" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "status=⚠️ Failed" >> $GITHUB_OUTPUT
|
||||
echo "output<<EOF" >> $GITHUB_OUTPUT
|
||||
cat build-output.txt | tail -20 >> $GITHUB_OUTPUT
|
||||
echo "EOF" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- name: Post frontend feedback
|
||||
if: always() && steps.check-web.outputs.exists == 'true'
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const lintStatus = '${{ steps.lint.outputs.status }}' || '⚠️ Skipped';
|
||||
const typecheckStatus = '${{ steps.typecheck.outputs.status }}' || '⚠️ Skipped';
|
||||
const buildStatus = '${{ steps.build.outputs.status }}' || '⚠️ Skipped';
|
||||
const lintOutput = `${{ steps.lint.outputs.output }}`;
|
||||
const typecheckOutput = `${{ steps.typecheck.outputs.output }}`;
|
||||
const buildOutput = `${{ steps.build.outputs.output }}`;
|
||||
|
||||
let comment = '## ⚛️ Frontend Checks (Advisory)\n\n';
|
||||
comment += '### Linting\n';
|
||||
comment += lintStatus + '\n';
|
||||
if (lintOutput) {
|
||||
comment += '\n```\n' + lintOutput.substring(0, 500) + '\n```\n';
|
||||
}
|
||||
comment += '\n### Type Checking\n';
|
||||
comment += typecheckStatus + '\n';
|
||||
if (typecheckOutput) {
|
||||
comment += '\n```\n' + typecheckOutput.substring(0, 500) + '\n```\n';
|
||||
}
|
||||
comment += '\n### Build\n';
|
||||
comment += buildStatus + '\n';
|
||||
if (buildOutput) {
|
||||
comment += '\n```\n' + buildOutput.substring(0, 500) + '\n```\n';
|
||||
}
|
||||
comment += '\n---\n\n';
|
||||
comment += '💡 **To fix locally:**\n';
|
||||
comment += '```bash\n';
|
||||
comment += 'cd web\n\n';
|
||||
comment += '# Fix linting issues\n';
|
||||
comment += 'npm run lint -- --fix\n\n';
|
||||
comment += '# Check types\n';
|
||||
comment += 'npm run type-check\n\n';
|
||||
comment += '# Test build\n';
|
||||
comment += 'npm run build\n';
|
||||
comment += '```\n\n';
|
||||
comment += '*These checks are advisory and won\'t block merging. Need help? Just ask!*';
|
||||
|
||||
github.rest.issues.createComment({
|
||||
issue_number: context.issue.number,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
body: comment
|
||||
});
|
||||
237
.github/workflows/pr-checks.yml
vendored
Normal file
237
.github/workflows/pr-checks.yml
vendored
Normal file
@@ -0,0 +1,237 @@
|
||||
name: PR Checks
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened, edited]
|
||||
branches:
|
||||
- dev
|
||||
- main
|
||||
|
||||
jobs:
|
||||
# Validate PR title and description
|
||||
validate-pr:
|
||||
name: Validate PR Format
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check PR title format
|
||||
uses: amannn/action-semantic-pull-request@v5
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
types: |
|
||||
feat
|
||||
fix
|
||||
docs
|
||||
style
|
||||
refactor
|
||||
perf
|
||||
test
|
||||
chore
|
||||
ci
|
||||
security
|
||||
scopes: |
|
||||
exchange
|
||||
trader
|
||||
ai
|
||||
api
|
||||
ui
|
||||
frontend
|
||||
backend
|
||||
security
|
||||
deps
|
||||
requireScope: false
|
||||
|
||||
- name: Check PR size
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const pr = context.payload.pull_request;
|
||||
const additions = pr.additions;
|
||||
const deletions = pr.deletions;
|
||||
const total = additions + deletions;
|
||||
|
||||
let label = '';
|
||||
let comment = '';
|
||||
|
||||
if (total < 300) {
|
||||
label = 'size: small';
|
||||
comment = '✅ This PR is **small** and easy to review!';
|
||||
} else if (total < 1000) {
|
||||
label = 'size: medium';
|
||||
comment = '⚠️ This PR is **medium** sized. Consider breaking it into smaller PRs if possible.';
|
||||
} else {
|
||||
label = 'size: large';
|
||||
comment = '🚨 This PR is **large** (>' + total + ' lines changed). Please consider breaking it into smaller, focused PRs for easier review.';
|
||||
}
|
||||
|
||||
// Add size label
|
||||
await github.rest.issues.addLabels({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: pr.number,
|
||||
labels: [label]
|
||||
});
|
||||
|
||||
// Add comment for large PRs
|
||||
if (total >= 1000) {
|
||||
await github.rest.issues.createComment({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: pr.number,
|
||||
body: comment
|
||||
});
|
||||
}
|
||||
|
||||
# Backend tests
|
||||
backend-tests:
|
||||
name: Backend Tests (Go)
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.21'
|
||||
|
||||
- name: Install TA-Lib
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y libta-lib-dev
|
||||
|
||||
- name: Cache Go modules
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/go/pkg/mod
|
||||
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-go-
|
||||
|
||||
- name: Download dependencies
|
||||
run: go mod download
|
||||
|
||||
- name: Run go fmt
|
||||
run: |
|
||||
if [ "$(gofmt -s -l . | wc -l)" -gt 0 ]; then
|
||||
echo "Please run 'go fmt' on your code"
|
||||
gofmt -s -l .
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Run go vet
|
||||
run: go vet ./...
|
||||
|
||||
- name: Run tests
|
||||
run: go test -v -race -coverprofile=coverage.out ./...
|
||||
|
||||
- name: Build
|
||||
run: go build -v -o nofx
|
||||
|
||||
- name: Upload coverage
|
||||
uses: codecov/codecov-action@v4
|
||||
with:
|
||||
file: ./coverage.out
|
||||
flags: backend
|
||||
|
||||
# Frontend tests
|
||||
frontend-tests:
|
||||
name: Frontend Tests (React/TypeScript)
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '18'
|
||||
|
||||
- name: Cache Node modules
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: web/node_modules
|
||||
key: ${{ runner.os }}-node-${{ hashFiles('web/package-lock.json') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-node-
|
||||
|
||||
- name: Install dependencies
|
||||
working-directory: ./web
|
||||
run: npm ci
|
||||
|
||||
- name: Run linter
|
||||
working-directory: ./web
|
||||
run: npm run lint
|
||||
|
||||
- name: Run type check
|
||||
working-directory: ./web
|
||||
run: npm run type-check || true # Don't fail on type errors for now
|
||||
|
||||
- name: Build
|
||||
working-directory: ./web
|
||||
run: npm run build
|
||||
|
||||
# Auto-label based on files changed
|
||||
auto-label:
|
||||
name: Auto Label PR
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
pull-requests: write
|
||||
steps:
|
||||
- uses: actions/labeler@v5
|
||||
with:
|
||||
configuration-path: .github/labeler.yml
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
# Check for security issues
|
||||
security-check:
|
||||
name: Security Scan
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Run Trivy vulnerability scanner
|
||||
uses: aquasecurity/trivy-action@master
|
||||
with:
|
||||
scan-type: 'fs'
|
||||
scan-ref: '.'
|
||||
format: 'sarif'
|
||||
output: 'trivy-results.sarif'
|
||||
|
||||
- name: Upload Trivy results
|
||||
uses: github/codeql-action/upload-sarif@v3
|
||||
if: always()
|
||||
with:
|
||||
sarif_file: 'trivy-results.sarif'
|
||||
|
||||
# Check for secrets in code
|
||||
secrets-check:
|
||||
name: Check for Secrets
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Run Gitleaks
|
||||
uses: gitleaks/gitleaks-action@v2
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
# All checks passed
|
||||
all-checks:
|
||||
name: All Checks Passed
|
||||
runs-on: ubuntu-latest
|
||||
needs: [validate-pr, backend-tests, frontend-tests, security-check, secrets-check]
|
||||
if: always()
|
||||
steps:
|
||||
- name: Check all jobs
|
||||
run: |
|
||||
if [ "${{ contains(needs.*.result, 'failure') }}" == "true" ]; then
|
||||
echo "Some checks failed"
|
||||
exit 1
|
||||
else
|
||||
echo "All checks passed!"
|
||||
fi
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -3,6 +3,9 @@
|
||||
*.iml
|
||||
*.xml
|
||||
|
||||
# AI 工具
|
||||
.claude/
|
||||
|
||||
# 编译产物
|
||||
nofx-auto
|
||||
*.exe
|
||||
|
||||
203
CHANGELOG.md
Normal file
203
CHANGELOG.md
Normal file
@@ -0,0 +1,203 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to the NOFX project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
**Languages:** [English](CHANGELOG.md) | [中文](CHANGELOG.zh-CN.md)
|
||||
|
||||
---
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Added
|
||||
- Documentation system with multi-language support (EN/CN/RU/UK)
|
||||
- Complete getting-started guides (Docker, PM2, Custom API)
|
||||
- Architecture documentation with system design details
|
||||
- User guides with FAQ and troubleshooting
|
||||
- Community documentation with bounty programs
|
||||
|
||||
### Changed
|
||||
- Reorganized documentation structure into logical categories
|
||||
- Updated all README files with proper navigation links
|
||||
|
||||
---
|
||||
|
||||
## [3.0.0] - 2025-10-30
|
||||
|
||||
### Added - Major Architecture Transformation 🚀
|
||||
|
||||
**Complete System Redesign - Web-Based Configuration Platform**
|
||||
|
||||
This is a **major breaking update** that completely transforms NOFX from a static config-based system to a modern web-based trading platform.
|
||||
|
||||
#### Database-Driven Architecture
|
||||
- SQLite integration replacing static JSON config
|
||||
- Persistent storage with automatic timestamps
|
||||
- Foreign key relationships and triggers for data consistency
|
||||
- Separate tables for AI models, exchanges, traders, and system config
|
||||
|
||||
#### Web-Based Configuration Interface
|
||||
- Complete web-based configuration management (no more JSON editing)
|
||||
- AI Model setup through web interface (DeepSeek/Qwen API keys)
|
||||
- Exchange management (Binance/Hyperliquid credentials)
|
||||
- Dynamic trader creation (combine any AI model with any exchange)
|
||||
- Real-time control (start/stop traders without system restart)
|
||||
|
||||
#### Flexible Architecture
|
||||
- Separation of concerns (AI models and exchanges independent)
|
||||
- Mix & match capability (unlimited combinations)
|
||||
- Scalable design (support for unlimited traders)
|
||||
- Clean slate approach (no default traders)
|
||||
|
||||
#### Enhanced API Layer
|
||||
- RESTful design with complete CRUD operations
|
||||
- New endpoints:
|
||||
- `GET/PUT /api/models` - AI model configuration
|
||||
- `GET/PUT /api/exchanges` - Exchange configuration
|
||||
- `POST/DELETE /api/traders` - Trader management
|
||||
- `POST /api/traders/:id/start|stop` - Trader control
|
||||
- Updated documentation for all API endpoints
|
||||
|
||||
#### Modernized Codebase
|
||||
- Type safety with proper separation of configuration types
|
||||
- Database abstraction with prepared statements
|
||||
- Comprehensive error handling and validation
|
||||
- Better code organization (database, API, business logic)
|
||||
|
||||
### Changed
|
||||
- **BREAKING**: Old `config.json` files no longer used
|
||||
- Configuration must be done through web interface
|
||||
- Much easier setup and better UX
|
||||
- No more server restarts for configuration changes
|
||||
|
||||
### Why This Matters
|
||||
- 🎯 **User Experience**: Much easier to configure and manage
|
||||
- 🔧 **Flexibility**: Create any combination of AI models and exchanges
|
||||
- 📊 **Scalability**: Support for complex multi-trader setups
|
||||
- 🔒 **Reliability**: Database ensures data persistence and consistency
|
||||
- 🚀 **Future-Proof**: Foundation for advanced features
|
||||
|
||||
---
|
||||
|
||||
## [2.0.2] - 2025-10-29
|
||||
|
||||
### Fixed - Critical Bug Fixes: Trade History & Performance Analysis
|
||||
|
||||
#### PnL Calculation - Major Error Fixed
|
||||
- **Fixed**: PnL now calculated as actual USDT amount instead of percentage only
|
||||
- Previously ignored position size and leverage (e.g., 100 USDT @ 5% = 1000 USDT @ 5%)
|
||||
- Now: `PnL (USDT) = Position Value × Price Change % × Leverage`
|
||||
- Impact: Win rate, profit factor, and Sharpe ratio now accurate
|
||||
|
||||
#### Position Tracking - Missing Critical Data
|
||||
- **Fixed**: Open position records now store quantity and leverage
|
||||
- Previously only stored price and time
|
||||
- Essential for accurate PnL calculations
|
||||
|
||||
#### Position Key Logic - Long/Short Conflict
|
||||
- **Fixed**: Changed from `symbol` to `symbol_side` format
|
||||
- Now properly distinguishes between long and short positions
|
||||
- Example: `BTCUSDT_long` vs `BTCUSDT_short`
|
||||
|
||||
#### Sharpe Ratio Calculation - Code Optimization
|
||||
- **Changed**: Replaced custom Newton's method with `math.Sqrt`
|
||||
- More reliable, maintainable, and efficient
|
||||
|
||||
### Why This Matters
|
||||
- Historical trade statistics now show real USDT profit/loss
|
||||
- Performance comparison between different leverage trades is accurate
|
||||
- AI self-learning mechanism receives correct feedback
|
||||
- Multi-position tracking (long + short simultaneously) works correctly
|
||||
|
||||
---
|
||||
|
||||
## [2.0.2] - 2025-10-29
|
||||
|
||||
### Fixed - Aster Exchange Precision Error
|
||||
|
||||
- Fixed Aster exchange precision error (code -1111)
|
||||
- Improved price and quantity formatting to match exchange requirements
|
||||
- Added detailed precision processing logs for debugging
|
||||
- Enhanced all order functions with proper precision handling
|
||||
|
||||
#### Technical Details
|
||||
- Added `formatFloatWithPrecision` function
|
||||
- Price and quantity formatted according to exchange specifications
|
||||
- Trailing zeros removed to optimize API requests
|
||||
|
||||
---
|
||||
|
||||
## [2.0.1] - 2025-10-29
|
||||
|
||||
### Fixed - ComparisonChart Data Processing
|
||||
|
||||
- Fixed ComparisonChart data processing logic
|
||||
- Switched from cycle_number to timestamp grouping
|
||||
- Resolved chart freezing issue when backend restarts
|
||||
- Improved chart data display (shows all historical data chronologically)
|
||||
- Enhanced debugging logs
|
||||
|
||||
---
|
||||
|
||||
## [2.0.0] - 2025-10-28
|
||||
|
||||
### Added - Major Updates
|
||||
|
||||
- AI self-learning mechanism (historical feedback, performance analysis)
|
||||
- Multi-trader competition mode (Qwen vs DeepSeek)
|
||||
- Binance-style UI (complete interface imitation)
|
||||
- Performance comparison charts (real-time ROI comparison)
|
||||
- Risk control optimization (per-coin position limit adjustment)
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed hardcoded initial balance issue
|
||||
- Fixed multi-trader data sync issue
|
||||
- Optimized chart data alignment (using cycle_number)
|
||||
|
||||
---
|
||||
|
||||
## [1.0.0] - 2025-10-27
|
||||
|
||||
### Added - Initial Release
|
||||
|
||||
- Basic AI trading functionality
|
||||
- Decision logging system
|
||||
- Simple Web interface
|
||||
- Support for Binance Futures
|
||||
- DeepSeek and Qwen AI model integration
|
||||
|
||||
---
|
||||
|
||||
## How to Use This Changelog
|
||||
|
||||
### For Users
|
||||
- Check the [Unreleased] section for upcoming features
|
||||
- Review version sections to understand what changed
|
||||
- Follow migration guides for breaking changes
|
||||
|
||||
### For Contributors
|
||||
When making changes, add them to the [Unreleased] section under appropriate categories:
|
||||
- **Added** - New features
|
||||
- **Changed** - Changes to existing functionality
|
||||
- **Deprecated** - Features that will be removed
|
||||
- **Removed** - Features that were removed
|
||||
- **Fixed** - Bug fixes
|
||||
- **Security** - Security fixes
|
||||
|
||||
When releasing a new version, move [Unreleased] items to a new version section with date.
|
||||
|
||||
---
|
||||
|
||||
## Links
|
||||
|
||||
- [Documentation](docs/README.md)
|
||||
- [Contributing Guidelines](CONTRIBUTING.md)
|
||||
- [Security Policy](SECURITY.md)
|
||||
- [GitHub Repository](https://github.com/tinkle-community/nofx)
|
||||
|
||||
---
|
||||
|
||||
**Last Updated:** 2025-11-01
|
||||
203
CHANGELOG.zh-CN.md
Normal file
203
CHANGELOG.zh-CN.md
Normal file
@@ -0,0 +1,203 @@
|
||||
# 更新日志
|
||||
|
||||
NOFX 项目的所有重要更改都将记录在此文件中。
|
||||
|
||||
本文件格式基于 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.0.0/),
|
||||
本项目遵循 [语义化版本](https://semver.org/lang/zh-CN/)。
|
||||
|
||||
**语言:** [English](CHANGELOG.md) | [中文](CHANGELOG.zh-CN.md)
|
||||
|
||||
---
|
||||
|
||||
## [未发布]
|
||||
|
||||
### 新增
|
||||
- 多语言文档系统(英文/中文/俄语/乌克兰语)
|
||||
- 完整的快速开始指南(Docker、PM2、自定义 API)
|
||||
- 架构文档,包含系统设计细节
|
||||
- 用户指南,包含 FAQ 和故障排除
|
||||
- 社区文档,包含悬赏计划
|
||||
|
||||
### 变更
|
||||
- 重组文档结构为逻辑分类
|
||||
- 更新所有 README 文件,添加适当的导航链接
|
||||
|
||||
---
|
||||
|
||||
## [3.0.0] - 2025-10-30
|
||||
|
||||
### 新增 - 重大架构变革 🚀
|
||||
|
||||
**系统完全重新设计 - 基于 Web 的配置平台**
|
||||
|
||||
这是一个**重大破坏性更新**,将 NOFX 从基于静态配置的系统完全转变为现代化的 Web 交易平台。
|
||||
|
||||
#### 数据库驱动架构
|
||||
- SQLite 集成,取代静态 JSON 配置
|
||||
- 持久化存储,自动时间戳
|
||||
- 外键关系和触发器确保数据一致性
|
||||
- 为 AI 模型、交易所、交易员和系统配置分离表结构
|
||||
|
||||
#### 基于 Web 的配置界面
|
||||
- 完整的 Web 配置管理(无需编辑 JSON)
|
||||
- 通过 Web 界面设置 AI 模型(DeepSeek/Qwen API 密钥)
|
||||
- 交易所管理(Binance/Hyperliquid 凭证)
|
||||
- 动态创建交易员(结合任意 AI 模型和交易所)
|
||||
- 实时控制(无需重启即可启动/停止交易员)
|
||||
|
||||
#### 灵活架构
|
||||
- 关注点分离(AI 模型和交易所独立)
|
||||
- 混合搭配能力(无限组合)
|
||||
- 可扩展设计(支持无限交易员)
|
||||
- 清洁起点(无默认交易员)
|
||||
|
||||
#### 增强的 API 层
|
||||
- RESTful 设计,完整的 CRUD 操作
|
||||
- 新端点:
|
||||
- `GET/PUT /api/models` - AI 模型配置
|
||||
- `GET/PUT /api/exchanges` - 交易所配置
|
||||
- `POST/DELETE /api/traders` - 交易员管理
|
||||
- `POST /api/traders/:id/start|stop` - 交易员控制
|
||||
- 更新所有 API 端点文档
|
||||
|
||||
#### 现代化代码库
|
||||
- 类型安全,适当分离配置类型
|
||||
- 数据库抽象,使用预处理语句
|
||||
- 全面的错误处理和验证
|
||||
- 更好的代码组织(数据库、API、业务逻辑)
|
||||
|
||||
### 变更
|
||||
- **破坏性变更**:不再使用旧的 `config.json` 文件
|
||||
- 必须通过 Web 界面进行配置
|
||||
- 设置更简单,用户体验更好
|
||||
- 配置更改无需重启服务器
|
||||
|
||||
### 为什么重要
|
||||
- 🎯 **用户体验**:配置和管理更容易
|
||||
- 🔧 **灵活性**:创建 AI 模型和交易所的任意组合
|
||||
- 📊 **可扩展性**:支持复杂的多交易员设置
|
||||
- 🔒 **可靠性**:数据库确保数据持久性和一致性
|
||||
- 🚀 **面向未来**:为高级功能奠定基础
|
||||
|
||||
---
|
||||
|
||||
## [2.0.2] - 2025-10-29
|
||||
|
||||
### 修复 - 关键错误修复:交易历史和性能分析
|
||||
|
||||
#### 盈亏计算 - 重大错误修复
|
||||
- **修复**:盈亏现在计算为实际 USDT 金额,而不是仅百分比
|
||||
- 之前忽略了仓位大小和杠杆(例如,100 USDT @ 5% = 1000 USDT @ 5%)
|
||||
- 现在:`盈亏 (USDT) = 仓位价值 × 价格变化 % × 杠杆`
|
||||
- 影响:胜率、盈利因子和夏普比率现在准确
|
||||
|
||||
#### 仓位跟踪 - 缺失关键数据
|
||||
- **修复**:持仓记录现在存储数量和杠杆
|
||||
- 之前只存储价格和时间
|
||||
- 这对准确的盈亏计算至关重要
|
||||
|
||||
#### 仓位键逻辑 - 多空冲突
|
||||
- **修复**:从 `symbol` 改为 `symbol_side` 格式
|
||||
- 现在正确区分多头和空头仓位
|
||||
- 示例:`BTCUSDT_long` vs `BTCUSDT_short`
|
||||
|
||||
#### 夏普比率计算 - 代码优化
|
||||
- **变更**:用 `math.Sqrt` 替换自定义牛顿法
|
||||
- 更可靠、可维护和高效
|
||||
|
||||
### 为什么重要
|
||||
- 历史交易统计现在显示真实的 USDT 盈亏
|
||||
- 不同杠杆交易之间的性能比较准确
|
||||
- AI 自学习机制接收正确的反馈
|
||||
- 多仓位跟踪(同时多空)正常工作
|
||||
|
||||
---
|
||||
|
||||
## [2.0.2] - 2025-10-29
|
||||
|
||||
### 修复 - Aster 交易所精度错误
|
||||
|
||||
- 修复 Aster 交易所精度错误(代码 -1111)
|
||||
- 改进价格和数量格式化以匹配交易所要求
|
||||
- 添加详细的精度处理日志用于调试
|
||||
- 增强所有订单函数的精度处理
|
||||
|
||||
#### 技术细节
|
||||
- 添加 `formatFloatWithPrecision` 函数
|
||||
- 根据交易所规范格式化价格和数量
|
||||
- 删除尾随零以优化 API 请求
|
||||
|
||||
---
|
||||
|
||||
## [2.0.1] - 2025-10-29
|
||||
|
||||
### 修复 - ComparisonChart 数据处理
|
||||
|
||||
- 修复 ComparisonChart 数据处理逻辑
|
||||
- 从 cycle_number 切换到时间戳分组
|
||||
- 解决后端重启时图表冻结问题
|
||||
- 改进图表数据显示(按时间顺序显示所有历史数据)
|
||||
- 增强调试日志
|
||||
|
||||
---
|
||||
|
||||
## [2.0.0] - 2025-10-28
|
||||
|
||||
### 新增 - 重大更新
|
||||
|
||||
- AI 自学习机制(历史反馈、性能分析)
|
||||
- 多交易员竞赛模式(Qwen vs DeepSeek)
|
||||
- 币安风格 UI(完整界面仿制)
|
||||
- 性能比较图表(实时 ROI 比较)
|
||||
- 风险控制优化(每币种仓位限制调整)
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复硬编码初始余额问题
|
||||
- 修复多交易员数据同步问题
|
||||
- 优化图表数据对齐(使用 cycle_number)
|
||||
|
||||
---
|
||||
|
||||
## [1.0.0] - 2025-10-27
|
||||
|
||||
### 新增 - 初始版本
|
||||
|
||||
- 基础 AI 交易功能
|
||||
- 决策日志系统
|
||||
- 简单的 Web 界面
|
||||
- 支持币安合约
|
||||
- DeepSeek 和 Qwen AI 模型集成
|
||||
|
||||
---
|
||||
|
||||
## 如何使用本更新日志
|
||||
|
||||
### 用户
|
||||
- 查看 [未发布] 部分了解即将推出的功能
|
||||
- 查看版本部分了解变更内容
|
||||
- 遵循破坏性变更的迁移指南
|
||||
|
||||
### 贡献者
|
||||
进行更改时,将它们添加到 [未发布] 部分的相应类别下:
|
||||
- **新增** - 新功能
|
||||
- **变更** - 现有功能的变更
|
||||
- **弃用** - 即将删除的功能
|
||||
- **移除** - 已删除的功能
|
||||
- **修复** - 错误修复
|
||||
- **安全** - 安全修复
|
||||
|
||||
发布新版本时,将 [未发布] 项目移动到带日期的新版本部分。
|
||||
|
||||
---
|
||||
|
||||
## 链接
|
||||
|
||||
- [文档](docs/README.md)
|
||||
- [贡献指南](CONTRIBUTING.md)
|
||||
- [安全策略](SECURITY.md)
|
||||
- [GitHub 仓库](https://github.com/tinkle-community/nofx)
|
||||
|
||||
---
|
||||
|
||||
**最后更新:** 2025-11-01
|
||||
237
CODE_OF_CONDUCT.md
Normal file
237
CODE_OF_CONDUCT.md
Normal file
@@ -0,0 +1,237 @@
|
||||
# Contributor Covenant Code of Conduct / 贡献者公约行为准则
|
||||
|
||||
**Languages:** [English](#english) | [中文](#中文)
|
||||
|
||||
---
|
||||
|
||||
# English
|
||||
|
||||
## Our Pledge
|
||||
|
||||
We as members, contributors, and leaders pledge to make participation in our
|
||||
community a harassment-free experience for everyone, regardless of age, body
|
||||
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
||||
identity and expression, level of experience, education, socio-economic status,
|
||||
nationality, personal appearance, race, caste, color, religion, or sexual
|
||||
identity and orientation.
|
||||
|
||||
We pledge to act and interact in ways that contribute to an open, welcoming,
|
||||
diverse, inclusive, and healthy community.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to a positive environment for our
|
||||
community include:
|
||||
|
||||
* Demonstrating empathy and kindness toward other people
|
||||
* Being respectful of differing opinions, viewpoints, and experiences
|
||||
* Giving and gracefully accepting constructive feedback
|
||||
* Accepting responsibility and apologizing to those affected by our mistakes,
|
||||
and learning from the experience
|
||||
* Focusing on what is best not just for us as individuals, but for the overall
|
||||
community
|
||||
|
||||
Examples of unacceptable behavior include:
|
||||
|
||||
* The use of sexualized language or imagery, and sexual attention or advances of
|
||||
any kind
|
||||
* Trolling, insulting or derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or email address,
|
||||
without their explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Enforcement Responsibilities
|
||||
|
||||
Community leaders are responsible for clarifying and enforcing our standards of
|
||||
acceptable behavior and will take appropriate and fair corrective action in
|
||||
response to any behavior that they deem inappropriate, threatening, offensive,
|
||||
or harmful.
|
||||
|
||||
Community leaders have the right and responsibility to remove, edit, or reject
|
||||
comments, commits, code, wiki edits, issues, and other contributions that are
|
||||
not aligned to this Code of Conduct, and will communicate reasons for moderation
|
||||
decisions when appropriate.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies within all community spaces, and also applies when
|
||||
an individual is officially representing the community in public spaces.
|
||||
Examples of representing our community include using an official e-mail address,
|
||||
posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported to the community leaders responsible for enforcement at:
|
||||
|
||||
|
||||
You can also report via:
|
||||
- **Telegram:** Direct message to [@Web3Tinkle](https://t.me/Web3Tinkle)
|
||||
- **Twitter:** DM to [@nofx_ai](https://x.com/nofx_ai)
|
||||
|
||||
All complaints will be reviewed and investigated promptly and fairly.
|
||||
|
||||
All community leaders are obligated to respect the privacy and security of the
|
||||
reporter of any incident.
|
||||
|
||||
## Enforcement Guidelines
|
||||
|
||||
Community leaders will follow these Community Impact Guidelines in determining
|
||||
the consequences for any action they deem in violation of this Code of Conduct:
|
||||
|
||||
### 1. Correction
|
||||
|
||||
**Community Impact**: Use of inappropriate language or other behavior deemed
|
||||
unprofessional or unwelcome in the community.
|
||||
|
||||
**Consequence**: A private, written warning from community leaders, providing
|
||||
clarity around the nature of the violation and an explanation of why the
|
||||
behavior was inappropriate. A public apology may be requested.
|
||||
|
||||
### 2. Warning
|
||||
|
||||
**Community Impact**: A violation through a single incident or series of
|
||||
actions.
|
||||
|
||||
**Consequence**: A warning with consequences for continued behavior. No
|
||||
interaction with the people involved, including unsolicited interaction with
|
||||
those enforcing the Code of Conduct, for a specified period of time. This
|
||||
includes avoiding interactions in community spaces as well as external channels
|
||||
like social media. Violating these terms may lead to a temporary or permanent
|
||||
ban.
|
||||
|
||||
### 3. Temporary Ban
|
||||
|
||||
**Community Impact**: A serious violation of community standards, including
|
||||
sustained inappropriate behavior.
|
||||
|
||||
**Consequence**: A temporary ban from any sort of interaction or public
|
||||
communication with the community for a specified period of time. No public or
|
||||
private interaction with the people involved, including unsolicited interaction
|
||||
with those enforcing the Code of Conduct, is allowed during this period.
|
||||
Violating these terms may lead to a permanent ban.
|
||||
|
||||
### 4. Permanent Ban
|
||||
|
||||
**Community Impact**: Demonstrating a pattern of violation of community
|
||||
standards, including sustained inappropriate behavior, harassment of an
|
||||
individual, or aggression toward or disparagement of classes of individuals.
|
||||
|
||||
**Consequence**: A permanent ban from any sort of public interaction within the
|
||||
community.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
||||
version 2.1, available at
|
||||
[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
|
||||
|
||||
Community Impact Guidelines were inspired by
|
||||
[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
|
||||
|
||||
For answers to common questions about this code of conduct, see the FAQ at
|
||||
[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
|
||||
[https://www.contributor-covenant.org/translations][translations].
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
|
||||
[Mozilla CoC]: https://github.com/mozilla/diversity
|
||||
[FAQ]: https://www.contributor-covenant.org/faq
|
||||
[translations]: https://www.contributor-covenant.org/translations
|
||||
|
||||
---
|
||||
|
||||
# 中文
|
||||
|
||||
## 我们的承诺
|
||||
|
||||
作为成员、贡献者和领导者,我们承诺使社区中的每个人都不受骚扰,无论其年龄、体型、明显或不明显的残疾、种族、性别特征、性别认同和表达、经验水平、教育程度、社会经济地位、国籍、个人外貌、种族、种姓、肤色、宗教或性认同和取向如何。
|
||||
|
||||
我们承诺以有助于开放、友好、多元、包容和健康社区的方式行事和互动。
|
||||
|
||||
## 我们的标准
|
||||
|
||||
有助于为我们的社区创造积极环境的行为示例包括:
|
||||
|
||||
* 对他人表现出同理心和善意
|
||||
* 尊重不同的意见、观点和经验
|
||||
* 给予并优雅地接受建设性反馈
|
||||
* 接受责任并向受我们错误影响的人道歉,并从经验中学习
|
||||
* 关注不仅对我们个人最好,而且对整个社区最好的事情
|
||||
|
||||
不可接受的行为示例包括:
|
||||
|
||||
* 使用性化的语言或图像,以及任何形式的性关注或性挑逗
|
||||
* 挑衅、侮辱性或贬损性评论,以及人身或政治攻击
|
||||
* 公开或私下骚扰
|
||||
* 未经他人明确许可,发布他人的私人信息,如物理地址或电子邮件地址
|
||||
* 在专业环境中可能被合理认为不适当的其他行为
|
||||
|
||||
## 执行责任
|
||||
|
||||
社区领导者负责阐明和执行我们可接受行为的标准,并将对他们认为不适当、威胁性、冒犯性或有害的任何行为采取适当和公平的纠正措施。
|
||||
|
||||
社区领导者有权利和责任删除、编辑或拒绝不符合本行为准则的评论、提交、代码、wiki 编辑、问题和其他贡献,并在适当时传达审核决定的原因。
|
||||
|
||||
## 范围
|
||||
|
||||
本行为准则适用于所有社区空间,也适用于个人在公共空间正式代表社区的情况。代表我们社区的示例包括使用官方电子邮件地址、通过官方社交媒体账户发布信息,或在线上或线下活动中担任指定代表。
|
||||
|
||||
## 执行
|
||||
|
||||
可以向负责执行的社区领导者报告滥用、骚扰或其他不可接受行为的实例:
|
||||
|
||||
|
||||
您也可以通过以下方式报告:
|
||||
- **Telegram:** 直接消息 [@Web3Tinkle](https://t.me/Web3Tinkle)
|
||||
- **Twitter:** 私信 [@nofx_ai](https://x.com/nofx_ai)
|
||||
|
||||
所有投诉都将得到迅速和公正的审查和调查。
|
||||
|
||||
所有社区领导者都有义务尊重任何事件报告者的隐私和安全。
|
||||
|
||||
## 执行指南
|
||||
|
||||
社区领导者将遵循这些社区影响指南来确定他们认为违反本行为准则的任何行动的后果:
|
||||
|
||||
### 1. 纠正
|
||||
|
||||
**社区影响**:使用不适当的语言或其他被认为在社区中不专业或不受欢迎的行为。
|
||||
|
||||
**后果**:社区领导者的私下书面警告,说明违规的性质和解释为什么行为不适当。可能要求公开道歉。
|
||||
|
||||
### 2. 警告
|
||||
|
||||
**社区影响**:通过单一事件或一系列行动违规。
|
||||
|
||||
**后果**:警告并说明持续行为的后果。在指定时间内不与相关人员互动,包括不主动与执行行为准则的人互动。这包括避免在社区空间以及外部渠道(如社交媒体)的互动。违反这些条款可能导致临时或永久禁令。
|
||||
|
||||
### 3. 临时禁令
|
||||
|
||||
**社区影响**:严重违反社区标准,包括持续的不当行为。
|
||||
|
||||
**后果**:在指定时间内临时禁止与社区进行任何形式的互动或公开交流。在此期间,不允许与相关人员进行公开或私下互动,包括不主动与执行行为准则的人互动。违反这些条款可能导致永久禁令。
|
||||
|
||||
### 4. 永久禁令
|
||||
|
||||
**社区影响**:表现出违反社区标准的模式,包括持续的不当行为、对个人的骚扰,或对个人类别的攻击或贬低。
|
||||
|
||||
**后果**:永久禁止在社区内进行任何形式的公开互动。
|
||||
|
||||
## 归属
|
||||
|
||||
本行为准则改编自 [贡献者公约][homepage] 2.1 版,可在
|
||||
[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1] 获取。
|
||||
|
||||
社区影响指南受到 [Mozilla 行为准则执行阶梯][Mozilla CoC] 的启发。
|
||||
|
||||
有关本行为准则的常见问题解答,请参阅 [https://www.contributor-covenant.org/faq][FAQ]。翻译版本可在 [https://www.contributor-covenant.org/translations][translations] 获取。
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
|
||||
[Mozilla CoC]: https://github.com/mozilla/diversity
|
||||
[FAQ]: https://www.contributor-covenant.org/faq
|
||||
[translations]: https://www.contributor-covenant.org/translations
|
||||
481
CONTRIBUTING.md
Normal file
481
CONTRIBUTING.md
Normal file
@@ -0,0 +1,481 @@
|
||||
# 🤝 Contributing to NOFX
|
||||
|
||||
**Language:** [English](CONTRIBUTING.md) | [中文](docs/i18n/zh-CN/CONTRIBUTING.md)
|
||||
|
||||
Thank you for your interest in contributing to NOFX! This document provides guidelines and workflows for contributing to the project.
|
||||
|
||||
---
|
||||
|
||||
## 📑 Table of Contents
|
||||
|
||||
- [Code of Conduct](#code-of-conduct)
|
||||
- [How Can I Contribute?](#how-can-i-contribute)
|
||||
- [Development Workflow](#development-workflow)
|
||||
- [PR Submission Guidelines](#pr-submission-guidelines)
|
||||
- [Coding Standards](#coding-standards)
|
||||
- [Commit Message Guidelines](#commit-message-guidelines)
|
||||
- [Review Process](#review-process)
|
||||
- [Bounty Program](#bounty-program)
|
||||
|
||||
---
|
||||
|
||||
## 📜 Code of Conduct
|
||||
|
||||
This project adheres to the [Code of Conduct](CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code.
|
||||
|
||||
---
|
||||
|
||||
## 🎯 How Can I Contribute?
|
||||
|
||||
### 1. Report Bugs 🐛
|
||||
|
||||
- Use the [Bug Report Template](.github/ISSUE_TEMPLATE/bug_report.md)
|
||||
- Check if the bug has already been reported
|
||||
- Include detailed reproduction steps
|
||||
- Provide environment information (OS, Go version, etc.)
|
||||
|
||||
### 2. Suggest Features ✨
|
||||
|
||||
- Use the [Feature Request Template](.github/ISSUE_TEMPLATE/feature_request.md)
|
||||
- Explain the use case and benefits
|
||||
- Check if it aligns with the [project roadmap](docs/roadmap/README.md)
|
||||
|
||||
### 3. Submit Pull Requests 🔧
|
||||
|
||||
Before submitting a PR, please check the following:
|
||||
|
||||
#### ✅ **Accepted Contributions**
|
||||
|
||||
**High Priority** (aligned with roadmap):
|
||||
- 🔒 Security enhancements (encryption, authentication, RBAC)
|
||||
- 🧠 AI model integrations (GPT-4, Claude, Gemini Pro)
|
||||
- 🔗 Exchange integrations (OKX, Bybit, Lighter, EdgeX)
|
||||
- 📊 Trading data APIs (AI500, OI analysis, NetFlow)
|
||||
- 🎨 UI/UX improvements (mobile responsiveness, charts)
|
||||
- ⚡ Performance optimizations
|
||||
- 🐛 Bug fixes
|
||||
- 📝 Documentation improvements
|
||||
|
||||
**Medium Priority:**
|
||||
- ✅ Test coverage improvements
|
||||
- 🌐 Internationalization (new language support)
|
||||
- 🔧 Build/deployment tooling
|
||||
- 📈 Monitoring and logging enhancements
|
||||
|
||||
#### ❌ **Not Accepted** (without prior discussion)
|
||||
|
||||
- Major architectural changes without RFC (Request for Comments)
|
||||
- Features not aligned with project roadmap
|
||||
- Breaking changes without migration path
|
||||
- Code that introduces new dependencies without justification
|
||||
- Experimental features without opt-in flag
|
||||
|
||||
**⚠️ Important:** For major features, please open an issue for discussion **before** starting work.
|
||||
|
||||
---
|
||||
|
||||
## 🛠️ Development Workflow
|
||||
|
||||
### 1. Fork and Clone
|
||||
|
||||
```bash
|
||||
# Fork the repository on GitHub
|
||||
# Then clone your fork
|
||||
git clone https://github.com/YOUR_USERNAME/nofx.git
|
||||
cd nofx
|
||||
|
||||
# Add upstream remote
|
||||
git remote add upstream https://github.com/tinkle-community/nofx.git
|
||||
```
|
||||
|
||||
### 2. Create a Feature Branch
|
||||
|
||||
```bash
|
||||
# Update your local dev branch
|
||||
git checkout dev
|
||||
git pull upstream dev
|
||||
|
||||
# Create a new branch
|
||||
git checkout -b feature/your-feature-name
|
||||
# or
|
||||
git checkout -b fix/your-bug-fix
|
||||
```
|
||||
|
||||
**Branch Naming Convention:**
|
||||
- `feature/` - New features
|
||||
- `fix/` - Bug fixes
|
||||
- `docs/` - Documentation updates
|
||||
- `refactor/` - Code refactoring
|
||||
- `perf/` - Performance improvements
|
||||
- `test/` - Test updates
|
||||
- `chore/` - Build/config changes
|
||||
|
||||
### 3. Set Up Development Environment
|
||||
|
||||
```bash
|
||||
# Install Go dependencies
|
||||
go mod download
|
||||
|
||||
# Install frontend dependencies
|
||||
cd web
|
||||
npm install
|
||||
cd ..
|
||||
|
||||
# Install TA-Lib (required)
|
||||
# macOS:
|
||||
brew install ta-lib
|
||||
|
||||
# Ubuntu/Debian:
|
||||
sudo apt-get install libta-lib0-dev
|
||||
```
|
||||
|
||||
### 4. Make Your Changes
|
||||
|
||||
- Follow the [coding standards](#coding-standards)
|
||||
- Write tests for new features
|
||||
- Update documentation as needed
|
||||
- Keep commits focused and atomic
|
||||
|
||||
### 5. Test Your Changes
|
||||
|
||||
```bash
|
||||
# Run backend tests
|
||||
go test ./...
|
||||
|
||||
# Build backend
|
||||
go build -o nofx
|
||||
|
||||
# Run frontend in dev mode
|
||||
cd web
|
||||
npm run dev
|
||||
|
||||
# Build frontend
|
||||
npm run build
|
||||
```
|
||||
|
||||
### 6. Commit Your Changes
|
||||
|
||||
Follow the [commit message guidelines](#commit-message-guidelines):
|
||||
|
||||
```bash
|
||||
git add .
|
||||
git commit -m "feat: add support for OKX exchange integration"
|
||||
```
|
||||
|
||||
### 7. Push and Create PR
|
||||
|
||||
```bash
|
||||
# Push to your fork
|
||||
git push origin feature/your-feature-name
|
||||
|
||||
# Go to GitHub and create a Pull Request
|
||||
# Use the PR template and fill in all sections
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📝 PR Submission Guidelines
|
||||
|
||||
### Before Submitting
|
||||
|
||||
- [ ] Code compiles successfully (`go build` and `npm run build`)
|
||||
- [ ] All tests pass (`go test ./...`)
|
||||
- [ ] No linting errors (`go fmt`, `go vet`)
|
||||
- [ ] Documentation is updated
|
||||
- [ ] Commits follow conventional commits format
|
||||
- [ ] Branch is rebased on latest `dev`
|
||||
|
||||
### PR Title Format
|
||||
|
||||
Use [Conventional Commits](https://www.conventionalcommits.org/) format:
|
||||
|
||||
```
|
||||
<type>(<scope>): <subject>
|
||||
|
||||
Examples:
|
||||
feat(exchange): add OKX exchange integration
|
||||
fix(trader): resolve position tracking bug
|
||||
docs(readme): update installation instructions
|
||||
perf(ai): optimize prompt generation
|
||||
refactor(core): extract common exchange interface
|
||||
```
|
||||
|
||||
**Types:**
|
||||
- `feat` - New feature
|
||||
- `fix` - Bug fix
|
||||
- `docs` - Documentation
|
||||
- `style` - Code style (formatting, no logic change)
|
||||
- `refactor` - Code refactoring
|
||||
- `perf` - Performance improvement
|
||||
- `test` - Test updates
|
||||
- `chore` - Build/config changes
|
||||
- `ci` - CI/CD changes
|
||||
- `security` - Security improvements
|
||||
|
||||
### PR Description
|
||||
|
||||
Use the [PR template](.github/PULL_REQUEST_TEMPLATE.md) and ensure:
|
||||
|
||||
1. **Clear description** of what and why
|
||||
2. **Type of change** is marked
|
||||
3. **Related issues** are linked
|
||||
4. **Testing steps** are documented
|
||||
5. **Screenshots** for UI changes
|
||||
6. **All checkboxes** are completed
|
||||
|
||||
### PR Size
|
||||
|
||||
Keep PRs focused and reasonably sized:
|
||||
|
||||
- ✅ **Small PR** (< 300 lines): Ideal, fast review
|
||||
- ⚠️ **Medium PR** (300-1000 lines): Acceptable, may take longer
|
||||
- ❌ **Large PR** (> 1000 lines): Please break into smaller PRs
|
||||
|
||||
---
|
||||
|
||||
## 💻 Coding Standards
|
||||
|
||||
### Go Code
|
||||
|
||||
```go
|
||||
// ✅ Good: Clear naming, proper error handling
|
||||
func ConnectToExchange(apiKey, secret string) (*Exchange, error) {
|
||||
if apiKey == "" || secret == "" {
|
||||
return nil, fmt.Errorf("API credentials are required")
|
||||
}
|
||||
|
||||
client, err := createClient(apiKey, secret)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create client: %w", err)
|
||||
}
|
||||
|
||||
return &Exchange{client: client}, nil
|
||||
}
|
||||
|
||||
// ❌ Bad: Poor naming, no error handling
|
||||
func ce(a, s string) *Exchange {
|
||||
c := createClient(a, s)
|
||||
return &Exchange{client: c}
|
||||
}
|
||||
```
|
||||
|
||||
**Best Practices:**
|
||||
- Use meaningful variable names
|
||||
- Handle all errors explicitly
|
||||
- Add comments for complex logic
|
||||
- Follow Go idioms and conventions
|
||||
- Run `go fmt` before committing
|
||||
- Use `go vet` and `golangci-lint`
|
||||
|
||||
### TypeScript/React Code
|
||||
|
||||
```typescript
|
||||
// ✅ Good: Type-safe, clear naming
|
||||
interface TraderConfig {
|
||||
id: string;
|
||||
exchange: 'binance' | 'hyperliquid' | 'aster';
|
||||
aiModel: string;
|
||||
enabled: boolean;
|
||||
}
|
||||
|
||||
const TraderCard: React.FC<{ trader: TraderConfig }> = ({ trader }) => {
|
||||
const [isRunning, setIsRunning] = useState(false);
|
||||
|
||||
const handleStart = async () => {
|
||||
try {
|
||||
await startTrader(trader.id);
|
||||
setIsRunning(true);
|
||||
} catch (error) {
|
||||
console.error('Failed to start trader:', error);
|
||||
}
|
||||
};
|
||||
|
||||
return <div>...</div>;
|
||||
};
|
||||
|
||||
// ❌ Bad: No types, unclear naming
|
||||
const TC = (props) => {
|
||||
const [r, setR] = useState(false);
|
||||
const h = () => { startTrader(props.t.id); setR(true); };
|
||||
return <div>...</div>;
|
||||
};
|
||||
```
|
||||
|
||||
**Best Practices:**
|
||||
- Use TypeScript strict mode
|
||||
- Define interfaces for all data structures
|
||||
- Avoid `any` type
|
||||
- Use functional components with hooks
|
||||
- Follow React best practices
|
||||
- Run `npm run lint` before committing
|
||||
|
||||
### File Structure
|
||||
|
||||
```
|
||||
NOFX/
|
||||
├── cmd/ # Main applications
|
||||
├── internal/ # Private code
|
||||
│ ├── exchange/ # Exchange adapters
|
||||
│ ├── trader/ # Trading logic
|
||||
│ ├── ai/ # AI integrations
|
||||
│ └── api/ # API handlers
|
||||
├── pkg/ # Public libraries
|
||||
├── web/ # Frontend
|
||||
│ ├── src/
|
||||
│ │ ├── components/
|
||||
│ │ ├── pages/
|
||||
│ │ ├── hooks/
|
||||
│ │ └── utils/
|
||||
│ └── public/
|
||||
└── docs/ # Documentation
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📋 Commit Message Guidelines
|
||||
|
||||
### Format
|
||||
|
||||
```
|
||||
<type>(<scope>): <subject>
|
||||
|
||||
<body>
|
||||
|
||||
<footer>
|
||||
```
|
||||
|
||||
### Examples
|
||||
|
||||
```
|
||||
feat(exchange): add OKX futures API integration
|
||||
|
||||
- Implement order placement and cancellation
|
||||
- Add balance and position retrieval
|
||||
- Support leverage configuration
|
||||
|
||||
Closes #123
|
||||
```
|
||||
|
||||
```
|
||||
fix(trader): prevent duplicate position opening
|
||||
|
||||
The trader was opening multiple positions in the same direction
|
||||
for the same symbol. Added check to prevent this behavior.
|
||||
|
||||
Fixes #456
|
||||
```
|
||||
|
||||
```
|
||||
docs: update Docker deployment guide
|
||||
|
||||
- Add troubleshooting section
|
||||
- Update environment variables
|
||||
- Add examples for common scenarios
|
||||
```
|
||||
|
||||
### Rules
|
||||
|
||||
- Use present tense ("add" not "added")
|
||||
- Use imperative mood ("move" not "moves")
|
||||
- First line ≤ 72 characters
|
||||
- Reference issues and PRs
|
||||
- Explain "what" and "why", not "how"
|
||||
|
||||
---
|
||||
|
||||
## 🔍 Review Process
|
||||
|
||||
### Timeline
|
||||
|
||||
- **Initial review:** Within 2-3 business days
|
||||
- **Follow-up reviews:** Within 1-2 business days
|
||||
- **Bounty PRs:** Priority review within 1 business day
|
||||
|
||||
### Review Criteria
|
||||
|
||||
Reviewers will check:
|
||||
|
||||
1. **Functionality**
|
||||
- Does it work as intended?
|
||||
- Are edge cases handled?
|
||||
- No regression in existing features?
|
||||
|
||||
2. **Code Quality**
|
||||
- Follows coding standards?
|
||||
- Well-structured and readable?
|
||||
- Proper error handling?
|
||||
|
||||
3. **Testing**
|
||||
- Adequate test coverage?
|
||||
- Tests pass in CI?
|
||||
- Manual testing documented?
|
||||
|
||||
4. **Documentation**
|
||||
- Code comments where needed?
|
||||
- README/docs updated?
|
||||
- API changes documented?
|
||||
|
||||
5. **Security**
|
||||
- No hardcoded secrets?
|
||||
- Input validation?
|
||||
- No known vulnerabilities?
|
||||
|
||||
### Response to Feedback
|
||||
|
||||
- Address all review comments
|
||||
- Ask questions if unclear
|
||||
- Mark conversations as resolved
|
||||
- Re-request review after changes
|
||||
|
||||
### Approval and Merge
|
||||
|
||||
- Requires **1 approval** from maintainers
|
||||
- All CI checks must pass
|
||||
- No unresolved conversations
|
||||
- Maintainers will merge (squash merge for small PRs, merge commit for features)
|
||||
|
||||
---
|
||||
|
||||
## 💰 Bounty Program
|
||||
|
||||
### How It Works
|
||||
|
||||
1. Check [open bounty issues](https://github.com/tinkle-community/nofx/labels/bounty)
|
||||
2. Comment to claim (first come, first served)
|
||||
3. Complete work within deadline
|
||||
4. Submit PR with bounty claim section filled
|
||||
5. Get paid upon merge
|
||||
|
||||
### Guidelines
|
||||
|
||||
- Read [Bounty Guide](docs/community/bounty-guide.md)
|
||||
- Meet all acceptance criteria
|
||||
- Include demo video/screenshots
|
||||
- Follow all contribution guidelines
|
||||
- Payment details discussed privately
|
||||
|
||||
---
|
||||
|
||||
## ❓ Questions?
|
||||
|
||||
- **General questions:** Join our [Telegram Community](https://t.me/nofx_dev_community)
|
||||
- **Technical questions:** Open a [Discussion](https://github.com/tinkle-community/nofx/discussions)
|
||||
- **Security issues:** See [Security Policy](SECURITY.md)
|
||||
- **Bug reports:** Use [Bug Report Template](.github/ISSUE_TEMPLATE/bug_report.md)
|
||||
|
||||
---
|
||||
|
||||
## 📚 Additional Resources
|
||||
|
||||
- [Project Roadmap](docs/roadmap/README.md)
|
||||
- [Architecture Documentation](docs/architecture/README.md)
|
||||
- [API Documentation](docs/api/README.md)
|
||||
- [Deployment Guide](docs/getting-started/docker-deploy.en.md)
|
||||
|
||||
---
|
||||
|
||||
## 🙏 Thank You!
|
||||
|
||||
Your contributions make NOFX better for everyone. We appreciate your time and effort!
|
||||
|
||||
**Happy coding! 🚀**
|
||||
21
LICENSE
Normal file
21
LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2025 Tinkle Community (NOFX Project)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
493
README.md
493
README.md
@@ -6,10 +6,36 @@
|
||||
[](LICENSE)
|
||||
[](https://amber.ac)
|
||||
|
||||
**Languages:** [English](README.md) | [中文](README.zh-CN.md) | [Українська](README.uk.md) | [Русский](README.ru.md)
|
||||
**Languages:** [English](README.md) | [中文](docs/i18n/zh-CN/README.md) | [Українська](docs/i18n/uk/README.md) | [Русский](docs/i18n/ru/README.md)
|
||||
|
||||
**Official Twitter:** [@nofx_ai](https://x.com/nofx_ai)
|
||||
|
||||
**📚 Documentation:** [Docs Home](docs/README.md) | [Getting Started](docs/getting-started/README.md) | [Changelog](CHANGELOG.md) | [Contributing](CONTRIBUTING.md) | [Security](SECURITY.md)
|
||||
|
||||
---
|
||||
|
||||
## 📑 Table of Contents
|
||||
|
||||
- [🚀 Universal AI Trading Operating System](#-universal-ai-trading-operating-system)
|
||||
- [👥 Developer Community](#-developer-community)
|
||||
- [🆕 What's New](#-whats-new-latest-update)
|
||||
- [📸 Screenshots](#-screenshots)
|
||||
- [✨ Current Implementation](#-current-implementation---crypto-markets)
|
||||
- [🔮 Roadmap](#-roadmap---universal-market-expansion)
|
||||
- [🏗️ Technical Architecture](#️-technical-architecture)
|
||||
- [💰 Register Binance Account](#-register-binance-account-save-on-fees)
|
||||
- [🚀 Quick Start](#-quick-start)
|
||||
- [📖 AI Decision Flow](#-ai-decision-flow)
|
||||
- [🧠 AI Self-Learning](#-ai-self-learning-example)
|
||||
- [📊 Web Interface Features](#-web-interface-features)
|
||||
- [🎛️ API Endpoints](#️-api-endpoints)
|
||||
- [⚠️ Important Risk Warnings](#️-important-risk-warnings)
|
||||
- [🛠️ Common Issues](#️-common-issues)
|
||||
- [📈 Performance Tips](#-performance-optimization-tips)
|
||||
- [🔄 Changelog](#-changelog)
|
||||
- [📄 License](#-license)
|
||||
- [🤝 Contributing](#-contributing)
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Universal AI Trading Operating System
|
||||
@@ -168,78 +194,50 @@ NOFX is currently **fully operational in cryptocurrency markets** with the follo
|
||||
|
||||
## 🔮 Roadmap - Universal Market Expansion
|
||||
|
||||
Our proven crypto infrastructure is being extended to:
|
||||
NOFX is on a mission to become the **Universal AI Trading Operating System** for all financial markets.
|
||||
|
||||
- **📈 Stock Markets**: US equities, A-shares, Hong Kong stocks
|
||||
- **📊 Futures Markets**: Commodity futures, index futures
|
||||
- **🎯 Options Trading**: Equity options, crypto options
|
||||
- **💱 Forex Markets**: Major currency pairs, cross rates
|
||||
**Vision:** Same architecture. Same agent framework. All markets.
|
||||
|
||||
**Same architecture. Same agent framework. All markets.**
|
||||
**Expansion Markets:**
|
||||
- 📈 **Stock Markets**: US equities, A-shares, Hong Kong stocks
|
||||
- 📊 **Futures Markets**: Commodity futures, index futures
|
||||
- 🎯 **Options Trading**: Equity options, crypto options
|
||||
- 💱 **Forex Markets**: Major currency pairs, cross rates
|
||||
|
||||
**Upcoming Features:**
|
||||
- Enhanced AI capabilities (GPT-4, Claude 3, Gemini Pro, flexible prompt templates)
|
||||
- New exchange integrations (OKX, Bybit, Lighter, EdgeX + CEX/Perp-DEX)
|
||||
- Project structure refactoring (high cohesion, low coupling, SOLID principles)
|
||||
- Security enhancements (AES-256 encryption for API keys, RBAC, 2FA improvements)
|
||||
- User experience improvements (mobile-responsive, TradingView charts, alert system)
|
||||
|
||||
📖 **For detailed roadmap and timeline, see:**
|
||||
- **English:** [Roadmap Documentation](docs/roadmap/README.md)
|
||||
- **中文:** [路线图文档](docs/roadmap/README.zh-CN.md)
|
||||
|
||||
---
|
||||
|
||||
## 🏗️ Technical Architecture
|
||||
|
||||
```
|
||||
nofx/
|
||||
├── main.go # Program entry (multi-trader manager)
|
||||
├── config.json # Configuration file (API keys, ~~multi-trader config~~) (Trader config via web interface)
|
||||
│
|
||||
├── api/ # HTTP API service
|
||||
│ └── server.go # Gin framework, RESTful API
|
||||
│
|
||||
├── trader/ # Trading core
|
||||
│ ├── auto_trader.go # Auto trading main controller (single trader)
|
||||
│ └── binance_futures.go # Binance futures API wrapper
|
||||
│
|
||||
├── manager/ # Multi-trader management
|
||||
│ └── trader_manager.go # Manages multiple trader instances
|
||||
│
|
||||
├── mcp/ # Model Context Protocol - AI communication
|
||||
│ └── client.go # AI API client (DeepSeek/Qwen integration)
|
||||
│
|
||||
├── decision/ # AI decision engine
|
||||
│ └── engine.go # Decision logic with historical feedback
|
||||
│
|
||||
├── market/ # Market data fetching
|
||||
│ └── data.go # Market data & technical indicators (K-line, RSI, MACD)
|
||||
│
|
||||
├── pool/ # Coin pool management
|
||||
│ └── coin_pool.go # AI500 + OI Top merged pool
|
||||
│
|
||||
├── logger/ # Logging system
|
||||
│ └── decision_logger.go # Decision recording + performance analysis
|
||||
│
|
||||
├── decision_logs/ # Decision log storage
|
||||
│ ├── qwen_trader/ # Qwen trader logs
|
||||
│ └── deepseek_trader/ # DeepSeek trader logs
|
||||
│
|
||||
└── web/ # React frontend
|
||||
├── src/
|
||||
│ ├── components/ # React components
|
||||
│ │ ├── EquityChart.tsx # Equity curve chart
|
||||
│ │ ├── ComparisonChart.tsx # Multi-AI comparison chart
|
||||
│ │ └── CompetitionPage.tsx # Competition leaderboard
|
||||
│ ├── lib/api.ts # API call wrapper
|
||||
│ ├── types/index.ts # TypeScript types
|
||||
│ ├── index.css # Binance-style CSS
|
||||
│ └── App.tsx # Main app
|
||||
└── package.json
|
||||
```
|
||||
NOFX is built with a modern, modular architecture:
|
||||
|
||||
### Core Dependencies
|
||||
- **Backend:** Go with Gin framework, SQLite database
|
||||
- **Frontend:** React 18 + TypeScript + Vite + TailwindCSS
|
||||
- **Multi-Exchange Support:** Binance, Hyperliquid, Aster DEX
|
||||
- **AI Integration:** DeepSeek, Qwen, and custom OpenAI-compatible APIs
|
||||
- **State Management:** Zustand for frontend, database-driven for backend
|
||||
- **Real-time Updates:** SWR with 5-10s polling intervals
|
||||
|
||||
**Backend (Go)**
|
||||
- `github.com/adshao/go-binance/v2` - Binance API client
|
||||
- `github.com/markcheno/go-talib` - Technical indicator calculation (TA-Lib)
|
||||
- `github.com/gin-gonic/gin` - HTTP API framework
|
||||
**Key Features:**
|
||||
- 🗄️ Database-driven configuration (no more JSON editing)
|
||||
- 🔐 JWT authentication with optional 2FA support
|
||||
- 📊 Real-time performance tracking and analytics
|
||||
- 🤖 Multi-AI competition mode with live comparison
|
||||
- 🔌 RESTful API for all configuration and monitoring
|
||||
|
||||
**Frontend (React + TypeScript)**
|
||||
- `react` + `react-dom` - UI framework
|
||||
- `recharts` - Chart library (equity curve, comparison charts)
|
||||
- `swr` - Data fetching and caching
|
||||
- `tailwindcss` - CSS framework
|
||||
📖 **For detailed architecture documentation, see:**
|
||||
- **English:** [Architecture Documentation](docs/architecture/README.md)
|
||||
- **中文:** [架构文档](docs/architecture/README.zh-CN.md)
|
||||
|
||||
---
|
||||
|
||||
@@ -326,8 +324,8 @@ Open your browser and visit: **http://localhost:3000**
|
||||
```
|
||||
|
||||
**📖 For detailed Docker deployment guide, troubleshooting, and advanced configuration:**
|
||||
- **English**: See [DOCKER_DEPLOY.en.md](DOCKER_DEPLOY.en.md)
|
||||
- **中文**: 查看 [DOCKER_DEPLOY.md](DOCKER_DEPLOY.md)
|
||||
- **English**: See [docs/getting-started/docker-deploy.en.md](docs/getting-started/docker-deploy.en.md)
|
||||
- **中文**: 查看 [docs/getting-started/docker-deploy.zh-CN.md](docs/getting-started/docker-deploy.zh-CN.md)
|
||||
|
||||
---
|
||||
|
||||
@@ -436,7 +434,7 @@ go build -o nofx
|
||||
|
||||
```
|
||||
╔════════════════════════════════════════════════════════════╗
|
||||
║ 🤖 AI多模型交易系统 - 支持 DeepSeek & Qwen ║
|
||||
║ 🤖 AI多模型交易系统 - 支持 DeepSeek & Qwen ║
|
||||
╚════════════════════════════════════════════════════════════╝
|
||||
|
||||
🤖 数据库中的AI交易员配置:
|
||||
@@ -688,12 +686,12 @@ The leverage settings control the maximum leverage the AI can use for each trade
|
||||
|
||||
~~**Configuration format:**~~
|
||||
|
||||
~~```json
|
||||
```json
|
||||
"leverage": {
|
||||
"btc_eth_leverage": 5, // Maximum leverage for BTC and ETH
|
||||
"altcoin_leverage": 5 // Maximum leverage for all other coins
|
||||
}
|
||||
```~~
|
||||
```
|
||||
|
||||
*Note: Leverage is now configured through the web interface*
|
||||
|
||||
@@ -715,20 +713,20 @@ The leverage settings control the maximum leverage the AI can use for each trade
|
||||
**Examples:**
|
||||
|
||||
~~**Safe configuration (subaccount or conservative):**~~
|
||||
~~```json
|
||||
```json
|
||||
"leverage": {
|
||||
"btc_eth_leverage": 5,
|
||||
"altcoin_leverage": 5
|
||||
}
|
||||
```~~
|
||||
```
|
||||
|
||||
~~**Aggressive configuration (main account only):**~~
|
||||
~~```json
|
||||
```json
|
||||
"leverage": {
|
||||
"btc_eth_leverage": 20,
|
||||
"altcoin_leverage": 15
|
||||
}
|
||||
```~~
|
||||
```
|
||||
|
||||
*Note: Leverage configuration is now done through the web interface*
|
||||
|
||||
@@ -915,109 +913,100 @@ Should return: `{"status":"ok"}`
|
||||
|
||||
Each decision cycle (default 3 minutes), the system executes the following intelligent process:
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────────────────────┐
|
||||
│ 1. 📊 Analyze Historical Performance (last 20 cycles) │
|
||||
├──────────────────────────────────────────────────────────┤
|
||||
│ ✓ Calculate overall win rate, avg profit, P/L ratio │
|
||||
│ ✓ Per-coin statistics (win rate, avg P/L in USDT) │
|
||||
│ ✓ Identify best/worst performing coins │
|
||||
│ ✓ List last 5 trade details with accurate PnL │
|
||||
│ ✓ Calculate Sharpe ratio for risk-adjusted performance │
|
||||
│ 📌 NEW (v2.0.2): Accurate USDT PnL with leverage │
|
||||
└──────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌──────────────────────────────────────────────────────────┐
|
||||
│ 2. 💰 Get Account Status │
|
||||
├──────────────────────────────────────────────────────────┤
|
||||
│ • Total equity & available balance │
|
||||
│ • Number of open positions & unrealized P/L │
|
||||
│ • Margin usage rate (AI manages up to 90%) │
|
||||
│ • Daily P/L tracking & drawdown monitoring │
|
||||
└──────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌──────────────────────────────────────────────────────────┐
|
||||
│ 3. 🔍 Analyze Existing Positions (if any) │
|
||||
├──────────────────────────────────────────────────────────┤
|
||||
│ • For each position, fetch latest market data │
|
||||
│ • Calculate real-time technical indicators: │
|
||||
│ - 3min K-line: RSI(7), MACD, EMA20 │
|
||||
│ - 4hour K-line: RSI(14), EMA20/50, ATR │
|
||||
│ • Track position holding duration (e.g., "2h 15min") │
|
||||
│ 📌 NEW (v2.0.2): Shows how long each position held │
|
||||
│ • Display: Entry price, current price, P/L%, duration │
|
||||
│ • AI evaluates: Should hold or close? │
|
||||
└──────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌──────────────────────────────────────────────────────────┐
|
||||
│ 4. 🎯 Evaluate New Opportunities (candidate coins) │
|
||||
├──────────────────────────────────────────────────────────┤
|
||||
│ • Fetch coin pool (2 modes): │
|
||||
│ 🌟 Default Mode: BTC, ETH, SOL, BNB, XRP, etc. │
|
||||
│ ⚙️ Advanced Mode: AI500 (top 20) + OI Top (top 20) │
|
||||
│ • Merge & deduplicate candidate coins │
|
||||
│ • Filter: Remove low liquidity (<15M USD OI value) │
|
||||
│ • Batch fetch market data + technical indicators │
|
||||
│ • Calculate volatility, trend strength, volume surge │
|
||||
└──────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌──────────────────────────────────────────────────────────┐
|
||||
│ 5. 🧠 AI Comprehensive Decision (DeepSeek/Qwen) │
|
||||
├──────────────────────────────────────────────────────────┤
|
||||
│ • Review historical feedback: │
|
||||
│ - Recent win rate & profit factor │
|
||||
│ - Best/worst coins performance │
|
||||
│ - Avoid repeating mistakes │
|
||||
│ • Analyze all raw sequence data: │
|
||||
│ - 3min price序列, 4hour K-line序列 │
|
||||
│ - Complete indicator sequences (not just latest) │
|
||||
│ 📌 NEW (v2.0.2): AI has full freedom to analyze │
|
||||
│ • Chain of Thought (CoT) reasoning process │
|
||||
│ • Output structured decisions: │
|
||||
│ - Action: close_long/close_short/open_long/open_short│
|
||||
│ - Coin symbol, quantity, leverage │
|
||||
│ - Stop-loss & take-profit levels (≥1:2 ratio) │
|
||||
│ • Decision: Wait/Hold/Close/Open │
|
||||
└──────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌──────────────────────────────────────────────────────────┐
|
||||
│ 6. ⚡ Execute Trades │
|
||||
├──────────────────────────────────────────────────────────┤
|
||||
│ • Priority order: Close existing → Then open new │
|
||||
│ • Risk checks before execution: │
|
||||
│ - Position size limits (1.5x for altcoins, 10x BTC) │
|
||||
│ - No duplicate positions (same coin + direction) │
|
||||
│ - Margin usage within 90% limit │
|
||||
│ • Auto-fetch & apply Binance LOT_SIZE precision │
|
||||
│ • Execute orders via Binance Futures API │
|
||||
│ • After closing: Auto-cancel all pending orders │
|
||||
│ • Record actual execution price & order ID │
|
||||
│ 📌 Track position open time for duration calculation │
|
||||
└──────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌──────────────────────────────────────────────────────────┐
|
||||
│ 7. 📝 Record Complete Logs & Update Performance │
|
||||
├──────────────────────────────────────────────────────────┤
|
||||
│ • Save decision log to decision_logs/{trader_id}/ │
|
||||
│ • Log includes: │
|
||||
│ - Complete Chain of Thought (CoT) │
|
||||
│ - Input prompt with all market data │
|
||||
│ - Structured decision JSON │
|
||||
│ - Account snapshot (balance, positions, margin) │
|
||||
│ - Execution results (success/failure, prices) │
|
||||
│ • Update performance database: │
|
||||
│ - Match open/close pairs by symbol_side key │
|
||||
│ 📌 NEW: Prevents long/short conflicts │
|
||||
│ - Calculate accurate USDT PnL: │
|
||||
│ PnL = Position Value × Price Δ% × Leverage │
|
||||
│ 📌 NEW: Considers quantity + leverage │
|
||||
│ - Store: quantity, leverage, open time, close time │
|
||||
│ - Update win rate, profit factor, Sharpe ratio │
|
||||
│ • Performance data feeds back into next cycle │
|
||||
└──────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
(Repeat every 3-5 min)
|
||||
```
|
||||
### Step 1: 📊 Analyze Historical Performance (last 20 cycles)
|
||||
- ✓ Calculate overall win rate, avg profit, P/L ratio
|
||||
- ✓ Per-coin statistics (win rate, avg P/L in USDT)
|
||||
- ✓ Identify best/worst performing coins
|
||||
- ✓ List last 5 trade details with accurate PnL
|
||||
- ✓ Calculate Sharpe ratio for risk-adjusted performance
|
||||
- 📌 **NEW (v2.0.2)**: Accurate USDT PnL with leverage
|
||||
|
||||
**↓**
|
||||
|
||||
### Step 2: 💰 Get Account Status
|
||||
- Total equity & available balance
|
||||
- Number of open positions & unrealized P/L
|
||||
- Margin usage rate (AI manages up to 90%)
|
||||
- Daily P/L tracking & drawdown monitoring
|
||||
|
||||
**↓**
|
||||
|
||||
### Step 3: 🔍 Analyze Existing Positions (if any)
|
||||
- For each position, fetch latest market data
|
||||
- Calculate real-time technical indicators:
|
||||
- 3min K-line: RSI(7), MACD, EMA20
|
||||
- 4hour K-line: RSI(14), EMA20/50, ATR
|
||||
- Track position holding duration (e.g., "2h 15min")
|
||||
- 📌 **NEW (v2.0.2)**: Shows how long each position held
|
||||
- Display: Entry price, current price, P/L%, duration
|
||||
- AI evaluates: Should hold or close?
|
||||
|
||||
**↓**
|
||||
|
||||
### Step 4: 🎯 Evaluate New Opportunities (candidate coins)
|
||||
- Fetch coin pool (2 modes):
|
||||
- 🌟 **Default Mode**: BTC, ETH, SOL, BNB, XRP, etc.
|
||||
- ⚙️ **Advanced Mode**: AI500 (top 20) + OI Top (top 20)
|
||||
- Merge & deduplicate candidate coins
|
||||
- Filter: Remove low liquidity (<15M USD OI value)
|
||||
- Batch fetch market data + technical indicators
|
||||
- Calculate volatility, trend strength, volume surge
|
||||
|
||||
**↓**
|
||||
|
||||
### Step 5: 🧠 AI Comprehensive Decision (DeepSeek/Qwen)
|
||||
- Review historical feedback:
|
||||
- Recent win rate & profit factor
|
||||
- Best/worst coins performance
|
||||
- Avoid repeating mistakes
|
||||
- Analyze all raw sequence data:
|
||||
- 3min price sequences, 4hour K-line sequences
|
||||
- Complete indicator sequences (not just latest)
|
||||
- 📌 **NEW (v2.0.2)**: AI has full freedom to analyze
|
||||
- Chain of Thought (CoT) reasoning process
|
||||
- Output structured decisions:
|
||||
- Action: `close_long` / `close_short` / `open_long` / `open_short`
|
||||
- Coin symbol, quantity, leverage
|
||||
- Stop-loss & take-profit levels (≥1:2 ratio)
|
||||
- Decision: Wait / Hold / Close / Open
|
||||
|
||||
**↓**
|
||||
|
||||
### Step 6: ⚡ Execute Trades
|
||||
- Priority order: Close existing → Then open new
|
||||
- Risk checks before execution:
|
||||
- Position size limits (1.5x for altcoins, 10x BTC)
|
||||
- No duplicate positions (same coin + direction)
|
||||
- Margin usage within 90% limit
|
||||
- Auto-fetch & apply Binance LOT_SIZE precision
|
||||
- Execute orders via Binance Futures API
|
||||
- After closing: Auto-cancel all pending orders
|
||||
- Record actual execution price & order ID
|
||||
- 📌 Track position open time for duration calculation
|
||||
|
||||
**↓**
|
||||
|
||||
### Step 7: 📝 Record Complete Logs & Update Performance
|
||||
- Save decision log to `decision_logs/{trader_id}/`
|
||||
- Log includes:
|
||||
- Complete Chain of Thought (CoT)
|
||||
- Input prompt with all market data
|
||||
- Structured decision JSON
|
||||
- Account snapshot (balance, positions, margin)
|
||||
- Execution results (success/failure, prices)
|
||||
- Update performance database:
|
||||
- Match open/close pairs by `symbol_side` key
|
||||
- 📌 **NEW**: Prevents long/short conflicts
|
||||
- Calculate accurate USDT PnL:
|
||||
- `PnL = Position Value × Price Δ% × Leverage`
|
||||
- 📌 **NEW**: Considers quantity + leverage
|
||||
- Store: quantity, leverage, open time, close time
|
||||
- Update win rate, profit factor, Sharpe ratio
|
||||
- Performance data feeds back into next cycle
|
||||
|
||||
**↓**
|
||||
|
||||
**🔄 (Repeat every 3-5 min)**
|
||||
|
||||
### Key Improvements in v2.0.2
|
||||
|
||||
@@ -1229,145 +1218,19 @@ sudo apt-get install libta-lib0-dev
|
||||
|
||||
## 🔄 Changelog
|
||||
|
||||
### v3.0.0 (2025-10-30) - Major Architecture Transformation
|
||||
📖 **For detailed version history and updates, see:**
|
||||
|
||||
**🚀 Complete System Redesign - Web-Based Configuration Platform**
|
||||
- **English:** [CHANGELOG.md](CHANGELOG.md)
|
||||
- **中文:** [CHANGELOG.zh-CN.md](CHANGELOG.zh-CN.md)
|
||||
|
||||
This is a **major breaking update** that completely transforms NOFX from a static config-based system to a modern web-based trading platform.
|
||||
**Latest Release:** v3.0.0 (2025-10-30) - Major Architecture Transformation
|
||||
|
||||
**Revolutionary Changes:**
|
||||
|
||||
**1. Database-Driven Architecture**
|
||||
- ✅ **SQLite Integration**: Replaced static JSON config with SQLite database
|
||||
- ✅ **Persistent Storage**: All configurations stored in database with automatic timestamps
|
||||
- ✅ **Data Integrity**: Foreign key relationships and triggers for data consistency
|
||||
- ✅ **Schema Design**: Separate tables for AI models, exchanges, traders, and system config
|
||||
|
||||
**2. Web-Based Configuration Interface**
|
||||
- ✅ **No More JSON Editing**: Complete web-based configuration management
|
||||
- ✅ **AI Model Setup**: Configure DeepSeek/Qwen API keys through web interface
|
||||
- ✅ **Exchange Management**: Set up Binance/Hyperliquid credentials independently
|
||||
- ✅ **Dynamic Trader Creation**: Create traders by combining any AI model with any exchange
|
||||
- ✅ **Real-Time Control**: Start/stop traders without system restart
|
||||
|
||||
**3. Flexible Architecture**
|
||||
- ✅ **Separation of Concerns**: AI models and exchanges configured independently
|
||||
- ✅ **Mix & Match**: Create unlimited combinations (e.g., Qwen + Binance, DeepSeek + Hyperliquid)
|
||||
- ✅ **Scalable Design**: Support for unlimited traders and configurations
|
||||
- ✅ **Clean Slate**: No default traders - create only what you need
|
||||
|
||||
**4. Enhanced API Layer**
|
||||
- ✅ **RESTful Design**: Complete CRUD operations for all configuration entities
|
||||
- ✅ **New Endpoints**:
|
||||
- `GET/PUT /api/models` - AI model configuration
|
||||
- `GET/PUT /api/exchanges` - Exchange configuration
|
||||
- `POST/DELETE /api/traders` - Trader management
|
||||
- `POST /api/traders/:id/start|stop` - Trader control
|
||||
- ✅ **Updated Documentation**: All API endpoints documented
|
||||
|
||||
**5. Modernized Codebase**
|
||||
- ✅ **Type Safety**: Proper separation of legacy and new configuration types
|
||||
- ✅ **Database Abstraction**: Clean database layer with prepared statements
|
||||
- ✅ **Error Handling**: Comprehensive error handling and validation
|
||||
- ✅ **Code Organization**: Better separation between database, API, and business logic
|
||||
|
||||
**Migration Notes:**
|
||||
- ⚠️ **Breaking Change**: Old ~~`config.json`~~ files are no longer used
|
||||
- ⚠️ **Fresh Start**: All configurations must be redone through web interface
|
||||
- ✅ **Easier Setup**: Web-based configuration is much more user-friendly
|
||||
- ✅ **Better UX**: No more server restarts for configuration changes
|
||||
|
||||
**Why This Update Matters:**
|
||||
- 🎯 **User Experience**: Much easier to configure and manage
|
||||
- 🔧 **Flexibility**: Create any combination of AI models and exchanges
|
||||
- 📊 **Scalability**: Support for complex multi-trader setups
|
||||
- 🔒 **Reliability**: Database ensures data persistence and consistency
|
||||
- 🚀 **Future-Proof**: Foundation for advanced features like trader templates, backtesting, etc.
|
||||
|
||||
### v2.0.2 (2025-10-29)
|
||||
|
||||
**Critical Bug Fixes - Trade History & Performance Analysis:**
|
||||
|
||||
This version fixes **critical calculation errors** in the historical trade record and performance analysis system that significantly affected profitability statistics.
|
||||
|
||||
**1. PnL Calculation - Major Error Fixed** (logger/decision_logger.go)
|
||||
- **Problem**: Previously calculated PnL as percentage only, completely ignoring position size and leverage
|
||||
- Example: 100 USDT position earning 5% and 1000 USDT position earning 5% both showed `5.0` as profit
|
||||
- This made performance analysis completely inaccurate
|
||||
- **Solution**: Now calculates actual USDT profit amount
|
||||
```
|
||||
PnL (USDT) = Position Value × Price Change % × Leverage
|
||||
Example: 1000 USDT × 5% × 20x = 1000 USDT actual profit
|
||||
```
|
||||
- **Impact**: Win rate, profit factor, and Sharpe ratio now based on accurate USDT amounts
|
||||
|
||||
**2. Position Tracking - Missing Critical Data**
|
||||
- **Problem**: Open position records only stored price and time, missing quantity and leverage
|
||||
- **Solution**: Now stores complete trade data:
|
||||
- `quantity`: Position size (in coins)
|
||||
- `leverage`: Leverage multiplier (e.g., 20x)
|
||||
- These are essential for accurate PnL calculations
|
||||
|
||||
**3. Position Key Logic - Long/Short Conflict**
|
||||
- **Problem**: Used `symbol` as position key, causing data conflicts when holding both long and short
|
||||
- Example: BTCUSDT long and BTCUSDT short would overwrite each other
|
||||
- **Solution**: Changed to `symbol_side` format (e.g., `BTCUSDT_long`, `BTCUSDT_short`)
|
||||
- Now properly distinguishes between long and short positions
|
||||
|
||||
**4. Sharpe Ratio Calculation - Code Optimization**
|
||||
- **Problem**: Used custom Newton's method for square root calculation
|
||||
- **Solution**: Replaced with standard library `math.Sqrt`
|
||||
- More reliable, maintainable, and efficient
|
||||
|
||||
**Why This Update Matters:**
|
||||
- ✅ Historical trade statistics now show **real USDT profit/loss** instead of meaningless percentages
|
||||
- ✅ Performance comparison between different leverage trades is now accurate
|
||||
- ✅ AI self-learning mechanism receives correct historical feedback
|
||||
- ✅ Profit factor and Sharpe ratio calculations are now meaningful
|
||||
- ✅ Multi-position tracking (long + short simultaneously) works correctly
|
||||
|
||||
**Recommendation**: If you were running the system before this update, your historical statistics were inaccurate. After updating to v2.0.2, new trades will be calculated correctly.
|
||||
|
||||
### v2.0.2 (2025-10-29)
|
||||
|
||||
**Bug Fixes:**
|
||||
- ✅ Fixed Aster exchange precision error (code -1111: "Precision is over the maximum defined for this asset")
|
||||
- ✅ Improved price and quantity formatting to match exchange precision requirements
|
||||
- ✅ Added detailed precision processing logs for debugging
|
||||
- ✅ Enhanced all order functions (OpenLong, OpenShort, CloseLong, CloseShort, SetStopLoss, SetTakeProfit) with proper precision handling
|
||||
|
||||
**Technical Details:**
|
||||
- Added `formatFloatWithPrecision` function to convert float64 to strings with correct precision
|
||||
- Price and quantity parameters are now formatted according to exchange's `pricePrecision` and `quantityPrecision` specifications
|
||||
- Trailing zeros are removed from formatted values to optimize API requests
|
||||
|
||||
### v2.0.1 (2025-10-29)
|
||||
|
||||
**Bug Fixes:**
|
||||
- ✅ Fixed ComparisonChart data processing logic - switched from cycle_number to timestamp grouping
|
||||
- ✅ Resolved chart freezing issue when backend restarts and cycle_number resets
|
||||
- ✅ Improved chart data display - now shows all historical data points chronologically
|
||||
- ✅ Enhanced debugging logs for better troubleshooting
|
||||
|
||||
### v2.0.0 (2025-10-28)
|
||||
|
||||
**Major Updates:**
|
||||
- ✅ AI self-learning mechanism (historical feedback, performance analysis)
|
||||
- ✅ Multi-trader competition mode (Qwen vs DeepSeek)
|
||||
- ✅ Binance-style UI (complete Binance interface imitation)
|
||||
- ✅ Performance comparison charts (real-time ROI comparison)
|
||||
- ✅ Risk control optimization (per-coin position limit adjustment)
|
||||
|
||||
**Bug Fixes:**
|
||||
- Fixed hardcoded initial balance issue
|
||||
- Fixed multi-trader data sync issue
|
||||
- Optimized chart data alignment (using cycle_number)
|
||||
|
||||
### v1.0.0 (2025-10-27)
|
||||
- Initial release
|
||||
- Basic AI trading functionality
|
||||
- Decision logging system
|
||||
- Simple Web interface
|
||||
**Recent Highlights:**
|
||||
- 🚀 Complete system redesign with web-based configuration
|
||||
- 🗄️ Database-driven architecture (SQLite)
|
||||
- 🎨 No more JSON editing - all configuration through web interface
|
||||
- 🔧 Mix & match AI models with any exchange
|
||||
- 📊 Enhanced API layer with comprehensive endpoints
|
||||
|
||||
---
|
||||
|
||||
@@ -1379,10 +1242,14 @@ MIT License - See [LICENSE](LICENSE) file for details
|
||||
|
||||
## 🤝 Contributing
|
||||
|
||||
Issues and Pull Requests are welcome!
|
||||
We welcome contributions from the community! See our comprehensive guides:
|
||||
|
||||
### Development Guide
|
||||
- **📖 [Contributing Guide](CONTRIBUTING.md)** - Complete development workflow, code standards, and PR process
|
||||
- **🤝 [Code of Conduct](CODE_OF_CONDUCT.md)** - Community guidelines and standards
|
||||
- **💰 [Bounty Program](docs/community/bounty-guide.md)** - Earn rewards for contributions
|
||||
- **🔒 [Security Policy](SECURITY.md)** - Report vulnerabilities responsibly
|
||||
|
||||
**Quick Start:**
|
||||
1. Fork the project
|
||||
2. Create feature branch (`git checkout -b feature/AmazingFeature`)
|
||||
3. Commit changes (`git commit -m 'Add some AmazingFeature'`)
|
||||
|
||||
469
SECURITY.md
Normal file
469
SECURITY.md
Normal file
@@ -0,0 +1,469 @@
|
||||
# Security Policy / 安全政策
|
||||
|
||||
**Languages:** [English](#english) | [中文](#中文)
|
||||
|
||||
---
|
||||
|
||||
# English
|
||||
|
||||
## 🛡️ Security Overview
|
||||
|
||||
NOFX is an AI-powered trading system that handles real funds and API credentials. We take security seriously and appreciate the security community's efforts to responsibly disclose vulnerabilities.
|
||||
|
||||
**Critical Areas:**
|
||||
- 🔑 API key storage and handling
|
||||
- 💰 Trading execution and fund management
|
||||
- 🔐 Authentication and authorization
|
||||
- 🗄️ Database security (SQLite)
|
||||
- 🌐 Web interface and API endpoints
|
||||
|
||||
---
|
||||
|
||||
## 📋 Supported Versions
|
||||
|
||||
We provide security updates for the following versions:
|
||||
|
||||
| Version | Supported | Notes |
|
||||
| ------- | ------------------ | -------------------- |
|
||||
| 3.x | ✅ Fully supported | Current stable release |
|
||||
| 2.x | ⚠️ Limited support | Security fixes only |
|
||||
| < 2.0 | ❌ Not supported | Please upgrade |
|
||||
|
||||
**Recommendation:** Always use the latest stable release (v3.x) for best security.
|
||||
|
||||
---
|
||||
|
||||
## 🔒 Reporting a Vulnerability
|
||||
|
||||
### ⚠️ Please DO NOT Publicly Disclose
|
||||
|
||||
If you discover a security vulnerability in NOFX, please **DO NOT**:
|
||||
- ❌ Open a public GitHub Issue
|
||||
- ❌ Discuss it on social media (Twitter, Reddit, etc.)
|
||||
- ❌ Share it in Telegram/Discord groups
|
||||
- ❌ Post it on security forums before we've had time to fix it
|
||||
|
||||
Public disclosure before a fix is available puts all users at risk.
|
||||
|
||||
### ✅ Responsible Disclosure Process
|
||||
|
||||
**Step 1: Report Privately**
|
||||
|
||||
Contact core team directly:
|
||||
- **Tinkle:** [@Web3Tinkle on Twitter](https://x.com/Web3Tinkle) (DM)
|
||||
|
||||
**Alternative:** Encrypted communication via [Keybase](https://keybase.io/) (if available)
|
||||
|
||||
**Step 2: Include These Details**
|
||||
|
||||
```markdown
|
||||
Subject: [SECURITY] Brief description of vulnerability
|
||||
|
||||
## Vulnerability Description
|
||||
Clear explanation of the security issue
|
||||
|
||||
## Affected Components
|
||||
- Which parts of the system are affected?
|
||||
- Which versions are vulnerable?
|
||||
|
||||
## Reproduction Steps
|
||||
1. Step-by-step instructions
|
||||
2. Sample code or commands (if applicable)
|
||||
3. Expected vs actual behavior
|
||||
|
||||
## Potential Impact
|
||||
- Can funds be stolen?
|
||||
- Can API keys be leaked?
|
||||
- Can accounts be compromised?
|
||||
- Rate the severity: Critical / High / Medium / Low
|
||||
|
||||
## Suggested Fix (Optional)
|
||||
If you have ideas for fixing it, please share!
|
||||
|
||||
## Your Information
|
||||
- Name (or pseudonym)
|
||||
- Contact info for follow-up
|
||||
- If you want public credit (yes/no)
|
||||
```
|
||||
|
||||
**Step 3: Wait for Our Response**
|
||||
|
||||
We will:
|
||||
- ✅ Acknowledge receipt within **24 hours**
|
||||
- ✅ Provide initial assessment within **72 hours**
|
||||
- ✅ Keep you updated on fix progress
|
||||
- ✅ Notify you before public disclosure
|
||||
|
||||
---
|
||||
|
||||
## ⏱️ Response Timeline
|
||||
|
||||
| Stage | Timeline | Action |
|
||||
|-------|----------|--------|
|
||||
| **Acknowledgment** | 24 hours | Confirm we received your report |
|
||||
| **Initial Assessment** | 72 hours | Verify vulnerability, rate severity |
|
||||
| **Fix Development** | 7-30 days | Depends on complexity and severity |
|
||||
| **Testing** | 3-7 days | Verify fix doesn't break functionality |
|
||||
| **Public Disclosure** | After fix deployed | Publish security advisory |
|
||||
|
||||
**Critical vulnerabilities** (fund theft, credential leaks) are prioritized and may be fixed within 48 hours.
|
||||
|
||||
---
|
||||
|
||||
## 💰 Security Bounty Program (Optional)
|
||||
|
||||
We offer rewards for valid security vulnerabilities:
|
||||
|
||||
| Severity | Criteria | Reward |
|
||||
|----------|----------|--------|
|
||||
| **🔴 Critical** | Fund theft, API key extraction, RCE | **$500-1000 USD** |
|
||||
| **🟠 High** | Authentication bypass, unauthorized trading | **$200-500 USD** |
|
||||
| **🟡 Medium** | Information disclosure, XSS, CSRF | **$100-200 USD** |
|
||||
| **🟢 Low** | Security improvements, minor issues | **$50-100 USD or Recognition** |
|
||||
|
||||
**Note:** Bounty amounts are at maintainers' discretion based on:
|
||||
- Severity and impact
|
||||
- Quality of report
|
||||
- Ease of exploitation
|
||||
- Number of affected users
|
||||
|
||||
**Out of Scope (No Bounty):**
|
||||
- Issues in third-party libraries (report to them directly)
|
||||
- Social engineering attacks
|
||||
- DoS/DDoS attacks
|
||||
- Issues requiring physical access
|
||||
- Previously known/reported vulnerabilities
|
||||
|
||||
---
|
||||
|
||||
## 🔐 Security Best Practices (For Users)
|
||||
|
||||
To keep your NOFX deployment secure:
|
||||
|
||||
### 1. API Key Management
|
||||
```bash
|
||||
# ✅ DO: Use environment variables
|
||||
export BINANCE_API_KEY="your_key"
|
||||
export BINANCE_SECRET_KEY="your_secret"
|
||||
|
||||
# ❌ DON'T: Hardcode in source files
|
||||
api_key = "abc123..." # NEVER DO THIS
|
||||
```
|
||||
|
||||
### 2. Database Security
|
||||
```bash
|
||||
# ✅ Set proper permissions
|
||||
chmod 600 nofx.db
|
||||
chmod 600 config.json
|
||||
|
||||
# ❌ DON'T: Leave files world-readable
|
||||
chmod 777 nofx.db # NEVER DO THIS
|
||||
```
|
||||
|
||||
### 3. Network Security
|
||||
```bash
|
||||
# ✅ Use firewall to restrict API access
|
||||
# Only allow localhost to access API server
|
||||
iptables -A INPUT -p tcp --dport 8080 -s 127.0.0.1 -j ACCEPT
|
||||
iptables -A INPUT -p tcp --dport 8080 -j DROP
|
||||
|
||||
# ❌ DON'T: Expose API to public internet without authentication
|
||||
```
|
||||
|
||||
### 4. Use Subaccounts
|
||||
- Create dedicated Binance subaccount for trading
|
||||
- Limit maximum balance
|
||||
- Restrict withdrawal permissions
|
||||
- Use IP whitelist
|
||||
|
||||
### 5. Test on Testnet First
|
||||
- Hyperliquid: Use testnet mode
|
||||
- Binance: Use testnet API (https://testnet.binancefuture.com)
|
||||
- Never test with real funds initially
|
||||
|
||||
### 6. Regular Updates
|
||||
```bash
|
||||
# Check for updates regularly
|
||||
git pull origin main
|
||||
go build -o nofx
|
||||
|
||||
# Subscribe to security advisories
|
||||
# Watch GitHub releases: https://github.com/tinkle-community/nofx/releases
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🚨 Security Advisories
|
||||
|
||||
Past security advisories will be published here:
|
||||
|
||||
### 2025-XX-XX: [Title]
|
||||
- **Severity:** [Critical/High/Medium/Low]
|
||||
- **Affected Versions:** [x.x.x - x.x.x]
|
||||
- **Fixed in:** [x.x.x]
|
||||
- **Description:** [Brief description]
|
||||
- **Mitigation:** [How to protect yourself]
|
||||
|
||||
*No security advisories have been published yet.*
|
||||
|
||||
---
|
||||
|
||||
## 🙏 Security Researchers Hall of Fame
|
||||
|
||||
We thank the following security researchers for responsibly disclosing vulnerabilities:
|
||||
|
||||
*No reports have been submitted yet. Be the first!*
|
||||
|
||||
---
|
||||
|
||||
## 📚 Additional Resources
|
||||
|
||||
**Security Documentation:**
|
||||
- [OWASP Top 10](https://owasp.org/www-project-top-ten/)
|
||||
- [CWE Top 25](https://cwe.mitre.org/top25/)
|
||||
- [Binance API Security Best Practices](https://www.binance.com/en/support/faq/360002502072)
|
||||
|
||||
**Audit Reports:**
|
||||
- No third-party audits completed yet
|
||||
- Self-audit checklist: [TODO: Add link]
|
||||
|
||||
---
|
||||
|
||||
## 📞 Contact
|
||||
|
||||
**For security issues ONLY:**
|
||||
- 🐦 **Twitter DM:** [@Web3Tinkle](https://x.com/Web3Tinkle)
|
||||
|
||||
**For general questions:**
|
||||
- See [CONTRIBUTING.md](CONTRIBUTING.md)
|
||||
- Join [Telegram Community](https://t.me/nofx_dev_community)
|
||||
|
||||
---
|
||||
|
||||
**Thank you for helping keep NOFX secure!** 🔒
|
||||
|
||||
---
|
||||
|
||||
# 中文
|
||||
|
||||
## 🛡️ 安全概述
|
||||
|
||||
NOFX 是一个处理真实资金和 API 凭证的 AI 交易系统。我们非常重视安全,并感谢安全社区负责任地披露漏洞的努力。
|
||||
|
||||
**关键领域:**
|
||||
- 🔑 API 密钥存储和处理
|
||||
- 💰 交易执行和资金管理
|
||||
- 🔐 身份验证和授权
|
||||
- 🗄️ 数据库安全(SQLite)
|
||||
- 🌐 Web 界面和 API 端点
|
||||
|
||||
---
|
||||
|
||||
## 📋 支持的版本
|
||||
|
||||
我们为以下版本提供安全更新:
|
||||
|
||||
| 版本 | 支持状态 | 说明 |
|
||||
| ------- | ------------------ | -------------------- |
|
||||
| 3.x | ✅ 完全支持 | 当前稳定版本 |
|
||||
| 2.x | ⚠️ 有限支持 | 仅安全修复 |
|
||||
| < 2.0 | ❌ 不支持 | 请升级 |
|
||||
|
||||
**建议:** 始终使用最新的稳定版本(v3.x)以获得最佳安全性。
|
||||
|
||||
---
|
||||
|
||||
## 🔒 报告漏洞
|
||||
|
||||
### ⚠️ 请勿公开披露
|
||||
|
||||
如果您在 NOFX 中发现安全漏洞,请**不要**:
|
||||
- ❌ 公开创建 GitHub Issue
|
||||
- ❌ 在社交媒体上讨论(Twitter、Reddit 等)
|
||||
- ❌ 在 Telegram/Discord 群组中分享
|
||||
- ❌ 在我们有时间修复之前发布到安全论坛
|
||||
|
||||
在修复可用之前公开披露会使所有用户面临风险。
|
||||
|
||||
### ✅ 负责任的披露流程
|
||||
|
||||
**步骤 1:私下报告**
|
||||
|
||||
直接联系核心团队:
|
||||
- **Tinkle:** [@Web3Tinkle on Twitter](https://x.com/Web3Tinkle)(私信)
|
||||
|
||||
**替代方案:** 通过 [Keybase](https://keybase.io/) 加密通信(如果可用)
|
||||
|
||||
**步骤 2:包含这些详细信息**
|
||||
|
||||
```markdown
|
||||
主题:[SECURITY] 漏洞简要描述
|
||||
|
||||
## 漏洞描述
|
||||
清楚解释安全问题
|
||||
|
||||
## 受影响的组件
|
||||
- 系统的哪些部分受到影响?
|
||||
- 哪些版本存在漏洞?
|
||||
|
||||
## 复现步骤
|
||||
1. 逐步说明
|
||||
2. 示例代码或命令(如果适用)
|
||||
3. 预期行为 vs 实际行为
|
||||
|
||||
## 潜在影响
|
||||
- 资金是否可能被盗?
|
||||
- API 密钥是否可能泄露?
|
||||
- 账户是否可能被入侵?
|
||||
- 严重程度评级:严重 / 高 / 中 / 低
|
||||
|
||||
## 建议修复(可选)
|
||||
如果您有修复的想法,请分享!
|
||||
|
||||
## 您的信息
|
||||
- 姓名(或化名)
|
||||
- 后续联系信息
|
||||
- 是否希望公开致谢(是/否)
|
||||
```
|
||||
|
||||
**步骤 3:等待我们的回复**
|
||||
|
||||
我们将:
|
||||
- ✅ 在 **24 小时**内确认收到
|
||||
- ✅ 在 **72 小时**内提供初步评估
|
||||
- ✅ 告知您修复进展
|
||||
- ✅ 在公开披露前通知您
|
||||
|
||||
---
|
||||
|
||||
## ⏱️ 响应时间表
|
||||
|
||||
| 阶段 | 时间线 | 行动 |
|
||||
|-------|----------|--------|
|
||||
| **确认** | 24 小时 | 确认我们收到了您的报告 |
|
||||
| **初步评估** | 72 小时 | 验证漏洞,评估严重程度 |
|
||||
| **修复开发** | 7-30 天 | 取决于复杂性和严重程度 |
|
||||
| **测试** | 3-7 天 | 验证修复不会破坏功能 |
|
||||
| **公开披露** | 修复部署后 | 发布安全公告 |
|
||||
|
||||
**严重漏洞**(资金盗窃、凭证泄露)会优先处理,可能在 48 小时内修复。
|
||||
|
||||
---
|
||||
|
||||
## 💰 安全奖励计划(可选)
|
||||
|
||||
我们为有效的安全漏洞提供奖励:
|
||||
|
||||
| 严重程度 | 标准 | 奖励 |
|
||||
|----------|----------|--------|
|
||||
| **🔴 严重** | 资金盗窃、API 密钥提取、RCE | **$500-1000 USD** |
|
||||
| **🟠 高** | 认证绕过、未授权交易 | **$200-500 USD** |
|
||||
| **🟡 中** | 信息泄露、XSS、CSRF | **$100-200 USD** |
|
||||
| **🟢 低** | 安全改进、小问题 | **$50-100 USD 或致谢** |
|
||||
|
||||
**注意:** 奖励金额由维护者根据以下因素酌情决定:
|
||||
- 严重性和影响
|
||||
- 报告质量
|
||||
- 利用难易度
|
||||
- 受影响用户数量
|
||||
|
||||
**不在范围内(无奖励):**
|
||||
- 第三方库的问题(直接向他们报告)
|
||||
- 社会工程攻击
|
||||
- DoS/DDoS 攻击
|
||||
- 需要物理访问的问题
|
||||
- 已知/已报告的漏洞
|
||||
|
||||
---
|
||||
|
||||
## 🔐 安全最佳实践(用户指南)
|
||||
|
||||
保护您的 NOFX 部署安全:
|
||||
|
||||
### 1. API 密钥管理
|
||||
```bash
|
||||
# ✅ 正确:使用环境变量
|
||||
export BINANCE_API_KEY="your_key"
|
||||
export BINANCE_SECRET_KEY="your_secret"
|
||||
|
||||
# ❌ 错误:在源文件中硬编码
|
||||
api_key = "abc123..." # 永远不要这样做
|
||||
```
|
||||
|
||||
### 2. 数据库安全
|
||||
```bash
|
||||
# ✅ 设置适当的权限
|
||||
chmod 600 nofx.db
|
||||
chmod 600 config.json
|
||||
|
||||
# ❌ 不要:让文件全局可读
|
||||
chmod 777 nofx.db # 永远不要这样做
|
||||
```
|
||||
|
||||
### 3. 网络安全
|
||||
```bash
|
||||
# ✅ 使用防火墙限制 API 访问
|
||||
# 仅允许本地访问 API 服务器
|
||||
iptables -A INPUT -p tcp --dport 8080 -s 127.0.0.1 -j ACCEPT
|
||||
iptables -A INPUT -p tcp --dport 8080 -j DROP
|
||||
|
||||
# ❌ 不要:在没有身份验证的情况下将 API 暴露到公共互联网
|
||||
```
|
||||
|
||||
### 4. 使用子账户
|
||||
- 为交易创建专用的 Binance 子账户
|
||||
- 限制最大余额
|
||||
- 限制提现权限
|
||||
- 使用 IP 白名单
|
||||
|
||||
### 5. 先在测试网上测试
|
||||
- Hyperliquid:使用测试网模式
|
||||
- Binance:使用测试网 API (https://testnet.binancefuture.com)
|
||||
- 最初永远不要用真实资金测试
|
||||
|
||||
### 6. 定期更新
|
||||
```bash
|
||||
# 定期检查更新
|
||||
git pull origin main
|
||||
go build -o nofx
|
||||
|
||||
# 订阅安全公告
|
||||
# 关注 GitHub 发布:https://github.com/tinkle-community/nofx/releases
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🚨 安全公告
|
||||
|
||||
过去的安全公告将在此发布:
|
||||
|
||||
### 2025-XX-XX: [标题]
|
||||
- **严重程度:** [严重/高/中/低]
|
||||
- **受影响版本:** [x.x.x - x.x.x]
|
||||
- **已修复版本:** [x.x.x]
|
||||
- **描述:** [简要描述]
|
||||
- **缓解措施:** [如何保护自己]
|
||||
|
||||
*尚未发布任何安全公告。*
|
||||
|
||||
---
|
||||
|
||||
## 🙏 安全研究员名人堂
|
||||
|
||||
我们感谢以下安全研究员负责任地披露漏洞:
|
||||
|
||||
*尚未收到任何报告。成为第一个!*
|
||||
|
||||
---
|
||||
|
||||
## 📞 联系方式
|
||||
|
||||
**仅限安全问题:**
|
||||
- 🐦 **Twitter 私信:** [@Web3Tinkle](https://x.com/Web3Tinkle)
|
||||
|
||||
**一般问题:**
|
||||
- 加入 [Telegram 社区](https://t.me/nofx_dev_community)
|
||||
|
||||
---
|
||||
|
||||
**感谢您帮助保持 NOFX 的安全!** 🔒
|
||||
106
api/server.go
106
api/server.go
@@ -88,12 +88,16 @@ func (s *Server) setupRoutes() {
|
||||
// 系统提示词模板管理(无需认证)
|
||||
api.GET("/prompt-templates", s.handleGetPromptTemplates)
|
||||
api.GET("/prompt-templates/:name", s.handleGetPromptTemplate)
|
||||
|
||||
// 公开的竞赛数据(无需认证)
|
||||
api.GET("/traders", s.handlePublicTraderList)
|
||||
api.GET("/competition", s.handlePublicCompetition)
|
||||
|
||||
// 需要认证的路由
|
||||
protected := api.Group("/", s.authMiddleware())
|
||||
{
|
||||
// AI交易员管理
|
||||
protected.GET("/traders", s.handleTraderList)
|
||||
protected.GET("/my-traders", s.handleTraderList)
|
||||
protected.GET("/traders/:id/config", s.handleGetTraderConfig)
|
||||
protected.POST("/traders", s.handleCreateTrader)
|
||||
protected.PUT("/traders/:id", s.handleUpdateTrader)
|
||||
@@ -115,8 +119,6 @@ func (s *Server) setupRoutes() {
|
||||
protected.POST("/user/signal-sources", s.handleSaveUserSignalSource)
|
||||
|
||||
|
||||
// 竞赛总览
|
||||
protected.GET("/competition", s.handleCompetition)
|
||||
|
||||
// 指定trader的数据(使用query参数 ?trader_id=xxx)
|
||||
protected.GET("/status", s.handleStatus)
|
||||
@@ -166,8 +168,13 @@ func (s *Server) handleGetSystemConfig(c *gin.Context) {
|
||||
altcoinLeverage = val
|
||||
}
|
||||
|
||||
// 获取内测模式配置
|
||||
betaModeStr, _ := s.database.GetSystemConfig("beta_mode")
|
||||
betaMode := betaModeStr == "true"
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"admin_mode": auth.IsAdminMode(),
|
||||
"beta_mode": betaMode,
|
||||
"default_coins": defaultCoins,
|
||||
"btc_eth_leverage": btcEthLeverage,
|
||||
"altcoin_leverage": altcoinLeverage,
|
||||
@@ -1168,6 +1175,7 @@ func (s *Server) handleRegister(c *gin.Context) {
|
||||
var req struct {
|
||||
Email string `json:"email" binding:"required,email"`
|
||||
Password string `json:"password" binding:"required,min=6"`
|
||||
BetaCode string `json:"beta_code"`
|
||||
}
|
||||
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
@@ -1175,6 +1183,27 @@ func (s *Server) handleRegister(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
// 检查是否开启了内测模式
|
||||
betaModeStr, _ := s.database.GetSystemConfig("beta_mode")
|
||||
if betaModeStr == "true" {
|
||||
// 内测模式下必须提供有效的内测码
|
||||
if req.BetaCode == "" {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "内测期间,注册需要提供内测码"})
|
||||
return
|
||||
}
|
||||
|
||||
// 验证内测码
|
||||
isValid, err := s.database.ValidateBetaCode(req.BetaCode)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "验证内测码失败"})
|
||||
return
|
||||
}
|
||||
if !isValid {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "内测码无效或已被使用"})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 检查邮箱是否已存在
|
||||
_, err := s.database.GetUserByEmail(req.Email)
|
||||
if err == nil {
|
||||
@@ -1212,6 +1241,18 @@ func (s *Server) handleRegister(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
// 如果是内测模式,标记内测码为已使用
|
||||
betaModeStr2, _ := s.database.GetSystemConfig("beta_mode")
|
||||
if betaModeStr2 == "true" && req.BetaCode != "" {
|
||||
err := s.database.UseBetaCode(req.BetaCode, req.Email)
|
||||
if err != nil {
|
||||
log.Printf("⚠️ 标记内测码为已使用失败: %v", err)
|
||||
// 这里不返回错误,因为用户已经创建成功
|
||||
} else {
|
||||
log.Printf("✓ 内测码 %s 已被用户 %s 使用", req.BetaCode, req.Email)
|
||||
}
|
||||
}
|
||||
|
||||
// 返回OTP设置信息
|
||||
qrCodeURL := auth.GetOTPQRCodeURL(otpSecret, req.Email)
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
@@ -1455,3 +1496,62 @@ func (s *Server) handleGetPromptTemplate(c *gin.Context) {
|
||||
"content": template.Content,
|
||||
})
|
||||
}
|
||||
|
||||
// handlePublicTraderList 获取公开的交易员列表(无需认证)
|
||||
func (s *Server) handlePublicTraderList(c *gin.Context) {
|
||||
// 从所有用户获取交易员信息
|
||||
competition, err := s.traderManager.GetCompetitionData()
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"error": fmt.Sprintf("获取交易员列表失败: %v", err),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 获取traders数组
|
||||
tradersData, exists := competition["traders"]
|
||||
if !exists {
|
||||
c.JSON(http.StatusOK, []map[string]interface{}{})
|
||||
return
|
||||
}
|
||||
|
||||
traders, ok := tradersData.([]map[string]interface{})
|
||||
if !ok {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"error": "交易员数据格式错误",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 返回交易员基本信息,过滤敏感信息
|
||||
result := make([]map[string]interface{}, 0, len(traders))
|
||||
for _, trader := range traders {
|
||||
result = append(result, map[string]interface{}{
|
||||
"trader_id": trader["trader_id"],
|
||||
"trader_name": trader["trader_name"],
|
||||
"ai_model": trader["ai_model"],
|
||||
"exchange": trader["exchange"],
|
||||
"is_running": trader["is_running"],
|
||||
"total_equity": trader["total_equity"],
|
||||
"total_pnl": trader["total_pnl"],
|
||||
"total_pnl_pct": trader["total_pnl_pct"],
|
||||
"position_count": trader["position_count"],
|
||||
"margin_used_pct": trader["margin_used_pct"],
|
||||
})
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, result)
|
||||
}
|
||||
|
||||
// handlePublicCompetition 获取公开的竞赛数据(无需认证)
|
||||
func (s *Server) handlePublicCompetition(c *gin.Context) {
|
||||
competition, err := s.traderManager.GetCompetitionData()
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"error": fmt.Sprintf("获取竞赛数据失败: %v", err),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, competition)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"admin_mode": true,
|
||||
"beta_mode": false,
|
||||
"leverage": {
|
||||
"btc_eth_leverage": 5,
|
||||
"altcoin_leverage": 5
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"encoding/base32"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -125,6 +126,15 @@ func (d *Database) createTables() error {
|
||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
)`,
|
||||
|
||||
// 内测码表
|
||||
`CREATE TABLE IF NOT EXISTS beta_codes (
|
||||
code TEXT PRIMARY KEY,
|
||||
used BOOLEAN DEFAULT 0,
|
||||
used_by TEXT DEFAULT '',
|
||||
used_at DATETIME DEFAULT NULL,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
)`,
|
||||
|
||||
// 触发器:自动更新 updated_at
|
||||
`CREATE TRIGGER IF NOT EXISTS update_users_updated_at
|
||||
AFTER UPDATE ON users
|
||||
@@ -246,6 +256,7 @@ func (d *Database) initDefaultData() error {
|
||||
// 初始化系统配置 - 创建所有字段,设置默认值,后续由config.json同步更新
|
||||
systemConfigs := map[string]string{
|
||||
"admin_mode": "true", // 默认开启管理员模式,便于首次使用
|
||||
"beta_mode": "false", // 默认关闭内测模式
|
||||
"api_server_port": "8080", // 默认API端口
|
||||
"use_default_coins": "true", // 默认使用内置币种列表
|
||||
"default_coins": `["BTCUSDT","ETHUSDT","SOLUSDT","BNBUSDT","XRPUSDT","DOGEUSDT","ADAUSDT","HYPEUSDT"]`, // 默认币种列表(JSON格式)
|
||||
@@ -943,4 +954,106 @@ func (d *Database) UpdateUserSignalSource(userID, coinPoolURL, oiTopURL string)
|
||||
// Close 关闭数据库连接
|
||||
func (d *Database) Close() error {
|
||||
return d.db.Close()
|
||||
}
|
||||
|
||||
// LoadBetaCodesFromFile 从文件加载内测码到数据库
|
||||
func (d *Database) LoadBetaCodesFromFile(filePath string) error {
|
||||
// 读取文件内容
|
||||
content, err := os.ReadFile(filePath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("读取内测码文件失败: %w", err)
|
||||
}
|
||||
|
||||
// 按行分割内测码
|
||||
lines := strings.Split(string(content), "\n")
|
||||
var codes []string
|
||||
for _, line := range lines {
|
||||
code := strings.TrimSpace(line)
|
||||
if code != "" && !strings.HasPrefix(code, "#") {
|
||||
codes = append(codes, code)
|
||||
}
|
||||
}
|
||||
|
||||
// 批量插入内测码
|
||||
tx, err := d.db.Begin()
|
||||
if err != nil {
|
||||
return fmt.Errorf("开始事务失败: %w", err)
|
||||
}
|
||||
defer tx.Rollback()
|
||||
|
||||
stmt, err := tx.Prepare(`INSERT OR IGNORE INTO beta_codes (code) VALUES (?)`)
|
||||
if err != nil {
|
||||
return fmt.Errorf("准备语句失败: %w", err)
|
||||
}
|
||||
defer stmt.Close()
|
||||
|
||||
insertedCount := 0
|
||||
for _, code := range codes {
|
||||
result, err := stmt.Exec(code)
|
||||
if err != nil {
|
||||
log.Printf("插入内测码 %s 失败: %v", code, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if rowsAffected, _ := result.RowsAffected(); rowsAffected > 0 {
|
||||
insertedCount++
|
||||
}
|
||||
}
|
||||
|
||||
if err := tx.Commit(); err != nil {
|
||||
return fmt.Errorf("提交事务失败: %w", err)
|
||||
}
|
||||
|
||||
log.Printf("✅ 成功加载 %d 个内测码到数据库 (总计 %d 个)", insertedCount, len(codes))
|
||||
return nil
|
||||
}
|
||||
|
||||
// ValidateBetaCode 验证内测码是否有效且未使用
|
||||
func (d *Database) ValidateBetaCode(code string) (bool, error) {
|
||||
var used bool
|
||||
err := d.db.QueryRow(`SELECT used FROM beta_codes WHERE code = ?`, code).Scan(&used)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return false, nil // 内测码不存在
|
||||
}
|
||||
return false, err
|
||||
}
|
||||
return !used, nil // 内测码存在且未使用
|
||||
}
|
||||
|
||||
// UseBetaCode 使用内测码(标记为已使用)
|
||||
func (d *Database) UseBetaCode(code, userEmail string) error {
|
||||
result, err := d.db.Exec(`
|
||||
UPDATE beta_codes SET used = 1, used_by = ?, used_at = CURRENT_TIMESTAMP
|
||||
WHERE code = ? AND used = 0
|
||||
`, userEmail, code)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
rowsAffected, err := result.RowsAffected()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if rowsAffected == 0 {
|
||||
return fmt.Errorf("内测码无效或已被使用")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetBetaCodeStats 获取内测码统计信息
|
||||
func (d *Database) GetBetaCodeStats() (total, used int, err error) {
|
||||
err = d.db.QueryRow(`SELECT COUNT(*) FROM beta_codes`).Scan(&total)
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
|
||||
err = d.db.QueryRow(`SELECT COUNT(*) FROM beta_codes WHERE used = 1`).Scan(&used)
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
|
||||
return total, used, nil
|
||||
}
|
||||
242
docs/MIGRATION_GUIDE.md
Normal file
242
docs/MIGRATION_GUIDE.md
Normal file
@@ -0,0 +1,242 @@
|
||||
# 📦 Documentation Migration Guide
|
||||
|
||||
## What Changed?
|
||||
|
||||
NOFX documentation has been reorganized into a structured `docs/` directory for better organization and navigation.
|
||||
|
||||
## 🗺️ File Locations (Old → New)
|
||||
|
||||
### Deployment Guides
|
||||
- `DOCKER_DEPLOY.en.md` → `docs/getting-started/docker-deploy.en.md`
|
||||
- `DOCKER_DEPLOY.md` → `docs/getting-started/docker-deploy.zh-CN.md`
|
||||
- `PM2_DEPLOYMENT.md` → `docs/getting-started/pm2-deploy.md`
|
||||
- `CUSTOM_API.md` → `docs/getting-started/custom-api.md`
|
||||
|
||||
### Community Docs
|
||||
- `HOW_TO_POST_BOUNTY.md` → `docs/community/bounty-guide.md`
|
||||
- `INTEGRATION_BOUNTY_HYPERLIQUID.md` → `docs/community/bounty-hyperliquid.md`
|
||||
- `INTEGRATION_BOUNTY_ASTER.md` → `docs/community/bounty-aster.md`
|
||||
|
||||
### Internationalization
|
||||
- `README.zh-CN.md` → `docs/i18n/zh-CN/README.md`
|
||||
- `README.ru.md` → `docs/i18n/ru/README.md`
|
||||
- `README.uk.md` → `docs/i18n/uk/README.md`
|
||||
- `常见问题.md` → `docs/guides/faq.zh-CN.md`
|
||||
|
||||
### Root Directory (Unchanged)
|
||||
These stay in the root for GitHub recognition:
|
||||
- `README.md` ✅ (stays in root)
|
||||
- `LICENSE` ✅ (stays in root)
|
||||
- `CONTRIBUTING.md` ✅ (stays in root)
|
||||
- `CODE_OF_CONDUCT.md` ✅ (stays in root)
|
||||
- `SECURITY.md` ✅ (stays in root)
|
||||
|
||||
## 🎯 Why This Change?
|
||||
|
||||
### Before (❌ Problems)
|
||||
```
|
||||
nofx/
|
||||
├── README.md
|
||||
├── README.zh-CN.md
|
||||
├── README.ru.md
|
||||
├── README.uk.md
|
||||
├── DOCKER_DEPLOY.md
|
||||
├── DOCKER_DEPLOY.en.md
|
||||
├── PM2_DEPLOYMENT.md
|
||||
├── CUSTOM_API.md
|
||||
├── HOW_TO_POST_BOUNTY.md
|
||||
├── INTEGRATION_BOUNTY_HYPERLIQUID.md
|
||||
├── INTEGRATION_BOUNTY_ASTER.md
|
||||
├── 常见问题.md
|
||||
└── ... (15+ markdown files in root!)
|
||||
```
|
||||
|
||||
**Issues:**
|
||||
- 😵 Too cluttered (15+ files in root)
|
||||
- 🔍 Hard to find specific docs
|
||||
- 🌍 Mixed languages
|
||||
- 📚 No clear organization
|
||||
|
||||
### After (✅ Benefits)
|
||||
```
|
||||
nofx/
|
||||
├── README.md # Project homepage
|
||||
├── LICENSE # Legal (GitHub needs it here)
|
||||
├── CONTRIBUTING.md # GitHub auto-links
|
||||
├── CODE_OF_CONDUCT.md # GitHub auto-links
|
||||
├── SECURITY.md # GitHub auto-links
|
||||
│
|
||||
└── docs/ # 📚 Documentation hub
|
||||
├── README.md # Documentation home
|
||||
├── getting-started/ # 🚀 Setup guides
|
||||
├── guides/ # 📘 User guides
|
||||
├── community/ # 👥 Contribution docs
|
||||
├── i18n/ # 🌍 Translations
|
||||
└── architecture/ # 🏗️ Technical docs
|
||||
```
|
||||
|
||||
**Benefits:**
|
||||
- ✅ Clean root directory
|
||||
- ✅ Logical categorization
|
||||
- ✅ Easy navigation
|
||||
- ✅ Scalable structure
|
||||
- ✅ Professional appearance
|
||||
|
||||
## 📚 New Documentation Structure
|
||||
|
||||
### Root Level
|
||||
Files GitHub needs to see:
|
||||
- `README.md` - Main project page
|
||||
- `LICENSE` - Open source license
|
||||
- `CONTRIBUTING.md` - Contributor guide
|
||||
- `CODE_OF_CONDUCT.md` - Community standards
|
||||
- `SECURITY.md` - Security policy
|
||||
|
||||
### docs/ Level
|
||||
|
||||
**Navigation:**
|
||||
- `docs/README.md` - **Start here!** Main documentation hub
|
||||
|
||||
**Categories:**
|
||||
|
||||
1. **`getting-started/`** - Deployment and setup
|
||||
- Docker deployment (EN/中文)
|
||||
- PM2 deployment
|
||||
- Custom API configuration
|
||||
|
||||
2. **`guides/`** - Usage guides and tutorials
|
||||
- FAQ (中文)
|
||||
- Troubleshooting (planned)
|
||||
- Configuration examples (planned)
|
||||
|
||||
3. **`community/`** - Contribution and bounties
|
||||
- Bounty guide
|
||||
- Active bounty tasks
|
||||
- Contributor recognition
|
||||
|
||||
4. **`i18n/`** - International translations
|
||||
- `zh-CN/` - Simplified Chinese
|
||||
- `ru/` - Russian
|
||||
- `uk/` - Ukrainian
|
||||
|
||||
5. **`architecture/`** - Technical documentation
|
||||
- System design (planned)
|
||||
- API reference (planned)
|
||||
- Database schema (planned)
|
||||
|
||||
## 🔗 Updating Your Links
|
||||
|
||||
### If you bookmarked old links:
|
||||
|
||||
| Old Link | New Link |
|
||||
|----------|----------|
|
||||
| `DOCKER_DEPLOY.en.md` | `docs/getting-started/docker-deploy.en.md` |
|
||||
| `README.zh-CN.md` | `docs/i18n/zh-CN/README.md` |
|
||||
| `HOW_TO_POST_BOUNTY.md` | `docs/community/bounty-guide.md` |
|
||||
|
||||
### If you linked in your own docs:
|
||||
|
||||
**Update relative links:**
|
||||
```markdown
|
||||
<!-- Old -->
|
||||
[Docker Deployment](DOCKER_DEPLOY.en.md)
|
||||
|
||||
<!-- New -->
|
||||
[Docker Deployment](docs/getting-started/docker-deploy.en.md)
|
||||
```
|
||||
|
||||
**GitHub URLs automatically redirect!**
|
||||
- Old: `github.com/tinkle-community/nofx/blob/main/DOCKER_DEPLOY.en.md`
|
||||
- Will redirect to: `github.com/.../docs/getting-started/docker-deploy.en.md`
|
||||
|
||||
## 🛠️ For Contributors
|
||||
|
||||
### Cloning/Pulling Latest
|
||||
|
||||
```bash
|
||||
# Pull latest changes
|
||||
git pull origin dev
|
||||
|
||||
# Your old bookmarks still work!
|
||||
# Git tracked the file moves (git mv)
|
||||
```
|
||||
|
||||
### Finding Documentation
|
||||
|
||||
**Use the navigation hub:**
|
||||
1. Start at [docs/README.md](README.md)
|
||||
2. Browse by category
|
||||
3. Use the quick navigation section
|
||||
|
||||
**Or search:**
|
||||
```bash
|
||||
# Find all markdown docs
|
||||
find docs -name "*.md"
|
||||
|
||||
# Search content
|
||||
grep -r "keyword" docs/
|
||||
```
|
||||
|
||||
### Adding New Documentation
|
||||
|
||||
**Follow the structure:**
|
||||
|
||||
```bash
|
||||
# Getting started guides
|
||||
docs/getting-started/your-guide.md
|
||||
|
||||
# User guides
|
||||
docs/guides/your-tutorial.md
|
||||
|
||||
# Community docs
|
||||
docs/community/your-doc.md
|
||||
|
||||
# Translations
|
||||
docs/i18n/ja/README.md # Japanese example
|
||||
```
|
||||
|
||||
**Update navigation:**
|
||||
- Add link in relevant category README
|
||||
- Add to `docs/README.md` main hub
|
||||
|
||||
## 📝 Commit Messages
|
||||
|
||||
This reorganization was committed as:
|
||||
|
||||
```
|
||||
docs: reorganize documentation into structured docs/ directory
|
||||
|
||||
- Move deployment guides to docs/getting-started/
|
||||
- Move community docs to docs/community/
|
||||
- Move translations to docs/i18n/
|
||||
- Create navigation hub at docs/README.md
|
||||
- Update all internal links in README.md
|
||||
- Add GitHub issue/PR templates
|
||||
|
||||
BREAKING CHANGE: Direct links to moved files will need updating
|
||||
(though GitHub redirects should work)
|
||||
|
||||
Closes #XXX
|
||||
```
|
||||
|
||||
## 🆘 Need Help?
|
||||
|
||||
**Can't find a document?**
|
||||
1. Check [docs/README.md](README.md) navigation hub
|
||||
2. Search GitHub repo
|
||||
3. Ask in [Telegram](https://t.me/nofx_dev_community)
|
||||
|
||||
**Link broken?**
|
||||
- Report in [GitHub Issues](https://github.com/tinkle-community/nofx/issues)
|
||||
- We'll fix it ASAP!
|
||||
|
||||
**Want to contribute docs?**
|
||||
- See [Contributing Guide](../CONTRIBUTING.md)
|
||||
- Check [docs/community/](community/README.md)
|
||||
|
||||
---
|
||||
|
||||
**Migration Date:** 2025-11-01
|
||||
**Maintainers:** Tinkle Community
|
||||
|
||||
[← Back to Documentation Home](README.md)
|
||||
192
docs/README.md
Normal file
192
docs/README.md
Normal file
@@ -0,0 +1,192 @@
|
||||
# 📚 NOFX Documentation Center / 文档中心
|
||||
|
||||
Welcome to the NOFX documentation! This page helps you find the right documentation quickly.
|
||||
|
||||
欢迎来到 NOFX 文档中心!本页面帮助您快速找到所需文档。
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Getting Started / 快速开始
|
||||
|
||||
**New to NOFX? Start here!**
|
||||
|
||||
| Document | Description | 描述 |
|
||||
|----------|-------------|------|
|
||||
| [Main README](../README.md) | Project overview, features, quick start | 项目概述、功能、快速入门 |
|
||||
| [Getting Started Index (EN)](getting-started/README.md) | All deployment options | 所有部署选项 |
|
||||
| [Getting Started Index (中文)](getting-started/README.zh-CN.md) | 所有部署选项 | All deployment options |
|
||||
| [Docker Deployment (EN)](getting-started/docker-deploy.en.md) | Deploy with Docker (recommended) | Docker 部署(推荐) |
|
||||
| [Docker Deployment (中文)](getting-started/docker-deploy.zh-CN.md) | Docker 部署指南(中文) | Docker deployment guide |
|
||||
| [PM2 Deployment (EN)](getting-started/pm2-deploy.en.md) | Deploy with PM2 process manager | PM2 进程管理器部署 |
|
||||
| [PM2 Deployment (中文)](getting-started/pm2-deploy.md) | PM2 部署指南(中文) | PM2 deployment guide |
|
||||
| [Custom API (EN)](getting-started/custom-api.en.md) | Connect custom AI API providers | 连接自定义 AI API |
|
||||
| [Custom API (中文)](getting-started/custom-api.md) | 连接自定义 AI API 提供商 | Custom AI provider guide |
|
||||
|
||||
**Quick Links:**
|
||||
- 📖 See all options → [Getting Started](getting-started/README.md) / [快速开始](getting-started/README.zh-CN.md)
|
||||
- 🐳 Want easiest setup? → [Docker (EN)](getting-started/docker-deploy.en.md) / [Docker (中文)](getting-started/docker-deploy.zh-CN.md)
|
||||
- 🔧 Advanced user? → [PM2 (EN)](getting-started/pm2-deploy.en.md) / [PM2 (中文)](getting-started/pm2-deploy.md)
|
||||
- 🤖 Custom AI model? → [Custom API (EN)](getting-started/custom-api.en.md) / [自定义 API](getting-started/custom-api.md)
|
||||
|
||||
---
|
||||
|
||||
## 📘 User Guides / 使用指南
|
||||
|
||||
**Learn how to use NOFX effectively**
|
||||
|
||||
| Document | Description | 描述 |
|
||||
|----------|-------------|------|
|
||||
| [User Guides Index (EN)](guides/README.md) | All usage guides and tips | 所有使用指南和技巧 |
|
||||
| [User Guides Index (中文)](guides/README.zh-CN.md) | 所有使用指南和技巧 | All usage guides and tips |
|
||||
| [FAQ (English)](guides/faq.en.md) | Frequently asked questions | 常见问题解答 |
|
||||
| [FAQ (中文)](guides/faq.zh-CN.md) | 常见问题解答 | Frequently asked questions |
|
||||
| Troubleshooting *(coming soon)* | Common issues and solutions | 故障排查 |
|
||||
| Configuration Guide *(coming soon)* | Advanced configuration options | 高级配置选项 |
|
||||
| Trading Strategies *(coming soon)* | AI trading strategy examples | AI 交易策略示例 |
|
||||
|
||||
---
|
||||
|
||||
## 👥 Community & Contributing / 社区与贡献
|
||||
|
||||
**Join the community and contribute!**
|
||||
|
||||
| Document | Description | 描述 |
|
||||
|----------|-------------|------|
|
||||
| [Code of Conduct](../CODE_OF_CONDUCT.md) | Community guidelines | 社区行为准则 |
|
||||
| [Security Policy](../SECURITY.md) | Report security vulnerabilities | 报告安全漏洞 |
|
||||
| [Bounty Guide](community/bounty-guide.md) | How to post bounty tasks | 如何发布悬赏任务 |
|
||||
| [Hyperliquid Bounty](community/bounty-hyperliquid.md) | Hyperliquid integration bounty | Hyperliquid 集成悬赏 |
|
||||
| [Aster Bounty](community/bounty-aster.md) | Aster DEX integration bounty | Aster DEX 集成悬赏 |
|
||||
|
||||
**Get Involved:**
|
||||
- 💬 [Telegram Community](https://t.me/nofx_dev_community)
|
||||
- 🐦 [Twitter @nofx_ai](https://x.com/nofx_ai)
|
||||
- 🐛 [Report Issues](https://github.com/tinkle-community/nofx/issues)
|
||||
|
||||
---
|
||||
|
||||
## 🌍 International / 国际化文档
|
||||
|
||||
**Documentation in other languages**
|
||||
|
||||
| Language | Main README | Status |
|
||||
|----------|-------------|--------|
|
||||
| 🇨🇳 Chinese (中文) | [README.md](i18n/zh-CN/README.md) | ✅ Complete |
|
||||
| 🇷🇺 Russian (Русский) | [README.md](i18n/ru/README.md) | ✅ Complete |
|
||||
| 🇺🇦 Ukrainian (Українська) | [README.md](i18n/uk/README.md) | ✅ Complete |
|
||||
| 🇬🇧 English | [README.md](../README.md) | ✅ Complete |
|
||||
|
||||
---
|
||||
|
||||
## 🏗️ Architecture & Development / 架构与开发
|
||||
|
||||
**For developers who want to understand the internals**
|
||||
|
||||
| Document | Description | 描述 |
|
||||
|----------|-------------|------|
|
||||
| [Architecture Overview (EN)](architecture/README.md) | System architecture, modules, and design | 系统架构、模块和设计 |
|
||||
| [Architecture Overview (中文)](architecture/README.zh-CN.md) | 系统架构、模块和设计 | System architecture overview |
|
||||
| API Reference *(coming soon)* | HTTP API documentation | HTTP API 文档 |
|
||||
| Database Schema *(coming soon)* | SQLite database structure | SQLite 数据库结构 |
|
||||
| Testing Guide *(coming soon)* | How to write tests | 如何编写测试 |
|
||||
|
||||
---
|
||||
|
||||
## 🗺️ Roadmap / 路线图
|
||||
|
||||
**NOFX's strategic development plan and market expansion**
|
||||
|
||||
| Document | Description | 描述 |
|
||||
|----------|-------------|------|
|
||||
| [Roadmap (EN)](roadmap/README.md) | Short-term and long-term roadmap, feature timeline | 短期和长期路线图、功能时间表 |
|
||||
| [Roadmap (中文)](roadmap/README.zh-CN.md) | 短期和长期路线图、功能时间表 | Strategic development plan |
|
||||
|
||||
**Roadmap Highlights:**
|
||||
- 📈 **Short-term (Q2-Q3 2025)**: Advanced risk management, multi-AI ensemble, new exchange integrations
|
||||
- 🚀 **Long-term (2026)**: Universal market expansion (stocks, futures, options, forex), reinforcement learning, enterprise features
|
||||
|
||||
---
|
||||
|
||||
## 📄 Legal & Policies / 法律与政策
|
||||
|
||||
| Document | Description | 描述 |
|
||||
|----------|-------------|------|
|
||||
| [License (MIT)](../LICENSE) | Open source license | 开源许可证 |
|
||||
| [Changelog (EN)](../CHANGELOG.md) | Version history and updates | 版本历史和更新 |
|
||||
| [Changelog (中文)](../CHANGELOG.zh-CN.md) | 版本历史和更新 | Version history and updates |
|
||||
| [Security Policy](../SECURITY.md) | Vulnerability disclosure | 漏洞披露政策 |
|
||||
| [Code of Conduct](../CODE_OF_CONDUCT.md) | Community standards | 社区标准 |
|
||||
|
||||
---
|
||||
|
||||
## 🔍 Quick Navigation / 快速导航
|
||||
|
||||
**Find what you need fast:**
|
||||
|
||||
### I want to...
|
||||
- 🚀 **Get started quickly** → [Getting Started](getting-started/README.md) / [快速开始](getting-started/README.zh-CN.md)
|
||||
- 🐛 **Report a bug** → [GitHub Issues](https://github.com/tinkle-community/nofx/issues/new)
|
||||
- 💡 **Suggest a feature** → [Feature Request](https://github.com/tinkle-community/nofx/issues/new?template=feature_request.md)
|
||||
- 🔒 **Report security issue** → [Security Policy](../SECURITY.md)
|
||||
- 💰 **Claim a bounty** → [Bounty Guide](community/bounty-guide.md)
|
||||
- 🤝 **Contribute code** → [Contributing Guide](../CONTRIBUTING.md)
|
||||
- 💬 **Ask questions** → [Telegram Community](https://t.me/nofx_dev_community)
|
||||
|
||||
### I'm looking for...
|
||||
- 🏗️ **System architecture** → [Architecture (EN)](architecture/README.md) / [架构文档](architecture/README.zh-CN.md)
|
||||
- 🗺️ **Product roadmap** → [Roadmap (EN)](roadmap/README.md) / [路线图](roadmap/README.zh-CN.md)
|
||||
- 📊 **API documentation** → Coming soon
|
||||
- 🧪 **Testing guide** → Coming soon
|
||||
- 🔧 **Configuration examples** → [Custom API (EN)](getting-started/custom-api.en.md) / [自定义 API](getting-started/custom-api.md)
|
||||
- 🌐 **Multi-language docs** → [International section](#-international--国际化文档)
|
||||
|
||||
---
|
||||
|
||||
## 📚 Documentation Status
|
||||
|
||||
| Category | Status | Last Updated |
|
||||
|----------|--------|--------------|
|
||||
| Getting Started | ✅ Complete | 2025-11-01 |
|
||||
| User Guides | ✅ Complete | 2025-11-01 |
|
||||
| Community | ✅ Complete | 2025-11-01 |
|
||||
| Architecture | ✅ Complete | 2025-11-01 |
|
||||
| Roadmap | ✅ Complete | 2025-11-01 |
|
||||
| API Reference | 📋 Planned | - |
|
||||
|
||||
**Legend:**
|
||||
- ✅ Complete - Documentation is ready
|
||||
- 🚧 In Progress - Being written
|
||||
- 📋 Planned - On the roadmap
|
||||
- ⚠️ Outdated - Needs update
|
||||
|
||||
---
|
||||
|
||||
## 🆘 Need Help?
|
||||
|
||||
**Can't find what you're looking for?**
|
||||
|
||||
1. **Search GitHub Issues** - Someone might have asked already
|
||||
2. **Join Telegram** - [NOFX Developer Community](https://t.me/nofx_dev_community)
|
||||
3. **Ask on Twitter** - Mention [@nofx_ai](https://x.com/nofx_ai)
|
||||
4. **Create an Issue** - [New Issue](https://github.com/tinkle-community/nofx/issues/new)
|
||||
|
||||
---
|
||||
|
||||
## 🤝 Contributing to Documentation
|
||||
|
||||
Found an error or want to improve the docs?
|
||||
|
||||
1. **Small fixes** - Click "Edit" on GitHub and submit PR
|
||||
2. **New documentation** - Create an issue first to discuss
|
||||
3. **Translations** - See [Contributing Guide](../CONTRIBUTING.md)
|
||||
|
||||
**Documentation Contributors:**
|
||||
- All documentation follows [Markdown Guide](https://www.markdownguide.org/)
|
||||
- Use clear, concise language
|
||||
- Include code examples where helpful
|
||||
- Add screenshots for UI-related docs
|
||||
|
||||
---
|
||||
|
||||
**Last Updated:** 2025-11-01
|
||||
**Maintained by:** [Tinkle Community](https://github.com/tinkle-community)
|
||||
570
docs/architecture/README.md
Normal file
570
docs/architecture/README.md
Normal file
@@ -0,0 +1,570 @@
|
||||
# 🏗️ NOFX Architecture Documentation
|
||||
|
||||
**Language:** [English](README.md) | [中文](README.zh-CN.md)
|
||||
|
||||
Technical documentation for developers who want to understand NOFX internals.
|
||||
|
||||
---
|
||||
|
||||
## 📋 Overview
|
||||
|
||||
NOFX is a full-stack AI trading platform with:
|
||||
- **Backend:** Go (Gin framework, SQLite)
|
||||
- **Frontend:** React/TypeScript (Vite, TailwindCSS)
|
||||
- **Architecture:** Microservice-inspired modular design
|
||||
|
||||
---
|
||||
|
||||
## 📁 Project Structure
|
||||
|
||||
```
|
||||
nofx/
|
||||
├── main.go # Program entry (multi-trader manager)
|
||||
├── config.json # ~~Multi-trader config~~ (Now via web interface)
|
||||
├── trading.db # SQLite database (traders, models, exchanges)
|
||||
│
|
||||
├── api/ # HTTP API service
|
||||
│ └── server.go # Gin framework, RESTful API
|
||||
│
|
||||
├── trader/ # Trading core
|
||||
│ ├── auto_trader.go # Auto trading main controller
|
||||
│ ├── interface.go # Unified trader interface
|
||||
│ ├── binance_futures.go # Binance API wrapper
|
||||
│ ├── hyperliquid_trader.go # Hyperliquid DEX wrapper
|
||||
│ └── aster_trader.go # Aster DEX wrapper
|
||||
│
|
||||
├── manager/ # Multi-trader management
|
||||
│ └── trader_manager.go # Manages multiple trader instances
|
||||
│
|
||||
├── config/ # Configuration & database
|
||||
│ └── database.go # SQLite operations and schema
|
||||
│
|
||||
├── auth/ # Authentication
|
||||
│ └── jwt.go # JWT token management & 2FA
|
||||
│
|
||||
├── mcp/ # Model Context Protocol - AI communication
|
||||
│ └── client.go # AI API client (DeepSeek/Qwen/Custom)
|
||||
│
|
||||
├── decision/ # AI decision engine
|
||||
│ ├── engine.go # Decision logic with historical feedback
|
||||
│ └── prompt_manager.go # Prompt template system
|
||||
│
|
||||
├── market/ # Market data fetching
|
||||
│ └── data.go # Market data & technical indicators (TA-Lib)
|
||||
│
|
||||
├── pool/ # Coin pool management
|
||||
│ └── coin_pool.go # AI500 + OI Top merged pool
|
||||
│
|
||||
├── logger/ # Logging system
|
||||
│ └── decision_logger.go # Decision recording + performance analysis
|
||||
│
|
||||
├── decision_logs/ # Decision log storage (JSON files)
|
||||
│ ├── {trader_id}/ # Per-trader logs
|
||||
│ └── {timestamp}.json # Individual decisions
|
||||
│
|
||||
└── web/ # React frontend
|
||||
├── src/
|
||||
│ ├── components/ # React components
|
||||
│ │ ├── EquityChart.tsx # Equity curve chart
|
||||
│ │ ├── ComparisonChart.tsx # Multi-AI comparison chart
|
||||
│ │ └── CompetitionPage.tsx # Competition leaderboard
|
||||
│ ├── lib/api.ts # API call wrapper
|
||||
│ ├── types/index.ts # TypeScript types
|
||||
│ ├── stores/ # Zustand state management
|
||||
│ ├── index.css # Binance-style CSS
|
||||
│ └── App.tsx # Main app
|
||||
├── package.json # Frontend dependencies
|
||||
└── vite.config.ts # Vite configuration
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Core Dependencies
|
||||
|
||||
### Backend (Go)
|
||||
|
||||
| Package | Purpose | Version |
|
||||
|---------|---------|---------|
|
||||
| `github.com/gin-gonic/gin` | HTTP API framework | v1.9+ |
|
||||
| `github.com/adshao/go-binance/v2` | Binance API client | v2.4+ |
|
||||
| `github.com/markcheno/go-talib` | Technical indicators (TA-Lib) | Latest |
|
||||
| `github.com/mattn/go-sqlite3` | SQLite database driver | v1.14+ |
|
||||
| `github.com/golang-jwt/jwt/v5` | JWT authentication | v5.0+ |
|
||||
| `github.com/pquerna/otp` | 2FA/TOTP support | v1.4+ |
|
||||
| `golang.org/x/crypto` | Password hashing (bcrypt) | Latest |
|
||||
|
||||
### Frontend (React + TypeScript)
|
||||
|
||||
| Package | Purpose | Version |
|
||||
|---------|---------|---------|
|
||||
| `react` + `react-dom` | UI framework | 18.3+ |
|
||||
| `typescript` | Type safety | 5.8+ |
|
||||
| `vite` | Build tool | 6.0+ |
|
||||
| `recharts` | Charts (equity, comparison) | 2.15+ |
|
||||
| `swr` | Data fetching & caching | 2.2+ |
|
||||
| `zustand` | State management | 5.0+ |
|
||||
| `tailwindcss` | CSS framework | 3.4+ |
|
||||
| `lucide-react` | Icon library | Latest |
|
||||
|
||||
---
|
||||
|
||||
## 🗂️ System Architecture
|
||||
|
||||
### High-Level Overview
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────────────────────────────┐
|
||||
│ PRESENTATION LAYER │
|
||||
│ React SPA (Vite + TypeScript + TailwindCSS) │
|
||||
│ - Competition dashboard, trader management UI │
|
||||
│ - Real-time charts (Recharts), authentication pages │
|
||||
└──────────────────────────────────────────────────────────────────┘
|
||||
↓ HTTP/JSON API
|
||||
┌──────────────────────────────────────────────────────────────────┐
|
||||
│ API LAYER (Gin Router) │
|
||||
│ /api/traders, /api/status, /api/positions, /api/decisions │
|
||||
│ Authentication middleware (JWT), CORS handling │
|
||||
└──────────────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌──────────────────────────────────────────────────────────────────┐
|
||||
│ BUSINESS LOGIC LAYER │
|
||||
│ ┌──────────────────┐ ┌──────────────────┐ ┌────────────────┐ │
|
||||
│ │ TraderManager │ │ DecisionEngine │ │ MarketData │ │
|
||||
│ │ - Multi-trader │ │ - AI reasoning │ │ - K-lines │ │
|
||||
│ │ orchestration │ │ - Risk control │ │ - Indicators │ │
|
||||
│ └──────────────────┘ └──────────────────┘ └────────────────┘ │
|
||||
└──────────────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌──────────────────────────────────────────────────────────────────┐
|
||||
│ DATA ACCESS LAYER │
|
||||
│ ┌──────────────┐ ┌──────────────┐ ┌────────────────────┐ │
|
||||
│ │ SQLite DB │ │ File Logger │ │ External APIs │ │
|
||||
│ │ - Traders │ │ - Decisions │ │ - Binance │ │
|
||||
│ │ - Models │ │ - Performance│ │ - Hyperliquid │ │
|
||||
│ │ - Exchanges │ │ analysis │ │ - Aster │ │
|
||||
│ └──────────────┘ └──────────────┘ └────────────────────┘ │
|
||||
└──────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Component Diagram
|
||||
|
||||
*(Coming soon: detailed component interaction diagram)*
|
||||
|
||||
---
|
||||
|
||||
## 📚 Core Modules
|
||||
|
||||
### 1. Trader System (`trader/`)
|
||||
|
||||
**Purpose:** Trading execution layer with multi-exchange support
|
||||
|
||||
**Key Files:**
|
||||
- `auto_trader.go` - Main trading orchestrator (100+ lines)
|
||||
- `interface.go` - Unified trader interface
|
||||
- `binance_futures.go` - Binance API wrapper
|
||||
- `hyperliquid_trader.go` - Hyperliquid DEX wrapper
|
||||
- `aster_trader.go` - Aster DEX wrapper
|
||||
|
||||
**Design Pattern:** Strategy pattern with interface-based abstraction
|
||||
|
||||
**Example:**
|
||||
```go
|
||||
type ExchangeClient interface {
|
||||
GetAccount() (*AccountInfo, error)
|
||||
GetPositions() ([]*Position, error)
|
||||
CreateOrder(*OrderParams) (*Order, error)
|
||||
// ... more methods
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2. Decision Engine (`decision/`)
|
||||
|
||||
**Purpose:** AI-powered trading decision making
|
||||
|
||||
**Key Files:**
|
||||
- `engine.go` - Decision logic with historical feedback
|
||||
- `prompt_manager.go` - Template system for AI prompts
|
||||
|
||||
**Features:**
|
||||
- Chain-of-Thought reasoning
|
||||
- Historical performance analysis
|
||||
- Risk-aware decision making
|
||||
- Multi-model support (DeepSeek, Qwen, custom)
|
||||
|
||||
**Flow:**
|
||||
```
|
||||
Historical Data → Prompt Generation → AI API Call →
|
||||
Decision Parsing → Risk Validation → Execution
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3. Market Data System (`market/`)
|
||||
|
||||
**Purpose:** Fetch and analyze market data
|
||||
|
||||
**Key Files:**
|
||||
- `data.go` - Market data fetching and technical indicators
|
||||
|
||||
**Features:**
|
||||
- Multi-timeframe K-line data (3min, 4hour)
|
||||
- Technical indicators via TA-Lib:
|
||||
- EMA (20, 50)
|
||||
- MACD
|
||||
- RSI (7, 14)
|
||||
- ATR (volatility)
|
||||
- Open Interest tracking
|
||||
|
||||
---
|
||||
|
||||
### 4. Manager (`manager/`)
|
||||
|
||||
**Purpose:** Multi-trader orchestration
|
||||
|
||||
**Key Files:**
|
||||
- `trader_manager.go` - Manages multiple trader instances
|
||||
|
||||
**Responsibilities:**
|
||||
- Trader lifecycle (start, stop, restart)
|
||||
- Resource allocation
|
||||
- Concurrent execution coordination
|
||||
|
||||
---
|
||||
|
||||
### 5. API Server (`api/`)
|
||||
|
||||
**Purpose:** HTTP API for frontend communication
|
||||
|
||||
**Key Files:**
|
||||
- `server.go` - Gin framework RESTful API
|
||||
|
||||
**Endpoints:**
|
||||
```
|
||||
GET /api/traders # List all traders
|
||||
POST /api/traders # Create trader
|
||||
POST /api/traders/:id/start # Start trader
|
||||
GET /api/status # System status
|
||||
GET /api/positions # Current positions
|
||||
GET /api/decisions/latest # Recent decisions
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 6. Database Layer (`config/`)
|
||||
|
||||
**Purpose:** SQLite data persistence
|
||||
|
||||
**Key Files:**
|
||||
- `database.go` - Database operations and schema
|
||||
|
||||
**Tables:**
|
||||
- `users` - User accounts (with 2FA support)
|
||||
- `ai_models` - AI model configurations
|
||||
- `exchanges` - Exchange credentials
|
||||
- `traders` - Trader instances
|
||||
- `equity_history` - Performance tracking
|
||||
- `system_config` - Application settings
|
||||
|
||||
---
|
||||
|
||||
### 7. Authentication (`auth/`)
|
||||
|
||||
**Purpose:** User authentication and authorization
|
||||
|
||||
**Features:**
|
||||
- JWT token-based auth
|
||||
- 2FA with TOTP (Google Authenticator)
|
||||
- Bcrypt password hashing
|
||||
- Admin mode (simplified single-user)
|
||||
|
||||
---
|
||||
|
||||
## 🔄 Request Flow Examples
|
||||
|
||||
### Example 1: Create New Trader
|
||||
|
||||
```
|
||||
User Action (Frontend)
|
||||
↓
|
||||
POST /api/traders
|
||||
↓
|
||||
API Server (auth middleware)
|
||||
↓
|
||||
Database.CreateTrader()
|
||||
↓
|
||||
TraderManager.StartTrader()
|
||||
↓
|
||||
AutoTrader.Run() → goroutine
|
||||
↓
|
||||
Response: {trader_id, status}
|
||||
```
|
||||
|
||||
### Example 2: Trading Decision Cycle
|
||||
|
||||
```
|
||||
AutoTrader (every 3-5 min)
|
||||
↓
|
||||
1. FetchAccountStatus()
|
||||
↓
|
||||
2. GetOpenPositions()
|
||||
↓
|
||||
3. FetchMarketData() → TA-Lib indicators
|
||||
↓
|
||||
4. AnalyzeHistory() → last 20 trades
|
||||
↓
|
||||
5. GeneratePrompt() → full context
|
||||
↓
|
||||
6. CallAI() → DeepSeek/Qwen
|
||||
↓
|
||||
7. ParseDecision() → structured output
|
||||
↓
|
||||
8. ValidateRisk() → position limits, margin
|
||||
↓
|
||||
9. ExecuteOrders() → exchange API
|
||||
↓
|
||||
10. LogDecision() → JSON file + database
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 Data Flow
|
||||
|
||||
### Market Data Flow
|
||||
|
||||
```
|
||||
Exchange API
|
||||
↓
|
||||
market.FetchKlines()
|
||||
↓
|
||||
TA-Lib.Calculate(EMA, MACD, RSI)
|
||||
↓
|
||||
DecisionEngine (as context)
|
||||
↓
|
||||
AI Model (reasoning)
|
||||
```
|
||||
|
||||
### Decision Logging Flow
|
||||
|
||||
```
|
||||
AI Response
|
||||
↓
|
||||
decision_logger.go
|
||||
↓
|
||||
JSON file: decision_logs/{trader_id}/{timestamp}.json
|
||||
↓
|
||||
Database: performance tracking
|
||||
↓
|
||||
Frontend: /api/decisions/latest
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🗄️ Database Schema
|
||||
|
||||
### Core Tables
|
||||
|
||||
**users**
|
||||
```sql
|
||||
- id (INTEGER PRIMARY KEY)
|
||||
- username (TEXT UNIQUE)
|
||||
- password_hash (TEXT)
|
||||
- totp_secret (TEXT)
|
||||
- is_admin (BOOLEAN)
|
||||
- created_at (DATETIME)
|
||||
```
|
||||
|
||||
**ai_models**
|
||||
```sql
|
||||
- id (INTEGER PRIMARY KEY)
|
||||
- name (TEXT)
|
||||
- model_type (TEXT) -- deepseek, qwen, custom
|
||||
- api_key (TEXT)
|
||||
- api_url (TEXT)
|
||||
- enabled (BOOLEAN)
|
||||
```
|
||||
|
||||
**traders**
|
||||
```sql
|
||||
- id (TEXT PRIMARY KEY)
|
||||
- name (TEXT)
|
||||
- ai_model_id (INTEGER FK)
|
||||
- exchange_id (INTEGER FK)
|
||||
- initial_balance (REAL)
|
||||
- current_equity (REAL)
|
||||
- status (TEXT) -- running, stopped
|
||||
- created_at (DATETIME)
|
||||
```
|
||||
|
||||
*(More details: database-schema.md - coming soon)*
|
||||
|
||||
---
|
||||
|
||||
## 🔌 API Reference
|
||||
|
||||
### Authentication
|
||||
|
||||
**POST /api/auth/login**
|
||||
```json
|
||||
Request: {
|
||||
"username": "string",
|
||||
"password": "string",
|
||||
"totp_code": "string" // optional
|
||||
}
|
||||
|
||||
Response: {
|
||||
"token": "jwt_token",
|
||||
"user": {...}
|
||||
}
|
||||
```
|
||||
|
||||
### Trader Management
|
||||
|
||||
**GET /api/traders**
|
||||
```json
|
||||
Response: {
|
||||
"traders": [
|
||||
{
|
||||
"id": "string",
|
||||
"name": "string",
|
||||
"status": "running|stopped",
|
||||
"balance": 1000.0,
|
||||
"roi": 5.2
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
*(Full API reference: api-reference.md - coming soon)*
|
||||
|
||||
---
|
||||
|
||||
## 🧪 Testing Architecture
|
||||
|
||||
### Current State
|
||||
- ⚠️ No unit tests yet
|
||||
- ⚠️ Manual testing only
|
||||
- ⚠️ Testnet verification
|
||||
|
||||
### Planned Testing Strategy
|
||||
|
||||
**Unit Tests (Priority 1)**
|
||||
```
|
||||
trader/binance_futures_test.go
|
||||
- Mock API responses
|
||||
- Test precision handling
|
||||
- Validate order construction
|
||||
```
|
||||
|
||||
**Integration Tests (Priority 2)**
|
||||
```
|
||||
- End-to-end trading flow (testnet)
|
||||
- Multi-trader scenarios
|
||||
- Database operations
|
||||
```
|
||||
|
||||
**Frontend Tests (Priority 3)**
|
||||
```
|
||||
- Component tests (Vitest + React Testing Library)
|
||||
- API integration tests
|
||||
- E2E tests (Playwright)
|
||||
```
|
||||
|
||||
*(Testing guide: testing-guide.md - coming soon)*
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Development Tools
|
||||
|
||||
### Build & Run
|
||||
|
||||
```bash
|
||||
# Backend
|
||||
go build -o nofx
|
||||
./nofx
|
||||
|
||||
# Frontend
|
||||
cd web
|
||||
npm run dev
|
||||
|
||||
# Docker
|
||||
docker compose up --build
|
||||
```
|
||||
|
||||
### Code Quality
|
||||
|
||||
```bash
|
||||
# Format Go code
|
||||
go fmt ./...
|
||||
|
||||
# Lint (if configured)
|
||||
golangci-lint run
|
||||
|
||||
# Type check TypeScript
|
||||
cd web && npm run build
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📈 Performance Considerations
|
||||
|
||||
### Backend
|
||||
- **Concurrency:** Each trader runs in separate goroutine
|
||||
- **Database:** SQLite (good for <100 traders)
|
||||
- **API Rate Limits:** Handled per exchange
|
||||
- **Memory:** ~50-100MB per trader
|
||||
|
||||
### Frontend
|
||||
- **Data Fetching:** SWR with 5-10s polling
|
||||
- **State:** Zustand (lightweight)
|
||||
- **Bundle Size:** ~500KB (gzipped)
|
||||
|
||||
---
|
||||
|
||||
## 🔮 Future Architecture Plans
|
||||
|
||||
### Planned Improvements
|
||||
|
||||
1. **Microservices Split** (if scaling needed)
|
||||
- Separate decision engine service
|
||||
- Market data service
|
||||
- Execution service
|
||||
|
||||
2. **Database Migration**
|
||||
- Mysql for production (>100 traders)
|
||||
- Redis for caching
|
||||
|
||||
3. **Event-Driven Architecture**
|
||||
- WebSocket for real-time updates
|
||||
- Message queue (RabbitMQ/NATS)
|
||||
|
||||
4. **Kubernetes Deployment**
|
||||
- Helm charts
|
||||
- Auto-scaling
|
||||
- High availability
|
||||
|
||||
---
|
||||
|
||||
## 🆘 For Developers
|
||||
|
||||
**Want to contribute?**
|
||||
- Read [Contributing Guide](../../CONTRIBUTING.md)
|
||||
- Check [Open Issues](https://github.com/tinkle-community/nofx/issues)
|
||||
- Join [Telegram Community](https://t.me/nofx_dev_community)
|
||||
|
||||
**Need clarification?**
|
||||
- Open a [GitHub Discussion](https://github.com/tinkle-community/nofx/discussions)
|
||||
- Ask in Telegram
|
||||
|
||||
---
|
||||
|
||||
## 📚 Related Documentation
|
||||
|
||||
- [Getting Started](../getting-started/README.md) - Setup and deployment
|
||||
- [Contributing](../../CONTRIBUTING.md) - How to contribute
|
||||
- [Community](../community/README.md) - Bounties and recognition
|
||||
|
||||
---
|
||||
|
||||
[← Back to Documentation Home](../README.md)
|
||||
570
docs/architecture/README.zh-CN.md
Normal file
570
docs/architecture/README.zh-CN.md
Normal file
@@ -0,0 +1,570 @@
|
||||
# 🏗️ NOFX 架构文档
|
||||
|
||||
**语言:** [English](README.md) | [中文](README.zh-CN.md)
|
||||
|
||||
为希望了解 NOFX 内部实现的开发者提供的技术文档。
|
||||
|
||||
---
|
||||
|
||||
## 📋 概述
|
||||
|
||||
NOFX 是一个全栈 AI 交易平台:
|
||||
- **后端:** Go (Gin 框架, SQLite)
|
||||
- **前端:** React/TypeScript (Vite, TailwindCSS)
|
||||
- **架构:** 微服务启发的模块化设计
|
||||
|
||||
---
|
||||
|
||||
## 📁 项目结构
|
||||
|
||||
```
|
||||
nofx/
|
||||
├── main.go # 程序入口(多交易员管理器)
|
||||
├── config.json # ~~多交易员配置~~ (现通过Web界面)
|
||||
├── trading.db # SQLite 数据库(交易员、模型、交易所)
|
||||
│
|
||||
├── api/ # HTTP API 服务
|
||||
│ └── server.go # Gin 框架,RESTful API
|
||||
│
|
||||
├── trader/ # 交易核心
|
||||
│ ├── auto_trader.go # 自动交易主控制器
|
||||
│ ├── interface.go # 统一交易员接口
|
||||
│ ├── binance_futures.go # Binance API 包装器
|
||||
│ ├── hyperliquid_trader.go # Hyperliquid DEX 包装器
|
||||
│ └── aster_trader.go # Aster DEX 包装器
|
||||
│
|
||||
├── manager/ # 多交易员管理
|
||||
│ └── trader_manager.go # 管理多个交易员实例
|
||||
│
|
||||
├── config/ # 配置与数据库
|
||||
│ └── database.go # SQLite 操作和模式
|
||||
│
|
||||
├── auth/ # 认证
|
||||
│ └── jwt.go # JWT token 管理 & 2FA
|
||||
│
|
||||
├── mcp/ # Model Context Protocol - AI 通信
|
||||
│ └── client.go # AI API 客户端(DeepSeek/Qwen/自定义)
|
||||
│
|
||||
├── decision/ # AI 决策引擎
|
||||
│ ├── engine.go # 带历史反馈的决策逻辑
|
||||
│ └── prompt_manager.go # 提示词模板系统
|
||||
│
|
||||
├── market/ # 市场数据获取
|
||||
│ └── data.go # 市场数据与技术指标(TA-Lib)
|
||||
│
|
||||
├── pool/ # 币种池管理
|
||||
│ └── coin_pool.go # AI500 + OI Top 合并池
|
||||
│
|
||||
├── logger/ # 日志系统
|
||||
│ └── decision_logger.go # 决策记录 + 性能分析
|
||||
│
|
||||
├── decision_logs/ # 决策日志存储(JSON 文件)
|
||||
│ ├── {trader_id}/ # 每个交易员的日志
|
||||
│ └── {timestamp}.json # 单个决策
|
||||
│
|
||||
└── web/ # React 前端
|
||||
├── src/
|
||||
│ ├── components/ # React 组件
|
||||
│ │ ├── EquityChart.tsx # 权益曲线图表
|
||||
│ │ ├── ComparisonChart.tsx # 多 AI 对比图表
|
||||
│ │ └── CompetitionPage.tsx # 竞赛排行榜
|
||||
│ ├── lib/api.ts # API 调用包装器
|
||||
│ ├── types/index.ts # TypeScript 类型
|
||||
│ ├── stores/ # Zustand 状态管理
|
||||
│ ├── index.css # Binance 风格样式
|
||||
│ └── App.tsx # 主应用
|
||||
├── package.json # 前端依赖
|
||||
└── vite.config.ts # Vite 配置
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔧 核心依赖
|
||||
|
||||
### 后端 (Go)
|
||||
|
||||
| 包 | 用途 | 版本 |
|
||||
|---------|---------|---------|
|
||||
| `github.com/gin-gonic/gin` | HTTP API 框架 | v1.9+ |
|
||||
| `github.com/adshao/go-binance/v2` | Binance API 客户端 | v2.4+ |
|
||||
| `github.com/markcheno/go-talib` | 技术指标(TA-Lib) | 最新 |
|
||||
| `github.com/mattn/go-sqlite3` | SQLite 数据库驱动 | v1.14+ |
|
||||
| `github.com/golang-jwt/jwt/v5` | JWT 认证 | v5.0+ |
|
||||
| `github.com/pquerna/otp` | 2FA/TOTP 支持 | v1.4+ |
|
||||
| `golang.org/x/crypto` | 密码哈希(bcrypt) | 最新 |
|
||||
|
||||
### 前端 (React + TypeScript)
|
||||
|
||||
| 包 | 用途 | 版本 |
|
||||
|---------|---------|---------|
|
||||
| `react` + `react-dom` | UI 框架 | 18.3+ |
|
||||
| `typescript` | 类型安全 | 5.8+ |
|
||||
| `vite` | 构建工具 | 6.0+ |
|
||||
| `recharts` | 图表(权益、对比) | 2.15+ |
|
||||
| `swr` | 数据获取与缓存 | 2.2+ |
|
||||
| `zustand` | 状态管理 | 5.0+ |
|
||||
| `tailwindcss` | CSS 框架 | 3.4+ |
|
||||
| `lucide-react` | 图标库 | 最新 |
|
||||
|
||||
---
|
||||
|
||||
## 🗂️ 系统架构
|
||||
|
||||
### 高层架构概览
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────────────────────────────┐
|
||||
│ 表现层 │
|
||||
│ React SPA (Vite + TypeScript + TailwindCSS) │
|
||||
│ - 竞赛仪表板、交易员管理 UI │
|
||||
│ - 实时图表 (Recharts)、认证页面 │
|
||||
└──────────────────────────────────────────────────────────────────┘
|
||||
↓ HTTP/JSON API
|
||||
┌──────────────────────────────────────────────────────────────────┐
|
||||
│ API 层 (Gin Router) │
|
||||
│ /api/traders, /api/status, /api/positions, /api/decisions │
|
||||
│ 认证中间件 (JWT)、CORS 处理 │
|
||||
└──────────────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌──────────────────────────────────────────────────────────────────┐
|
||||
│ 业务逻辑层 │
|
||||
│ ┌──────────────────┐ ┌──────────────────┐ ┌────────────────┐ │
|
||||
│ │ TraderManager │ │ DecisionEngine │ │ MarketData │ │
|
||||
│ │ - 多交易员 │ │ - AI 推理 │ │ - K线数据 │ │
|
||||
│ │ 编排 │ │ - 风险控制 │ │ - 技术指标 │ │
|
||||
│ └──────────────────┘ └──────────────────┘ └────────────────┘ │
|
||||
└──────────────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌──────────────────────────────────────────────────────────────────┐
|
||||
│ 数据访问层 │
|
||||
│ ┌──────────────┐ ┌──────────────┐ ┌────────────────────┐ │
|
||||
│ │ SQLite DB │ │ 文件日志 │ │ 外部 APIs │ │
|
||||
│ │ - Traders │ │ - Decisions │ │ - Binance │ │
|
||||
│ │ - Models │ │ - Performance│ │ - Hyperliquid │ │
|
||||
│ │ - Exchanges │ │ analysis │ │ - Aster │ │
|
||||
│ └──────────────┘ └──────────────┘ └────────────────────┘ │
|
||||
└──────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 组件图
|
||||
|
||||
*(即将推出:详细的组件交互图)*
|
||||
|
||||
---
|
||||
|
||||
## 📚 核心模块
|
||||
|
||||
### 1. 交易系统 (`trader/`)
|
||||
|
||||
**用途:** 支持多交易所的交易执行层
|
||||
|
||||
**关键文件:**
|
||||
- `auto_trader.go` - 主交易编排器(100+ 行)
|
||||
- `interface.go` - 统一的交易员接口
|
||||
- `binance_futures.go` - Binance API 包装器
|
||||
- `hyperliquid_trader.go` - Hyperliquid DEX 包装器
|
||||
- `aster_trader.go` - Aster DEX 包装器
|
||||
|
||||
**设计模式:** 基于接口抽象的策略模式
|
||||
|
||||
**示例:**
|
||||
```go
|
||||
type ExchangeClient interface {
|
||||
GetAccount() (*AccountInfo, error)
|
||||
GetPositions() ([]*Position, error)
|
||||
CreateOrder(*OrderParams) (*Order, error)
|
||||
// ... 更多方法
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2. 决策引擎 (`decision/`)
|
||||
|
||||
**用途:** AI 驱动的交易决策制定
|
||||
|
||||
**关键文件:**
|
||||
- `engine.go` - 带历史反馈的决策逻辑
|
||||
- `prompt_manager.go` - AI 提示词模板系统
|
||||
|
||||
**特性:**
|
||||
- 思维链推理
|
||||
- 历史表现分析
|
||||
- 风险感知决策
|
||||
- 多模型支持(DeepSeek、Qwen、自定义)
|
||||
|
||||
**流程:**
|
||||
```
|
||||
历史数据 → 提示词生成 → AI API 调用 →
|
||||
决策解析 → 风险验证 → 执行
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3. 市场数据系统 (`market/`)
|
||||
|
||||
**用途:** 获取和分析市场数据
|
||||
|
||||
**关键文件:**
|
||||
- `data.go` - 市场数据获取和技术指标
|
||||
|
||||
**特性:**
|
||||
- 多时间周期 K线数据(3分钟、4小时)
|
||||
- 通过 TA-Lib 计算技术指标:
|
||||
- EMA (20, 50)
|
||||
- MACD
|
||||
- RSI (7, 14)
|
||||
- ATR(波动率)
|
||||
- 持仓量跟踪
|
||||
|
||||
---
|
||||
|
||||
### 4. 管理器 (`manager/`)
|
||||
|
||||
**用途:** 多交易员编排
|
||||
|
||||
**关键文件:**
|
||||
- `trader_manager.go` - 管理多个交易员实例
|
||||
|
||||
**职责:**
|
||||
- 交易员生命周期(启动、停止、重启)
|
||||
- 资源分配
|
||||
- 并发执行协调
|
||||
|
||||
---
|
||||
|
||||
### 5. API 服务器 (`api/`)
|
||||
|
||||
**用途:** 前端通信的 HTTP API
|
||||
|
||||
**关键文件:**
|
||||
- `server.go` - Gin 框架 RESTful API
|
||||
|
||||
**端点:**
|
||||
```
|
||||
GET /api/traders # 列出所有交易员
|
||||
POST /api/traders # 创建交易员
|
||||
POST /api/traders/:id/start # 启动交易员
|
||||
GET /api/status # 系统状态
|
||||
GET /api/positions # 当前持仓
|
||||
GET /api/decisions/latest # 最近决策
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 6. 数据库层 (`config/`)
|
||||
|
||||
**用途:** SQLite 数据持久化
|
||||
|
||||
**关键文件:**
|
||||
- `database.go` - 数据库操作和模式
|
||||
|
||||
**表:**
|
||||
- `users` - 用户账户(支持 2FA)
|
||||
- `ai_models` - AI 模型配置
|
||||
- `exchanges` - 交易所凭证
|
||||
- `traders` - 交易员实例
|
||||
- `equity_history` - 绩效跟踪
|
||||
- `system_config` - 应用程序设置
|
||||
|
||||
---
|
||||
|
||||
### 7. 认证 (`auth/`)
|
||||
|
||||
**用途:** 用户认证和授权
|
||||
|
||||
**特性:**
|
||||
- 基于 JWT token 的认证
|
||||
- 使用 TOTP 的 2FA(Google Authenticator)
|
||||
- Bcrypt 密码哈希
|
||||
- 管理员模式(简化的单用户模式)
|
||||
|
||||
---
|
||||
|
||||
## 🔄 请求流程示例
|
||||
|
||||
### 示例 1:创建新交易员
|
||||
|
||||
```
|
||||
用户操作(前端)
|
||||
↓
|
||||
POST /api/traders
|
||||
↓
|
||||
API 服务器(认证中间件)
|
||||
↓
|
||||
Database.CreateTrader()
|
||||
↓
|
||||
TraderManager.StartTrader()
|
||||
↓
|
||||
AutoTrader.Run() → goroutine
|
||||
↓
|
||||
响应: {trader_id, status}
|
||||
```
|
||||
|
||||
### 示例 2:交易决策周期
|
||||
|
||||
```
|
||||
AutoTrader(每 3-5 分钟)
|
||||
↓
|
||||
1. FetchAccountStatus()
|
||||
↓
|
||||
2. GetOpenPositions()
|
||||
↓
|
||||
3. FetchMarketData() → TA-Lib 指标
|
||||
↓
|
||||
4. AnalyzeHistory() → 最近 20 笔交易
|
||||
↓
|
||||
5. GeneratePrompt() → 完整上下文
|
||||
↓
|
||||
6. CallAI() → DeepSeek/Qwen
|
||||
↓
|
||||
7. ParseDecision() → 结构化输出
|
||||
↓
|
||||
8. ValidateRisk() → 仓位限制、保证金
|
||||
↓
|
||||
9. ExecuteOrders() → 交易所 API
|
||||
↓
|
||||
10. LogDecision() → JSON 文件 + 数据库
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 数据流
|
||||
|
||||
### 市场数据流
|
||||
|
||||
```
|
||||
交易所 API
|
||||
↓
|
||||
market.FetchKlines()
|
||||
↓
|
||||
TA-Lib.Calculate(EMA, MACD, RSI)
|
||||
↓
|
||||
DecisionEngine(作为上下文)
|
||||
↓
|
||||
AI 模型(推理)
|
||||
```
|
||||
|
||||
### 决策日志流
|
||||
|
||||
```
|
||||
AI 响应
|
||||
↓
|
||||
decision_logger.go
|
||||
↓
|
||||
JSON 文件: decision_logs/{trader_id}/{timestamp}.json
|
||||
↓
|
||||
数据库: 绩效跟踪
|
||||
↓
|
||||
前端: /api/decisions/latest
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🗄️ 数据库架构
|
||||
|
||||
### 核心表
|
||||
|
||||
**users**
|
||||
```sql
|
||||
- id (INTEGER PRIMARY KEY)
|
||||
- username (TEXT UNIQUE)
|
||||
- password_hash (TEXT)
|
||||
- totp_secret (TEXT)
|
||||
- is_admin (BOOLEAN)
|
||||
- created_at (DATETIME)
|
||||
```
|
||||
|
||||
**ai_models**
|
||||
```sql
|
||||
- id (INTEGER PRIMARY KEY)
|
||||
- name (TEXT)
|
||||
- model_type (TEXT) -- deepseek, qwen, custom
|
||||
- api_key (TEXT)
|
||||
- api_url (TEXT)
|
||||
- enabled (BOOLEAN)
|
||||
```
|
||||
|
||||
**traders**
|
||||
```sql
|
||||
- id (TEXT PRIMARY KEY)
|
||||
- name (TEXT)
|
||||
- ai_model_id (INTEGER FK)
|
||||
- exchange_id (INTEGER FK)
|
||||
- initial_balance (REAL)
|
||||
- current_equity (REAL)
|
||||
- status (TEXT) -- running, stopped
|
||||
- created_at (DATETIME)
|
||||
```
|
||||
|
||||
*(更多详情:database-schema.md - 即将推出)*
|
||||
|
||||
---
|
||||
|
||||
## 🔌 API 参考
|
||||
|
||||
### 认证
|
||||
|
||||
**POST /api/auth/login**
|
||||
```json
|
||||
请求: {
|
||||
"username": "string",
|
||||
"password": "string",
|
||||
"totp_code": "string" // 可选
|
||||
}
|
||||
|
||||
响应: {
|
||||
"token": "jwt_token",
|
||||
"user": {...}
|
||||
}
|
||||
```
|
||||
|
||||
### 交易员管理
|
||||
|
||||
**GET /api/traders**
|
||||
```json
|
||||
响应: {
|
||||
"traders": [
|
||||
{
|
||||
"id": "string",
|
||||
"name": "string",
|
||||
"status": "running|stopped",
|
||||
"balance": 1000.0,
|
||||
"roi": 5.2
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
*(完整 API 参考:api-reference.md - 即将推出)*
|
||||
|
||||
---
|
||||
|
||||
## 🧪 测试架构
|
||||
|
||||
### 当前状态
|
||||
- ⚠️ 尚无单元测试
|
||||
- ⚠️ 仅手动测试
|
||||
- ⚠️ 测试网验证
|
||||
|
||||
### 计划的测试策略
|
||||
|
||||
**单元测试(优先级 1)**
|
||||
```
|
||||
trader/binance_futures_test.go
|
||||
- 模拟 API 响应
|
||||
- 测试精度处理
|
||||
- 验证订单构造
|
||||
```
|
||||
|
||||
**集成测试(优先级 2)**
|
||||
```
|
||||
- 端到端交易流程(测试网)
|
||||
- 多交易员场景
|
||||
- 数据库操作
|
||||
```
|
||||
|
||||
**前端测试(优先级 3)**
|
||||
```
|
||||
- 组件测试(Vitest + React Testing Library)
|
||||
- API 集成测试
|
||||
- E2E 测试(Playwright)
|
||||
```
|
||||
|
||||
*(测试指南:testing-guide.md - 即将推出)*
|
||||
|
||||
---
|
||||
|
||||
## 🔧 开发工具
|
||||
|
||||
### 构建与运行
|
||||
|
||||
```bash
|
||||
# 后端
|
||||
go build -o nofx
|
||||
./nofx
|
||||
|
||||
# 前端
|
||||
cd web
|
||||
npm run dev
|
||||
|
||||
# Docker
|
||||
docker compose up --build
|
||||
```
|
||||
|
||||
### 代码质量
|
||||
|
||||
```bash
|
||||
# 格式化 Go 代码
|
||||
go fmt ./...
|
||||
|
||||
# Lint(如果配置)
|
||||
golangci-lint run
|
||||
|
||||
# TypeScript 类型检查
|
||||
cd web && npm run build
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📈 性能考虑
|
||||
|
||||
### 后端
|
||||
- **并发:** 每个交易员在独立的 goroutine 中运行
|
||||
- **数据库:** SQLite(适用于 <100 个交易员)
|
||||
- **API 速率限制:** 按交易所处理
|
||||
- **内存:** 每个交易员 ~50-100MB
|
||||
|
||||
### 前端
|
||||
- **数据获取:** SWR,5-10 秒轮询
|
||||
- **状态:** Zustand(轻量级)
|
||||
- **包大小:** ~500KB(gzipped)
|
||||
|
||||
---
|
||||
|
||||
## 🔮 未来架构计划
|
||||
|
||||
### 计划改进
|
||||
|
||||
1. **微服务拆分**(如需扩展)
|
||||
- 独立的决策引擎服务
|
||||
- 市场数据服务
|
||||
- 执行服务
|
||||
|
||||
2. **数据库迁移**
|
||||
- 生产环境使用 Mysql (>100 个交易员)
|
||||
- Redis 缓存
|
||||
|
||||
3. **事件驱动架构**
|
||||
- WebSocket 实时更新
|
||||
- 消息队列(RabbitMQ/NATS)
|
||||
|
||||
4. **Kubernetes 部署**
|
||||
- Helm charts
|
||||
- 自动扩展
|
||||
- 高可用性
|
||||
|
||||
---
|
||||
|
||||
## 🆘 开发者资源
|
||||
|
||||
**想要贡献?**
|
||||
- 阅读[贡献指南](../../CONTRIBUTING.md)
|
||||
- 查看[开放问题](https://github.com/tinkle-community/nofx/issues)
|
||||
- 加入 [Telegram 社区](https://t.me/nofx_dev_community)
|
||||
|
||||
**需要澄清?**
|
||||
- 开启 [GitHub 讨论](https://github.com/tinkle-community/nofx/discussions)
|
||||
- 在 Telegram 提问
|
||||
|
||||
---
|
||||
|
||||
## 📚 相关文档
|
||||
|
||||
- [快速开始](../getting-started/README.zh-CN.md) - 设置和部署
|
||||
- [贡献指南](../../CONTRIBUTING.md) - 如何贡献
|
||||
- [社区](../community/README.md) - 悬赏和认可
|
||||
|
||||
---
|
||||
|
||||
[← 返回文档首页](../README.md)
|
||||
272
docs/community/HOW_TO_MIGRATE_YOUR_PR.md
Normal file
272
docs/community/HOW_TO_MIGRATE_YOUR_PR.md
Normal file
@@ -0,0 +1,272 @@
|
||||
# 🔄 How to Migrate Your PR to the New Format
|
||||
|
||||
**Language:** [English](HOW_TO_MIGRATE_YOUR_PR.md) | [中文](HOW_TO_MIGRATE_YOUR_PR.zh-CN.md)
|
||||
|
||||
This guide helps you migrate your existing PR to meet the new PR management system requirements.
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Why Migrate?
|
||||
|
||||
While your existing PR **will still be reviewed and merged** under current standards, migrating it to the new format gives you:
|
||||
|
||||
✅ **Faster reviews** - Automated checks catch issues early
|
||||
✅ **Better feedback** - Clear, actionable feedback from CI
|
||||
✅ **Higher quality** - Consistent code standards
|
||||
✅ **Learning** - Understand our new contribution workflow
|
||||
|
||||
---
|
||||
|
||||
## ⚡ Quick Check (Recommended)
|
||||
|
||||
### Step 1: Analyze Your PR
|
||||
|
||||
```bash
|
||||
# Run the PR health check (reads only, doesn't modify anything)
|
||||
./scripts/pr-check.sh
|
||||
```
|
||||
|
||||
This will analyze your PR and tell you:
|
||||
- ✅ What's good
|
||||
- ⚠️ What needs attention
|
||||
- 💡 How to fix issues
|
||||
- 📊 Overall health score
|
||||
|
||||
### Step 2: Fix Issues
|
||||
|
||||
Based on the suggestions, fix the issues manually. Common fixes:
|
||||
|
||||
```bash
|
||||
# Rebase on latest dev
|
||||
git fetch upstream && git rebase upstream/dev
|
||||
|
||||
# Format Go code
|
||||
go fmt ./...
|
||||
|
||||
# Run tests
|
||||
go test ./...
|
||||
|
||||
# Format frontend code
|
||||
cd web && npm run lint -- --fix
|
||||
```
|
||||
|
||||
### Step 3: Run Check Again
|
||||
|
||||
```bash
|
||||
# Verify all issues are fixed
|
||||
./scripts/pr-check.sh
|
||||
```
|
||||
|
||||
### Step 4: Push Changes
|
||||
|
||||
```bash
|
||||
git push -f origin <your-pr-branch>
|
||||
```
|
||||
|
||||
### What the Script Does
|
||||
|
||||
1. ✅ Syncs with latest `upstream/dev`
|
||||
2. ✅ Rebases your changes
|
||||
3. ✅ Formats Go code (`go fmt`)
|
||||
4. ✅ Runs Go linting (`go vet`)
|
||||
5. ✅ Runs tests
|
||||
6. ✅ Formats frontend code (if applicable)
|
||||
7. ✅ Pushes changes to your PR
|
||||
|
||||
---
|
||||
|
||||
## 🛠️ Manual Migration (Step by Step)
|
||||
|
||||
If you prefer to do it manually:
|
||||
|
||||
### Step 1: Sync with Upstream
|
||||
|
||||
```bash
|
||||
# Add upstream if not already added
|
||||
git remote add upstream https://github.com/tinkle-community/nofx.git
|
||||
|
||||
# Fetch latest changes
|
||||
git fetch upstream
|
||||
|
||||
# Rebase your branch
|
||||
git checkout <your-pr-branch>
|
||||
git rebase upstream/dev
|
||||
```
|
||||
|
||||
### Step 2: Backend Checks (Go)
|
||||
|
||||
```bash
|
||||
# Format Go code
|
||||
go fmt ./...
|
||||
|
||||
# Run linting
|
||||
go vet ./...
|
||||
|
||||
# Run tests
|
||||
go test ./...
|
||||
|
||||
# If you made changes, commit them
|
||||
git add .
|
||||
git commit -m "chore: format and fix backend issues"
|
||||
```
|
||||
|
||||
### Step 3: Frontend Checks (if applicable)
|
||||
|
||||
```bash
|
||||
cd web
|
||||
|
||||
# Install dependencies
|
||||
npm install
|
||||
|
||||
# Fix linting issues
|
||||
npm run lint -- --fix
|
||||
|
||||
# Check types
|
||||
npm run type-check
|
||||
|
||||
# Test build
|
||||
npm run build
|
||||
|
||||
cd ..
|
||||
|
||||
# Commit any fixes
|
||||
git add .
|
||||
git commit -m "chore: fix frontend issues"
|
||||
```
|
||||
|
||||
### Step 4: Update PR Title (if needed)
|
||||
|
||||
Ensure your PR title follows [Conventional Commits](https://www.conventionalcommits.org/):
|
||||
|
||||
```
|
||||
<type>(<scope>): <description>
|
||||
|
||||
Examples:
|
||||
feat(exchange): add OKX integration
|
||||
fix(trader): resolve position tracking bug
|
||||
docs(readme): update installation guide
|
||||
```
|
||||
|
||||
**Types:**
|
||||
- `feat` - New feature
|
||||
- `fix` - Bug fix
|
||||
- `docs` - Documentation
|
||||
- `refactor` - Code refactoring
|
||||
- `perf` - Performance improvement
|
||||
- `test` - Test updates
|
||||
- `chore` - Build/config changes
|
||||
- `security` - Security improvements
|
||||
|
||||
### Step 5: Push Changes
|
||||
|
||||
```bash
|
||||
git push -f origin <your-pr-branch>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📋 Checklist
|
||||
|
||||
After migrating, verify:
|
||||
|
||||
- [ ] PR is rebased on latest `dev`
|
||||
- [ ] No merge conflicts
|
||||
- [ ] Backend tests pass locally
|
||||
- [ ] Frontend builds successfully
|
||||
- [ ] PR title follows Conventional Commits format
|
||||
- [ ] All commits are meaningful
|
||||
- [ ] Changes pushed to GitHub
|
||||
|
||||
---
|
||||
|
||||
## 🤖 What Happens After Migration?
|
||||
|
||||
After you push your changes:
|
||||
|
||||
1. **Automated checks will run** (they won't block merging, just provide feedback)
|
||||
2. **You'll get a comment** with check results and suggestions
|
||||
3. **Maintainers will review** your PR with the new context
|
||||
4. **Faster review** thanks to pre-checks
|
||||
|
||||
---
|
||||
|
||||
## ❓ Troubleshooting
|
||||
|
||||
### "Rebase conflicts"
|
||||
|
||||
If you get conflicts during rebase:
|
||||
|
||||
```bash
|
||||
# Fix conflicts in your editor
|
||||
# Then:
|
||||
git add <fixed-files>
|
||||
git rebase --continue
|
||||
|
||||
# Or abort and ask for help:
|
||||
git rebase --abort
|
||||
```
|
||||
|
||||
**Need help?** Just comment on your PR and we'll assist!
|
||||
|
||||
### "Tests failing"
|
||||
|
||||
If tests fail:
|
||||
|
||||
```bash
|
||||
# Run tests to see the error
|
||||
go test ./...
|
||||
|
||||
# Fix the issue
|
||||
# Then commit and push
|
||||
git add .
|
||||
git commit -m "fix: resolve test failures"
|
||||
git push -f origin <your-pr-branch>
|
||||
```
|
||||
|
||||
### "Script not working"
|
||||
|
||||
If the migration script doesn't work:
|
||||
|
||||
1. Check you have Go and Node.js installed
|
||||
2. Try manual migration (steps above)
|
||||
3. Ask for help in your PR comments
|
||||
|
||||
---
|
||||
|
||||
## 💡 Tips
|
||||
|
||||
**Don't want to migrate?**
|
||||
- That's okay! Your PR will still be reviewed and merged
|
||||
- Migration is optional but recommended
|
||||
|
||||
**First time using Git rebase?**
|
||||
- Check our [Git guide](https://git-scm.com/book/en/v2/Git-Branching-Rebasing)
|
||||
- Ask questions in your PR - we're here to help!
|
||||
|
||||
**Want to learn more?**
|
||||
- [Contributing Guidelines](../../CONTRIBUTING.md)
|
||||
- [Migration Announcement](MIGRATION_ANNOUNCEMENT.md)
|
||||
- [PR Review Guide](../maintainers/PR_REVIEW_GUIDE.md)
|
||||
|
||||
---
|
||||
|
||||
## 📞 Need Help?
|
||||
|
||||
**Stuck on migration?**
|
||||
- Comment on your PR
|
||||
- Ask in [Telegram](https://t.me/nofx_dev_community)
|
||||
- Open a [Discussion](https://github.com/tinkle-community/nofx/discussions)
|
||||
|
||||
**We're here to help you succeed!** 🚀
|
||||
|
||||
---
|
||||
|
||||
## 🎉 After Migration
|
||||
|
||||
Once migrated:
|
||||
1. ✅ Wait for automated checks to run
|
||||
2. ✅ Address any feedback in comments
|
||||
3. ✅ Wait for maintainer review
|
||||
4. ✅ Celebrate when merged! 🎉
|
||||
|
||||
**Thank you for contributing to NOFX!**
|
||||
272
docs/community/HOW_TO_MIGRATE_YOUR_PR.zh-CN.md
Normal file
272
docs/community/HOW_TO_MIGRATE_YOUR_PR.zh-CN.md
Normal file
@@ -0,0 +1,272 @@
|
||||
# 🔄 如何将你的 PR 迁移到新格式
|
||||
|
||||
**语言:** [English](HOW_TO_MIGRATE_YOUR_PR.md) | [中文](HOW_TO_MIGRATE_YOUR_PR.zh-CN.md)
|
||||
|
||||
本指南帮助你将现有 PR 迁移以满足新的 PR 管理系统要求。
|
||||
|
||||
---
|
||||
|
||||
## 🎯 为什么要迁移?
|
||||
|
||||
虽然你的现有 PR **仍将按照当前标准审核和合并**,但将其迁移到新格式可以获得:
|
||||
|
||||
✅ **更快的审核** - 自动化检查尽早捕获问题
|
||||
✅ **更好的反馈** - CI 提供清晰、可操作的反馈
|
||||
✅ **更高质量** - 一致的代码标准
|
||||
✅ **学习机会** - 了解我们新的贡献工作流程
|
||||
|
||||
---
|
||||
|
||||
## ⚡ 快速检查(推荐)
|
||||
|
||||
### 步骤 1:分析你的 PR
|
||||
|
||||
```bash
|
||||
# 运行 PR 健康检查(只读,不修改任何内容)
|
||||
./scripts/pr-check.sh
|
||||
```
|
||||
|
||||
这将分析你的 PR 并告诉你:
|
||||
- ✅ 什么是好的
|
||||
- ⚠️ 什么需要注意
|
||||
- 💡 如何修复问题
|
||||
- 📊 整体健康评分
|
||||
|
||||
### 步骤 2:修复问题
|
||||
|
||||
根据建议,手动修复问题。常见修复:
|
||||
|
||||
```bash
|
||||
# Rebase 到最新 dev
|
||||
git fetch upstream && git rebase upstream/dev
|
||||
|
||||
# 格式化 Go 代码
|
||||
go fmt ./...
|
||||
|
||||
# 运行测试
|
||||
go test ./...
|
||||
|
||||
# 格式化前端代码
|
||||
cd web && npm run lint -- --fix
|
||||
```
|
||||
|
||||
### 步骤 3:再次运行检查
|
||||
|
||||
```bash
|
||||
# 验证所有问题都已修复
|
||||
./scripts/pr-check.sh
|
||||
```
|
||||
|
||||
### 步骤 4:推送更改
|
||||
|
||||
```bash
|
||||
git push -f origin <your-pr-branch>
|
||||
```
|
||||
|
||||
### 脚本做什么
|
||||
|
||||
1. ✅ 与最新的 `upstream/dev` 同步
|
||||
2. ✅ Rebase 你的更改
|
||||
3. ✅ 格式化 Go 代码(`go fmt`)
|
||||
4. ✅ 运行 Go linting(`go vet`)
|
||||
5. ✅ 运行测试
|
||||
6. ✅ 格式化前端代码(如果适用)
|
||||
7. ✅ 推送更改到你的 PR
|
||||
|
||||
---
|
||||
|
||||
## 🛠️ 手动迁移(逐步指南)
|
||||
|
||||
如果你更喜欢手动操作:
|
||||
|
||||
### 步骤 1:与 Upstream 同步
|
||||
|
||||
```bash
|
||||
# 如果还没添加 upstream,添加它
|
||||
git remote add upstream https://github.com/tinkle-community/nofx.git
|
||||
|
||||
# 获取最新更改
|
||||
git fetch upstream
|
||||
|
||||
# Rebase 你的分支
|
||||
git checkout <your-pr-branch>
|
||||
git rebase upstream/dev
|
||||
```
|
||||
|
||||
### 步骤 2:后端检查(Go)
|
||||
|
||||
```bash
|
||||
# 格式化 Go 代码
|
||||
go fmt ./...
|
||||
|
||||
# 运行 linting
|
||||
go vet ./...
|
||||
|
||||
# 运行测试
|
||||
go test ./...
|
||||
|
||||
# 如果有更改,提交它们
|
||||
git add .
|
||||
git commit -m "chore: format and fix backend issues"
|
||||
```
|
||||
|
||||
### 步骤 3:前端检查(如果适用)
|
||||
|
||||
```bash
|
||||
cd web
|
||||
|
||||
# 安装依赖
|
||||
npm install
|
||||
|
||||
# 修复 linting 问题
|
||||
npm run lint -- --fix
|
||||
|
||||
# 检查类型
|
||||
npm run type-check
|
||||
|
||||
# 测试构建
|
||||
npm run build
|
||||
|
||||
cd ..
|
||||
|
||||
# 提交任何修复
|
||||
git add .
|
||||
git commit -m "chore: fix frontend issues"
|
||||
```
|
||||
|
||||
### 步骤 4:更新 PR 标题(如果需要)
|
||||
|
||||
确保你的 PR 标题遵循 [Conventional Commits](https://www.conventionalcommits.org/):
|
||||
|
||||
```
|
||||
<type>(<scope>): <description>
|
||||
|
||||
示例:
|
||||
feat(exchange): add OKX integration
|
||||
fix(trader): resolve position tracking bug
|
||||
docs(readme): update installation guide
|
||||
```
|
||||
|
||||
**类型:**
|
||||
- `feat` - 新功能
|
||||
- `fix` - Bug 修复
|
||||
- `docs` - 文档
|
||||
- `refactor` - 代码重构
|
||||
- `perf` - 性能改进
|
||||
- `test` - 测试更新
|
||||
- `chore` - 构建/配置更改
|
||||
- `security` - 安全改进
|
||||
|
||||
### 步骤 5:推送更改
|
||||
|
||||
```bash
|
||||
git push -f origin <your-pr-branch>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📋 检查清单
|
||||
|
||||
迁移后,验证:
|
||||
|
||||
- [ ] PR 已基于最新 `dev` rebase
|
||||
- [ ] 没有合并冲突
|
||||
- [ ] 后端测试在本地通过
|
||||
- [ ] 前端构建成功
|
||||
- [ ] PR 标题遵循 Conventional Commits 格式
|
||||
- [ ] 所有 commit 都有意义
|
||||
- [ ] 更改已推送到 GitHub
|
||||
|
||||
---
|
||||
|
||||
## 🤖 迁移后会发生什么?
|
||||
|
||||
推送更改后:
|
||||
|
||||
1. **自动化检查将运行**(不会阻止合并,只提供反馈)
|
||||
2. **你将收到评论**,包含检查结果和建议
|
||||
3. **维护者将审核** 你的 PR,有了新的上下文
|
||||
4. **更快的审核** 得益于预检查
|
||||
|
||||
---
|
||||
|
||||
## ❓ 故障排除
|
||||
|
||||
### "Rebase 冲突"
|
||||
|
||||
如果在 rebase 期间遇到冲突:
|
||||
|
||||
```bash
|
||||
# 在编辑器中修复冲突
|
||||
# 然后:
|
||||
git add <fixed-files>
|
||||
git rebase --continue
|
||||
|
||||
# 或中止并寻求帮助:
|
||||
git rebase --abort
|
||||
```
|
||||
|
||||
**需要帮助?** 在你的 PR 中评论,我们会协助!
|
||||
|
||||
### "测试失败"
|
||||
|
||||
如果测试失败:
|
||||
|
||||
```bash
|
||||
# 运行测试查看错误
|
||||
go test ./...
|
||||
|
||||
# 修复问题
|
||||
# 然后提交并推送
|
||||
git add .
|
||||
git commit -m "fix: resolve test failures"
|
||||
git push -f origin <your-pr-branch>
|
||||
```
|
||||
|
||||
### "脚本不工作"
|
||||
|
||||
如果迁移脚本不工作:
|
||||
|
||||
1. 检查你是否安装了 Go 和 Node.js
|
||||
2. 尝试手动迁移(上面的步骤)
|
||||
3. 在你的 PR 评论中寻求帮助
|
||||
|
||||
---
|
||||
|
||||
## 💡 提示
|
||||
|
||||
**不想迁移?**
|
||||
- 没关系!你的 PR 仍将被审核和合并
|
||||
- 迁移是可选的但推荐的
|
||||
|
||||
**第一次使用 Git rebase?**
|
||||
- 查看我们的 [Git 指南](https://git-scm.com/book/zh/v2/Git-%E5%88%86%E6%94%AF-%E5%8F%98%E5%9F%BA)
|
||||
- 在你的 PR 中提问 - 我们在这里帮助!
|
||||
|
||||
**想了解更多?**
|
||||
- [贡献指南](../../docs/i18n/zh-CN/CONTRIBUTING.md)
|
||||
- [迁移公告](MIGRATION_ANNOUNCEMENT.zh-CN.md)
|
||||
- [PR 审核指南](../maintainers/PR_REVIEW_GUIDE.zh-CN.md)
|
||||
|
||||
---
|
||||
|
||||
## 📞 需要帮助?
|
||||
|
||||
**迁移遇到困难?**
|
||||
- 在你的 PR 中评论
|
||||
- 在 [Telegram](https://t.me/nofx_dev_community) 提问
|
||||
- 开启 [Discussion](https://github.com/tinkle-community/nofx/discussions)
|
||||
|
||||
**我们在这里帮助你成功!** 🚀
|
||||
|
||||
---
|
||||
|
||||
## 🎉 迁移后
|
||||
|
||||
迁移完成后:
|
||||
1. ✅ 等待自动化检查运行
|
||||
2. ✅ 处理评论中的任何反馈
|
||||
3. ✅ 等待维护者审核
|
||||
4. ✅ 合并时庆祝!🎉
|
||||
|
||||
**感谢你为 NOFX 做出贡献!**
|
||||
358
docs/community/MIGRATION_ANNOUNCEMENT.md
Normal file
358
docs/community/MIGRATION_ANNOUNCEMENT.md
Normal file
@@ -0,0 +1,358 @@
|
||||
# 📢 PR Management System Update - What Contributors Need to Know
|
||||
|
||||
**Language:** [English](MIGRATION_ANNOUNCEMENT.md) | [中文](MIGRATION_ANNOUNCEMENT.zh-CN.md)
|
||||
|
||||
We're introducing a new PR management system to improve code quality and make contributing easier! This guide explains what's changing and what you need to do.
|
||||
|
||||
---
|
||||
|
||||
## 🎯 What's Changing?
|
||||
|
||||
We're introducing:
|
||||
|
||||
✅ **Clear contribution guidelines** aligned with our [roadmap](../roadmap/README.md)
|
||||
✅ **Automated checks** (tests, linting, security scans)
|
||||
✅ **Better labeling** for organization and prioritization
|
||||
✅ **Faster review turnaround** with pre-checks
|
||||
✅ **Transparent process** so you know exactly what to expect
|
||||
|
||||
---
|
||||
|
||||
## 📅 Timeline
|
||||
|
||||
```
|
||||
Week 1-2: Existing PR Review Period
|
||||
Week 3: Soft Launch (checks are advisory only)
|
||||
Week 4+: Full Launch (checks are required)
|
||||
```
|
||||
|
||||
**Important:** This rollout is gradual. You'll have time to adapt!
|
||||
|
||||
---
|
||||
|
||||
## 🤔 What This Means for YOU
|
||||
|
||||
### If You Have an Existing Open PR
|
||||
|
||||
**Good news:** Your PR will NOT be blocked by new rules!
|
||||
|
||||
- ✅ Your PR will be reviewed under current (relaxed) standards
|
||||
- ✅ We'll review and provide feedback within 1-2 weeks
|
||||
- ✅ Some PRs may need a quick rebase or minor updates
|
||||
|
||||
**What you might need to do:**
|
||||
1. **Rebase on latest `dev` branch** if there are conflicts
|
||||
2. **Respond to review comments** within 1 week
|
||||
3. **Be patient** as we work through the backlog
|
||||
|
||||
**What happens if I don't respond?**
|
||||
- We may close your PR after 2 weeks of inactivity
|
||||
- You can always reopen it later with updates!
|
||||
- No hard feelings - we're just cleaning up the backlog
|
||||
|
||||
### 🚀 Want to Check Your PR? (Optional)
|
||||
|
||||
We've created a **PR health check tool** to help you see if your PR meets the new standards!
|
||||
|
||||
**Run this in your local fork:**
|
||||
```bash
|
||||
./scripts/pr-check.sh
|
||||
```
|
||||
|
||||
**What it does:**
|
||||
- 🔍 Analyzes your PR (doesn't modify anything)
|
||||
- ✅ Shows what's good
|
||||
- ⚠️ Points out issues
|
||||
- 💡 Gives you specific fix suggestions
|
||||
- 📊 Overall health score
|
||||
|
||||
**Then fix issues and push:**
|
||||
```bash
|
||||
# Fix the issues (see suggestions from script)
|
||||
# Run check again
|
||||
./scripts/pr-check.sh
|
||||
|
||||
# Push when ready
|
||||
git push -f origin <your-branch>
|
||||
```
|
||||
|
||||
**📖 Full Guide:** [How to Migrate Your PR](HOW_TO_MIGRATE_YOUR_PR.md)
|
||||
|
||||
**Remember:** This is completely **optional** for existing PRs!
|
||||
|
||||
---
|
||||
|
||||
### If You're Submitting a NEW PR
|
||||
|
||||
**Timeline matters:**
|
||||
|
||||
#### Week 3 (Soft Launch):
|
||||
- ✅ Automated checks will run (tests, linting, security)
|
||||
- ⚠️ **Checks are advisory only** - they won't block your PR
|
||||
- ✅ This is a learning period - we're here to help!
|
||||
- ✅ Get familiar with the new [Contributing Guidelines](../../CONTRIBUTING.md)
|
||||
|
||||
#### Week 4+ (Full Launch):
|
||||
- ✅ All automated checks must pass before merge
|
||||
- ✅ PR must follow [Conventional Commits](https://www.conventionalcommits.org/) format
|
||||
- ✅ PR template must be filled out
|
||||
- ✅ Must align with [roadmap](../roadmap/README.md) priorities
|
||||
|
||||
---
|
||||
|
||||
## ✅ How to Prepare for New System
|
||||
|
||||
### 1. Read the Contributing Guidelines
|
||||
|
||||
📖 [CONTRIBUTING.md](../../CONTRIBUTING.md)
|
||||
|
||||
**Key points:**
|
||||
- We accept PRs aligned with our roadmap (security, AI, exchanges, UI/UX)
|
||||
- PRs should be focused and small (<300 lines preferred)
|
||||
- Use Conventional Commits format: `feat(area): description`
|
||||
- Include tests for new features
|
||||
|
||||
### 2. Check the Roadmap
|
||||
|
||||
🗺️ [Roadmap](../roadmap/README.md)
|
||||
|
||||
**Current priorities (Phase 1):**
|
||||
- 🔒 Security enhancements
|
||||
- 🧠 AI model integrations
|
||||
- 🔗 Exchange integrations (OKX, Bybit, Lighter, EdgeX)
|
||||
- 🎨 UI/UX improvements
|
||||
- ⚡ Performance optimizations
|
||||
- 🐛 Bug fixes
|
||||
|
||||
**Lower priority (Phase 2+):**
|
||||
- Universal market expansion (stocks, futures)
|
||||
- Advanced AI features
|
||||
- Enterprise features
|
||||
|
||||
💡 **Pro tip:** If your PR aligns with Phase 1, it'll be reviewed faster!
|
||||
|
||||
### 3. Set Up Local Testing
|
||||
|
||||
Before submitting a PR, test locally:
|
||||
|
||||
```bash
|
||||
# Backend tests
|
||||
go test ./...
|
||||
go fmt ./...
|
||||
go vet ./...
|
||||
|
||||
# Frontend tests
|
||||
cd web
|
||||
npm run lint
|
||||
npm run type-check
|
||||
npm run build
|
||||
```
|
||||
|
||||
This helps your PR pass automated checks on first try!
|
||||
|
||||
---
|
||||
|
||||
## 📝 PR Title Format
|
||||
|
||||
Use [Conventional Commits](https://www.conventionalcommits.org/) format:
|
||||
|
||||
```
|
||||
<type>(<scope>): <description>
|
||||
|
||||
Examples:
|
||||
feat(exchange): add OKX futures support
|
||||
fix(trader): resolve position tracking bug
|
||||
docs(readme): update installation instructions
|
||||
perf(ai): optimize prompt generation
|
||||
```
|
||||
|
||||
**Types:**
|
||||
- `feat` - New feature
|
||||
- `fix` - Bug fix
|
||||
- `docs` - Documentation
|
||||
- `refactor` - Code refactoring
|
||||
- `perf` - Performance improvement
|
||||
- `test` - Test updates
|
||||
- `chore` - Build/config changes
|
||||
- `security` - Security improvements
|
||||
|
||||
---
|
||||
|
||||
## 🎯 What Makes a Good PR?
|
||||
|
||||
### ✅ Good PR Example
|
||||
|
||||
```
|
||||
Title: feat(exchange): add OKX exchange integration
|
||||
|
||||
Description:
|
||||
Implements OKX exchange support with the following features:
|
||||
- Order placement and cancellation
|
||||
- Balance and position retrieval
|
||||
- Leverage configuration
|
||||
- Error handling and retry logic
|
||||
|
||||
Closes #123
|
||||
|
||||
Testing:
|
||||
- [x] Unit tests added and passing
|
||||
- [x] Manually tested with real API
|
||||
- [x] Documentation updated
|
||||
```
|
||||
|
||||
**Why it's good:**
|
||||
- ✅ Clear, descriptive title
|
||||
- ✅ Explains what and why
|
||||
- ✅ Links to issue
|
||||
- ✅ Includes testing details
|
||||
- ✅ Small, focused change
|
||||
|
||||
### ❌ Avoid These
|
||||
|
||||
**Too vague:**
|
||||
```
|
||||
Title: update code
|
||||
Description: made some changes
|
||||
```
|
||||
|
||||
**Too large:**
|
||||
```
|
||||
Title: feat: complete rewrite of entire trading system
|
||||
Files changed: 2,500+
|
||||
```
|
||||
|
||||
**Off roadmap:**
|
||||
```
|
||||
Title: feat: add support for stock trading
|
||||
(This is Phase 3, not current priority)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🐛 If Your PR Fails Checks
|
||||
|
||||
Don't panic! We're here to help.
|
||||
|
||||
**Week 3 (Soft Launch):**
|
||||
- Checks are advisory - we'll help you fix issues
|
||||
- Ask questions in your PR comments
|
||||
- We can guide you through debugging
|
||||
|
||||
**Week 4+ (Full Launch):**
|
||||
- Checks must pass, but we still help!
|
||||
- Common issues:
|
||||
- Test failures → Run `go test ./...` locally
|
||||
- Linting errors → Run `go fmt` and `npm run lint`
|
||||
- Merge conflicts → Rebase on latest `dev`
|
||||
|
||||
**Need help?** Just ask! Comment in your PR or reach out:
|
||||
- [GitHub Discussions](https://github.com/tinkle-community/nofx/discussions)
|
||||
- [Telegram Community](https://t.me/nofx_dev_community)
|
||||
|
||||
---
|
||||
|
||||
## 💰 Special Note for Bounty Contributors
|
||||
|
||||
If you're working on a bounty:
|
||||
|
||||
✅ **Your PRs get priority review** (24-48 hours)
|
||||
✅ **Extra support** to meet requirements
|
||||
✅ **Flexible during transition** - we'll work with you
|
||||
|
||||
Just make sure to:
|
||||
- Reference the bounty issue number
|
||||
- Meet all acceptance criteria
|
||||
- Include demo video/screenshots
|
||||
|
||||
---
|
||||
|
||||
## ❓ FAQ
|
||||
|
||||
### Q: Will my existing PR be rejected?
|
||||
|
||||
**A:** No! Existing PRs use relaxed standards. We may ask for minor updates (rebase, small fixes), but you won't be held to new strict requirements.
|
||||
|
||||
### Q: What if I can't pass the new CI checks?
|
||||
|
||||
**A:** Week 3 is a learning period. We'll help you understand and fix issues. By Week 4, you'll be familiar with the process!
|
||||
|
||||
### Q: Will this slow down contributions?
|
||||
|
||||
**A:** Actually, no! Automated checks catch issues early, making reviews faster. Clear guidelines help you submit better PRs on first try.
|
||||
|
||||
### Q: Can I still contribute if I'm a beginner?
|
||||
|
||||
**A:** Absolutely! Look for issues labeled `good first issue`. We're here to mentor and help you succeed.
|
||||
|
||||
### Q: My PR is large (>1000 lines). What should I do?
|
||||
|
||||
**A:** Consider breaking it into smaller PRs. This gets you:
|
||||
- ✅ Faster reviews
|
||||
- ✅ Easier testing
|
||||
- ✅ Higher chance of quick merge
|
||||
|
||||
Need help planning? Just ask in your PR!
|
||||
|
||||
### Q: What if my feature isn't on the roadmap?
|
||||
|
||||
**A:** Open an issue first to discuss! We're open to good ideas, but want to ensure alignment before you spend time coding.
|
||||
|
||||
### Q: When will this be fully active?
|
||||
|
||||
**A:** Week 4+ (approximately 4 weeks from announcement date). Check the pinned Discussion post for exact dates.
|
||||
|
||||
---
|
||||
|
||||
## 🎉 Benefits for Contributors
|
||||
|
||||
This new system helps YOU by:
|
||||
|
||||
✅ **Faster reviews** - Automated pre-checks reduce review time
|
||||
✅ **Clear expectations** - You know exactly what's required
|
||||
✅ **Better feedback** - Automated checks catch issues early
|
||||
✅ **Fair prioritization** - Roadmap-aligned PRs reviewed faster
|
||||
✅ **Recognition** - Contributor tiers and recognition program
|
||||
|
||||
---
|
||||
|
||||
## 📚 Resources
|
||||
|
||||
### Must Read
|
||||
- [Contributing Guidelines](../../CONTRIBUTING.md) - Complete guide
|
||||
- [Roadmap](../roadmap/README.md) - Current priorities
|
||||
|
||||
### Helpful Links
|
||||
- [Conventional Commits](https://www.conventionalcommits.org/) - Commit format
|
||||
- [Good First Issues](https://github.com/tinkle-community/nofx/labels/good%20first%20issue) - Beginner-friendly tasks
|
||||
- [Bounty Program](../bounty-guide.md) - Get paid to contribute
|
||||
|
||||
### Get Help
|
||||
- [GitHub Discussions](https://github.com/tinkle-community/nofx/discussions) - Ask questions
|
||||
- [Telegram](https://t.me/nofx_dev_community) - Community chat
|
||||
- [Twitter](https://x.com/nofx_ai) - Updates and announcements
|
||||
|
||||
---
|
||||
|
||||
## 💬 Feedback Welcome!
|
||||
|
||||
This is a new system and we want YOUR input:
|
||||
|
||||
- 📝 What's unclear?
|
||||
- 🤔 What concerns do you have?
|
||||
- 💡 How can we improve?
|
||||
|
||||
Share in the [Migration Feedback Discussion](https://github.com/tinkle-community/nofx/discussions) (link TBD)
|
||||
|
||||
---
|
||||
|
||||
## 🙏 Thank You!
|
||||
|
||||
We appreciate your contributions and patience during this transition. Together, we're building something amazing!
|
||||
|
||||
**Questions?** Don't hesitate to ask. We're here to help! 🚀
|
||||
|
||||
---
|
||||
|
||||
**Last Updated:** 2025-01-XX
|
||||
**Status:** Announcement (Week 0)
|
||||
**Full Launch:** Week 4+ (TBD)
|
||||
358
docs/community/MIGRATION_ANNOUNCEMENT.zh-CN.md
Normal file
358
docs/community/MIGRATION_ANNOUNCEMENT.zh-CN.md
Normal file
@@ -0,0 +1,358 @@
|
||||
# 📢 PR 管理系统更新 - 贡献者须知
|
||||
|
||||
**语言:** [English](MIGRATION_ANNOUNCEMENT.md) | [中文](MIGRATION_ANNOUNCEMENT.zh-CN.md)
|
||||
|
||||
我们正在引入新的 PR 管理系统,以提高代码质量并让贡献变得更容易!本指南解释了变化内容以及你需要做什么。
|
||||
|
||||
---
|
||||
|
||||
## 🎯 有什么变化?
|
||||
|
||||
我们正在引入:
|
||||
|
||||
✅ **清晰的贡献指南** 与我们的[路线图](../roadmap/README.zh-CN.md)对齐
|
||||
✅ **自动化检查**(测试、linting、安全扫描)
|
||||
✅ **更好的标签** 用于组织和优先级排序
|
||||
✅ **更快的审核周转** 通过预检查
|
||||
✅ **透明的流程** 让你准确知道期望什么
|
||||
|
||||
---
|
||||
|
||||
## 📅 时间表
|
||||
|
||||
```
|
||||
第 1-2 周:现有 PR 审核期
|
||||
第 3 周: 软启动(检查仅是建议性的)
|
||||
第 4 周+: 完全启动(检查是必需的)
|
||||
```
|
||||
|
||||
**重要:** 这个推出是渐进式的。你将有时间适应!
|
||||
|
||||
---
|
||||
|
||||
## 🤔 这对你意味着什么
|
||||
|
||||
### 如果你有现有的打开的 PR
|
||||
|
||||
**好消息:** 你的 PR 不会被新规则阻塞!
|
||||
|
||||
- ✅ 你的 PR 将按照当前(宽松)标准进行审核
|
||||
- ✅ 我们将在 1-2 周内审核并提供反馈
|
||||
- ✅ 一些 PR 可能需要快速 rebase 或次要更新
|
||||
|
||||
**你可能需要做什么:**
|
||||
1. **基于最新 `dev` 分支 rebase** 如果有冲突
|
||||
2. **在 1 周内回应审核评论**
|
||||
3. **保持耐心** 我们正在处理积压
|
||||
|
||||
**如果我不回应会怎样?**
|
||||
- 我们可能会在 2 周不活动后关闭你的 PR
|
||||
- 你随时可以稍后重新打开并更新!
|
||||
- 没有恶意 - 我们只是在清理积压
|
||||
|
||||
### 🚀 想要检查你的 PR?(可选)
|
||||
|
||||
我们创建了一个 **PR 健康检查工具**来帮助你看 PR 是否符合新标准!
|
||||
|
||||
**在你的本地 fork 中运行:**
|
||||
```bash
|
||||
./scripts/pr-check.sh
|
||||
```
|
||||
|
||||
**它做什么:**
|
||||
- 🔍 分析你的 PR(不修改任何内容)
|
||||
- ✅ 显示什么是好的
|
||||
- ⚠️ 指出问题
|
||||
- 💡 给你具体的修复建议
|
||||
- 📊 整体健康评分
|
||||
|
||||
**然后修复问题并推送:**
|
||||
```bash
|
||||
# 修复问题(查看脚本的建议)
|
||||
# 再次运行检查
|
||||
./scripts/pr-check.sh
|
||||
|
||||
# 准备好后推送
|
||||
git push -f origin <your-branch>
|
||||
```
|
||||
|
||||
**📖 完整指南:** [如何迁移你的 PR](HOW_TO_MIGRATE_YOUR_PR.zh-CN.md)
|
||||
|
||||
**记住:** 对于现有 PR,这是完全**可选的**!
|
||||
|
||||
---
|
||||
|
||||
### 如果你要提交新的 PR
|
||||
|
||||
**时间很重要:**
|
||||
|
||||
#### 第 3 周(软启动):
|
||||
- ✅ 自动化检查将运行(测试、linting、安全性)
|
||||
- ⚠️ **检查仅是建议性的** - 不会阻塞你的 PR
|
||||
- ✅ 这是一个学习期 - 我们在这里帮助!
|
||||
- ✅ 熟悉新的[贡献指南](../../docs/i18n/zh-CN/CONTRIBUTING.md)
|
||||
|
||||
#### 第 4 周+(完全启动):
|
||||
- ✅ 所有自动化检查必须通过才能合并
|
||||
- ✅ PR 必须遵循 [Conventional Commits](https://www.conventionalcommits.org/) 格式
|
||||
- ✅ 必须填写 PR 模板
|
||||
- ✅ 必须与[路线图](../roadmap/README.zh-CN.md)优先级对齐
|
||||
|
||||
---
|
||||
|
||||
## ✅ 如何为新系统做准备
|
||||
|
||||
### 1. 阅读贡献指南
|
||||
|
||||
📖 [CONTRIBUTING.md](../../docs/i18n/zh-CN/CONTRIBUTING.md)
|
||||
|
||||
**关键点:**
|
||||
- 我们接受与路线图对齐的 PR(安全性、AI、交易所、UI/UX)
|
||||
- PR 应该集中且小型(<300 行优先)
|
||||
- 使用 Conventional Commits 格式:`feat(area): description`
|
||||
- 为新功能包含测试
|
||||
|
||||
### 2. 查看路线图
|
||||
|
||||
🗺️ [路线图](../roadmap/README.zh-CN.md)
|
||||
|
||||
**当前优先级(Phase 1):**
|
||||
- 🔒 安全增强
|
||||
- 🧠 AI 模型集成
|
||||
- 🔗 交易所集成(OKX、Bybit、Lighter、EdgeX)
|
||||
- 🎨 UI/UX 改进
|
||||
- ⚡ 性能优化
|
||||
- 🐛 Bug 修复
|
||||
|
||||
**较低优先级(Phase 2+):**
|
||||
- 通用市场扩展(股票、期货)
|
||||
- 高级 AI 功能
|
||||
- 企业功能
|
||||
|
||||
💡 **专业提示:** 如果你的 PR 与 Phase 1 对齐,它会被更快审核!
|
||||
|
||||
### 3. 设置本地测试
|
||||
|
||||
提交 PR 前,在本地测试:
|
||||
|
||||
```bash
|
||||
# 后端测试
|
||||
go test ./...
|
||||
go fmt ./...
|
||||
go vet ./...
|
||||
|
||||
# 前端测试
|
||||
cd web
|
||||
npm run lint
|
||||
npm run type-check
|
||||
npm run build
|
||||
```
|
||||
|
||||
这有助于你的 PR 第一次就通过自动化检查!
|
||||
|
||||
---
|
||||
|
||||
## 📝 PR 标题格式
|
||||
|
||||
使用 [Conventional Commits](https://www.conventionalcommits.org/) 格式:
|
||||
|
||||
```
|
||||
<type>(<scope>): <description>
|
||||
|
||||
示例:
|
||||
feat(exchange): add OKX futures support
|
||||
fix(trader): resolve position tracking bug
|
||||
docs(readme): update installation instructions
|
||||
perf(ai): optimize prompt generation
|
||||
```
|
||||
|
||||
**类型:**
|
||||
- `feat` - 新功能
|
||||
- `fix` - Bug 修复
|
||||
- `docs` - 文档
|
||||
- `refactor` - 代码重构
|
||||
- `perf` - 性能改进
|
||||
- `test` - 测试更新
|
||||
- `chore` - 构建/配置变更
|
||||
- `security` - 安全改进
|
||||
|
||||
---
|
||||
|
||||
## 🎯 什么是好的 PR?
|
||||
|
||||
### ✅ 好的 PR 示例
|
||||
|
||||
```
|
||||
标题:feat(exchange): add OKX exchange integration
|
||||
|
||||
描述:
|
||||
使用以下功能实现 OKX 交易所支持:
|
||||
- 订单下达和取消
|
||||
- 余额和仓位检索
|
||||
- 杠杆配置
|
||||
- 错误处理和重试逻辑
|
||||
|
||||
关闭 #123
|
||||
|
||||
测试:
|
||||
- [x] 单元测试已添加并通过
|
||||
- [x] 使用真实 API 手动测试
|
||||
- [x] 文档已更新
|
||||
```
|
||||
|
||||
**为什么好:**
|
||||
- ✅ 清晰、描述性标题
|
||||
- ✅ 解释了什么和为什么
|
||||
- ✅ 链接到 issue
|
||||
- ✅ 包含测试详情
|
||||
- ✅ 小型、集中的变更
|
||||
|
||||
### ❌ 避免这些
|
||||
|
||||
**太模糊:**
|
||||
```
|
||||
标题:update code
|
||||
描述:made some changes
|
||||
```
|
||||
|
||||
**太大:**
|
||||
```
|
||||
标题:feat: complete rewrite of entire trading system
|
||||
文件变更:2,500+
|
||||
```
|
||||
|
||||
**不在路线图上:**
|
||||
```
|
||||
标题:feat: add support for stock trading
|
||||
(这是 Phase 3,不是当前优先级)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🐛 如果你的 PR 检查失败
|
||||
|
||||
不要恐慌!我们在这里帮助。
|
||||
|
||||
**第 3 周(软启动):**
|
||||
- 检查是建议性的 - 我们会帮你解决问题
|
||||
- 在你的 PR 评论中提问
|
||||
- 我们可以指导你进行调试
|
||||
|
||||
**第 4 周+(完全启动):**
|
||||
- 检查必须通过,但我们仍然会帮助!
|
||||
- 常见问题:
|
||||
- 测试失败 → 在本地运行 `go test ./...`
|
||||
- Linting 错误 → 运行 `go fmt` 和 `npm run lint`
|
||||
- 合并冲突 → 基于最新 `dev` rebase
|
||||
|
||||
**需要帮助?** 只管问!在你的 PR 中评论或联系:
|
||||
- [GitHub Discussions](https://github.com/tinkle-community/nofx/discussions)
|
||||
- [Telegram 社区](https://t.me/nofx_dev_community)
|
||||
|
||||
---
|
||||
|
||||
## 💰 悬赏贡献者特别说明
|
||||
|
||||
如果你正在做悬赏任务:
|
||||
|
||||
✅ **你的 PR 获得优先审核**(24-48 小时)
|
||||
✅ **额外支持** 以满足要求
|
||||
✅ **过渡期间灵活** - 我们会与你合作
|
||||
|
||||
只需确保:
|
||||
- 引用悬赏 issue 编号
|
||||
- 满足所有验收标准
|
||||
- 包含演示视频/截图
|
||||
|
||||
---
|
||||
|
||||
## ❓ 常见问题
|
||||
|
||||
### Q:我的现有 PR 会被拒绝吗?
|
||||
|
||||
**A:** 不会!现有 PR 使用宽松标准。我们可能会要求次要更新(rebase、小修复),但你不会被要求满足新的严格要求。
|
||||
|
||||
### Q:如果我无法通过新的 CI 检查怎么办?
|
||||
|
||||
**A:** 第 3 周是学习期。我们会帮你理解和修复问题。到第 4 周,你将熟悉这个流程!
|
||||
|
||||
### Q:这会减慢贡献速度吗?
|
||||
|
||||
**A:** 实际上不会!自动化检查尽早捕获问题,使审核更快。清晰的指南帮助你第一次就提交更好的 PR。
|
||||
|
||||
### Q:如果我是初学者,我还能贡献吗?
|
||||
|
||||
**A:** 绝对可以!查找标记为 `good first issue` 的 issue。我们在这里指导并帮助你成功。
|
||||
|
||||
### Q:我的 PR 很大(>1000 行)。我应该怎么做?
|
||||
|
||||
**A:** 考虑将其拆分为更小的 PR。这让你获得:
|
||||
- ✅ 更快的审核
|
||||
- ✅ 更容易的测试
|
||||
- ✅ 更高的快速合并机会
|
||||
|
||||
需要帮助规划?在你的 PR 中提问即可!
|
||||
|
||||
### Q:如果我的功能不在路线图上怎么办?
|
||||
|
||||
**A:** 先开一个 issue 讨论!我们对好想法持开放态度,但在你花时间编码之前想确保对齐。
|
||||
|
||||
### Q:这将何时完全激活?
|
||||
|
||||
**A:** 第 4 周+(从公告日期起大约 4 周)。查看置顶的 Discussion 帖子了解确切日期。
|
||||
|
||||
---
|
||||
|
||||
## 🎉 对贡献者的好处
|
||||
|
||||
这个新系统通过以下方式帮助你:
|
||||
|
||||
✅ **更快的审核** - 自动化预检查减少审核时间
|
||||
✅ **清晰的期望** - 你准确知道需要什么
|
||||
✅ **更好的反馈** - 自动化检查尽早捕获问题
|
||||
✅ **公平的优先级排序** - 路线图对齐的 PR 审核更快
|
||||
✅ **表彰** - 贡献者等级和表彰计划
|
||||
|
||||
---
|
||||
|
||||
## 📚 资源
|
||||
|
||||
### 必读
|
||||
- [贡献指南](../../docs/i18n/zh-CN/CONTRIBUTING.md) - 完整指南
|
||||
- [路线图](../roadmap/README.zh-CN.md) - 当前优先级
|
||||
|
||||
### 有用链接
|
||||
- [Conventional Commits](https://www.conventionalcommits.org/) - Commit 格式
|
||||
- [Good First Issues](https://github.com/tinkle-community/nofx/labels/good%20first%20issue) - 适合初学者的任务
|
||||
- [悬赏计划](../bounty-guide.md) - 获得报酬来贡献
|
||||
|
||||
### 获取帮助
|
||||
- [GitHub Discussions](https://github.com/tinkle-community/nofx/discussions) - 提问
|
||||
- [Telegram](https://t.me/nofx_dev_community) - 社区聊天
|
||||
- [Twitter](https://x.com/nofx_ai) - 更新和公告
|
||||
|
||||
---
|
||||
|
||||
## 💬 欢迎反馈!
|
||||
|
||||
这是一个新系统,我们想要你的意见:
|
||||
|
||||
- 📝 什么不清楚?
|
||||
- 🤔 你有什么顾虑?
|
||||
- 💡 我们如何改进?
|
||||
|
||||
在[迁移反馈讨论](https://github.com/tinkle-community/nofx/discussions)中分享(链接待定)
|
||||
|
||||
---
|
||||
|
||||
## 🙏 谢谢你!
|
||||
|
||||
我们感谢你的贡献和在这次过渡期间的耐心。我们一起正在构建令人惊叹的东西!
|
||||
|
||||
**问题?** 不要犹豫提问。我们在这里帮助!🚀
|
||||
|
||||
---
|
||||
|
||||
**最后更新:** 2025-01-XX
|
||||
**状态:** 公告(第 0 周)
|
||||
**完全启动:** 第 4 周+(待定)
|
||||
173
docs/community/PR_COMMENT_TEMPLATE.md
Normal file
173
docs/community/PR_COMMENT_TEMPLATE.md
Normal file
@@ -0,0 +1,173 @@
|
||||
# 📢 PR Comment Template for Existing PRs
|
||||
|
||||
This template is for maintainers to comment on existing PRs to introduce the new system.
|
||||
|
||||
---
|
||||
|
||||
## Template (English)
|
||||
|
||||
```markdown
|
||||
Hi @{username}! 👋
|
||||
|
||||
Thank you for your contribution to NOFX!
|
||||
|
||||
## 🚀 New PR Management System
|
||||
|
||||
We're introducing a new PR management system to improve code quality and make reviews faster. Your PR will **not be blocked** by these changes - we'll review it under current standards.
|
||||
|
||||
### ✨ Optional: Want to check your PR against new standards?
|
||||
|
||||
We've created a **PR health check tool** that analyzes your PR and gives you suggestions!
|
||||
|
||||
**How to use:**
|
||||
|
||||
```bash
|
||||
# In your local fork, on your PR branch
|
||||
cd /path/to/your/nofx-fork
|
||||
git checkout <your-branch-name>
|
||||
|
||||
# Run the health check (reads only, doesn't modify)
|
||||
./scripts/pr-check.sh
|
||||
```
|
||||
|
||||
**What it does:**
|
||||
- 🔍 Analyzes your PR (doesn't modify anything)
|
||||
- ✅ Shows what's already good
|
||||
- ⚠️ Points out issues
|
||||
- 💡 Gives specific suggestions on how to fix
|
||||
- 📊 Overall health score
|
||||
|
||||
**Then fix and re-check:**
|
||||
```bash
|
||||
# Fix the issues based on suggestions
|
||||
# Run check again to verify
|
||||
./scripts/pr-check.sh
|
||||
|
||||
# Push when everything looks good
|
||||
git push origin <your-branch-name>
|
||||
```
|
||||
|
||||
### 📖 Learn More
|
||||
|
||||
- [Migration Announcement](https://github.com/tinkle-community/nofx/blob/dev/docs/community/MIGRATION_ANNOUNCEMENT.md)
|
||||
- [Contributing Guidelines](https://github.com/tinkle-community/nofx/blob/dev/CONTRIBUTING.md)
|
||||
|
||||
### ❓ Questions?
|
||||
|
||||
Just ask here! We're happy to help. 🙏
|
||||
|
||||
---
|
||||
|
||||
**Note:** This migration is **completely optional** for existing PRs. We'll review and merge your PR either way!
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Template (Chinese / 中文)
|
||||
|
||||
```markdown
|
||||
嗨 @{username}!👋
|
||||
|
||||
感谢你为 NOFX 做出的贡献!
|
||||
|
||||
## 🚀 新的 PR 管理系统
|
||||
|
||||
我们正在引入新的 PR 管理系统,以提高代码质量并加快审核速度。你的 PR **不会被阻止** - 我们将按照当前标准审核它。
|
||||
|
||||
### ✨ 可选:想要检查你的 PR 吗?
|
||||
|
||||
我们创建了一个 **PR 健康检查工具**来帮助你看 PR 是否符合新标准!
|
||||
|
||||
**在你的本地 fork 中运行:**
|
||||
|
||||
```bash
|
||||
# 在你的本地 fork 中,切换到你的 PR 分支
|
||||
cd /path/to/your/nofx-fork
|
||||
git checkout <your-branch-name>
|
||||
|
||||
# 运行健康检查(只读,不修改任何内容)
|
||||
./scripts/pr-check.sh
|
||||
```
|
||||
|
||||
**它做什么:**
|
||||
- 🔍 分析你的 PR(不修改任何内容)
|
||||
- ✅ 显示什么是好的
|
||||
- ⚠️ 指出问题
|
||||
- 💡 给你具体的修复建议
|
||||
- 📊 整体健康评分
|
||||
|
||||
**然后修复问题并推送:**
|
||||
```bash
|
||||
# 修复问题(查看脚本的建议)
|
||||
# 再次运行检查
|
||||
./scripts/pr-check.sh
|
||||
|
||||
# 准备好后推送
|
||||
git push origin <your-branch-name>
|
||||
```
|
||||
|
||||
### 📖 了解更多
|
||||
|
||||
- [迁移公告](https://github.com/tinkle-community/nofx/blob/dev/docs/community/MIGRATION_ANNOUNCEMENT.zh-CN.md)
|
||||
- [贡献指南](https://github.com/tinkle-community/nofx/blob/dev/docs/i18n/zh-CN/CONTRIBUTING.md)
|
||||
|
||||
### ❓ 问题?
|
||||
|
||||
在这里提问即可!我们很乐意帮助。🙏
|
||||
|
||||
---
|
||||
|
||||
**注意:** 对于现有 PR,此迁移是**完全可选的**。无论如何我们都会审核和合并你的 PR!
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Quick Copy-Paste Template
|
||||
|
||||
For quick commenting on multiple PRs:
|
||||
|
||||
```markdown
|
||||
👋 Hi! Thanks for your PR!
|
||||
|
||||
We're introducing a new PR system. Your PR won't be blocked - we'll review it normally.
|
||||
|
||||
**Want to check your PR?** Run this in your fork:
|
||||
```bash
|
||||
./scripts/pr-check.sh
|
||||
```
|
||||
|
||||
[Learn more](https://github.com/tinkle-community/nofx/blob/dev/docs/community/MIGRATION_ANNOUNCEMENT.md) | This is optional!
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Bulk Comment Script (for maintainers)
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
||||
# Comment on all open PRs
|
||||
gh pr list --state open --json number --jq '.[].number' | while read pr_number; do
|
||||
echo "Commenting on PR #$pr_number"
|
||||
|
||||
gh pr comment "$pr_number" --body "👋 Hi! Thanks for your PR!
|
||||
|
||||
We're introducing a new PR system. Your PR won't be blocked - we'll review it normally.
|
||||
|
||||
**Want to check your PR?** Run this in your fork:
|
||||
\`\`\`bash
|
||||
./scripts/pr-check.sh
|
||||
\`\`\`
|
||||
|
||||
[Learn more](https://github.com/tinkle-community/nofx/blob/dev/docs/community/MIGRATION_ANNOUNCEMENT.md) | This is optional!"
|
||||
|
||||
echo "✅ Commented on PR #$pr_number"
|
||||
sleep 2 # Be nice to GitHub API
|
||||
done
|
||||
```
|
||||
|
||||
Save as `comment-all-prs.sh` and run:
|
||||
```bash
|
||||
chmod +x comment-all-prs.sh
|
||||
./comment-all-prs.sh
|
||||
```
|
||||
247
docs/community/README.md
Normal file
247
docs/community/README.md
Normal file
@@ -0,0 +1,247 @@
|
||||
# 👥 NOFX Community
|
||||
|
||||
Welcome to the NOFX community! This section contains everything you need to contribute and participate.
|
||||
|
||||
---
|
||||
|
||||
## 📢 Important Announcement
|
||||
|
||||
**🚀 New PR Management System Coming Soon!**
|
||||
|
||||
We're introducing a new PR management system to improve code quality and make contributing easier!
|
||||
|
||||
**📖 Read:** [Migration Announcement](MIGRATION_ANNOUNCEMENT.md) | [迁移公告(中文)](MIGRATION_ANNOUNCEMENT.zh-CN.md)
|
||||
|
||||
**Timeline:** 4-week gradual rollout starting soon
|
||||
|
||||
**For existing PRs:** Don't worry! Your PRs will not be blocked by new rules.
|
||||
|
||||
---
|
||||
|
||||
## 🤝 How to Contribute
|
||||
|
||||
### Getting Started
|
||||
|
||||
1. **Read the Guides**
|
||||
- [Contributing Guide](../../CONTRIBUTING.md) - Complete contribution workflow
|
||||
- [Code of Conduct](../../CODE_OF_CONDUCT.md) - Community standards
|
||||
- [Security Policy](../../SECURITY.md) - Report vulnerabilities
|
||||
|
||||
2. **Find Something to Work On**
|
||||
- Browse [GitHub Issues](https://github.com/tinkle-community/nofx/issues)
|
||||
- Look for `good first issue` label
|
||||
- Check out [bounty tasks](#-bounty-program)
|
||||
|
||||
3. **Join the Community**
|
||||
- 💬 [Telegram Developer Community](https://t.me/nofx_dev_community)
|
||||
- 🐦 [Twitter @nofx_ai](https://x.com/nofx_ai)
|
||||
- 🐙 [GitHub Discussions](https://github.com/tinkle-community/nofx/discussions)
|
||||
|
||||
---
|
||||
|
||||
## 💰 Bounty Program
|
||||
|
||||
### Active Bounties
|
||||
|
||||
NOFX offers bounties for valuable contributions:
|
||||
|
||||
| Category | Reward Range | Examples |
|
||||
|----------|--------------|----------|
|
||||
| 🥇 Major Features | $500-1000 | Exchange integration, core architecture |
|
||||
| 🥈 Medium Features | $200-500 | WebSocket support, new AI models |
|
||||
| 🥉 Small Features | $50-200 | Bug fixes, UI improvements, documentation |
|
||||
|
||||
### How to Claim Bounties
|
||||
|
||||
**📖 Complete Guide:** [bounty-guide.md](bounty-guide.md)
|
||||
|
||||
**Quick Steps:**
|
||||
1. Find issue tagged `[BOUNTY]`
|
||||
2. Comment with your proposal
|
||||
3. Wait for approval
|
||||
4. Work on the task
|
||||
5. Submit PR with demo
|
||||
6. Get paid after merge!
|
||||
|
||||
### Current Bounty Tasks
|
||||
|
||||
| Task | Reward | Difficulty | Status |
|
||||
|------|--------|------------|--------|
|
||||
| [Hyperliquid Integration](bounty-hyperliquid.md) | TBD | Hard | 🟡 Open |
|
||||
| [Aster DEX Integration](bounty-aster.md) | TBD | Medium | ✅ Completed |
|
||||
|
||||
---
|
||||
|
||||
## 🏆 Recognition
|
||||
|
||||
### Ways to Get Recognized
|
||||
|
||||
**Contributor Levels:**
|
||||
- 🌟 **Active Contributor** - Submit quality PRs
|
||||
- ⭐ **Trusted Contributor** - 3+ merged PRs, given review rights
|
||||
- 💎 **Core Team** - Top contributors, invited by maintainers
|
||||
|
||||
**Benefits:**
|
||||
- Listed in README and release notes
|
||||
- Direct access to maintainer discussions
|
||||
- Priority support for your issues
|
||||
- Invitation to private roadmap planning
|
||||
|
||||
### Hall of Fame
|
||||
|
||||
**Top Contributors:**
|
||||
- Coming soon! Be the first! 🚀
|
||||
|
||||
---
|
||||
|
||||
## 📋 Contribution Types
|
||||
|
||||
### Code Contributions
|
||||
- New exchange integrations
|
||||
- AI model adapters
|
||||
- Bug fixes and improvements
|
||||
- Performance optimizations
|
||||
|
||||
**Required:**
|
||||
- ✅ Code compiles and runs
|
||||
- ✅ Follows code style guidelines
|
||||
- ✅ Includes basic tests (preferred)
|
||||
- ✅ Updates documentation if needed
|
||||
|
||||
### Documentation
|
||||
- Tutorial writing
|
||||
- Translation (中文, Русский, Українська)
|
||||
- FAQ updates
|
||||
- Video guides
|
||||
|
||||
**Rewards:**
|
||||
- $50-200 for comprehensive guides
|
||||
- Recognition in docs
|
||||
- Contributor badge
|
||||
|
||||
### Testing & QA
|
||||
- Bug reports with reproduction steps
|
||||
- Security vulnerability reports (see [Security Policy](../../SECURITY.md))
|
||||
- Testnet verification
|
||||
- Performance testing
|
||||
|
||||
**Rewards:**
|
||||
- $50-500 for critical bug finds
|
||||
- Up to $1000 for security vulnerabilities
|
||||
- Recognition in security hall of fame
|
||||
|
||||
---
|
||||
|
||||
## 🌍 Community Channels
|
||||
|
||||
### Primary Channels
|
||||
|
||||
| Platform | Purpose | Link |
|
||||
|----------|---------|------|
|
||||
| 💬 Telegram | Real-time chat, questions | [Join](https://t.me/nofx_dev_community) |
|
||||
| 🐙 GitHub | Issues, PRs, discussions | [Visit](https://github.com/tinkle-community/nofx) |
|
||||
| 🐦 Twitter | Announcements, updates | [@nofx_ai](https://x.com/nofx_ai) |
|
||||
|
||||
### Core Team
|
||||
|
||||
- **Tinkle** - [@Web3Tinkle](https://x.com/Web3Tinkle)
|
||||
- **Zack** - [@0x_ZackH](https://x.com/0x_ZackH)
|
||||
|
||||
**Contact:**
|
||||
- Technical questions → Telegram or GitHub Issues
|
||||
- Business inquiries → Twitter DM to core team
|
||||
- Security reports → [SECURITY.md](../../SECURITY.md)
|
||||
|
||||
---
|
||||
|
||||
## 📅 Community Events
|
||||
|
||||
### Regular Activities
|
||||
- **Weekly Updates** - Development progress (Telegram)
|
||||
- **Monthly AMA** - Ask maintainers anything
|
||||
- **Quarterly Roadmap** - Future plans discussion
|
||||
|
||||
### Upcoming Events
|
||||
- *No scheduled events yet*
|
||||
|
||||
**Want to organize an event?**
|
||||
- Contact core team on Telegram
|
||||
- Propose in GitHub Discussions
|
||||
- Tweet and tag @nofx_ai
|
||||
|
||||
---
|
||||
|
||||
## 🎓 Learning Resources
|
||||
|
||||
### For Contributors
|
||||
|
||||
**Understanding NOFX:**
|
||||
- [System Architecture](../architecture/README.md) *(coming soon)*
|
||||
- [API Reference](../architecture/api-reference.md) *(coming soon)*
|
||||
- [Database Schema](../architecture/database-schema.md) *(coming soon)*
|
||||
|
||||
**Learning Materials:**
|
||||
- Go programming: [Tour of Go](https://go.dev/tour/)
|
||||
- React/TypeScript: [React Docs](https://react.dev/)
|
||||
- Trading basics: [Binance Academy](https://academy.binance.com/)
|
||||
|
||||
### Recommended Reading
|
||||
|
||||
1. **Before Contributing:**
|
||||
- [Contributing Guide](../../CONTRIBUTING.md)
|
||||
- [Code of Conduct](../../CODE_OF_CONDUCT.md)
|
||||
|
||||
2. **For Exchange Integration:**
|
||||
- [Hyperliquid Bounty](bounty-hyperliquid.md)
|
||||
- [Aster Bounty](bounty-aster.md)
|
||||
- Existing code: `trader/binance_futures.go`
|
||||
|
||||
3. **For AI Features:**
|
||||
- [Custom API Guide](../getting-started/custom-api.md)
|
||||
- MCP client code: `mcp/client.go`
|
||||
- Decision engine: `decision/engine.go`
|
||||
|
||||
---
|
||||
|
||||
## 🛡️ Community Guidelines
|
||||
|
||||
### Our Values
|
||||
- **Respect** - Treat everyone with courtesy
|
||||
- **Transparency** - Open communication and decisions
|
||||
- **Quality** - High standards for contributions
|
||||
- **Collaboration** - Work together, help each other
|
||||
|
||||
### Not Acceptable
|
||||
- ❌ Harassment or discrimination
|
||||
- ❌ Spam or self-promotion
|
||||
- ❌ Sharing malicious code
|
||||
- ❌ Violating [Code of Conduct](../../CODE_OF_CONDUCT.md)
|
||||
|
||||
**Violations will result in:**
|
||||
1. Warning
|
||||
2. Temporary ban
|
||||
3. Permanent ban (serious cases)
|
||||
|
||||
---
|
||||
|
||||
## 📊 Community Stats
|
||||
|
||||
| Metric | Count |
|
||||
|--------|-------|
|
||||
| GitHub Stars | Check [repo](https://github.com/tinkle-community/nofx) |
|
||||
| Contributors | 21+ |
|
||||
| Open Issues | Check [issues](https://github.com/tinkle-community/nofx/issues) |
|
||||
| Merged PRs | Check [pulls](https://github.com/tinkle-community/nofx/pulls?q=is%3Apr+is%3Amerged) |
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Quick Links
|
||||
|
||||
- **Want to contribute code?** → [Contributing Guide](../../CONTRIBUTING.md)
|
||||
- **Want to claim bounty?** → [Bounty Guide](bounty-guide.md)
|
||||
- **Found a security issue?** → [Security Policy](../../SECURITY.md)
|
||||
- **Have questions?** → [Telegram Community](https://t.me/nofx_dev_community)
|
||||
|
||||
---
|
||||
|
||||
[← Back to Documentation Home](../README.md)
|
||||
127
docs/getting-started/README.md
Normal file
127
docs/getting-started/README.md
Normal file
@@ -0,0 +1,127 @@
|
||||
# 🚀 Getting Started with NOFX
|
||||
|
||||
**Language:** [English](README.md) | [中文](README.zh-CN.md)
|
||||
|
||||
This section contains all the documentation you need to get NOFX up and running.
|
||||
|
||||
## 📋 Deployment Options
|
||||
|
||||
Choose the method that best fits your needs:
|
||||
|
||||
### 🐳 Docker Deployment (Recommended)
|
||||
|
||||
**Best for:** Beginners, quick setup, production deployments
|
||||
|
||||
- **English:** [docker-deploy.en.md](docker-deploy.en.md)
|
||||
- **中文:** [docker-deploy.zh-CN.md](docker-deploy.zh-CN.md)
|
||||
|
||||
**Pros:**
|
||||
- ✅ One-command setup
|
||||
- ✅ All dependencies included
|
||||
- ✅ Easy to update and manage
|
||||
- ✅ Isolated environment
|
||||
|
||||
**Quick Start:**
|
||||
```bash
|
||||
cp config.example.jsonc config.json
|
||||
./start.sh start --build
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 🔧 PM2 Deployment
|
||||
|
||||
**Best for:** Advanced users, development, custom setups
|
||||
|
||||
- **English:** [pm2-deploy.en.md](pm2-deploy.en.md)
|
||||
- **中文:** [pm2-deploy.md](pm2-deploy.md)
|
||||
|
||||
**Pros:**
|
||||
- ✅ Direct process control
|
||||
- ✅ Better for development
|
||||
- ✅ Lower resource usage
|
||||
- ✅ More flexible
|
||||
|
||||
**Quick Start:**
|
||||
```bash
|
||||
go build -o nofx
|
||||
cd web && npm install && npm run build
|
||||
pm2 start ecosystem.config.js
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🤖 AI Configuration
|
||||
|
||||
### Custom AI Providers
|
||||
|
||||
- **English:** [custom-api.en.md](custom-api.en.md)
|
||||
- **中文:** [custom-api.md](custom-api.md)
|
||||
|
||||
Use custom AI models or third-party OpenAI-compatible APIs:
|
||||
- Custom DeepSeek endpoints
|
||||
- Self-hosted models
|
||||
- Other LLM providers
|
||||
|
||||
---
|
||||
|
||||
## 🔑 Prerequisites
|
||||
|
||||
Before starting, ensure you have:
|
||||
|
||||
### For Docker Method:
|
||||
- ✅ Docker 20.10+
|
||||
- ✅ Docker Compose V2
|
||||
|
||||
### For Manual Method:
|
||||
- ✅ Go 1.21+
|
||||
- ✅ Node.js 18+
|
||||
- ✅ TA-Lib library
|
||||
- ✅ PM2 (optional)
|
||||
|
||||
---
|
||||
|
||||
## 📚 Next Steps
|
||||
|
||||
After deployment:
|
||||
|
||||
1. **Configure AI Models** → Web interface at http://localhost:3000
|
||||
2. **Set Up Exchange** → Add Binance/Hyperliquid credentials
|
||||
3. **Create Traders** → Combine AI models with exchanges
|
||||
4. **Start Trading** → Monitor performance in dashboard
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ Important Notes
|
||||
|
||||
**Before Trading:**
|
||||
- ⚠️ Test on testnet first
|
||||
- ⚠️ Start with small amounts
|
||||
- ⚠️ Understand the risks
|
||||
- ⚠️ Read [Security Policy](../../SECURITY.md)
|
||||
|
||||
**API Keys:**
|
||||
- 🔑 Never commit API keys to git
|
||||
- 🔑 Use environment variables
|
||||
- 🔑 Restrict IP access
|
||||
- 🔑 Enable 2FA on exchanges
|
||||
|
||||
---
|
||||
|
||||
## 🆘 Troubleshooting
|
||||
|
||||
**Common Issues:**
|
||||
|
||||
1. **Docker build fails** → Check Docker version, update to 20.10+
|
||||
2. **TA-Lib not found** → `brew install ta-lib` (macOS) or `apt-get install libta-lib0-dev` (Ubuntu)
|
||||
3. **Port 8080 in use** → Change `API_PORT` in .env file
|
||||
4. **Frontend won't connect** → Check backend is running on port 8080
|
||||
|
||||
**Need more help?**
|
||||
- 📖 [FAQ](../guides/faq.zh-CN.md)
|
||||
- 💬 [Telegram Community](https://t.me/nofx_dev_community)
|
||||
- 🐛 [GitHub Issues](https://github.com/tinkle-community/nofx/issues)
|
||||
|
||||
---
|
||||
|
||||
[← Back to Documentation Home](../README.md)
|
||||
125
docs/getting-started/README.zh-CN.md
Normal file
125
docs/getting-started/README.zh-CN.md
Normal file
@@ -0,0 +1,125 @@
|
||||
# 🚀 NOFX 快速开始
|
||||
|
||||
本节包含让 NOFX 运行起来所需的所有文档。
|
||||
|
||||
## 📋 部署选项
|
||||
|
||||
选择最适合您的方式:
|
||||
|
||||
### 🐳 Docker 部署(推荐)
|
||||
|
||||
**适合:** 初学者、快速部署、生产环境
|
||||
|
||||
- **中文文档:** [docker-deploy.zh-CN.md](docker-deploy.zh-CN.md)
|
||||
- **English:** [docker-deploy.en.md](docker-deploy.en.md)
|
||||
|
||||
**优势:**
|
||||
- ✅ 一键启动
|
||||
- ✅ 包含所有依赖
|
||||
- ✅ 易于更新和管理
|
||||
- ✅ 隔离环境
|
||||
|
||||
**快速开始:**
|
||||
```bash
|
||||
cp config.example.jsonc config.json
|
||||
./start.sh start --build
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 🔧 PM2 部署
|
||||
|
||||
**适合:** 进阶用户、开发环境、自定义设置
|
||||
|
||||
- **中文文档:** [pm2-deploy.md](pm2-deploy.md)
|
||||
- **English:** [pm2-deploy.en.md](pm2-deploy.en.md)
|
||||
|
||||
**优势:**
|
||||
- ✅ 直接进程控制
|
||||
- ✅ 更适合开发
|
||||
- ✅ 资源占用更低
|
||||
- ✅ 更灵活
|
||||
|
||||
**快速开始:**
|
||||
```bash
|
||||
go build -o nofx
|
||||
cd web && npm install && npm run build
|
||||
pm2 start ecosystem.config.js
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🤖 AI 配置
|
||||
|
||||
### 自定义 AI 提供商
|
||||
|
||||
- **中文文档:** [custom-api.md](custom-api.md)
|
||||
- **English:** [custom-api.en.md](custom-api.en.md)
|
||||
|
||||
使用自定义 AI 模型或第三方 OpenAI 兼容 API:
|
||||
- 自定义 DeepSeek 端点
|
||||
- 本地部署的模型
|
||||
- 其他 LLM 提供商
|
||||
|
||||
---
|
||||
|
||||
## 🔑 环境要求
|
||||
|
||||
开始之前,请确保已安装:
|
||||
|
||||
### Docker 方式:
|
||||
- ✅ Docker 20.10+
|
||||
- ✅ Docker Compose V2
|
||||
|
||||
### 手动部署方式:
|
||||
- ✅ Go 1.21+
|
||||
- ✅ Node.js 18+
|
||||
- ✅ TA-Lib 库
|
||||
- ✅ PM2(可选)
|
||||
|
||||
---
|
||||
|
||||
## 📚 下一步
|
||||
|
||||
部署完成后:
|
||||
|
||||
1. **配置 AI 模型** → 访问 Web 界面 http://localhost:3000
|
||||
2. **设置交易所** → 添加 Binance/Hyperliquid 凭证
|
||||
3. **创建交易员** → 将 AI 模型与交易所结合
|
||||
4. **开始交易** → 在仪表板中监控表现
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ 重要提示
|
||||
|
||||
**交易前:**
|
||||
- ⚠️ 先在测试网测试
|
||||
- ⚠️ 从小金额开始
|
||||
- ⚠️ 了解风险
|
||||
- ⚠️ 阅读[安全策略](../../SECURITY.md)
|
||||
|
||||
**API 密钥:**
|
||||
- 🔑 永远不要提交 API 密钥到 git
|
||||
- 🔑 使用环境变量
|
||||
- 🔑 限制 IP 访问
|
||||
- 🔑 在交易所启用 2FA
|
||||
|
||||
---
|
||||
|
||||
## 🆘 故障排除
|
||||
|
||||
**常见问题:**
|
||||
|
||||
1. **Docker 构建失败** → 检查 Docker 版本,更新到 20.10+
|
||||
2. **找不到 TA-Lib** → `brew install ta-lib` (macOS) 或 `apt-get install libta-lib0-dev` (Ubuntu)
|
||||
3. **端口 8080 被占用** → 在 .env 文件中更改 `API_PORT`
|
||||
4. **前端无法连接** → 检查后端是否在端口 8080 上运行
|
||||
|
||||
**需要更多帮助?**
|
||||
- 📖 [常见问题](../guides/faq.zh-CN.md)
|
||||
- 💬 [Telegram 社区](https://t.me/nofx_dev_community)
|
||||
- 🐛 [GitHub Issues](https://github.com/tinkle-community/nofx/issues)
|
||||
|
||||
---
|
||||
|
||||
[← 返回文档首页](../README.md)
|
||||
207
docs/getting-started/custom-api.en.md
Normal file
207
docs/getting-started/custom-api.en.md
Normal file
@@ -0,0 +1,207 @@
|
||||
# Custom AI API Usage Guide
|
||||
|
||||
## Features
|
||||
|
||||
NOFX now supports using any OpenAI-compatible API format, including:
|
||||
- OpenAI official API (gpt-4o, gpt-4-turbo, etc.)
|
||||
- OpenRouter (access to multiple models)
|
||||
- Locally deployed models (Ollama, LM Studio, etc.)
|
||||
- Other OpenAI-compatible API services
|
||||
|
||||
## Configuration Method
|
||||
|
||||
~~Add trader using custom API in `config.json` (deprecated):~~
|
||||
|
||||
*Note: Custom APIs and traders are now configured through the Web interface. config.json only retains basic settings.*
|
||||
|
||||
```json
|
||||
{
|
||||
"traders": [
|
||||
{
|
||||
"id": "trader_custom",
|
||||
"name": "My Custom AI Trader",
|
||||
"ai_model": "custom",
|
||||
"exchange": "binance",
|
||||
|
||||
"binance_api_key": "your_binance_api_key",
|
||||
"binance_secret_key": "your_binance_secret_key",
|
||||
|
||||
"custom_api_url": "https://api.openai.com/v1",
|
||||
"custom_api_key": "sk-your-openai-api-key",
|
||||
"custom_model_name": "gpt-4o",
|
||||
|
||||
"initial_balance": 1000,
|
||||
"scan_interval_minutes": 3
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Configuration Fields
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
|-------|------|----------|-------------|
|
||||
| `ai_model` | string | ✅ | Set to `"custom"` to enable custom API |
|
||||
| `custom_api_url` | string | ✅ | API Base URL (without `/chat/completions`). Special usage: If ending with `#`, use full URL (no auto path append) |
|
||||
| `custom_api_key` | string | ✅ | API key |
|
||||
| `custom_model_name` | string | ✅ | Model name (e.g. `gpt-4o`, `claude-3-5-sonnet`, etc.) |
|
||||
|
||||
## Usage Examples
|
||||
|
||||
### 1. OpenAI Official API
|
||||
|
||||
```json
|
||||
{
|
||||
"ai_model": "custom",
|
||||
"custom_api_url": "https://api.openai.com/v1",
|
||||
"custom_api_key": "sk-proj-xxxxx",
|
||||
"custom_model_name": "gpt-4o"
|
||||
}
|
||||
```
|
||||
|
||||
### 2. OpenRouter
|
||||
|
||||
```json
|
||||
{
|
||||
"ai_model": "custom",
|
||||
"custom_api_url": "https://openrouter.ai/api/v1",
|
||||
"custom_api_key": "sk-or-xxxxx",
|
||||
"custom_model_name": "anthropic/claude-3.5-sonnet"
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Local Ollama
|
||||
|
||||
```json
|
||||
{
|
||||
"ai_model": "custom",
|
||||
"custom_api_url": "http://localhost:11434/v1",
|
||||
"custom_api_key": "ollama",
|
||||
"custom_model_name": "llama3.1:70b"
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Azure OpenAI
|
||||
|
||||
```json
|
||||
{
|
||||
"ai_model": "custom",
|
||||
"custom_api_url": "https://your-resource.openai.azure.com/openai/deployments/your-deployment",
|
||||
"custom_api_key": "your-azure-api-key",
|
||||
"custom_model_name": "gpt-4"
|
||||
}
|
||||
```
|
||||
|
||||
### 5. Using Full Custom Path (append #)
|
||||
|
||||
For certain special API endpoints that already include the full path (including `/chat/completions` or other custom paths), you can append `#` at the end of the URL to force using the full URL:
|
||||
|
||||
```json
|
||||
{
|
||||
"ai_model": "custom",
|
||||
"custom_api_url": "https://api.example.com/v2/ai/chat/completions#",
|
||||
"custom_api_key": "your-api-key",
|
||||
"custom_model_name": "custom-model"
|
||||
}
|
||||
```
|
||||
|
||||
**Note**: The `#` will be automatically removed, and the actual request will be sent to `https://api.example.com/v2/ai/chat/completions`
|
||||
|
||||
## Compatibility Requirements
|
||||
|
||||
Custom APIs must:
|
||||
1. Support OpenAI Chat Completions format
|
||||
2. Accept `POST` requests to `/chat/completions` endpoint (or append `#` at URL end for custom path)
|
||||
3. Support `Authorization: Bearer {api_key}` authentication
|
||||
4. Return standard OpenAI response format
|
||||
|
||||
## Important Notes
|
||||
|
||||
1. **URL Format**: `custom_api_url` should be the Base URL, system will auto-append `/chat/completions`
|
||||
- ✅ Correct: `https://api.openai.com/v1`
|
||||
- ❌ Wrong: `https://api.openai.com/v1/chat/completions`
|
||||
- 🔧 **Special usage**: If you need to use a full custom path (without auto-appending `/chat/completions`), append `#` at the URL end
|
||||
- Example: `https://api.example.com/custom/path/chat/completions#`
|
||||
- System will automatically remove `#` and use the full URL directly
|
||||
|
||||
2. **Model Name**: Ensure `custom_model_name` exactly matches the model name supported by your API provider
|
||||
|
||||
3. **API Key**: Some locally deployed models may not require a real API key, you can fill in any string
|
||||
|
||||
4. **Timeout Settings**: Default timeout is 120 seconds, may need adjustment if model response is slow
|
||||
|
||||
## Multi-AI Comparison Trading
|
||||
|
||||
You can configure multiple traders with different AIs for comparison:
|
||||
|
||||
```json
|
||||
{
|
||||
"traders": [
|
||||
{
|
||||
"id": "deepseek_trader",
|
||||
"ai_model": "deepseek",
|
||||
"deepseek_key": "sk-xxxxx",
|
||||
...
|
||||
},
|
||||
{
|
||||
"id": "gpt4_trader",
|
||||
"ai_model": "custom",
|
||||
"custom_api_url": "https://api.openai.com/v1",
|
||||
"custom_api_key": "sk-xxxxx",
|
||||
"custom_model_name": "gpt-4o",
|
||||
...
|
||||
},
|
||||
{
|
||||
"id": "claude_trader",
|
||||
"ai_model": "custom",
|
||||
"custom_api_url": "https://openrouter.ai/api/v1",
|
||||
"custom_api_key": "sk-or-xxxxx",
|
||||
"custom_model_name": "anthropic/claude-3.5-sonnet",
|
||||
...
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Issue: Configuration Validation Failed
|
||||
|
||||
**Error Message**: `使用自定义API时必须配置custom_api_url` (custom_api_url must be configured when using custom API)
|
||||
|
||||
**Solution**: After setting `ai_model: "custom"`, ensure you also configure:
|
||||
- `custom_api_url`
|
||||
- `custom_api_key`
|
||||
- `custom_model_name`
|
||||
|
||||
### Issue: API Call Failed
|
||||
|
||||
**Possible Causes**:
|
||||
1. URL format error
|
||||
- Normal usage: Should not include `/chat/completions` (system will auto-append)
|
||||
- Special usage: If full path is needed, remember to append `#` at URL end
|
||||
2. Invalid API key
|
||||
3. Incorrect model name
|
||||
4. Network connection issues
|
||||
|
||||
**Debug Method**: Check error messages in logs, usually includes HTTP status code and error details
|
||||
|
||||
## Backward Compatibility
|
||||
|
||||
Existing `deepseek` and `qwen` configurations are unaffected and can continue to be used:
|
||||
|
||||
```json
|
||||
{
|
||||
"ai_model": "deepseek",
|
||||
"deepseek_key": "sk-xxxxx"
|
||||
}
|
||||
```
|
||||
|
||||
Or
|
||||
|
||||
```json
|
||||
{
|
||||
"ai_model": "qwen",
|
||||
"qwen_key": "sk-xxxxx"
|
||||
}
|
||||
```
|
||||
303
docs/getting-started/pm2-deploy.en.md
Normal file
303
docs/getting-started/pm2-deploy.en.md
Normal file
@@ -0,0 +1,303 @@
|
||||
# NoFX Trading Bot - PM2 Deployment Guide
|
||||
|
||||
Complete guide for local development and production deployment using PM2.
|
||||
|
||||
## 🚀 Quick Start
|
||||
|
||||
### 1. Install PM2
|
||||
|
||||
```bash
|
||||
npm install -g pm2
|
||||
```
|
||||
|
||||
### 2. One-Command Launch
|
||||
|
||||
```bash
|
||||
./pm2.sh start
|
||||
```
|
||||
|
||||
That's it! Frontend and backend will start automatically.
|
||||
|
||||
---
|
||||
|
||||
## 📋 All Commands
|
||||
|
||||
### Service Management
|
||||
|
||||
```bash
|
||||
# Start services
|
||||
./pm2.sh start
|
||||
|
||||
# Stop services
|
||||
./pm2.sh stop
|
||||
|
||||
# Restart services
|
||||
./pm2.sh restart
|
||||
|
||||
# View status
|
||||
./pm2.sh status
|
||||
|
||||
# Delete services
|
||||
./pm2.sh delete
|
||||
```
|
||||
|
||||
### Log Viewing
|
||||
|
||||
```bash
|
||||
# View all logs (live)
|
||||
./pm2.sh logs
|
||||
|
||||
# Backend logs only
|
||||
./pm2.sh logs backend
|
||||
|
||||
# Frontend logs only
|
||||
./pm2.sh logs frontend
|
||||
```
|
||||
|
||||
### Build & Compile
|
||||
|
||||
```bash
|
||||
# Compile backend
|
||||
./pm2.sh build
|
||||
|
||||
# Recompile backend and restart
|
||||
./pm2.sh rebuild
|
||||
```
|
||||
|
||||
### Monitoring
|
||||
|
||||
```bash
|
||||
# Open PM2 monitoring dashboard (real-time CPU/Memory)
|
||||
./pm2.sh monitor
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 Access URLs
|
||||
|
||||
After successful startup:
|
||||
|
||||
- **Frontend Web Interface**: http://localhost:3000
|
||||
- **Backend API**: http://localhost:8080
|
||||
- **Health Check**: http://localhost:8080/api/health
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Configuration Files
|
||||
|
||||
### pm2.config.js
|
||||
|
||||
PM2 configuration file, defines frontend and backend startup parameters:
|
||||
|
||||
```javascript
|
||||
const path = require('path');
|
||||
|
||||
module.exports = {
|
||||
apps: [
|
||||
{
|
||||
name: 'nofx-backend',
|
||||
script: './nofx', // Go binary
|
||||
cwd: __dirname, // Dynamically get current directory
|
||||
autorestart: true,
|
||||
max_memory_restart: '500M'
|
||||
},
|
||||
{
|
||||
name: 'nofx-frontend',
|
||||
script: 'npm',
|
||||
args: 'run dev', // Vite dev server
|
||||
cwd: path.join(__dirname, 'web'), // Dynamically join path
|
||||
autorestart: true,
|
||||
max_memory_restart: '300M'
|
||||
}
|
||||
]
|
||||
};
|
||||
```
|
||||
|
||||
**After modifying configuration, restart is required:**
|
||||
```bash
|
||||
./pm2.sh restart
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📝 Log File Locations
|
||||
|
||||
- **Backend Logs**: `./logs/backend-error.log` and `./logs/backend-out.log`
|
||||
- **Frontend Logs**: `./web/logs/frontend-error.log` and `./web/logs/frontend-out.log`
|
||||
|
||||
---
|
||||
|
||||
## 🔄 Startup on Boot
|
||||
|
||||
Set PM2 to start on boot:
|
||||
|
||||
```bash
|
||||
# 1. Start services
|
||||
./pm2.sh start
|
||||
|
||||
# 2. Save current process list
|
||||
pm2 save
|
||||
|
||||
# 3. Generate startup script
|
||||
pm2 startup
|
||||
|
||||
# 4. Follow the instructions to execute command (requires sudo)
|
||||
```
|
||||
|
||||
**Disable startup on boot:**
|
||||
```bash
|
||||
pm2 unstartup
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🛠️ Common Operations
|
||||
|
||||
### Restart After Code Changes
|
||||
|
||||
**Backend changes:**
|
||||
```bash
|
||||
./pm2.sh rebuild # Auto compile and restart
|
||||
```
|
||||
|
||||
**Frontend changes:**
|
||||
```bash
|
||||
./pm2.sh restart # Vite will auto hot-reload, no restart needed
|
||||
```
|
||||
|
||||
### View Real-time Resource Usage
|
||||
|
||||
```bash
|
||||
./pm2.sh monitor
|
||||
```
|
||||
|
||||
### View Detailed Information
|
||||
|
||||
```bash
|
||||
pm2 info nofx-backend # Backend details
|
||||
pm2 info nofx-frontend # Frontend details
|
||||
```
|
||||
|
||||
### Clear Logs
|
||||
|
||||
```bash
|
||||
pm2 flush
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🐛 Troubleshooting
|
||||
|
||||
### Service Startup Failed
|
||||
|
||||
```bash
|
||||
# 1. View detailed errors
|
||||
./pm2.sh logs
|
||||
|
||||
# 2. Check port usage
|
||||
lsof -i :8080 # Backend port
|
||||
lsof -i :3000 # Frontend port
|
||||
|
||||
# 3. Manual compile test
|
||||
go build -o nofx
|
||||
./nofx
|
||||
```
|
||||
|
||||
### Backend Won't Start
|
||||
|
||||
```bash
|
||||
# ~~Check if config.json exists~~
|
||||
# ~~ls -l config.json~~
|
||||
|
||||
# Check if database file exists
|
||||
ls -l trading.db
|
||||
|
||||
# Check permissions
|
||||
chmod +x nofx
|
||||
|
||||
# Run manually to see errors
|
||||
./nofx
|
||||
```
|
||||
|
||||
### Frontend Not Accessible
|
||||
|
||||
```bash
|
||||
# Check node_modules
|
||||
cd web && npm install
|
||||
|
||||
# Manual start test
|
||||
npm run dev
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Production Environment Recommendations
|
||||
|
||||
### 1. Use Production Mode
|
||||
|
||||
Modify `pm2.config.js`:
|
||||
|
||||
```javascript
|
||||
{
|
||||
name: 'nofx-frontend',
|
||||
script: 'npm',
|
||||
args: 'run preview', // Change to preview (requires npm run build first)
|
||||
env: {
|
||||
NODE_ENV: 'production'
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Increase Instances (Load Balancing)
|
||||
|
||||
```javascript
|
||||
{
|
||||
name: 'nofx-backend',
|
||||
script: './nofx',
|
||||
instances: 2, // Start 2 instances
|
||||
exec_mode: 'cluster'
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Auto Restart Strategy
|
||||
|
||||
```javascript
|
||||
{
|
||||
autorestart: true,
|
||||
max_restarts: 10,
|
||||
min_uptime: '10s',
|
||||
max_memory_restart: '500M'
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📦 Comparison with Docker Deployment
|
||||
|
||||
| Feature | PM2 Deployment | Docker Deployment |
|
||||
|---------|---------------|-------------------|
|
||||
| Startup Speed | ⚡ Fast | 🐌 Slower |
|
||||
| Resource Usage | 💚 Low | 🟡 Medium |
|
||||
| Isolation | 🟡 Medium | 💚 High |
|
||||
| Use Case | Dev/Single-machine | Production/Cluster |
|
||||
| Configuration Complexity | 💚 Simple | 🟡 Medium |
|
||||
|
||||
**Recommendations:**
|
||||
- **Development Environment**: Use `./pm2.sh`
|
||||
- **Production Environment**: Use `./start.sh` (Docker)
|
||||
|
||||
---
|
||||
|
||||
## 🆘 Getting Help
|
||||
|
||||
```bash
|
||||
./pm2.sh help
|
||||
```
|
||||
|
||||
Or check PM2 official documentation: https://pm2.keymetrics.io/
|
||||
|
||||
---
|
||||
|
||||
## 📄 License
|
||||
|
||||
MIT
|
||||
138
docs/guides/README.md
Normal file
138
docs/guides/README.md
Normal file
@@ -0,0 +1,138 @@
|
||||
# 📘 NOFX User Guides
|
||||
|
||||
**Language:** [English](README.md) | [中文](README.zh-CN.md)
|
||||
|
||||
Comprehensive guides to help you use NOFX effectively.
|
||||
|
||||
---
|
||||
|
||||
## 📚 Available Guides
|
||||
|
||||
### 🔧 Basic Usage
|
||||
|
||||
| Guide | Description | Status |
|
||||
|-------|-------------|--------|
|
||||
| [FAQ (English)](faq.en.md) | Frequently asked questions | ✅ Available |
|
||||
| [FAQ (中文)](faq.zh-CN.md) | 常见问题解答 | ✅ Available |
|
||||
| Configuration Guide | Advanced settings and options | 🚧 Coming Soon |
|
||||
| Trading Strategies | AI trading strategy examples | 🚧 Coming Soon |
|
||||
|
||||
---
|
||||
|
||||
## 🐛 Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
**Issue: TA-Lib not found**
|
||||
```bash
|
||||
# macOS
|
||||
brew install ta-lib
|
||||
|
||||
# Ubuntu/Debian
|
||||
sudo apt-get install libta-lib0-dev
|
||||
```
|
||||
|
||||
**Issue: Precision error**
|
||||
- System auto-handles LOT_SIZE from exchange
|
||||
- Check network connection
|
||||
- Verify exchange API is accessible
|
||||
|
||||
**Issue: AI API timeout**
|
||||
- Check API key validity
|
||||
- Verify network connection
|
||||
- Check API balance/credits
|
||||
- Timeout is set to 120 seconds
|
||||
|
||||
**Issue: Frontend can't connect**
|
||||
- Ensure backend is running (http://localhost:8080)
|
||||
- Check if port 8080 is available
|
||||
- Check browser console for errors
|
||||
|
||||
---
|
||||
|
||||
## 📖 Usage Tips
|
||||
|
||||
### Best Practices
|
||||
|
||||
**1. Risk Management**
|
||||
- Start with small amounts (100-500 USDT)
|
||||
- Use subaccounts for additional safety
|
||||
- Set reasonable leverage limits
|
||||
- Monitor daily loss limits
|
||||
|
||||
**2. Performance Monitoring**
|
||||
- Check decision logs regularly
|
||||
- Analyze win rate and profit factor
|
||||
- Review AI reasoning (Chain of Thought)
|
||||
- Track equity curve trends
|
||||
|
||||
**3. Configuration**
|
||||
- Test on testnet first
|
||||
- Gradually increase trading amounts
|
||||
- Adjust scan intervals (3-5 minutes recommended)
|
||||
- Use default coin list for beginners
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Advanced Topics
|
||||
|
||||
### Multi-Trader Competition
|
||||
Run multiple AI models simultaneously:
|
||||
- Qwen vs DeepSeek head-to-head
|
||||
- Compare performance in real-time
|
||||
- Identify best-performing strategies
|
||||
|
||||
### Custom Coin Pools
|
||||
- Use external API for coin selection
|
||||
- Combine AI500 + OI Top data
|
||||
- Filter by liquidity and volume
|
||||
|
||||
### Exchange Integration
|
||||
- Binance Futures (CEX)
|
||||
- Hyperliquid (DEX)
|
||||
- Aster DEX (Binance-compatible)
|
||||
|
||||
---
|
||||
|
||||
## 📊 Understanding Metrics
|
||||
|
||||
### Key Performance Indicators
|
||||
|
||||
**Win Rate**
|
||||
- Percentage of profitable trades
|
||||
- Target: >50% for consistent profit
|
||||
|
||||
**Profit Factor**
|
||||
- Ratio of gross profit to gross loss
|
||||
- Target: >1.5 (1.5:1 or better)
|
||||
|
||||
**Sharpe Ratio**
|
||||
- Risk-adjusted return measure
|
||||
- Higher is better (>1.0 is good)
|
||||
|
||||
**Maximum Drawdown**
|
||||
- Largest peak-to-trough decline
|
||||
- Keep under 20% for safety
|
||||
|
||||
---
|
||||
|
||||
## 🔗 Related Documentation
|
||||
|
||||
- [Getting Started (EN)](../getting-started/README.md) - Initial setup
|
||||
- [Getting Started (中文)](../getting-started/README.zh-CN.md) - 初始设置
|
||||
- [Community](../community/README.md) - Contributing and bounties
|
||||
- [FAQ (English)](faq.en.md) - Common questions
|
||||
- [FAQ (中文)](faq.zh-CN.md) - 常见问题
|
||||
|
||||
---
|
||||
|
||||
## 🆘 Need Help?
|
||||
|
||||
**Can't find what you need?**
|
||||
- 💬 [Telegram Community](https://t.me/nofx_dev_community)
|
||||
- 🐛 [GitHub Issues](https://github.com/tinkle-community/nofx/issues)
|
||||
- 🐦 [Twitter @nofx_ai](https://x.com/nofx_ai)
|
||||
|
||||
---
|
||||
|
||||
[← Back to Documentation Home](../README.md)
|
||||
137
docs/guides/README.zh-CN.md
Normal file
137
docs/guides/README.zh-CN.md
Normal file
@@ -0,0 +1,137 @@
|
||||
# 📘 NOFX 使用指南
|
||||
|
||||
**语言:** [English](README.md) | [中文](README.zh-CN.md)
|
||||
|
||||
帮助您有效使用 NOFX 的综合指南。
|
||||
|
||||
---
|
||||
|
||||
## 📚 可用指南
|
||||
|
||||
### 🔧 基础使用
|
||||
|
||||
| 指南 | 描述 | 状态 |
|
||||
|------|------|------|
|
||||
| [FAQ (中文)](faq.zh-CN.md) | 常见问题解答 | ✅ 可用 |
|
||||
| [FAQ (English)](faq.en.md) | Frequently asked questions | ✅ 可用 |
|
||||
| 配置指南 | 高级设置和选项 | 🚧 即将推出 |
|
||||
| 交易策略 | AI 交易策略示例 | 🚧 即将推出 |
|
||||
|
||||
---
|
||||
|
||||
## 🐛 故障排除
|
||||
|
||||
### 常见问题
|
||||
|
||||
**问题:找不到 TA-Lib**
|
||||
```bash
|
||||
# macOS
|
||||
brew install ta-lib
|
||||
|
||||
# Ubuntu/Debian
|
||||
sudo apt-get install libta-lib0-dev
|
||||
```
|
||||
|
||||
**问题:精度错误**
|
||||
- 系统自动处理交易所的 LOT_SIZE
|
||||
- 检查网络连接
|
||||
- 验证交易所 API 可访问
|
||||
|
||||
**问题:AI API 超时**
|
||||
- 检查 API 密钥有效性
|
||||
- 验证网络连接
|
||||
- 检查 API 余额/额度
|
||||
- 超时设置为 120 秒
|
||||
|
||||
**问题:前端无法连接**
|
||||
- 确保后端正在运行 (http://localhost:8080)
|
||||
- 检查端口 8080 是否可用
|
||||
- 检查浏览器控制台错误
|
||||
|
||||
---
|
||||
|
||||
## 📖 使用技巧
|
||||
|
||||
### 最佳实践
|
||||
|
||||
**1. 风险管理**
|
||||
- 从小金额开始(100-500 USDT)
|
||||
- 使用子账户增加安全性
|
||||
- 设置合理的杠杆限制
|
||||
- 监控每日亏损限制
|
||||
|
||||
**2. 性能监控**
|
||||
- 定期检查决策日志
|
||||
- 分析胜率和盈利因子
|
||||
- 审查 AI 推理(思维链)
|
||||
- 跟踪权益曲线趋势
|
||||
|
||||
**3. 配置**
|
||||
- 先在测试网测试
|
||||
- 逐步增加交易金额
|
||||
- 调整扫描间隔(推荐 3-5 分钟)
|
||||
- 初学者使用默认币种列表
|
||||
|
||||
---
|
||||
|
||||
## 🎯 进阶主题
|
||||
|
||||
### 多交易员竞赛
|
||||
同时运行多个 AI 模型:
|
||||
- Qwen vs DeepSeek 对决
|
||||
- 实时比较性能
|
||||
- 识别表现最佳的策略
|
||||
|
||||
### 自定义币种池
|
||||
- 使用外部 API 进行币种选择
|
||||
- 结合 AI500 + OI Top 数据
|
||||
- 按流动性和交易量过滤
|
||||
|
||||
### 交易所集成
|
||||
- Binance Futures(中心化交易所)
|
||||
- Hyperliquid(去中心化交易所)
|
||||
- Aster DEX(兼容 Binance)
|
||||
|
||||
---
|
||||
|
||||
## 📊 理解指标
|
||||
|
||||
### 关键性能指标
|
||||
|
||||
**胜率(Win Rate)**
|
||||
- 盈利交易的百分比
|
||||
- 目标:>50% 以获得稳定盈利
|
||||
|
||||
**盈利因子(Profit Factor)**
|
||||
- 总盈利与总亏损的比率
|
||||
- 目标:>1.5(1.5:1 或更好)
|
||||
|
||||
**夏普比率(Sharpe Ratio)**
|
||||
- 风险调整后的收益衡量
|
||||
- 越高越好(>1.0 为良好)
|
||||
|
||||
**最大回撤(Maximum Drawdown)**
|
||||
- 从峰值到谷值的最大跌幅
|
||||
- 为安全起见保持在 20% 以下
|
||||
|
||||
---
|
||||
|
||||
## 🔗 相关文档
|
||||
|
||||
- [快速开始](../getting-started/README.zh-CN.md) - 初始设置
|
||||
- [社区](../community/README.md) - 贡献和悬赏
|
||||
- [FAQ 中文](faq.zh-CN.md) - 常见问题
|
||||
- [FAQ English](faq.en.md) - Common questions
|
||||
|
||||
---
|
||||
|
||||
## 🆘 需要帮助?
|
||||
|
||||
**找不到您需要的内容?**
|
||||
- 💬 [Telegram 社区](https://t.me/nofx_dev_community)
|
||||
- 🐛 [GitHub Issues](https://github.com/tinkle-community/nofx/issues)
|
||||
- 🐦 [Twitter @nofx_ai](https://x.com/nofx_ai)
|
||||
|
||||
---
|
||||
|
||||
[← 返回文档首页](../README.md)
|
||||
25
docs/guides/faq.en.md
Normal file
25
docs/guides/faq.en.md
Normal file
@@ -0,0 +1,25 @@
|
||||
# Frequently Asked Questions
|
||||
|
||||
## Binance Position Mode Error (code=-4061)
|
||||
|
||||
**Error Message**: `Order's position side does not match user's setting`
|
||||
|
||||
**Cause**: The system requires Hedge Mode (dual position), but your Binance account is set to One-way Mode.
|
||||
|
||||
### Solution
|
||||
|
||||
1. Login to [Binance Futures Trading Platform](https://www.binance.com/en/futures/BTCUSDT)
|
||||
|
||||
2. Click **⚙️ Preferences** in the top right corner
|
||||
|
||||
3. Select **Position Mode**
|
||||
|
||||
4. Switch to **Hedge Mode** (Dual Position)
|
||||
|
||||
5. Confirm the change
|
||||
|
||||
**Note**: You must close all open positions before switching modes.
|
||||
|
||||
---
|
||||
|
||||
For more issues, check [GitHub Issues](https://github.com/tinkle-community/nofx/issues)
|
||||
231
docs/i18n/README.md
Normal file
231
docs/i18n/README.md
Normal file
@@ -0,0 +1,231 @@
|
||||
# 🌍 International Documentation / 国际化文档
|
||||
|
||||
NOFX documentation is available in multiple languages.
|
||||
|
||||
NOFX 文档提供多种语言版本。
|
||||
|
||||
---
|
||||
|
||||
## 📚 Available Languages / 可用语言
|
||||
|
||||
| Language | Main README | Status | Maintainers |
|
||||
|----------|-------------|--------|-------------|
|
||||
| 🇬🇧 **English** | [README.md](../../README.md) | ✅ Complete | Core Team |
|
||||
| 🇨🇳 **Chinese (中文)** | [README.md](zh-CN/README.md) | ✅ Complete | Community |
|
||||
| 🇷🇺 **Russian (Русский)** | [README.md](ru/README.md) | ✅ Complete | Community |
|
||||
| 🇺🇦 **Ukrainian (Українська)** | [README.md](uk/README.md) | ✅ Complete | Community |
|
||||
|
||||
---
|
||||
|
||||
## 🔗 Quick Access / 快速访问
|
||||
|
||||
### English 🇬🇧
|
||||
- **Main README:** [../../README.md](../../README.md)
|
||||
- **Contributing:** [../../CONTRIBUTING.md](../../CONTRIBUTING.md)
|
||||
- **Security:** [../../SECURITY.md](../../SECURITY.md)
|
||||
|
||||
### 中文 🇨🇳
|
||||
- **主 README:** [zh-CN/README.md](zh-CN/README.md)
|
||||
- **贡献指南:** [../../CONTRIBUTING.md](../../CONTRIBUTING.md#中文)
|
||||
- **安全政策:** [../../SECURITY.md](../../SECURITY.md#中文)
|
||||
- **常见问题:** [../guides/faq.zh-CN.md](../guides/faq.zh-CN.md)
|
||||
|
||||
### Русский 🇷🇺
|
||||
- **Основной README:** [ru/README.md](ru/README.md)
|
||||
- **Руководство по участию:** [../../CONTRIBUTING.md](../../CONTRIBUTING.md)
|
||||
- **Политика безопасности:** [../../SECURITY.md](../../SECURITY.md)
|
||||
|
||||
### Українська 🇺🇦
|
||||
- **Головний README:** [uk/README.md](uk/README.md)
|
||||
- **Посібник із внесків:** [../../CONTRIBUTING.md](../../CONTRIBUTING.md)
|
||||
- **Політика безпеки:** [../../SECURITY.md](../../SECURITY.md)
|
||||
|
||||
---
|
||||
|
||||
## 🤝 Help with Translations / 帮助翻译
|
||||
|
||||
### Want to Contribute Translations? / 想要贡献翻译?
|
||||
|
||||
We welcome translation contributions! / 我们欢迎翻译贡献!
|
||||
|
||||
**What needs translation? / 需要翻译什么?**
|
||||
- ✅ Main README (complete for 4 languages)
|
||||
- 🚧 Deployment guides (partial)
|
||||
- 📋 User guides (needed)
|
||||
- 📋 Contributing guide (needed for RU/UK)
|
||||
|
||||
**How to contribute translations? / 如何贡献翻译?**
|
||||
|
||||
1. **Check existing translations / 检查现有翻译**
|
||||
- Browse this directory
|
||||
- See what's missing
|
||||
|
||||
2. **Claim a translation task / 认领翻译任务**
|
||||
- Open a GitHub Issue
|
||||
- Title: `[TRANSLATION] Document name to Language`
|
||||
- Example: `[TRANSLATION] CONTRIBUTING.md to Chinese`
|
||||
|
||||
3. **Submit translation / 提交翻译**
|
||||
- Follow [Contributing Guide](../../CONTRIBUTING.md)
|
||||
- Place file in appropriate language folder
|
||||
- Keep formatting and structure consistent
|
||||
|
||||
4. **Get recognized / 获得认可**
|
||||
- Listed as translator in credits
|
||||
- Eligible for contributor badges
|
||||
- Possible bounty rewards ($50-200)
|
||||
|
||||
---
|
||||
|
||||
## 📝 Translation Guidelines / 翻译指南
|
||||
|
||||
### File Naming Convention / 文件命名规范
|
||||
|
||||
**Pattern:** `document-name.{language-code}.md`
|
||||
|
||||
**Examples:**
|
||||
```
|
||||
README.md → en (default)
|
||||
docker-deploy.zh-CN.md → Chinese
|
||||
docker-deploy.ru.md → Russian
|
||||
faq.zh-CN.md → Chinese FAQ
|
||||
```
|
||||
|
||||
**Language Codes:**
|
||||
- `en` - English (default, no suffix needed)
|
||||
- `zh-CN` - Simplified Chinese
|
||||
- `ru` - Russian
|
||||
- `uk` - Ukrainian
|
||||
- `ja` - Japanese *(future)*
|
||||
- `ko` - Korean *(future)*
|
||||
|
||||
### Quality Standards / 质量标准
|
||||
|
||||
**Must have / 必须具备:**
|
||||
- ✅ Accurate technical terms
|
||||
- ✅ Natural, fluent language
|
||||
- ✅ Consistent terminology
|
||||
- ✅ Preserved formatting (markdown)
|
||||
- ✅ Working internal links
|
||||
|
||||
**Avoid / 避免:**
|
||||
- ❌ Machine translation without review
|
||||
- ❌ Inconsistent terminology
|
||||
- ❌ Broken links or formatting
|
||||
- ❌ Cultural insensitivity
|
||||
|
||||
### Technical Terms / 技术术语
|
||||
|
||||
**Keep in English (don't translate):**
|
||||
- API, HTTP, REST, JSON
|
||||
- Docker, Kubernetes
|
||||
- GitHub, Git, Pull Request
|
||||
- Specific tool names (Binance, Hyperliquid)
|
||||
|
||||
**Example - Chinese:**
|
||||
- ✅ "启动 Docker 容器" (start Docker container)
|
||||
- ❌ "启动 多克 容器" (transliterated Docker)
|
||||
|
||||
---
|
||||
|
||||
## 🌐 Request a New Language / 请求新语言
|
||||
|
||||
### Want NOFX in your language? / 希望 NOFX 支持你的语言?
|
||||
|
||||
**Steps / 步骤:**
|
||||
|
||||
1. **Check if it's planned / 检查是否已计划**
|
||||
- See list below
|
||||
- Search GitHub Issues
|
||||
|
||||
2. **Create a request / 创建请求**
|
||||
- Open GitHub Issue
|
||||
- Title: `[TRANSLATION REQUEST] Language name`
|
||||
- Explain: Number of potential users, your willingness to help
|
||||
|
||||
3. **Volunteer to help / 志愿帮助**
|
||||
- Offer to translate
|
||||
- Find other speakers to review
|
||||
- Commit to maintaining updates
|
||||
|
||||
### Planned Languages / 计划中的语言
|
||||
|
||||
| Language | Status | Need Volunteers? |
|
||||
|----------|--------|------------------|
|
||||
| 🇯🇵 Japanese | 📋 Planned | ✅ Yes |
|
||||
| 🇰🇷 Korean | 📋 Planned | ✅ Yes |
|
||||
| 🇪🇸 Spanish | 📋 Planned | ✅ Yes |
|
||||
| 🇫🇷 French | 📋 Planned | ✅ Yes |
|
||||
| 🇩🇪 German | 📋 Planned | ✅ Yes |
|
||||
|
||||
---
|
||||
|
||||
## 👥 Translation Team / 翻译团队
|
||||
|
||||
### Current Translators / 当前翻译者
|
||||
|
||||
| Language | Translators | Status |
|
||||
|----------|-------------|--------|
|
||||
| 🇨🇳 Chinese | Community | Active |
|
||||
| 🇷🇺 Russian | Community | Active |
|
||||
| 🇺🇦 Ukrainian | Community | Active |
|
||||
|
||||
**Want to join the team? / 想加入团队?**
|
||||
- Contact on [Telegram](https://t.me/nofx_dev_community)
|
||||
- Open an issue on GitHub
|
||||
- DM [@nofx_ai](https://x.com/nofx_ai) on Twitter
|
||||
|
||||
---
|
||||
|
||||
## 📊 Translation Progress / 翻译进度
|
||||
|
||||
### Document Coverage / 文档覆盖率
|
||||
|
||||
| Document | EN | 中文 | РУ | УК |
|
||||
|----------|----|----|----|----|
|
||||
| Main README | ✅ | ✅ | ✅ | ✅ |
|
||||
| CONTRIBUTING | ✅ | ✅ | 🚧 | 🚧 |
|
||||
| CODE_OF_CONDUCT | ✅ | ✅ | 🚧 | 🚧 |
|
||||
| SECURITY | ✅ | ✅ | 🚧 | 🚧 |
|
||||
| Docker Deploy | ✅ | ✅ | ❌ | ❌ |
|
||||
| FAQ | ✅ | ✅ | ❌ | ❌ |
|
||||
|
||||
**Legend / 图例:**
|
||||
- ✅ Complete / 完成
|
||||
- 🚧 In Progress / 进行中
|
||||
- ❌ Not Started / 未开始
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Priority Translations / 优先翻译
|
||||
|
||||
**High Priority / 高优先级:**
|
||||
1. CONTRIBUTING.md (all languages)
|
||||
2. Docker deployment guides
|
||||
3. FAQ sections
|
||||
|
||||
**Medium Priority / 中优先级:**
|
||||
1. User guides
|
||||
2. Troubleshooting docs
|
||||
3. API reference
|
||||
|
||||
**Low Priority / 低优先级:**
|
||||
1. Architecture docs (technical, less urgent)
|
||||
2. Advanced configuration guides
|
||||
|
||||
---
|
||||
|
||||
## 🆘 Translation Help / 翻译帮助
|
||||
|
||||
**Questions? / 有问题?**
|
||||
- 💬 Ask in [Telegram Community](https://t.me/nofx_dev_community)
|
||||
- 🐙 Open a [GitHub Issue](https://github.com/tinkle-community/nofx/issues)
|
||||
- 📧 Contact maintainers
|
||||
|
||||
**Resources / 资源:**
|
||||
- [Contributing Guide](../../CONTRIBUTING.md) - How to submit
|
||||
- [Markdown Guide](https://www.markdownguide.org/) - Formatting reference
|
||||
|
||||
---
|
||||
|
||||
[← Back to Documentation Home](../README.md)
|
||||
@@ -6,10 +6,29 @@
|
||||
[](LICENSE)
|
||||
[](https://amber.ac)
|
||||
|
||||
**Языки / Languages:** [English](README.md) | [中文](README.zh-CN.md) | [Українська](README.uk.md) | [Русский](README.ru.md)
|
||||
**Языки / Languages:** [English](../../../README.md) | [中文](../zh-CN/README.md) | [Українська](../uk/README.md) | [Русский](../ru/README.md)
|
||||
|
||||
**Официальный Twitter:** [@nofx_ai](https://x.com/nofx_ai)
|
||||
|
||||
**📚 Документация:** [Главная](../../README.md) | [Начало работы](../../getting-started/README.md) | [Журнал изменений](../../../CHANGELOG.zh-CN.md) | [Сообщество](../../community/README.md)
|
||||
|
||||
---
|
||||
|
||||
## 📑 Содержание
|
||||
|
||||
- [🚀 Универсальная AI Торговая Операционная Система](#-универсальная-ai-торговая-операционная-система)
|
||||
- [👥 Сообщество Разработчиков](#-сообщество-разработчиков)
|
||||
- [🆕 Что Нового](#-что-нового)
|
||||
- [📸 Скриншоты](#-скриншоты)
|
||||
- [✨ Текущая Реализация - Криптовалютные Рынки](#-текущая-реализация---криптовалютные-рынки)
|
||||
- [🔮 Дорожная Карта](#-дорожная-карта---расширение-на-универсальные-рынки)
|
||||
- [🏗️ Техническая Архитектура](#️-техническая-архитектура)
|
||||
- [🚀 Быстрый Старт](#-быстрый-старт)
|
||||
- [📊 Функции Web-интерфейса](#-функции-web-интерфейса)
|
||||
- [⚠️ Важные Предупреждения о Рисках](#️-важные-предупреждения-о-рисках)
|
||||
- [🛠️ Общие Проблемы](#️-общие-проблемы)
|
||||
- [🔄 Журнал Изменений](#-журнал-изменений)
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Универсальная AI Торговая Операционная Система
|
||||
@@ -74,7 +93,7 @@ NOFX теперь поддерживает **три основные биржи*
|
||||
|
||||
**Быстрый старт:**
|
||||
1. Получите приватный ключ MetaMask (удалите префикс `0x`)
|
||||
2. Установите `"exchange": "hyperliquid"` в config.json
|
||||
2. ~~Установите `"exchange": "hyperliquid"` в config.json~~ *Настройте через веб-интерфейс*
|
||||
3. Добавьте `"hyperliquid_private_key": "your_key"`
|
||||
4. Начните торговать!
|
||||
|
||||
@@ -109,15 +128,19 @@ NOFX теперь поддерживает **три основные биржи*
|
||||
## 📸 Скриншоты
|
||||
|
||||
### 🏆 Режим конкуренции - Битва AI в реальном времени
|
||||

|
||||

|
||||
*Лидерборд с несколькими AI и графики сравнения производительности в реальном времени показывают битву Qwen против DeepSeek*
|
||||
|
||||
### 📊 Детали трейдера - Полная торговая панель
|
||||

|
||||

|
||||
*Профессиональный торговый интерфейс с кривыми капитала, живыми позициями и логами решений AI с раскрываемыми входными промптами и цепочкой рассуждений*
|
||||
|
||||
---
|
||||
|
||||
> 📘 **Примечание**: Это упрощенная русская версия README. Для получения полной технической документации, включая архитектуру системы, API-интерфейсы и расширенные конфигурации, см. [Английскую версию](../../../README.md) или [Китайскую версию](../zh-CN/README.md).
|
||||
|
||||
---
|
||||
|
||||
## ✨ Основные возможности
|
||||
|
||||
### 🏆 Режим конкуренции нескольких AI
|
||||
@@ -173,6 +196,55 @@ NOFX теперь поддерживает **три основные биржи*
|
||||
|
||||
---
|
||||
|
||||
## 🔮 Дорожная Карта - Расширение на Универсальные Рынки
|
||||
|
||||
Миссия NOFX - стать **Универсальной AI Торговой Операционной Системой** для всех финансовых рынков.
|
||||
|
||||
**Видение:** Та же архитектура. Та же агентная структура. Все рынки.
|
||||
|
||||
**Расширение на Рынки:**
|
||||
- 📈 **Фондовые Рынки**: Акции США, A-акции, Гонконгская биржа
|
||||
- 📊 **Рынки Фьючерсов**: Товарные фьючерсы, индексные фьючерсы
|
||||
- 🎯 **Опционная Торговля**: Опционы на акции, крипто опционы
|
||||
- 💱 **Рынки Форекс**: Основные валютные пары, кросс-курсы
|
||||
|
||||
**Предстоящие Функции:**
|
||||
- Расширенные AI возможности (GPT-4, Claude 3, Gemini Pro, гибкие шаблоны промптов)
|
||||
- Новые интеграции бирж (OKX, Bybit, Lighter, EdgeX + CEX/Perp-DEX)
|
||||
- Рефакторинг структуры проекта (высокая связность, низкая связанность, принципы SOLID)
|
||||
- Улучшения безопасности (AES-256 шифрование API ключей, RBAC, улучшения 2FA)
|
||||
- Улучшения пользовательского опыта (мобильный интерфейс, графики TradingView, система оповещений)
|
||||
|
||||
📖 **Для подробной дорожной карты и сроков см.:**
|
||||
- **English:** [Roadmap Documentation](../../roadmap/README.md)
|
||||
- **中文:** [路线图文档](../../roadmap/README.zh-CN.md)
|
||||
|
||||
---
|
||||
|
||||
## 🏗️ Техническая Архитектура
|
||||
|
||||
NOFX построен на современной модульной архитектуре:
|
||||
|
||||
- **Backend:** Go с фреймворком Gin, база данных SQLite
|
||||
- **Frontend:** React 18 + TypeScript + Vite + TailwindCSS
|
||||
- **Поддержка Бирж:** Binance, Hyperliquid, Aster DEX
|
||||
- **Интеграция AI:** DeepSeek, Qwen и пользовательские OpenAI-совместимые API
|
||||
- **Управление Состоянием:** Zustand для фронтенда, на основе базы данных для бэкенда
|
||||
- **Обновления в Реальном Времени:** SWR с интервалами опроса 5-10 секунд
|
||||
|
||||
**Ключевые Особенности:**
|
||||
- 🗄️ Конфигурация на основе базы данных (больше никакого редактирования JSON)
|
||||
- 🔐 JWT аутентификация с опциональной поддержкой 2FA
|
||||
- 📊 Отслеживание производительности и аналитика в реальном времени
|
||||
- 🤖 Режим конкуренции Multi-AI с живым сравнением
|
||||
- 🔌 RESTful API для всех настроек и мониторинга
|
||||
|
||||
📖 **Для подробной документации по архитектуре см.:**
|
||||
- **Русский:** [Документация по Архитектуре](../../architecture/README.md)
|
||||
- **中文:** [架构文档](../../architecture/README.zh-CN.md)
|
||||
|
||||
---
|
||||
|
||||
## 💰 Регистрация аккаунта Binance (Экономьте на комиссиях!)
|
||||
|
||||
Перед использованием этой системы вам нужен аккаунт Binance Futures. **Используйте нашу реферальную ссылку для получения скидки на комиссии:**
|
||||
@@ -824,103 +896,73 @@ curl http://localhost:8080/api/health
|
||||
|
||||
Каждый цикл принятия решений (по умолчанию 3 минуты), система работает по следующему процессу:
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────────────────────┐
|
||||
│ 1. 📊 Анализ исторической производительности │
|
||||
│ (последние 20 циклов) │
|
||||
├──────────────────────────────────────────────────────────┤
|
||||
│ ✓ Расчет общего процента выигрышей, средней прибыли, │
|
||||
│ соотношения прибыли/убытка │
|
||||
│ ✓ Статистика по каждой монете (процент выигрышей, │
|
||||
│ средний P/L в USDT) │
|
||||
│ ✓ Определение лучших/худших монет по производительности │
|
||||
│ ✓ Список деталей последних 5 сделок с точным P/L │
|
||||
│ ✓ Расчет коэффициента Шарпа для оценки риска │
|
||||
│ 📌 НОВОЕ (v2.0.2): Точный P/L в USDT с учетом плеча │
|
||||
└──────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌──────────────────────────────────────────────────────────┐
|
||||
│ 2. 💰 Получение состояния аккаунта │
|
||||
├──────────────────────────────────────────────────────────┤
|
||||
│ • Капитал аккаунта, доступный баланс, нереализованный │
|
||||
│ P/L │
|
||||
│ • Количество позиций, общий P/L (реализованный + │
|
||||
│ нереализованный) │
|
||||
│ • Использование маржи (текущее/максимальное) │
|
||||
│ • Индикаторы оценки риска │
|
||||
└──────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌──────────────────────────────────────────────────────────┐
|
||||
│ 3. 🔍 Анализ существующих позиций (если есть) │
|
||||
├──────────────────────────────────────────────────────────┤
|
||||
│ • Получение рыночных данных для каждой позиции │
|
||||
│ (3-минутные + 4-часовые свечи) │
|
||||
│ • Расчет технических индикаторов (RSI, MACD, EMA) │
|
||||
│ • Отображение длительности удержания позиции │
|
||||
│ (например, "удерживается 2 часа 15 минут") │
|
||||
│ • AI определяет, нужно ли закрыть (тейк-профит, │
|
||||
│ стоп-лосс или корректировка) │
|
||||
│ 📌 НОВОЕ (v2.0.2): Отслеживание длительности позиции │
|
||||
│ помогает AI решать │
|
||||
└──────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌──────────────────────────────────────────────────────────┐
|
||||
│ 4. 🎯 Оценка новых возможностей (пул кандидатов монет) │
|
||||
├──────────────────────────────────────────────────────────┤
|
||||
│ • Получение топ-20 монет с высоким рейтингом AI500 │
|
||||
│ • Получение топ-20 монет с самым быстрым ростом OI │
|
||||
│ • Объединение, удаление дубликатов, фильтрация монет с │
|
||||
│ низкой ликвидностью (OI < 15M USD) │
|
||||
│ • Массовое получение рыночных данных и технических │
|
||||
│ индикаторов │
|
||||
│ • Подготовка полных последовательностей сырых данных │
|
||||
│ для каждой монеты-кандидата │
|
||||
└──────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌──────────────────────────────────────────────────────────┐
|
||||
│ 5. 🧠 Комплексное решение AI │
|
||||
├──────────────────────────────────────────────────────────┤
|
||||
│ • Просмотр исторической обратной связи (процент │
|
||||
│ выигрышей, коэффициент P/L, лучшие/худшие монеты) │
|
||||
│ • Получение всех данных последовательностей (свечи, │
|
||||
│ индикаторы, открытый интерес) │
|
||||
│ • Анализ Chain of Thought │
|
||||
│ • Вывод решения: закрыть/открыть/удерживать/наблюдать │
|
||||
│ • Включает параметры плеча, размера, стоп-лосса, │
|
||||
│ тейк-профита │
|
||||
│ 📌 НОВОЕ (v2.0.2): AI может свободно анализировать │
|
||||
│ сырые последовательности, не ограничен заранее │
|
||||
│ определенными индикаторами │
|
||||
└──────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌──────────────────────────────────────────────────────────┐
|
||||
│ 6. ⚡ Исполнение сделок │
|
||||
├──────────────────────────────────────────────────────────┤
|
||||
│ • Приоритизация: сначала закрытие, затем открытие │
|
||||
│ • Автоматическая адаптация точности (правила LOT_SIZE) │
|
||||
│ • Предотвращение накопления позиций (отклонение │
|
||||
│ дублирования монета/направление) │
|
||||
│ • Автоматическая отмена всех ордеров после закрытия │
|
||||
│ • Запись времени открытия для отслеживания │
|
||||
│ длительности позиции │
|
||||
│ 📌 НОВОЕ (v2.0.2): Отслеживание времени открытия │
|
||||
│ позиции │
|
||||
└──────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌──────────────────────────────────────────────────────────┐
|
||||
│ 7. 📝 Запись логов │
|
||||
├──────────────────────────────────────────────────────────┤
|
||||
│ • Сохранение полной записи решения в decision_logs/ │
|
||||
│ • Включает цепочку рассуждений, JSON решения, снимок │
|
||||
│ аккаунта, результаты исполнения │
|
||||
│ • Хранение полных данных позиции (количество, плечо, │
|
||||
│ время открытия/закрытия) │
|
||||
│ • Использование ключей symbol_side для предотвращения │
|
||||
│ конфликтов лонг/шорт │
|
||||
│ 📌 НОВОЕ (v2.0.2): Предотвращение конфликтов при │
|
||||
│ удержании лонг + шорт, учет количества + плеча │
|
||||
└──────────────────────────────────────────────────────────┘
|
||||
```
|
||||
### Шаг 1: 📊 Анализ исторической производительности (последние 20 циклов)
|
||||
- ✓ Расчет общего процента выигрышей, средней прибыли, соотношения прибыли/убытка
|
||||
- ✓ Статистика по каждой монете (процент выигрышей, средний P/L в USDT)
|
||||
- ✓ Определение лучших/худших монет по производительности
|
||||
- ✓ Список деталей последних 5 сделок с точным P/L
|
||||
- ✓ Расчет коэффициента Шарпа для оценки риска
|
||||
- 📌 **НОВОЕ (v2.0.2)**: Точный P/L в USDT с учетом плеча
|
||||
|
||||
**↓**
|
||||
|
||||
### Шаг 2: 💰 Получение состояния аккаунта
|
||||
- Капитал аккаунта, доступный баланс, нереализованный P/L
|
||||
- Количество позиций, общий P/L (реализованный + нереализованный)
|
||||
- Использование маржи (текущее/максимальное)
|
||||
- Индикаторы оценки риска
|
||||
|
||||
**↓**
|
||||
|
||||
### Шаг 3: 🔍 Анализ существующих позиций (если есть)
|
||||
- Получение рыночных данных для каждой позиции (3-минутные + 4-часовые свечи)
|
||||
- Расчет технических индикаторов (RSI, MACD, EMA)
|
||||
- Отображение длительности удержания позиции (например, "удерживается 2 часа 15 минут")
|
||||
- AI определяет, нужно ли закрыть (тейк-профит, стоп-лосс или корректировка)
|
||||
- 📌 **НОВОЕ (v2.0.2)**: Отслеживание длительности позиции помогает AI решать
|
||||
|
||||
**↓**
|
||||
|
||||
### Шаг 4: 🎯 Оценка новых возможностей (пул кандидатов монет)
|
||||
- Получение пула монет (2 режима):
|
||||
- 🌟 **Режим по умолчанию**: BTC, ETH, SOL, BNB, XRP и т.д.
|
||||
- ⚙️ **Расширенный режим**: AI500 (топ-20) + OI Top (топ-20)
|
||||
- Объединение, удаление дубликатов, фильтрация монет с низкой ликвидностью (OI < 15M USD)
|
||||
- Массовое получение рыночных данных и технических индикаторов
|
||||
- Подготовка полных последовательностей сырых данных для каждой монеты-кандидата
|
||||
|
||||
**↓**
|
||||
|
||||
### Шаг 5: 🧠 Комплексное решение AI
|
||||
- Просмотр исторической обратной связи (процент выигрышей, коэффициент P/L, лучшие/худшие монеты)
|
||||
- Получение всех данных последовательностей (свечи, индикаторы, открытый интерес)
|
||||
- Анализ Chain of Thought
|
||||
- Вывод решения: закрыть/открыть/удерживать/наблюдать
|
||||
- Включает параметры плеча, размера, стоп-лосса, тейк-профита
|
||||
- 📌 **НОВОЕ (v2.0.2)**: AI может свободно анализировать сырые последовательности, не ограничен заранее определенными индикаторами
|
||||
|
||||
**↓**
|
||||
|
||||
### Шаг 6: ⚡ Исполнение сделок
|
||||
- Приоритизация: сначала закрытие, затем открытие
|
||||
- Автоматическая адаптация точности (правила LOT_SIZE)
|
||||
- Предотвращение накопления позиций (отклонение дублирования монета/направление)
|
||||
- Автоматическая отмена всех ордеров после закрытия
|
||||
- Запись времени открытия для отслеживания длительности позиции
|
||||
- 📌 Отслеживание времени открытия позиции
|
||||
|
||||
**↓**
|
||||
|
||||
### Шаг 7: 📝 Запись логов
|
||||
- Сохранение полной записи решения в `decision_logs/`
|
||||
- Включает цепочку рассуждений, JSON решения, снимок аккаунта, результаты исполнения
|
||||
- Хранение полных данных позиции (количество, плечо, время открытия/закрытия)
|
||||
- Использование ключей `symbol_side` для предотвращения конфликтов лонг/шорт
|
||||
- 📌 **НОВОЕ (v2.0.2)**: Предотвращение конфликтов при удержании лонг + шорт, учет количества + плеча
|
||||
|
||||
**↓**
|
||||
|
||||
**🔄 (Повтор каждые 3-5 минут)**
|
||||
|
||||
### Ключевые улучшения в v2.0.2
|
||||
|
||||
@@ -1058,263 +1100,24 @@ sudo apt-get install libta-lib0-dev
|
||||
|
||||
---
|
||||
|
||||
## 🔄 История изменений
|
||||
## 🔄 Журнал Изменений
|
||||
|
||||
```json
|
||||
{
|
||||
"traders": [
|
||||
{
|
||||
"id": "qwen_trader",
|
||||
"name": "Qwen AI Trader",
|
||||
"ai_model": "qwen",
|
||||
"binance_api_key": "ВАШ_BINANCE_API_KEY",
|
||||
"binance_secret_key": "ВАШ_BINANCE_SECRET_KEY",
|
||||
"use_qwen": true,
|
||||
"qwen_key": "sk-xxxxx",
|
||||
"scan_interval_minutes": 3,
|
||||
"initial_balance": 1000.0
|
||||
},
|
||||
{
|
||||
"id": "deepseek_trader",
|
||||
"name": "DeepSeek AI Trader",
|
||||
"ai_model": "deepseek",
|
||||
"binance_api_key": "ВАШ_BINANCE_API_KEY_2",
|
||||
"binance_secret_key": "ВАШ_BINANCE_SECRET_KEY_2",
|
||||
"use_qwen": false,
|
||||
"deepseek_key": "sk-xxxxx",
|
||||
"scan_interval_minutes": 3,
|
||||
"initial_balance": 1000.0
|
||||
}
|
||||
],
|
||||
"use_default_coins": false,
|
||||
"coin_pool_api_url": "http://x.x.x.x:xxx/api/ai500/list?auth=ВАШ_AUTH",
|
||||
"oi_top_api_url": "http://x.x.x.x:xxx/api/oi/top?auth=ВАШ_AUTH",
|
||||
"api_server_port": 8080
|
||||
}
|
||||
```
|
||||
📖 **Для подробной истории версий и обновлений см.:**
|
||||
|
||||
**Примечания к конфигурации:**
|
||||
- `traders`: Настройте 1-N трейдеров (один AI или соревнование нескольких AI)
|
||||
- `id`: Уникальный идентификатор трейдера (используется для директории логов)
|
||||
- `ai_model`: "qwen" или "deepseek"
|
||||
- `binance_api_key/secret_key`: Каждый трейдер использует независимый аккаунт Binance
|
||||
- `initial_balance`: Начальный баланс (для расчета P/L%)
|
||||
- `scan_interval_minutes`: Цикл принятия решений (рекомендуется 3-5 минут)
|
||||
- `use_default_coins`: **true** = Использовать 8 основных монет по умолчанию | **false** = Использовать API пул монет (рекомендуется для новичков: true)
|
||||
- `coin_pool_api_url`: API пула монет AI500 (опционально, игнорируется при use_default_coins=true)
|
||||
- `oi_top_api_url`: API открытого интереса OI Top (опционально, если пусто, данные OI Top пропускаются)
|
||||
- **Русский:** [CHANGELOG.zh-CN.md](../../../CHANGELOG.zh-CN.md)
|
||||
- **English:** [CHANGELOG.md](../../../CHANGELOG.md)
|
||||
|
||||
**Список монет по умолчанию** (когда `use_default_coins: true`):
|
||||
- BTC, ETH, SOL, BNB, XRP, DOGE, ADA, HYPE
|
||||
**Последняя Версия:** v3.0.0 (2025-10-30) - Масштабная Трансформация Архитектуры
|
||||
|
||||
### 5. Запуск системы
|
||||
|
||||
**Запуск backend (система AI торговли + API сервер):**
|
||||
|
||||
```bash
|
||||
go build -o nofx
|
||||
./nofx
|
||||
```
|
||||
|
||||
**Запуск frontend (веб-панель):**
|
||||
|
||||
Откройте новый терминал:
|
||||
|
||||
```bash
|
||||
cd web
|
||||
npm run dev
|
||||
```
|
||||
|
||||
**Доступ к интерфейсу:**
|
||||
```
|
||||
Веб-панель: http://localhost:3000
|
||||
API сервер: http://localhost:8080
|
||||
```
|
||||
|
||||
### 6. Остановка системы
|
||||
|
||||
Нажмите `Ctrl+C` в обоих терминалах
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ Важные предупреждения о рисках
|
||||
|
||||
### Торговые риски
|
||||
|
||||
1. **Рынки криптовалют чрезвычайно волатильны**, решения AI не гарантируют прибыль
|
||||
2. **Торговля фьючерсами использует плечо**, убытки могут превысить основную сумму
|
||||
3. **Экстремальные рыночные условия** могут привести к ликвидации
|
||||
4. **Комиссии за финансирование** могут повлиять на стоимость удержания
|
||||
5. **Риск ликвидности**: Некоторые монеты могут испытывать проскальзывание
|
||||
|
||||
### Технические риски
|
||||
|
||||
1. **Задержка сети** может вызвать проскальзывание цены
|
||||
2. **Лимиты API** могут повлиять на исполнение сделок
|
||||
3. **Тайм-ауты AI API** могут вызвать сбои решений
|
||||
4. **Системные ошибки** могут вызвать неожиданное поведение
|
||||
|
||||
### Рекомендации по использованию
|
||||
|
||||
✅ **Рекомендуется**
|
||||
- Используйте только средства, потерю которых вы можете позволить для тестирования
|
||||
- Начните с небольших сумм (рекомендуется 100-500 USDT)
|
||||
- Регулярно проверяйте состояние работы системы
|
||||
- Отслеживайте изменения баланса счета
|
||||
- Анализируйте логи решений AI для понимания стратегии
|
||||
|
||||
❌ **Не рекомендуется**
|
||||
- Инвестировать все средства или заемные деньги
|
||||
- Запускать без присмотра на длительные периоды
|
||||
- Слепо доверять решениям AI
|
||||
- Использовать без понимания системы
|
||||
- Запускать во время экстремальной волатильности рынка
|
||||
|
||||
---
|
||||
|
||||
## 🛠️ Частые проблемы
|
||||
|
||||
### 1. Ошибка компиляции: TA-Lib не найдена
|
||||
|
||||
**Решение**: Установите библиотеку TA-Lib
|
||||
```bash
|
||||
# macOS
|
||||
brew install ta-lib
|
||||
|
||||
# Ubuntu
|
||||
sudo apt-get install libta-lib0-dev
|
||||
```
|
||||
|
||||
### 2. Ошибка точности: Точность превышает максимум
|
||||
|
||||
**Решение**: Система автоматически обрабатывает точность из Binance LOT_SIZE. Если ошибка сохраняется, проверьте сетевое подключение.
|
||||
|
||||
### 3. Тайм-аут AI API
|
||||
|
||||
**Решение**:
|
||||
- Проверьте правильность API ключа
|
||||
- Проверьте сетевое подключение (может потребоваться прокси)
|
||||
- Тайм-аут системы установлен на 120 секунд
|
||||
|
||||
### 4. Frontend не может подключиться к backend
|
||||
|
||||
**Решение**:
|
||||
- Убедитесь, что backend запущен (http://localhost:8080)
|
||||
- Проверьте, не занят ли порт 8080
|
||||
- Проверьте ошибки в консоли браузера
|
||||
|
||||
### 5. Сбой API пула монет
|
||||
|
||||
**Решение**:
|
||||
- API пула монет опционален
|
||||
- Если API не работает, система использует основные монеты по умолчанию (BTC, ETH и т.д.)
|
||||
- Проверьте URL API и параметр auth в config.json
|
||||
|
||||
---
|
||||
|
||||
## 📄 Лицензия
|
||||
|
||||
Лицензия MIT - См. файл [LICENSE](LICENSE) для деталей
|
||||
|
||||
---
|
||||
|
||||
## 🤝 Вклад в проект
|
||||
|
||||
Приветствуются Issues и Pull Requests!
|
||||
|
||||
### Руководство по разработке
|
||||
|
||||
1. Сделайте Fork проекта
|
||||
2. Создайте ветку функции (`git checkout -b feature/AmazingFeature`)
|
||||
3. Зафиксируйте изменения (`git commit -m 'Add some AmazingFeature'`)
|
||||
4. Отправьте в ветку (`git push origin feature/AmazingFeature`)
|
||||
5. Откройте Pull Request
|
||||
|
||||
---
|
||||
|
||||
## 📬 Контакты
|
||||
|
||||
- **Twitter/X**: [@Web3Tinkle](https://x.com/Web3Tinkle)
|
||||
- **GitHub Issues**: [Создать Issue](https://github.com/tinkle-community/nofx/issues)
|
||||
|
||||
---
|
||||
|
||||
## 🙏 Благодарности
|
||||
|
||||
- [Binance API](https://binance-docs.github.io/apidocs/futures/en/) - Binance Futures API
|
||||
- [DeepSeek](https://platform.deepseek.com/) - DeepSeek AI API
|
||||
- [Qwen](https://dashscope.aliyuncs.com/) - Alibaba Cloud Qwen
|
||||
- [TA-Lib](https://ta-lib.org/) - Библиотека технических индикаторов
|
||||
- [Recharts](https://recharts.org/) - Библиотека графиков React
|
||||
|
||||
---
|
||||
|
||||
## 🔄 История изменений
|
||||
|
||||
### v2.0.2 (2025-10-29)
|
||||
|
||||
**Критические исправления ошибок - История сделок и анализ производительности:**
|
||||
|
||||
Эта версия исправляет **критические ошибки расчета** в системе исторических записей сделок и анализа производительности, которые значительно влияли на статистику прибыльности.
|
||||
|
||||
**1. Расчет P/L - Исправление крупной ошибки** (logger/decision_logger.go)
|
||||
- **Проблема**: Ранее P/L рассчитывался только как процент, полностью игнорируя размер позиции и плечо
|
||||
- Пример: Позиция 100 USDT с доходом 5% и позиция 1000 USDT с доходом 5% обе показывали `5.0` как прибыль
|
||||
- Это делало анализ производительности полностью неточным
|
||||
- **Решение**: Теперь рассчитывается фактическая прибыль в USDT
|
||||
```
|
||||
P/L (USDT) = Стоимость позиции × Изменение цены % × Плечо
|
||||
Пример: 1000 USDT × 5% × 20x = 1000 USDT фактической прибыли
|
||||
```
|
||||
- **Влияние**: Процент выигрышей, коэффициент прибыли и коэффициент Шарпа теперь основаны на точных суммах USDT
|
||||
|
||||
**2. Отслеживание позиций - Отсутствие критических данных**
|
||||
- **Проблема**: Записи открытых позиций хранили только цену и время, пропуская количество и плечо
|
||||
- **Решение**: Теперь хранит полные торговые данные:
|
||||
- `quantity`: Размер позиции (в монетах)
|
||||
- `leverage`: Множитель плеча (например, 20x)
|
||||
- Эти данные необходимы для точного расчета P/L
|
||||
|
||||
**3. Логика ключа позиции - Конфликт Long/Short**
|
||||
- **Проблема**: Использовался `symbol` как ключ позиции, что вызывало конфликты данных при одновременном удержании лонгов и шортов
|
||||
- Пример: BTCUSDT лонг и BTCUSDT шорт перезаписывали друг друга
|
||||
- **Решение**: Изменено на формат `symbol_side` (например, `BTCUSDT_long`, `BTCUSDT_short`)
|
||||
- Теперь правильно различает лонг и шорт позиции
|
||||
|
||||
**4. Расчет коэффициента Шарпа - Оптимизация кода**
|
||||
- **Проблема**: Использовался пользовательский метод Ньютона для расчета квадратного корня
|
||||
- **Решение**: Заменен на стандартную библиотеку `math.Sqrt`
|
||||
- Более надежный, поддерживаемый и эффективный
|
||||
|
||||
**Почему это обновление важно:**
|
||||
- ✅ Историческая статистика сделок теперь показывает **реальную прибыль/убыток в USDT** вместо бессмысленных процентов
|
||||
- ✅ Сравнение производительности между сделками с разным плечом теперь точно
|
||||
- ✅ Механизм самообучения AI получает правильную историческую обратную связь
|
||||
- ✅ Расчеты коэффициента прибыли и коэффициента Шарпа теперь имеют смысл
|
||||
- ✅ Отслеживание нескольких позиций (лонг + шорт одновременно) теперь работает правильно
|
||||
|
||||
**Рекомендация**: Если вы запускали систему до этого обновления, ваша историческая статистика была неточной. После обновления до v2.0.2, новые сделки будут рассчитываться правильно.
|
||||
|
||||
### v2.0.1 (2025-10-29)
|
||||
|
||||
**Исправления ошибок:**
|
||||
- ✅ Исправлена логика обработки данных ComparisonChart - переход от группировки по cycle_number к timestamp
|
||||
- ✅ Решена проблема замораживания графика при перезапуске backend и сбросе cycle_number
|
||||
- ✅ Улучшено отображение данных графика - теперь показывает все исторические точки в хронологическом порядке
|
||||
- ✅ Улучшенные отладочные логи для лучшей диагностики
|
||||
|
||||
### v2.0.0 (2025-10-28)
|
||||
|
||||
**Основные обновления:**
|
||||
- ✅ Механизм самообучения AI (исторический анализ, анализ производительности)
|
||||
- ✅ Режим конкуренции нескольких трейдеров (Qwen vs DeepSeek)
|
||||
- ✅ UI в стиле Binance (полная имитация интерфейса Binance)
|
||||
- ✅ Графики сравнения производительности (сравнение ROI в реальном времени)
|
||||
- ✅ Оптимизация контроля рисков (корректировка лимита позиции по монетам)
|
||||
|
||||
---
|
||||
|
||||
**Последнее обновление**: 2025-10-29 (v2.0.2)
|
||||
**Недавние Основные Моменты:**
|
||||
- 🚀 Полная переработка системы с веб-конфигурацией
|
||||
- 🗄️ Архитектура на основе базы данных (SQLite)
|
||||
- 🎨 Никакого редактирования JSON - вся конфигурация через веб-интерфейс
|
||||
- 🔧 Комбинируйте AI модели с любой биржей
|
||||
- 📊 Расширенный API слой с комплексными эндпоинтами
|
||||
- 🔐 Аутентификация JWT + поддержка 2FA
|
||||
- 🌐 Поддержка кастомных API (совместимых с OpenAI)
|
||||
- 📈 Система шаблонов промптов с удаленной аутентификацией
|
||||
|
||||
**⚡ Исследуйте возможности количественной торговли с силой AI!**
|
||||
|
||||
@@ -6,10 +6,30 @@
|
||||
[](LICENSE)
|
||||
[](https://amber.ac)
|
||||
|
||||
**Мови / Languages:** [English](README.md) | [中文](README.zh-CN.md) | [Українська](README.uk.md) | [Русский](README.ru.md)
|
||||
**Мови / Languages:** [English](../../../README.md) | [中文](../zh-CN/README.md) | [Українська](../uk/README.md) | [Русский](../ru/README.md)
|
||||
|
||||
**Офіційний Twitter:** [@nofx_ai](https://x.com/nofx_ai)
|
||||
|
||||
**📚 Документація:** [Головна](../../README.md) | [Початок роботи](../../getting-started/README.md) | [Спільнота](../../community/README.md) | [Журнал Змін](../../../CHANGELOG.md)
|
||||
|
||||
---
|
||||
|
||||
## 📑 Зміст
|
||||
|
||||
- [🚀 Універсальна AI Торгова Операційна Система](#-універсальна-ai-торгова-операційна-система)
|
||||
- [👥 Спільнота розробників](#-спільнота-розробників)
|
||||
- [🆕 Останні оновлення](#-останні-оновлення)
|
||||
- [🏗️ Технічна Архітектура](#️-технічна-архітектура)
|
||||
- [📸 Системні Скріншоти](#-системні-скріншоти)
|
||||
- [🎮 Швидкий Старт](#-швидкий-старт)
|
||||
- [📊 AI Модель](#-ai-модель)
|
||||
- [📈 Огляд Продуктивності](#-огляд-продуктивності)
|
||||
- [📄 Ліцензія](#-ліцензія)
|
||||
- [🤝 Внесок у проєкт](#-внесок-у-проєкт)
|
||||
- [📬 Контакти](#-контакти)
|
||||
- [🙏 Подяки](#-подяки)
|
||||
- [🔄 Журнал Змін](#-журнал-змін)
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Універсальна AI Торгова Операційна Система
|
||||
@@ -74,7 +94,7 @@ NOFX тепер підтримує **три основні біржі**: Binance
|
||||
|
||||
**Швидкий старт:**
|
||||
1. Отримайте приватний ключ MetaMask (видаліть префікс `0x`)
|
||||
2. Встановіть `"exchange": "hyperliquid"` в config.json
|
||||
2. ~~Встановіть `"exchange": "hyperliquid"` в config.json~~ *Налаштуйте через веб-інтерфейс*
|
||||
3. Додайте `"hyperliquid_private_key": "your_key"`
|
||||
4. Почніть торгувати!
|
||||
|
||||
@@ -109,15 +129,19 @@ NOFX тепер підтримує **три основні біржі**: Binance
|
||||
## 📸 Скриншоти
|
||||
|
||||
### 🏆 Режим змагання - Битва AI в реальному часі
|
||||

|
||||

|
||||
*Лідерборд з кількома AI та графіки порівняння продуктивності в реальному часі показують битву Qwen проти DeepSeek*
|
||||
|
||||
### 📊 Деталі трейдера - Повна торгова панель
|
||||

|
||||

|
||||
*Професійний торговий інтерфейс з кривими капіталу, живими позиціями та логами рішень AI з розкриваємими вхідними промптами та ланцюгом міркувань*
|
||||
|
||||
---
|
||||
|
||||
> 📘 **Примітка**: Це спрощена українська версія README. Для отримання повної технічної документації, включаючи архітектуру системи, API-інтерфейси та розширені конфігурації, див. [Англійську версію](../../../README.md) або [Китайську версію](../zh-CN/README.md).
|
||||
|
||||
---
|
||||
|
||||
## ✨ Основні можливості
|
||||
|
||||
### 🏆 Режим змагання кількох AI
|
||||
@@ -173,6 +197,57 @@ NOFX тепер підтримує **три основні біржі**: Binance
|
||||
|
||||
---
|
||||
|
||||
## 🔮 Дорожня Карта - Розширення на Універсальні Ринки
|
||||
|
||||
Місія NOFX - стати **Універсальною AI Торговою Операційною Системою** для всіх фінансових ринків.
|
||||
|
||||
**Бачення:** Та сама архітектура. Та сама агентна структура. Всі ринки.
|
||||
|
||||
**Розширення на Ринки:**
|
||||
- 📈 **Фондові Ринки**: Акції США, A-акції, Гонконгська біржа
|
||||
- 📊 **Ринки Ф'ючерсів**: Товарні ф'ючерси, індексні ф'ючерси
|
||||
- 🎯 **Опціонна Торгівля**: Опціони на акції, крипто опціони
|
||||
- 💱 **Ринки Форекс**: Основні валютні пари, крос-курси
|
||||
|
||||
**Майбутні Функції:**
|
||||
- Розширені AI можливості (GPT-4, Claude 3, Gemini Pro, гнучкі шаблони промптів)
|
||||
- Нові інтеграції бірж (OKX, Bybit, Lighter, EdgeX + CEX/Perp-DEX)
|
||||
- Рефакторинг структури проєкту (висока зв'язність, низька зчепленість, принципи SOLID)
|
||||
- Покращення безпеки (AES-256 шифрування API ключів, RBAC, покращення 2FA)
|
||||
- Покращення користувацького досвіду (мобільний інтерфейс, графіки TradingView, система сповіщень)
|
||||
|
||||
📖 **Для детальної дорожньої карти та термінів див.:**
|
||||
- **English:** [Roadmap Documentation](../../roadmap/README.md)
|
||||
- **中文:** [路线图文档](../../roadmap/README.zh-CN.md)
|
||||
|
||||
---
|
||||
|
||||
## 🏗️ Технічна Архітектура
|
||||
|
||||
NOFX побудовано на сучасній модульній архітектурі:
|
||||
|
||||
- **Backend:** Go з фреймворком Gin, база даних SQLite
|
||||
- **Frontend:** React 18 + TypeScript + Vite + TailwindCSS
|
||||
- **AI інтеграція:** DeepSeek, Qwen, кастомні API (сумісні з OpenAI)
|
||||
- **Підтримка бірж:** Binance Futures, Hyperliquid DEX, Aster DEX
|
||||
- **Аутентифікація:** JWT токени + підтримка 2FA
|
||||
- **Управління станом:** Zustand (легковагове)
|
||||
- **Отримання даних:** SWR з опитуванням 5-10с
|
||||
- **Графіки:** Recharts для кривих капіталу та порівнянь
|
||||
|
||||
**Ключові особливості:**
|
||||
- 🔧 Архітектура на основі бази даних (конфігурація через веб-інтерфейс, без JSON)
|
||||
- 🎯 Комбінуйте будь-яку AI модель з будь-якою біржею
|
||||
- 📊 RESTful API з комплексними ендпоінтами
|
||||
- 🔐 Безпечне управління облікових даних
|
||||
- 📈 Система шаблонів промптів з віддаленою аутентифікацією
|
||||
|
||||
📖 **Детальна документація по архітектурі:**
|
||||
- **English:** [Architecture Documentation](../../architecture/README.md)
|
||||
- **中文:** [架构文档](../../architecture/README.zh-CN.md)
|
||||
|
||||
---
|
||||
|
||||
## 💰 Реєстрація акаунта Binance (Заощаджуйте на комісіях!)
|
||||
|
||||
Перед використанням цієї системи вам потрібен акаунт Binance Futures. **Використовуйте наше реферальне посилання для отримання знижки на комісії:**
|
||||
@@ -824,104 +899,73 @@ curl http://localhost:8080/api/health
|
||||
|
||||
Кожен цикл прийняття рішень (за замовчуванням 3 хвилини), система працює за наступним процесом:
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────────────────────┐
|
||||
│ 1. 📊 Аналіз історичної продуктивності │
|
||||
│ (останні 20 циклів) │
|
||||
├──────────────────────────────────────────────────────────┤
|
||||
│ ✓ Розрахунок загального відсотка виграшів, середнього │
|
||||
│ прибутку, співвідношення прибутку/збитку │
|
||||
│ ✓ Статистика по кожній монеті (відсоток виграшів, │
|
||||
│ середній P/L в USDT) │
|
||||
│ ✓ Визначення найкращих/найгірших монет за │
|
||||
│ продуктивністю │
|
||||
│ ✓ Список деталей останніх 5 угод з точним P/L │
|
||||
│ ✓ Розрахунок коефіцієнта Шарпа для оцінки ризику │
|
||||
│ 📌 НОВЕ (v2.0.2): Точний P/L в USDT з врахуванням │
|
||||
│ плеча │
|
||||
└──────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌──────────────────────────────────────────────────────────┐
|
||||
│ 2. 💰 Отримання стану акаунта │
|
||||
├──────────────────────────────────────────────────────────┤
|
||||
│ • Капітал акаунта, доступний баланс, нереалізований │
|
||||
│ P/L │
|
||||
│ • Кількість позицій, загальний P/L (реалізований + │
|
||||
│ нереалізований) │
|
||||
│ • Використання маржі (поточне/максимальне) │
|
||||
│ • Індикатори оцінки ризику │
|
||||
└──────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌──────────────────────────────────────────────────────────┐
|
||||
│ 3. 🔍 Аналіз існуючих позицій (якщо є) │
|
||||
├──────────────────────────────────────────────────────────┤
|
||||
│ • Отримання ринкових даних для кожної позиції │
|
||||
│ (3-хвилинні + 4-годинні свічки) │
|
||||
│ • Розрахунок технічних індикаторів (RSI, MACD, EMA) │
|
||||
│ • Відображення тривалості утримання позиції │
|
||||
│ (наприклад, "утримується 2 години 15 хвилин") │
|
||||
│ • AI визначає, чи потрібно закрити (тейк-профіт, │
|
||||
│ стоп-лосс або коригування) │
|
||||
│ 📌 НОВЕ (v2.0.2): Відстеження тривалості позиції │
|
||||
│ допомагає AI вирішувати │
|
||||
└──────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌──────────────────────────────────────────────────────────┐
|
||||
│ 4. 🎯 Оцінка нових можливостей (пул кандидатів монет) │
|
||||
├──────────────────────────────────────────────────────────┤
|
||||
│ • Отримання топ-20 монет з високим рейтингом AI500 │
|
||||
│ • Отримання топ-20 монет з найшвидшим зростанням OI │
|
||||
│ • Об'єднання, видалення дублікатів, фільтрація монет з │
|
||||
│ низькою ліквідністю (OI < 15M USD) │
|
||||
│ • Масове отримання ринкових даних та технічних │
|
||||
│ індикаторів │
|
||||
│ • Підготовка повних послідовностей сирих даних для │
|
||||
│ кожної монети-кандидата │
|
||||
└──────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌──────────────────────────────────────────────────────────┐
|
||||
│ 5. 🧠 Комплексне рішення AI │
|
||||
├──────────────────────────────────────────────────────────┤
|
||||
│ • Перегляд історичного зворотного зв'язку (відсоток │
|
||||
│ виграшів, коефіцієнт P/L, найкращі/найгірші монети) │
|
||||
│ • Отримання всіх даних послідовностей (свічки, │
|
||||
│ індикатори, відкритий інтерес) │
|
||||
│ • Аналіз Chain of Thought │
|
||||
│ • Вивід рішення: закрити/відкрити/утримувати/спостерігати │
|
||||
│ • Включає параметри плеча, розміру, стоп-лосса, │
|
||||
│ тейк-профіта │
|
||||
│ 📌 НОВЕ (v2.0.2): AI може вільно аналізувати сирі │
|
||||
│ послідовності, не обмежений заздалегідь визначеними │
|
||||
│ індикаторами │
|
||||
└──────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌──────────────────────────────────────────────────────────┐
|
||||
│ 6. ⚡ Виконання угод │
|
||||
├──────────────────────────────────────────────────────────┤
|
||||
│ • Пріоритизація: спочатку закриття, потім відкриття │
|
||||
│ • Автоматична адаптація точності (правила LOT_SIZE) │
|
||||
│ • Запобігання накопиченню позицій (відхилення │
|
||||
│ дублювання монета/напрямок) │
|
||||
│ • Автоматична відміна всіх ордерів після закриття │
|
||||
│ • Запис часу відкриття для відстеження тривалості │
|
||||
│ позиції │
|
||||
│ 📌 НОВЕ (v2.0.2): Відстеження часу відкриття позиції │
|
||||
└──────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌──────────────────────────────────────────────────────────┐
|
||||
│ 7. 📝 Запис логів │
|
||||
├──────────────────────────────────────────────────────────┤
|
||||
│ • Збереження повного запису рішення в decision_logs/ │
|
||||
│ • Включає ланцюг міркувань, JSON рішення, знімок │
|
||||
│ акаунта, результати виконання │
|
||||
│ • Зберігання повних даних позиції (кількість, плече, │
|
||||
│ час відкриття/закриття) │
|
||||
│ • Використання ключів symbol_side для запобігання │
|
||||
│ конфліктів лонг/шорт │
|
||||
│ 📌 НОВЕ (v2.0.2): Запобігання конфліктів при утриманні │
|
||||
│ лонг + шорт, врахування кількості + плеча │
|
||||
└──────────────────────────────────────────────────────────┘
|
||||
```
|
||||
### Крок 1: 📊 Аналіз історичної продуктивності (останні 20 циклів)
|
||||
- ✓ Розрахунок загального відсотка виграшів, середнього прибутку, співвідношення прибутку/збитку
|
||||
- ✓ Статистика по кожній монеті (відсоток виграшів, середній P/L в USDT)
|
||||
- ✓ Визначення найкращих/найгірших монет за продуктивністю
|
||||
- ✓ Список деталей останніх 5 угод з точним P/L
|
||||
- ✓ Розрахунок коефіцієнта Шарпа для оцінки ризику
|
||||
- 📌 **НОВЕ (v2.0.2)**: Точний P/L в USDT з врахуванням плеча
|
||||
|
||||
**↓**
|
||||
|
||||
### Крок 2: 💰 Отримання стану акаунта
|
||||
- Капітал акаунта, доступний баланс, нереалізований P/L
|
||||
- Кількість позицій, загальний P/L (реалізований + нереалізований)
|
||||
- Використання маржі (поточне/максимальне)
|
||||
- Індикатори оцінки ризику
|
||||
|
||||
**↓**
|
||||
|
||||
### Крок 3: 🔍 Аналіз існуючих позицій (якщо є)
|
||||
- Отримання ринкових даних для кожної позиції (3-хвилинні + 4-годинні свічки)
|
||||
- Розрахунок технічних індикаторів (RSI, MACD, EMA)
|
||||
- Відображення тривалості утримання позиції (наприклад, "утримується 2 години 15 хвилин")
|
||||
- AI визначає, чи потрібно закрити (тейк-профіт, стоп-лосс або коригування)
|
||||
- 📌 **НОВЕ (v2.0.2)**: Відстеження тривалості позиції допомагає AI вирішувати
|
||||
|
||||
**↓**
|
||||
|
||||
### Крок 4: 🎯 Оцінка нових можливостей (пул кандидатів монет)
|
||||
- Отримання пулу монет (2 режими):
|
||||
- 🌟 **Режим за замовчуванням**: BTC, ETH, SOL, BNB, XRP тощо
|
||||
- ⚙️ **Розширений режим**: AI500 (топ-20) + OI Top (топ-20)
|
||||
- Об'єднання, видалення дублікатів, фільтрація монет з низькою ліквідністю (OI < 15M USD)
|
||||
- Масове отримання ринкових даних та технічних індикаторів
|
||||
- Підготовка повних послідовностей сирих даних для кожної монети-кандидата
|
||||
|
||||
**↓**
|
||||
|
||||
### Крок 5: 🧠 Комплексне рішення AI
|
||||
- Перегляд історичного зворотного зв'язку (відсоток виграшів, коефіцієнт P/L, найкращі/найгірші монети)
|
||||
- Отримання всіх даних послідовностей (свічки, індикатори, відкритий інтерес)
|
||||
- Аналіз Chain of Thought
|
||||
- Вивід рішення: закрити/відкрити/утримувати/спостерігати
|
||||
- Включає параметри плеча, розміру, стоп-лосса, тейк-профіта
|
||||
- 📌 **НОВЕ (v2.0.2)**: AI може вільно аналізувати сирі послідовності, не обмежений заздалегідь визначеними індикаторами
|
||||
|
||||
**↓**
|
||||
|
||||
### Крок 6: ⚡ Виконання угод
|
||||
- Пріоритизація: спочатку закриття, потім відкриття
|
||||
- Автоматична адаптація точності (правила LOT_SIZE)
|
||||
- Запобігання накопиченню позицій (відхилення дублювання монета/напрямок)
|
||||
- Автоматична відміна всіх ордерів після закриття
|
||||
- Запис часу відкриття для відстеження тривалості позиції
|
||||
- 📌 Відстеження часу відкриття позиції
|
||||
|
||||
**↓**
|
||||
|
||||
### Крок 7: 📝 Запис логів
|
||||
- Збереження повного запису рішення в `decision_logs/`
|
||||
- Включає ланцюг міркувань, JSON рішення, знімок акаунта, результати виконання
|
||||
- Зберігання повних даних позиції (кількість, плече, час відкриття/закриття)
|
||||
- Використання ключів `symbol_side` для запобігання конфліктів лонг/шорт
|
||||
- 📌 **НОВЕ (v2.0.2)**: Запобігання конфліктів при утриманні лонг + шорт, врахування кількості + плеча
|
||||
|
||||
**↓**
|
||||
|
||||
**🔄 (Повтор кожні 3-5 хвилин)**
|
||||
|
||||
### Ключові покращення в v2.0.2
|
||||
|
||||
@@ -950,6 +994,7 @@ curl http://localhost:8080/api/health
|
||||
## ⚠️ Важливі попередження про ризики
|
||||
|
||||
### Торговельні ризики
|
||||
```
|
||||
{
|
||||
"id": "qwen_trader",
|
||||
"name": "Qwen AI Trader",
|
||||
@@ -1013,6 +1058,7 @@ npm run dev
|
||||
```
|
||||
|
||||
**Доступ до інтерфейсу:**
|
||||
|
||||
```
|
||||
Веб-панель: http://localhost:3000
|
||||
API сервер: http://localhost:8080
|
||||
@@ -1024,184 +1070,26 @@ API сервер: http://localhost:8080
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ Важливі попередження про ризики
|
||||
|
||||
### Торговельні ризики
|
||||
|
||||
1. **Ринки криптовалют надзвичайно волатильні**, рішення AI не гарантують прибуток
|
||||
2. **Торгівля ф'ючерсами використовує плече**, збитки можуть перевищити основну суму
|
||||
3. **Екстремальні ринкові умови** можуть призвести до ліквідації
|
||||
4. **Комісії за фінансування** можуть вплинути на вартість утримання
|
||||
5. **Ризик ліквідності**: Деякі монети можуть відчувати проковзування
|
||||
|
||||
### Технічні ризики
|
||||
|
||||
1. **Затримка мережі** може викликати проковзування ціни
|
||||
2. **Ліміти API** можуть вплинути на виконання угод
|
||||
3. **Тайм-аути AI API** можуть викликати збої рішень
|
||||
4. **Системні помилки** можуть викликати неочікувану поведінку
|
||||
|
||||
### Рекомендації щодо використання
|
||||
|
||||
✅ **Рекомендується**
|
||||
- Використовуйте лише кошти, втрату яких ви можете дозволити для тестування
|
||||
- Почніть з невеликих сум (рекомендується 100-500 USDT)
|
||||
- Регулярно перевіряйте стан роботи системи
|
||||
- Відстежуйте зміни балансу рахунку
|
||||
- Аналізуйте логи рішень AI для розуміння стратегії
|
||||
|
||||
❌ **Не рекомендується**
|
||||
- Інвестувати всі кошти або позичені гроші
|
||||
- Запускати без нагляду на тривалі періоди
|
||||
- Сліпо довіряти рішенням AI
|
||||
- Використовувати без розуміння системи
|
||||
- Запускати під час екстремальної волатильності ринку
|
||||
|
||||
---
|
||||
|
||||
## 🛠️ Часті проблеми
|
||||
## 🔄 Журнал Змін
|
||||
|
||||
### 1. Помилка компіляції: TA-Lib не знайдена
|
||||
📖 **Для детальної історії версій та оновлень див.:**
|
||||
|
||||
**Рішення**: Встановіть бібліотеку TA-Lib
|
||||
```bash
|
||||
# macOS
|
||||
brew install ta-lib
|
||||
- **Українська:** [CHANGELOG.zh-CN.md](../../../CHANGELOG.zh-CN.md)
|
||||
- **English:** [CHANGELOG.md](../../../CHANGELOG.md)
|
||||
|
||||
# Ubuntu
|
||||
sudo apt-get install libta-lib0-dev
|
||||
```
|
||||
**Остання Версія:** v3.0.0 (2025-10-30) - Масштабна Трансформація Архітектури
|
||||
|
||||
### 2. Помилка точності: Точність перевищує максимум
|
||||
|
||||
**Рішення**: Система автоматично обробляє точність з Binance LOT_SIZE. Якщо помилка зберігається, перевірте мережеве підключення.
|
||||
|
||||
### 3. Тайм-аут AI API
|
||||
|
||||
**Рішення**:
|
||||
- Перевірте правильність API ключа
|
||||
- Перевірте мережеве підключення (може знадобитися проксі)
|
||||
- Тайм-аут системи встановлено на 120 секунд
|
||||
|
||||
### 4. Frontend не може підключитися до backend
|
||||
|
||||
**Рішення**:
|
||||
- Переконайтеся, що backend запущено (http://localhost:8080)
|
||||
- Перевірте, чи не зайнятий порт 8080
|
||||
- Перевірте помилки в консолі браузера
|
||||
|
||||
### 5. Збій API пулу монет
|
||||
|
||||
**Рішення**:
|
||||
- API пулу монет опціонален
|
||||
- Якщо API не працює, система використовує основні монети за замовчуванням (BTC, ETH тощо)
|
||||
- Перевірте URL API та параметр auth в config.json
|
||||
|
||||
---
|
||||
|
||||
## 📄 Ліцензія
|
||||
|
||||
Ліцензія MIT - Див. файл [LICENSE](LICENSE) для деталей
|
||||
|
||||
---
|
||||
|
||||
## 🤝 Внесок у проєкт
|
||||
|
||||
Вітаються Issues та Pull Requests!
|
||||
|
||||
### Керівництво з розробки
|
||||
|
||||
1. Зробіть Fork проєкту
|
||||
2. Створіть гілку функції (`git checkout -b feature/AmazingFeature`)
|
||||
3. Зафіксуйте зміни (`git commit -m 'Add some AmazingFeature'`)
|
||||
4. Надішліть до гілки (`git push origin feature/AmazingFeature`)
|
||||
5. Відкрийте Pull Request
|
||||
|
||||
---
|
||||
|
||||
## 📬 Контакти
|
||||
|
||||
- **Twitter/X**: [@Web3Tinkle](https://x.com/Web3Tinkle)
|
||||
- **GitHub Issues**: [Створити Issue](https://github.com/tinkle-community/nofx/issues)
|
||||
|
||||
---
|
||||
|
||||
## 🙏 Подяки
|
||||
|
||||
- [Binance API](https://binance-docs.github.io/apidocs/futures/en/) - Binance Futures API
|
||||
- [DeepSeek](https://platform.deepseek.com/) - DeepSeek AI API
|
||||
- [Qwen](https://dashscope.aliyuncs.com/) - Alibaba Cloud Qwen
|
||||
- [TA-Lib](https://ta-lib.org/) - Бібліотека технічних індикаторів
|
||||
- [Recharts](https://recharts.org/) - Бібліотека графіків React
|
||||
|
||||
---
|
||||
|
||||
## 🔄 Історія змін
|
||||
|
||||
### v2.0.2 (2025-10-29)
|
||||
|
||||
**Критичні виправлення помилок - Історія угод та аналіз продуктивності:**
|
||||
|
||||
Ця версія виправляє **критичні помилки розрахунку** в системі історичних записів угод та аналізу продуктивності, які значно впливали на статистику прибутковості.
|
||||
|
||||
**1. Розрахунок P/L - Виправлення великої помилки** (logger/decision_logger.go)
|
||||
- **Проблема**: Раніше P/L розраховувався лише як відсоток, повністю ігноруючи розмір позиції та плече
|
||||
- Приклад: Позиція 100 USDT з доходом 5% та позиція 1000 USDT з доходом 5% обидві показували `5.0` як прибуток
|
||||
- Це робило аналіз продуктивності повністю неточним
|
||||
- **Рішення**: Тепер розраховується фактичний прибуток в USDT
|
||||
```
|
||||
P/L (USDT) = Вартість позиції × Зміна ціни % × Плече
|
||||
Приклад: 1000 USDT × 5% × 20x = 1000 USDT фактичного прибутку
|
||||
```
|
||||
- **Вплив**: Відсоток виграшів, коефіцієнт прибутку та коефіцієнт Шарпа тепер засновані на точних сумах USDT
|
||||
|
||||
**2. Відстеження позицій - Відсутність критичних даних**
|
||||
- **Проблема**: Записи відкритих позицій зберігали лише ціну та час, пропускаючи кількість та плече
|
||||
- **Рішення**: Тепер зберігає повні торгові дані:
|
||||
- `quantity`: Розмір позиції (в монетах)
|
||||
- `leverage`: Множник плеча (наприклад, 20x)
|
||||
- Ці дані необхідні для точного розрахунку P/L
|
||||
|
||||
**3. Логіка ключа позиції - Конфлікт Long/Short**
|
||||
- **Проблема**: Використовувався `symbol` як ключ позиції, що викликало конфлікти даних при одночасному утриманні лонгів та шортів
|
||||
- Приклад: BTCUSDT лонг та BTCUSDT шорт перезаписували один одного
|
||||
- **Рішення**: Змінено на формат `symbol_side` (наприклад, `BTCUSDT_long`, `BTCUSDT_short`)
|
||||
- Тепер правильно розрізняє лонг та шорт позиції
|
||||
|
||||
**4. Розрахунок коефіцієнта Шарпа - Оптимізація коду**
|
||||
- **Проблема**: Використовувався користувацький метод Ньютона для розрахунку квадратного кореня
|
||||
- **Рішення**: Замінено на стандартну бібліотеку `math.Sqrt`
|
||||
- Більш надійний, підтримуваний та ефективний
|
||||
|
||||
**Чому це оновлення важливе:**
|
||||
- ✅ Історична статистика угод тепер показує **реальний прибуток/збиток в USDT** замість безглуздих відсотків
|
||||
- ✅ Порівняння продуктивності між угодами з різним плечем тепер точне
|
||||
- ✅ Механізм самонавчання AI отримує правильний історичний зворотний зв'язок
|
||||
- ✅ Розрахунки коефіцієнта прибутку та коефіцієнта Шарпа тепер мають сенс
|
||||
- ✅ Відстеження кількох позицій (лонг + шорт одночасно) тепер працює правильно
|
||||
|
||||
**Рекомендація**: Якщо ви запускали систему до цього оновлення, ваша історична статистика була неточною. Після оновлення до v2.0.2, нові угоди будуть розраховуватися правильно.
|
||||
|
||||
### v2.0.1 (2025-10-29)
|
||||
|
||||
**Виправлення помилок:**
|
||||
- ✅ Виправлено логіку обробки даних ComparisonChart - перехід від групування по cycle_number до timestamp
|
||||
- ✅ Вирішено проблему заморожування графіка при перезапуску backend та скиданні cycle_number
|
||||
- ✅ Покращено відображення даних графіка - тепер показує всі історичні точки в хронологічному порядку
|
||||
- ✅ Покращені відладочні логи для кращої діагностики
|
||||
|
||||
### v2.0.0 (2025-10-28)
|
||||
|
||||
**Основні оновлення:**
|
||||
- ✅ Механізм самонавчання AI (історичний аналіз, аналіз продуктивності)
|
||||
- ✅ Режим змагання кількох трейдерів (Qwen vs DeepSeek)
|
||||
- ✅ UI в стилі Binance (повна імітація інтерфейсу Binance)
|
||||
- ✅ Графіки порівняння продуктивності (порівняння ROI в реальному часі)
|
||||
- ✅ Оптимізація контролю ризиків (коригування ліміту позиції по монетах)
|
||||
|
||||
---
|
||||
|
||||
**Останнє оновлення**: 2025-10-29 (v2.0.2)
|
||||
**Недавні Основні Моменти:**
|
||||
- 🚀 Повна переробка системи з веб-конфігурацією
|
||||
- 🗄️ Архітектура на основі бази даних (SQLite)
|
||||
- 🎨 Ніякого редагування JSON - вся конфігурація через веб-інтерфейс
|
||||
- 🔧 Комбінуйте AI моделі з будь-якою біржею
|
||||
- 📊 Розширений API шар з комплексними ендпоінтами
|
||||
- 🔐 Аутентифікація JWT + підтримка 2FA
|
||||
- 🌐 Підтримка кастомних API (сумісних з OpenAI)
|
||||
- 📈 Система шаблонів промптів з віддаленою аутентифікацією
|
||||
|
||||
**⚡ Досліджуйте можливості кількісної торгівлі з силою AI!**
|
||||
|
||||
481
docs/i18n/zh-CN/CONTRIBUTING.md
Normal file
481
docs/i18n/zh-CN/CONTRIBUTING.md
Normal file
@@ -0,0 +1,481 @@
|
||||
# 🤝 为 NOFX 做贡献
|
||||
|
||||
**语言:** [English](../../../CONTRIBUTING.md) | [中文](CONTRIBUTING.md)
|
||||
|
||||
感谢您有兴趣为 NOFX 做贡献!本文档提供了为项目做贡献的指南和工作流程。
|
||||
|
||||
---
|
||||
|
||||
## 📑 目录
|
||||
|
||||
- [行为准则](#行为准则)
|
||||
- [如何贡献](#如何贡献)
|
||||
- [开发工作流程](#开发工作流程)
|
||||
- [PR 提交指南](#pr-提交指南)
|
||||
- [编码规范](#编码规范)
|
||||
- [提交信息指南](#提交信息指南)
|
||||
- [审核流程](#审核流程)
|
||||
- [悬赏计划](#悬赏计划)
|
||||
|
||||
---
|
||||
|
||||
## 📜 行为准则
|
||||
|
||||
本项目遵守[行为准则](../../../CODE_OF_CONDUCT.md)。参与项目即表示您同意遵守此准则。
|
||||
|
||||
---
|
||||
|
||||
## 🎯 如何贡献
|
||||
|
||||
### 1. 报告 Bug 🐛
|
||||
|
||||
- 使用 [Bug 报告模板](../../../.github/ISSUE_TEMPLATE/bug_report.md)
|
||||
- 检查 bug 是否已被报告
|
||||
- 包含详细的重现步骤
|
||||
- 提供环境信息(操作系统、Go 版本等)
|
||||
|
||||
### 2. 建议功能 ✨
|
||||
|
||||
- 使用[功能请求模板](../../../.github/ISSUE_TEMPLATE/feature_request.md)
|
||||
- 解释使用场景和好处
|
||||
- 检查是否与[项目路线图](../../roadmap/README.zh-CN.md)一致
|
||||
|
||||
### 3. 提交 Pull Request 🔧
|
||||
|
||||
提交 PR 前,请检查以下内容:
|
||||
|
||||
#### ✅ **接受的贡献**
|
||||
|
||||
**高优先级**(与路线图一致):
|
||||
- 🔒 安全增强(加密、认证、RBAC)
|
||||
- 🧠 AI 模型集成(GPT-4、Claude、Gemini Pro)
|
||||
- 🔗 交易所集成(OKX、Bybit、Lighter、EdgeX)
|
||||
- 📊 交易数据 API(AI500、OI 分析、NetFlow)
|
||||
- 🎨 UI/UX 改进(移动端响应式、图表)
|
||||
- ⚡ 性能优化
|
||||
- 🐛 Bug 修复
|
||||
- 📝 文档改进
|
||||
|
||||
**中等优先级:**
|
||||
- ✅ 测试覆盖率改进
|
||||
- 🌐 国际化(新语言支持)
|
||||
- 🔧 构建/部署工具
|
||||
- 📈 监控和日志增强
|
||||
|
||||
#### ❌ **不接受**(未经事先讨论)
|
||||
|
||||
- 没有 RFC(征求意见稿)的重大架构变更
|
||||
- 与项目路线图不一致的功能
|
||||
- 没有迁移路径的破坏性变更
|
||||
- 引入新依赖但没有充分理由的代码
|
||||
- 没有可选标志的实验性功能
|
||||
|
||||
**⚠️ 重要:** 对于重大功能,请在开始工作**之前**先开 issue 讨论。
|
||||
|
||||
---
|
||||
|
||||
## 🛠️ 开发工作流程
|
||||
|
||||
### 1. Fork 和 Clone
|
||||
|
||||
```bash
|
||||
# 在 GitHub 上 Fork 仓库
|
||||
# 然后 clone 你的 fork
|
||||
git clone https://github.com/YOUR_USERNAME/nofx.git
|
||||
cd nofx
|
||||
|
||||
# 添加 upstream remote
|
||||
git remote add upstream https://github.com/tinkle-community/nofx.git
|
||||
```
|
||||
|
||||
### 2. 创建功能分支
|
||||
|
||||
```bash
|
||||
# 更新你的本地 dev 分支
|
||||
git checkout dev
|
||||
git pull upstream dev
|
||||
|
||||
# 创建新分支
|
||||
git checkout -b feature/your-feature-name
|
||||
# 或
|
||||
git checkout -b fix/your-bug-fix
|
||||
```
|
||||
|
||||
**分支命名规范:**
|
||||
- `feature/` - 新功能
|
||||
- `fix/` - Bug 修复
|
||||
- `docs/` - 文档更新
|
||||
- `refactor/` - 代码重构
|
||||
- `perf/` - 性能改进
|
||||
- `test/` - 测试更新
|
||||
- `chore/` - 构建/配置更改
|
||||
|
||||
### 3. 设置开发环境
|
||||
|
||||
```bash
|
||||
# 安装 Go 依赖
|
||||
go mod download
|
||||
|
||||
# 安装前端依赖
|
||||
cd web
|
||||
npm install
|
||||
cd ..
|
||||
|
||||
# 安装 TA-Lib(必需)
|
||||
# macOS:
|
||||
brew install ta-lib
|
||||
|
||||
# Ubuntu/Debian:
|
||||
sudo apt-get install libta-lib0-dev
|
||||
```
|
||||
|
||||
### 4. 进行更改
|
||||
|
||||
- 遵循[编码规范](#编码规范)
|
||||
- 为新功能编写测试
|
||||
- 根据需要更新文档
|
||||
- 保持提交专注和原子性
|
||||
|
||||
### 5. 测试你的更改
|
||||
|
||||
```bash
|
||||
# 运行后端测试
|
||||
go test ./...
|
||||
|
||||
# 构建后端
|
||||
go build -o nofx
|
||||
|
||||
# 以开发模式运行前端
|
||||
cd web
|
||||
npm run dev
|
||||
|
||||
# 构建前端
|
||||
npm run build
|
||||
```
|
||||
|
||||
### 6. 提交你的更改
|
||||
|
||||
遵循[提交信息指南](#提交信息指南):
|
||||
|
||||
```bash
|
||||
git add .
|
||||
git commit -m "feat: add support for OKX exchange integration"
|
||||
```
|
||||
|
||||
### 7. 推送并创建 PR
|
||||
|
||||
```bash
|
||||
# 推送到你的 fork
|
||||
git push origin feature/your-feature-name
|
||||
|
||||
# 前往 GitHub 创建 Pull Request
|
||||
# 使用 PR 模板并填写所有部分
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📝 PR 提交指南
|
||||
|
||||
### 提交前检查
|
||||
|
||||
- [ ] 代码成功编译(`go build` 和 `npm run build`)
|
||||
- [ ] 所有测试通过(`go test ./...`)
|
||||
- [ ] 没有 linting 错误(`go fmt`、`go vet`)
|
||||
- [ ] 文档已更新
|
||||
- [ ] 提交遵循 conventional commits 格式
|
||||
- [ ] 分支已基于最新的 `dev` rebase
|
||||
|
||||
### PR 标题格式
|
||||
|
||||
使用 [Conventional Commits](https://www.conventionalcommits.org/) 格式:
|
||||
|
||||
```
|
||||
<type>(<scope>): <subject>
|
||||
|
||||
示例:
|
||||
feat(exchange): add OKX exchange integration
|
||||
fix(trader): resolve position tracking bug
|
||||
docs(readme): update installation instructions
|
||||
perf(ai): optimize prompt generation
|
||||
refactor(core): extract common exchange interface
|
||||
```
|
||||
|
||||
**类型:**
|
||||
- `feat` - 新功能
|
||||
- `fix` - Bug 修复
|
||||
- `docs` - 文档
|
||||
- `style` - 代码样式(格式化,无逻辑变更)
|
||||
- `refactor` - 代码重构
|
||||
- `perf` - 性能改进
|
||||
- `test` - 测试更新
|
||||
- `chore` - 构建/配置更改
|
||||
- `ci` - CI/CD 更改
|
||||
- `security` - 安全改进
|
||||
|
||||
### PR 描述
|
||||
|
||||
使用 [PR 模板](../../../.github/PULL_REQUEST_TEMPLATE.md)并确保:
|
||||
|
||||
1. **清晰描述**更改内容和原因
|
||||
2. **变更类型**已标记
|
||||
3. **相关 issue** 已链接
|
||||
4. **测试步骤**已记录
|
||||
5. UI 更改有**截图**
|
||||
6. **所有复选框**已完成
|
||||
|
||||
### PR 大小
|
||||
|
||||
保持 PR 专注且大小合理:
|
||||
|
||||
- ✅ **小型 PR**(< 300 行):理想,审核快速
|
||||
- ⚠️ **中型 PR**(300-1000 行):可接受,可能需要更长时间
|
||||
- ❌ **大型 PR**(> 1000 行):请拆分为更小的 PR
|
||||
|
||||
---
|
||||
|
||||
## 💻 编码规范
|
||||
|
||||
### Go 代码
|
||||
|
||||
```go
|
||||
// ✅ 好:清晰的命名,正确的错误处理
|
||||
func ConnectToExchange(apiKey, secret string) (*Exchange, error) {
|
||||
if apiKey == "" || secret == "" {
|
||||
return nil, fmt.Errorf("API credentials are required")
|
||||
}
|
||||
|
||||
client, err := createClient(apiKey, secret)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create client: %w", err)
|
||||
}
|
||||
|
||||
return &Exchange{client: client}, nil
|
||||
}
|
||||
|
||||
// ❌ 差:糟糕的命名,没有错误处理
|
||||
func ce(a, s string) *Exchange {
|
||||
c := createClient(a, s)
|
||||
return &Exchange{client: c}
|
||||
}
|
||||
```
|
||||
|
||||
**最佳实践:**
|
||||
- 使用有意义的变量名
|
||||
- 显式处理所有错误
|
||||
- 为复杂逻辑添加注释
|
||||
- 遵循 Go 习惯用法和约定
|
||||
- 提交前运行 `go fmt`
|
||||
- 使用 `go vet` 和 `golangci-lint`
|
||||
|
||||
### TypeScript/React 代码
|
||||
|
||||
```typescript
|
||||
// ✅ 好:类型安全,清晰的命名
|
||||
interface TraderConfig {
|
||||
id: string;
|
||||
exchange: 'binance' | 'hyperliquid' | 'aster';
|
||||
aiModel: string;
|
||||
enabled: boolean;
|
||||
}
|
||||
|
||||
const TraderCard: React.FC<{ trader: TraderConfig }> = ({ trader }) => {
|
||||
const [isRunning, setIsRunning] = useState(false);
|
||||
|
||||
const handleStart = async () => {
|
||||
try {
|
||||
await startTrader(trader.id);
|
||||
setIsRunning(true);
|
||||
} catch (error) {
|
||||
console.error('Failed to start trader:', error);
|
||||
}
|
||||
};
|
||||
|
||||
return <div>...</div>;
|
||||
};
|
||||
|
||||
// ❌ 差:没有类型,不清晰的命名
|
||||
const TC = (props) => {
|
||||
const [r, setR] = useState(false);
|
||||
const h = () => { startTrader(props.t.id); setR(true); };
|
||||
return <div>...</div>;
|
||||
};
|
||||
```
|
||||
|
||||
**最佳实践:**
|
||||
- 使用 TypeScript 严格模式
|
||||
- 为所有数据结构定义接口
|
||||
- 避免使用 `any` 类型
|
||||
- 使用带 hooks 的函数式组件
|
||||
- 遵循 React 最佳实践
|
||||
- 提交前运行 `npm run lint`
|
||||
|
||||
### 文件结构
|
||||
|
||||
```
|
||||
NOFX/
|
||||
├── cmd/ # 主应用程序
|
||||
├── internal/ # 私有代码
|
||||
│ ├── exchange/ # 交易所适配器
|
||||
│ ├── trader/ # 交易逻辑
|
||||
│ ├── ai/ # AI 集成
|
||||
│ └── api/ # API 处理器
|
||||
├── pkg/ # 公共库
|
||||
├── web/ # 前端
|
||||
│ ├── src/
|
||||
│ │ ├── components/
|
||||
│ │ ├── pages/
|
||||
│ │ ├── hooks/
|
||||
│ │ └── utils/
|
||||
│ └── public/
|
||||
└── docs/ # 文档
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📋 提交信息指南
|
||||
|
||||
### 格式
|
||||
|
||||
```
|
||||
<type>(<scope>): <subject>
|
||||
|
||||
<body>
|
||||
|
||||
<footer>
|
||||
```
|
||||
|
||||
### 示例
|
||||
|
||||
```
|
||||
feat(exchange): add OKX futures API integration
|
||||
|
||||
- Implement order placement and cancellation
|
||||
- Add balance and position retrieval
|
||||
- Support leverage configuration
|
||||
|
||||
Closes #123
|
||||
```
|
||||
|
||||
```
|
||||
fix(trader): prevent duplicate position opening
|
||||
|
||||
The trader was opening multiple positions in the same direction
|
||||
for the same symbol. Added check to prevent this behavior.
|
||||
|
||||
Fixes #456
|
||||
```
|
||||
|
||||
```
|
||||
docs: update Docker deployment guide
|
||||
|
||||
- Add troubleshooting section
|
||||
- Update environment variables
|
||||
- Add examples for common scenarios
|
||||
```
|
||||
|
||||
### 规则
|
||||
|
||||
- 使用现在时("add" 而非 "added")
|
||||
- 使用祈使语气("move" 而非 "moves")
|
||||
- 第一行 ≤ 72 字符
|
||||
- 引用 issue 和 PR
|
||||
- 解释"是什么"和"为什么",而非"如何做"
|
||||
|
||||
---
|
||||
|
||||
## 🔍 审核流程
|
||||
|
||||
### 时间线
|
||||
|
||||
- **初次审核:** 2-3 个工作日内
|
||||
- **后续审核:** 1-2 个工作日内
|
||||
- **悬赏 PR:** 1 个工作日内优先审核
|
||||
|
||||
### 审核标准
|
||||
|
||||
审核者将检查:
|
||||
|
||||
1. **功能性**
|
||||
- 是否按预期工作?
|
||||
- 边界情况是否处理?
|
||||
- 现有功能没有退化?
|
||||
|
||||
2. **代码质量**
|
||||
- 遵循编码规范?
|
||||
- 结构良好且可读?
|
||||
- 正确的错误处理?
|
||||
|
||||
3. **测试**
|
||||
- 测试覆盖率足够?
|
||||
- CI 中测试通过?
|
||||
- 手动测试已记录?
|
||||
|
||||
4. **文档**
|
||||
- 需要的地方有代码注释?
|
||||
- README/文档已更新?
|
||||
- API 变更已记录?
|
||||
|
||||
5. **安全性**
|
||||
- 没有硬编码的密钥?
|
||||
- 输入验证?
|
||||
- 没有已知漏洞?
|
||||
|
||||
### 回应反馈
|
||||
|
||||
- 处理所有审核评论
|
||||
- 不清楚时提问
|
||||
- 标记对话为已解决
|
||||
- 更改后重新请求审核
|
||||
|
||||
### 批准和合并
|
||||
|
||||
- 需要维护者 **1 个批准**
|
||||
- 所有 CI 检查必须通过
|
||||
- 没有未解决的对话
|
||||
- 维护者将合并(小型 PR 使用 squash merge,功能使用 merge commit)
|
||||
|
||||
---
|
||||
|
||||
## 💰 悬赏计划
|
||||
|
||||
### 工作方式
|
||||
|
||||
1. 查看[悬赏 issue](https://github.com/tinkle-community/nofx/labels/bounty)
|
||||
2. 评论认领(先到先得)
|
||||
3. 在截止日期前完成工作
|
||||
4. 提交 PR 并填写悬赏认领部分
|
||||
5. 合并后获得报酬
|
||||
|
||||
### 指南
|
||||
|
||||
- 阅读[悬赏指南](../../community/bounty-guide.md)
|
||||
- 满足所有验收标准
|
||||
- 包含演示视频/截图
|
||||
- 遵循所有贡献指南
|
||||
- 私下讨论付款详情
|
||||
|
||||
---
|
||||
|
||||
## ❓ 问题?
|
||||
|
||||
- **一般问题:** 加入我们的 [Telegram 社区](https://t.me/nofx_dev_community)
|
||||
- **技术问题:** 开启[讨论](https://github.com/tinkle-community/nofx/discussions)
|
||||
- **安全问题:** 查看[安全政策](../../../SECURITY.md)
|
||||
- **Bug 报告:** 使用 [Bug 报告模板](../../../.github/ISSUE_TEMPLATE/bug_report.md)
|
||||
|
||||
---
|
||||
|
||||
## 📚 其他资源
|
||||
|
||||
- [项目路线图](../../roadmap/README.zh-CN.md)
|
||||
- [架构文档](../../architecture/README.zh-CN.md)
|
||||
- [API 文档](../../api/README.md)
|
||||
- [部署指南](../../getting-started/docker-deploy.zh-CN.md)
|
||||
|
||||
---
|
||||
|
||||
## 🙏 感谢你!
|
||||
|
||||
你的贡献让 NOFX 变得更好。我们感谢你的时间和努力!
|
||||
|
||||
**编码愉快!🚀**
|
||||
@@ -6,10 +6,38 @@
|
||||
[](LICENSE)
|
||||
[](https://amber.ac)
|
||||
|
||||
**语言 / Languages:** [English](README.md) | [中文](README.zh-CN.md) | [Українська](README.uk.md) | [Русский](README.ru.md)
|
||||
**语言 / Languages:** [English](../../../README.md) | [中文](../zh-CN/README.md) | [Українська](../uk/README.md) | [Русский](../ru/README.md)
|
||||
|
||||
**官方推特:** [@nofx_ai](https://x.com/nofx_ai)
|
||||
|
||||
**📚 文档中心:** [文档首页](../../README.md) | [快速开始](../../getting-started/README.zh-CN.md) | [更新日志](../../../CHANGELOG.zh-CN.md) | [社区指南](../../community/README.md)
|
||||
|
||||
---
|
||||
|
||||
## 📑 目录
|
||||
|
||||
- [🚀 通用AI交易操作系统](#-通用ai交易操作系统)
|
||||
- [👥 开发者社区](#-开发者社区)
|
||||
- [🆕 最新更新](#-最新更新)
|
||||
- [📸 系统截图](#-系统截图)
|
||||
- [✨ 当前实现](#-当前实现---加密货币市场)
|
||||
- [🔮 路线图](#-路线图---通用市场扩展)
|
||||
- [🏗️ 技术架构](#️-技术架构)
|
||||
- [💰 注册币安账户](#-注册币安账户省手续费)
|
||||
- [🚀 快速开始](#-快速开始)
|
||||
- [📖 AI决策流程](#-ai决策流程)
|
||||
- [🧠 AI自我学习示例](#-ai自我学习示例)
|
||||
- [📊 Web界面功能](#-web界面功能)
|
||||
- [🎛️ API接口](#️-api接口)
|
||||
- [📝 决策日志格式](#-决策日志格式)
|
||||
- [🔧 风险控制详解](#-风险控制详解)
|
||||
- [⚠️ 重要风险提示](#️-重要风险提示)
|
||||
- [🛠️ 常见问题](#️-常见问题)
|
||||
- [📈 性能优化建议](#-性能优化建议)
|
||||
- [🔄 更新日志](#-更新日志)
|
||||
- [📄 开源协议](#-开源协议)
|
||||
- [🤝 贡献指南](#-贡献指南)
|
||||
|
||||
---
|
||||
|
||||
## 🚀 通用AI交易操作系统
|
||||
@@ -109,11 +137,11 @@ NOFX现已支持**三大交易所**:Binance、Hyperliquid和Aster DEX!
|
||||
## 📸 系统截图
|
||||
|
||||
### 🏆 竞赛模式 - AI实时对战
|
||||

|
||||

|
||||
*多AI排行榜和实时性能对比图表,展示Qwen vs DeepSeek实时交易对战*
|
||||
|
||||
### 📊 交易详情 - 完整交易仪表盘
|
||||

|
||||

|
||||
*专业交易界面,包含权益曲线、实时持仓、AI决策日志,支持展开查看输入提示词和AI思维链推理过程*
|
||||
|
||||
---
|
||||
@@ -168,78 +196,50 @@ NOFX 目前已在**加密货币市场全面运行**,具备以下经过验证
|
||||
|
||||
## 🔮 路线图 - 通用市场扩展
|
||||
|
||||
我们经过验证的加密货币基础设施正在扩展到:
|
||||
NOFX 的使命是成为所有金融市场的**通用 AI 交易操作系统**。
|
||||
|
||||
- **📈 股票市场**:美股、A股、港股
|
||||
- **📊 期货市场**:商品期货、指数期货
|
||||
- **🎯 期权交易**:股票期权、加密期权
|
||||
- **💱 外汇市场**:主要货币对、交叉盘
|
||||
**愿景:** 相同架构。相同智能体框架。所有市场。
|
||||
|
||||
**相同架构。相同智能体框架。所有市场。**
|
||||
**扩展市场:**
|
||||
- 📈 **股票市场**:美股、A股、港股
|
||||
- 📊 **期货市场**:商品期货、指数期货
|
||||
- 🎯 **期权交易**:股票期权、加密期权
|
||||
- 💱 **外汇市场**:主要货币对、交叉盘
|
||||
|
||||
**即将推出的功能:**
|
||||
- 增强AI能力(GPT-4、Claude 3、Gemini Pro、灵活prompt模板)
|
||||
- 新交易所集成(OKX、Bybit、Lighter、EdgeX + CEX/Perp-DEX)
|
||||
- 项目结构重构(高内聚低耦合、SOLID原则)
|
||||
- 安全性增强(API密钥AES-256加密、RBAC、2FA改进)
|
||||
- 用户体验改进(移动端响应式、TradingView图表、告警系统)
|
||||
|
||||
📖 **详细路线图和时间表,请参阅:**
|
||||
- **中文:** [路线图文档](../../roadmap/README.zh-CN.md)
|
||||
- **English:** [Roadmap Documentation](../../roadmap/README.md)
|
||||
|
||||
---
|
||||
|
||||
## 🏗️ 技术架构
|
||||
|
||||
```
|
||||
nofx/
|
||||
├── main.go # 程序入口(多trader管理器)
|
||||
├── config.json # 配置文件(API密钥、~~多trader配置~~)(交易员配置通过Web界面)
|
||||
│
|
||||
├── api/ # HTTP API服务
|
||||
│ └── server.go # Gin框架,RESTful API
|
||||
│
|
||||
├── trader/ # 交易核心
|
||||
│ ├── auto_trader.go # 自动交易主控(单trader)
|
||||
│ └── binance_futures.go # 币安合约API封装
|
||||
│
|
||||
├── manager/ # 多trader管理
|
||||
│ └── trader_manager.go # 管理多个trader实例
|
||||
│
|
||||
├── mcp/ # Model Context Protocol - AI通信
|
||||
│ └── client.go # AI API客户端(DeepSeek/Qwen集成)
|
||||
│
|
||||
├── decision/ # AI决策引擎
|
||||
│ └── engine.go # 决策逻辑(含历史反馈)
|
||||
│
|
||||
├── market/ # 市场数据获取
|
||||
│ └── data.go # 市场数据与技术指标(K线、RSI、MACD)
|
||||
│
|
||||
├── pool/ # 币种池管理
|
||||
│ └── coin_pool.go # AI500 + OI Top合并池
|
||||
│
|
||||
├── logger/ # 日志系统
|
||||
│ └── decision_logger.go # 决策记录 + 表现分析
|
||||
│
|
||||
├── decision_logs/ # 决策日志存储
|
||||
│ ├── qwen_trader/ # Qwen trader日志
|
||||
│ └── deepseek_trader/ # DeepSeek trader日志
|
||||
│
|
||||
└── web/ # React前端
|
||||
├── src/
|
||||
│ ├── components/ # React组件
|
||||
│ │ ├── EquityChart.tsx # 收益率曲线图
|
||||
│ │ ├── ComparisonChart.tsx # 多AI对比图
|
||||
│ │ └── CompetitionPage.tsx # 竞赛排行榜
|
||||
│ ├── lib/api.ts # API调用封装
|
||||
│ ├── types/index.ts # TypeScript类型
|
||||
│ ├── index.css # Binance风格样式
|
||||
│ └── App.tsx # 主应用
|
||||
└── package.json
|
||||
```
|
||||
NOFX 采用现代化的模块化架构:
|
||||
|
||||
### 核心依赖
|
||||
- **后端:** Go + Gin 框架,SQLite 数据库
|
||||
- **前端:** React 18 + TypeScript + Vite + TailwindCSS
|
||||
- **多交易所支持:** Binance、Hyperliquid、Aster DEX
|
||||
- **AI 集成:** DeepSeek、Qwen 及自定义 OpenAI 兼容 API
|
||||
- **状态管理:** 前端 Zustand,后端数据库驱动
|
||||
- **实时更新:** SWR,5-10 秒轮询间隔
|
||||
|
||||
**后端 (Go)**
|
||||
- `github.com/adshao/go-binance/v2` - 币安API客户端
|
||||
- `github.com/markcheno/go-talib` - 技术指标计算(TA-Lib)
|
||||
- `github.com/gin-gonic/gin` - HTTP API框架
|
||||
**核心特性:**
|
||||
- 🗄️ 数据库驱动的配置(无需编辑 JSON)
|
||||
- 🔐 JWT 认证,支持可选的 2FA
|
||||
- 📊 实时性能跟踪和分析
|
||||
- 🤖 多 AI 竞赛模式,实时对比
|
||||
- 🔌 RESTful API,完整的配置和监控
|
||||
|
||||
**前端 (React + TypeScript)**
|
||||
- `react` + `react-dom` - UI框架
|
||||
- `recharts` - 图表库(收益率曲线、对比图)
|
||||
- `swr` - 数据获取和缓存
|
||||
- `tailwindcss` - CSS框架
|
||||
📖 **详细架构文档,请查看:**
|
||||
- **中文版:** [架构文档](../../architecture/README.zh-CN.md)
|
||||
- **English:** [Architecture Documentation](../../architecture/README.md)
|
||||
|
||||
---
|
||||
|
||||
@@ -420,9 +420,9 @@ cd ..
|
||||
|
||||
~~**步骤1**:复制并重命名示例配置文件~~
|
||||
|
||||
~~```bash
|
||||
```bash
|
||||
cp config.example.jsonc config.json
|
||||
```~~
|
||||
```
|
||||
|
||||
~~**步骤2**:编辑`config.json`填入您的API密钥~~
|
||||
|
||||
@@ -897,79 +897,73 @@ curl http://localhost:8080/api/health
|
||||
|
||||
每个决策周期(默认3分钟),系统按以下流程运行:
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────────────────────┐
|
||||
│ 1. 📊 分析历史表现(最近20个周期) │
|
||||
├──────────────────────────────────────────────────────────┤
|
||||
│ ✓ 计算整体胜率、平均盈利、盈亏比 │
|
||||
│ ✓ 统计各币种表现(胜率、平均USDT盈亏) │
|
||||
│ ✓ 识别最佳/最差币种 │
|
||||
│ ✓ 列出最近5笔交易详情(含准确盈亏金额) │
|
||||
│ ✓ 计算夏普比率衡量风险调整后收益 │
|
||||
│ 📌 新增 (v2.0.2): 考虑杠杆的准确USDT盈亏计算 │
|
||||
└──────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌──────────────────────────────────────────────────────────┐
|
||||
│ 2. 💰 获取账户状态 │
|
||||
├──────────────────────────────────────────────────────────┤
|
||||
│ • 账户净值、可用余额、未实现盈亏 │
|
||||
│ • 持仓数量、总盈亏(已实现+未实现) │
|
||||
│ • 保证金使用率(current/maximum) │
|
||||
│ • 风险评估指标 │
|
||||
└──────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌──────────────────────────────────────────────────────────┐
|
||||
│ 3. 🔍 分析现有持仓(如果有) │
|
||||
├──────────────────────────────────────────────────────────┤
|
||||
│ • 获取每个持仓的市场数据(3分钟+4小时K线) │
|
||||
│ • 计算技术指标(RSI、MACD、EMA) │
|
||||
│ • 显示持仓时长(例如"持仓时长2小时15分钟") │
|
||||
│ • AI判断是否需要平仓(止盈、止损或调整) │
|
||||
│ 📌 新增 (v2.0.2): 追踪持仓时长帮助AI决策 │
|
||||
└──────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌──────────────────────────────────────────────────────────┐
|
||||
│ 4. 🎯 评估新机会(候选币种池) │
|
||||
├──────────────────────────────────────────────────────────┤
|
||||
│ • 获取AI500高评分币种(前20个) │
|
||||
│ • 获取OI Top持仓增长币种(前20个) │
|
||||
│ • 合并去重,过滤低流动性币种(持仓量<15M USD) │
|
||||
│ • 批量获取市场数据和技术指标 │
|
||||
│ • 为每个候选币种准备完整的原始数据序列 │
|
||||
└──────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌──────────────────────────────────────────────────────────┐
|
||||
│ 5. 🧠 AI综合决策 │
|
||||
├──────────────────────────────────────────────────────────┤
|
||||
│ • 查看历史反馈(胜率、盈亏比、最佳/最差币种) │
|
||||
│ • 接收所有原始序列数据(K线、指标、持仓量) │
|
||||
│ • Chain of Thought 思维链分析 │
|
||||
│ • 输出决策:平仓/开仓/持有/观望 │
|
||||
│ • 包含杠杆、仓位、止损、止盈参数 │
|
||||
│ 📌 新增 (v2.0.2): AI可自由分析原始序列,不受预定义指标限制 │
|
||||
└──────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌──────────────────────────────────────────────────────────┐
|
||||
│ 6. ⚡ 执行交易 │
|
||||
├──────────────────────────────────────────────────────────┤
|
||||
│ • 优先级排序:先平仓,再开仓 │
|
||||
│ • 精度自动适配(LOT_SIZE规则) │
|
||||
│ • 防止仓位叠加(同币种同方向拒绝开仓) │
|
||||
│ • 平仓后自动取消所有挂单 │
|
||||
│ • 记录开仓时间用于持仓时长追踪 │
|
||||
│ 📌 新增 (v2.0.2): 追踪持仓开仓时间 │
|
||||
└──────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌──────────────────────────────────────────────────────────┐
|
||||
│ 7. 📝 记录日志 │
|
||||
├──────────────────────────────────────────────────────────┤
|
||||
│ • 保存完整决策记录到 decision_logs/ │
|
||||
│ • 包含思维链、决策JSON、账户快照、执行结果 │
|
||||
│ • 存储完整持仓数据(数量、杠杆、开/平仓时间) │
|
||||
│ • 使用symbol_side键值防止多空冲突 │
|
||||
│ 📌 新增 (v2.0.2): 防止多空持仓冲突,考虑数量+杠杆 │
|
||||
└──────────────────────────────────────────────────────────┘
|
||||
```
|
||||
### 步骤1: 📊 分析历史表现(最近20个周期)
|
||||
- ✓ 计算整体胜率、平均盈利、盈亏比
|
||||
- ✓ 统计各币种表现(胜率、平均USDT盈亏)
|
||||
- ✓ 识别最佳/最差币种
|
||||
- ✓ 列出最近5笔交易详情(含准确盈亏金额)
|
||||
- ✓ 计算夏普比率衡量风险调整后收益
|
||||
- 📌 **新增 (v2.0.2)**: 考虑杠杆的准确USDT盈亏计算
|
||||
|
||||
**↓**
|
||||
|
||||
### 步骤2: 💰 获取账户状态
|
||||
- 账户净值、可用余额、未实现盈亏
|
||||
- 持仓数量、总盈亏(已实现+未实现)
|
||||
- 保证金使用率(current/maximum)
|
||||
- 风险评估指标
|
||||
|
||||
**↓**
|
||||
|
||||
### 步骤3: 🔍 分析现有持仓(如果有)
|
||||
- 获取每个持仓的市场数据(3分钟+4小时K线)
|
||||
- 计算技术指标(RSI、MACD、EMA)
|
||||
- 显示持仓时长(例如"持仓时长2小时15分钟")
|
||||
- AI判断是否需要平仓(止盈、止损或调整)
|
||||
- 📌 **新增 (v2.0.2)**: 追踪持仓时长帮助AI决策
|
||||
|
||||
**↓**
|
||||
|
||||
### 步骤4: 🎯 评估新机会(候选币种池)
|
||||
- 获取币种池(2种模式):
|
||||
- 🌟 **默认模式**: BTC、ETH、SOL、BNB、XRP等
|
||||
- ⚙️ **高级模式**: AI500(前20) + OI Top(前20)
|
||||
- 合并去重,过滤低流动性币种(持仓量<15M USD)
|
||||
- 批量获取市场数据和技术指标
|
||||
- 为每个候选币种准备完整的原始数据序列
|
||||
|
||||
**↓**
|
||||
|
||||
### 步骤5: 🧠 AI综合决策
|
||||
- 查看历史反馈(胜率、盈亏比、最佳/最差币种)
|
||||
- 接收所有原始序列数据(K线、指标、持仓量)
|
||||
- Chain of Thought 思维链分析
|
||||
- 输出决策:平仓/开仓/持有/观望
|
||||
- 包含杠杆、仓位、止损、止盈参数
|
||||
- 📌 **新增 (v2.0.2)**: AI可自由分析原始序列,不受预定义指标限制
|
||||
|
||||
**↓**
|
||||
|
||||
### 步骤6: ⚡ 执行交易
|
||||
- 优先级排序:先平仓,再开仓
|
||||
- 精度自动适配(LOT_SIZE规则)
|
||||
- 防止仓位叠加(同币种同方向拒绝开仓)
|
||||
- 平仓后自动取消所有挂单
|
||||
- 记录开仓时间用于持仓时长追踪
|
||||
- 📌 追踪持仓开仓时间
|
||||
|
||||
**↓**
|
||||
|
||||
### 步骤7: 📝 记录日志
|
||||
- 保存完整决策记录到 `decision_logs/`
|
||||
- 包含思维链、决策JSON、账户快照、执行结果
|
||||
- 存储完整持仓数据(数量、杠杆、开/平仓时间)
|
||||
- 使用 `symbol_side` 键值防止多空冲突
|
||||
- 📌 **新增 (v2.0.2)**: 防止多空持仓冲突,考虑数量+杠杆
|
||||
|
||||
**↓**
|
||||
|
||||
**🔄 (每3-5分钟重复一次)**
|
||||
|
||||
### v2.0.2的核心改进
|
||||
|
||||
@@ -1248,77 +1242,19 @@ sudo apt-get install libta-lib0-dev
|
||||
|
||||
## 🔄 更新日志
|
||||
|
||||
### v2.0.2 (2025-10-29)
|
||||
📖 **详细的版本历史和更新,请查看:**
|
||||
|
||||
**关键Bug修复 - 交易历史记录与性能分析:**
|
||||
- **中文版:** [CHANGELOG.zh-CN.md](../../../CHANGELOG.zh-CN.md)
|
||||
- **English:** [CHANGELOG.md](../../../CHANGELOG.md)
|
||||
|
||||
本版本修复了历史交易记录和性能分析系统中的**严重计算错误**,这些错误严重影响了盈利统计的准确性。
|
||||
**最新版本:** v3.0.0 (2025-10-30) - 重大架构变革
|
||||
|
||||
**1. 盈亏计算 - 重大错误修复** (logger/decision_logger.go)
|
||||
- **问题**:之前只用百分比计算盈亏,完全忽略了仓位大小和杠杆倍数
|
||||
- 示例:100 USDT仓位赚5%和1000 USDT仓位赚5%都显示`5.0`作为盈利
|
||||
- 这导致性能分析完全不准确
|
||||
- **解决方案**:现在计算实际USDT盈亏金额
|
||||
```
|
||||
盈亏(USDT) = 仓位价值 × 价格变化% × 杠杆倍数
|
||||
示例: 1000 USDT × 5% × 20倍 = 1000 USDT实际盈利
|
||||
```
|
||||
- **影响**:胜率、盈亏比和夏普比率现在基于准确的USDT金额计算
|
||||
|
||||
**2. 持仓追踪 - 缺失关键数据**
|
||||
- **问题**:开仓记录只存储了价格和时间,缺少数量和杠杆
|
||||
- **解决方案**:现在存储完整交易数据:
|
||||
- `quantity`: 持仓数量(币数)
|
||||
- `leverage`: 杠杆倍数(如20倍)
|
||||
- 这些是准确计算盈亏的必要数据
|
||||
|
||||
**3. 持仓键值逻辑 - 多空冲突**
|
||||
- **问题**:使用`symbol`作为持仓键值,导致同时持有多空仓时数据冲突
|
||||
- 示例:BTCUSDT多头和BTCUSDT空头会互相覆盖
|
||||
- **解决方案**:改为`symbol_side`格式(如`BTCUSDT_long`、`BTCUSDT_short`)
|
||||
- 现在可以正确区分多空持仓
|
||||
|
||||
**4. 夏普比率计算 - 代码优化**
|
||||
- **问题**:使用自定义的牛顿迭代法计算平方根
|
||||
- **解决方案**:替换为标准库`math.Sqrt`
|
||||
- 更可靠、易维护且高效
|
||||
|
||||
**为什么这次更新很重要:**
|
||||
- ✅ 历史交易统计现在显示**真实的USDT盈亏**而不是无意义的百分比
|
||||
- ✅ 不同杠杆倍数的交易对比现在准确了
|
||||
- ✅ AI自我学习机制接收到正确的历史反馈
|
||||
- ✅ 盈亏比和夏普比率计算现在有意义了
|
||||
- ✅ 多持仓追踪(同时持有多空)现在正常工作
|
||||
|
||||
**建议**:如果您在此更新前运行过系统,您的历史统计数据是不准确的。更新到v2.0.2后,新的交易将被正确计算。
|
||||
|
||||
### v2.0.1 (2025-10-29)
|
||||
|
||||
**Bug修复:**
|
||||
- ✅ 修复ComparisonChart数据处理逻辑 - 从cycle_number分组改为timestamp分组
|
||||
- ✅ 解决后端重启导致cycle_number重置时图表冻结的问题
|
||||
- ✅ 改进图表数据显示 - 现在按时间顺序显示所有历史数据点
|
||||
- ✅ 增强调试日志,便于问题排查
|
||||
|
||||
### v2.0.0 (2025-10-28)
|
||||
|
||||
**重大更新:**
|
||||
- ✅ AI自我学习机制(历史反馈、表现分析)
|
||||
- ✅ 多Trader竞赛模式(Qwen vs DeepSeek)
|
||||
- ✅ Binance风格UI(完整模仿币安界面)
|
||||
- ✅ 性能对比图表(收益率实时对比)
|
||||
- ✅ 风险控制优化(单币种仓位上限调整)
|
||||
|
||||
**Bug修复:**
|
||||
- 修复初始余额硬编码问题
|
||||
- 修复多trader数据同步问题
|
||||
- 优化图表数据对齐(使用cycle_number)
|
||||
|
||||
### v1.0.0 (2025-10-27)
|
||||
- 初始版本发布
|
||||
- 基础AI交易功能
|
||||
- 决策日志系统
|
||||
- 简单Web界面
|
||||
**近期亮点:**
|
||||
- 🚀 完整系统重新设计,基于Web的配置平台
|
||||
- 🗄️ 数据库驱动架构(SQLite)
|
||||
- 🎨 无需编辑JSON - 全部通过Web界面配置
|
||||
- 🔧 AI模型与交易所任意组合
|
||||
- 📊 增强的API层,提供全面的端点
|
||||
|
||||
---
|
||||
|
||||
398
docs/maintainers/PROJECT_MANAGEMENT.md
Normal file
398
docs/maintainers/PROJECT_MANAGEMENT.md
Normal file
@@ -0,0 +1,398 @@
|
||||
# 📊 Project Management Guide
|
||||
|
||||
**Language:** [English](PROJECT_MANAGEMENT.md) | [中文](PROJECT_MANAGEMENT.zh-CN.md)
|
||||
|
||||
This guide explains how we manage the NOFX project, track progress, and prioritize work.
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Project Structure
|
||||
|
||||
### GitHub Projects
|
||||
|
||||
We use **GitHub Projects (Beta)** with these boards:
|
||||
|
||||
#### 1. **NOFX Development Board**
|
||||
|
||||
**Columns:**
|
||||
```
|
||||
Backlog → Triaged → In Progress → In Review → Done
|
||||
```
|
||||
|
||||
**Views:**
|
||||
- 📋 **All Issues** - Kanban view of all work items
|
||||
- 🏃 **Sprint** - Current sprint items (2-week sprints)
|
||||
- 🗺️ **Roadmap** - Timeline view by roadmap phase
|
||||
- 🏷️ **By Area** - Grouped by area labels
|
||||
- 🔥 **Priority** - Sorted by priority (critical/high/medium/low)
|
||||
- 👥 **By Assignee** - Grouped by assigned maintainer
|
||||
|
||||
#### 2. **Bounty Program Board**
|
||||
|
||||
**Columns:**
|
||||
```
|
||||
Available → Claimed → In Progress → Under Review → Paid
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📅 Sprint Planning (Bi-weekly)
|
||||
|
||||
### Sprint Schedule
|
||||
|
||||
**Sprint Duration:** 2 weeks
|
||||
**Sprint Planning:** Every other Monday
|
||||
**Sprint Review:** Every other Friday
|
||||
|
||||
### Planning Process
|
||||
|
||||
**Monday - Sprint Planning (1 hour):**
|
||||
|
||||
1. **Review previous sprint** (15 min)
|
||||
- What was completed?
|
||||
- What was not completed and why?
|
||||
- Metrics review
|
||||
|
||||
2. **Prioritize backlog** (20 min)
|
||||
- Review new issues/PRs
|
||||
- Update priorities based on roadmap
|
||||
- Assign labels
|
||||
|
||||
3. **Plan next sprint** (25 min)
|
||||
- Select items for next sprint
|
||||
- Assign to maintainers
|
||||
- Set clear acceptance criteria
|
||||
- Estimate effort (S/M/L)
|
||||
|
||||
**Friday - Sprint Review (30 min):**
|
||||
|
||||
1. **Demo completed work** (15 min)
|
||||
- Show merged PRs
|
||||
- Demonstrate new features
|
||||
|
||||
2. **Retrospective** (15 min)
|
||||
- What went well?
|
||||
- What can improve?
|
||||
- Action items for next sprint
|
||||
|
||||
---
|
||||
|
||||
## 🏷️ Issue Triage Process
|
||||
|
||||
### Daily Triage (Mon-Fri, 15 min)
|
||||
|
||||
Review new issues and PRs:
|
||||
|
||||
1. **Verify completeness**
|
||||
- Template filled properly?
|
||||
- Reproduction steps clear (for bugs)?
|
||||
- Use case explained (for features)?
|
||||
|
||||
2. **Apply labels**
|
||||
```yaml
|
||||
Priority:
|
||||
- priority: critical # Security, data loss, production down
|
||||
- priority: high # Major bugs, high-value features
|
||||
- priority: medium # Regular bugs, standard features
|
||||
- priority: low # Nice-to-have, minor improvements
|
||||
|
||||
Type:
|
||||
- type: bug
|
||||
- type: feature
|
||||
- type: enhancement
|
||||
- type: documentation
|
||||
- type: security
|
||||
|
||||
Area:
|
||||
- area: exchange
|
||||
- area: ai
|
||||
- area: frontend
|
||||
- area: backend
|
||||
- area: security
|
||||
- area: ui/ux
|
||||
|
||||
Roadmap:
|
||||
- roadmap: phase-1 # Core Infrastructure
|
||||
- roadmap: phase-2 # Testing & Stability
|
||||
- roadmap: phase-3 # Universal Markets
|
||||
```
|
||||
|
||||
3. **Assign or tag for discussion**
|
||||
- Can handle immediately? Assign to maintainer
|
||||
- Needs discussion? Tag for next planning session
|
||||
- Needs more info? Request from author
|
||||
|
||||
4. **Close if needed**
|
||||
- Duplicate? Close with link to original
|
||||
- Invalid? Close with explanation
|
||||
- Out of scope? Close politely with reasoning
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Priority Decision Matrix
|
||||
|
||||
Use this matrix to decide priority:
|
||||
|
||||
| Impact / Urgency | High Urgency | Medium Urgency | Low Urgency |
|
||||
|------------------|--------------|----------------|-------------|
|
||||
| **High Impact** | 🔴 Critical | 🔴 Critical | 🟡 High |
|
||||
| **Medium Impact** | 🔴 Critical | 🟡 High | 🟢 Medium |
|
||||
| **Low Impact** | 🟡 High | 🟢 Medium | ⚪ Low |
|
||||
|
||||
**Impact:**
|
||||
- High: Affects core functionality, security, or many users
|
||||
- Medium: Affects specific features or moderate users
|
||||
- Low: Nice-to-have, minor improvements
|
||||
|
||||
**Urgency:**
|
||||
- High: Needs immediate attention
|
||||
- Medium: Should be addressed soon
|
||||
- Low: Can wait for natural inclusion
|
||||
|
||||
---
|
||||
|
||||
## 📊 Roadmap Alignment
|
||||
|
||||
All work should align with our [roadmap](../roadmap/README.md):
|
||||
|
||||
### Phase 1: Core Infrastructure (Current Focus)
|
||||
|
||||
**Must Accept:**
|
||||
- Security enhancements
|
||||
- AI model integrations
|
||||
- Exchange integrations (OKX, Bybit, Lighter, EdgeX)
|
||||
- Project structure refactoring
|
||||
- UI/UX improvements
|
||||
|
||||
**Can Accept:**
|
||||
- Related bug fixes
|
||||
- Documentation improvements
|
||||
- Performance optimizations
|
||||
|
||||
**Should Defer:**
|
||||
- Universal market expansion (stocks, futures)
|
||||
- Advanced AI features (RL, multi-agent)
|
||||
- Enterprise features
|
||||
|
||||
### Phase 2-5: Future Work
|
||||
|
||||
Mark with appropriate `roadmap: phase-X` label and add to backlog.
|
||||
|
||||
---
|
||||
|
||||
## 🎫 Issue Templates
|
||||
|
||||
We have these issue templates:
|
||||
|
||||
### 1. Bug Report
|
||||
- Use for bugs and errors
|
||||
- Must include reproduction steps
|
||||
- Label: `type: bug`
|
||||
|
||||
### 2. Feature Request
|
||||
- Use for new features
|
||||
- Must include use case and benefits
|
||||
- Label: `type: feature`
|
||||
|
||||
### 3. Bounty Claim
|
||||
- Use when claiming a bounty
|
||||
- Must reference bounty issue
|
||||
- Label: `bounty: claimed`
|
||||
|
||||
### 4. Security Vulnerability
|
||||
- Use for security issues (private)
|
||||
- Follow responsible disclosure
|
||||
- Label: `type: security`
|
||||
|
||||
**Missing a template?**
|
||||
- Use blank issue
|
||||
- Maintainers will convert to appropriate template
|
||||
|
||||
---
|
||||
|
||||
## 📈 Metrics We Track
|
||||
|
||||
### Weekly Metrics
|
||||
|
||||
- **PR Metrics:**
|
||||
- Number of PRs opened
|
||||
- Number of PRs merged
|
||||
- Average time to first review
|
||||
- Average time to merge
|
||||
|
||||
- **Issue Metrics:**
|
||||
- Number of issues opened
|
||||
- Number of issues closed
|
||||
- Issue backlog size
|
||||
- Issues by priority/type/area
|
||||
|
||||
- **Community Metrics:**
|
||||
- New contributors
|
||||
- Active contributors
|
||||
- Community engagement (comments, reactions)
|
||||
|
||||
### Monthly Metrics
|
||||
|
||||
- **Roadmap Progress:**
|
||||
- % completion per phase
|
||||
- Items completed vs planned
|
||||
- Blockers and risks
|
||||
|
||||
- **Code Quality:**
|
||||
- Test coverage
|
||||
- Code review comments per PR
|
||||
- Bug fix vs feature ratio
|
||||
|
||||
- **Bounty Program:**
|
||||
- Bounties created
|
||||
- Bounties claimed
|
||||
- Bounties paid
|
||||
- Average completion time
|
||||
|
||||
---
|
||||
|
||||
## 🤖 Automation
|
||||
|
||||
We use GitHub Actions for automation:
|
||||
|
||||
### PR Automation
|
||||
|
||||
- **Automatic labeling** based on files changed
|
||||
- **PR size labeling** (small/medium/large)
|
||||
- **CI checks** (tests, linting, build)
|
||||
- **Security scans** (Trivy, Gitleaks)
|
||||
- **Conventional commit validation**
|
||||
|
||||
### Issue Automation
|
||||
|
||||
- **Stale issue detection** (closes after 30 days inactive)
|
||||
- **Automatic bounty labeling** when "bounty" keyword used
|
||||
- **Duplicate detection** using issue similarity
|
||||
|
||||
### Release Automation
|
||||
|
||||
- **Changelog generation** from conventional commits
|
||||
- **Version bumping** based on commit types
|
||||
- **Release notes** auto-generated
|
||||
- **Deployment** to staging/production
|
||||
|
||||
---
|
||||
|
||||
## 🔄 Regular Tasks
|
||||
|
||||
### Daily
|
||||
- ✅ Triage new issues/PRs
|
||||
- ✅ Review urgent PRs
|
||||
- ✅ Respond to community questions
|
||||
|
||||
### Weekly
|
||||
- ✅ Sprint planning (Monday)
|
||||
- ✅ Sprint review (Friday)
|
||||
- ✅ Review metrics dashboard
|
||||
- ✅ Update project boards
|
||||
|
||||
### Monthly
|
||||
- ✅ Roadmap progress review
|
||||
- ✅ Community update post
|
||||
- ✅ Bounty program review
|
||||
- ✅ Dependency updates
|
||||
- ✅ Security audit
|
||||
|
||||
### Quarterly
|
||||
- ✅ Roadmap update
|
||||
- ✅ Major release planning
|
||||
- ✅ Contributor recognition
|
||||
- ✅ Documentation audit
|
||||
|
||||
---
|
||||
|
||||
## 📞 Communication Channels
|
||||
|
||||
### Internal (Maintainers)
|
||||
|
||||
- **GitHub Discussions:** Architecture decisions, RFC
|
||||
- **Private channel:** Sensitive discussions, bounty payments
|
||||
- **Weekly sync:** Sprint planning and review
|
||||
|
||||
### External (Community)
|
||||
|
||||
- **Telegram:** [@nofx_dev_community](https://t.me/nofx_dev_community)
|
||||
- **GitHub Issues:** Bug reports, feature requests
|
||||
- **GitHub Discussions:** General questions, ideas
|
||||
- **Twitter:** [@nofx_ai](https://x.com/nofx_ai) - Announcements
|
||||
|
||||
---
|
||||
|
||||
## 🎓 Onboarding New Maintainers
|
||||
|
||||
### Checklist for New Maintainers
|
||||
|
||||
- [ ] Add to GitHub organization
|
||||
- [ ] Grant write access to repository
|
||||
- [ ] Add to private maintainer channel
|
||||
- [ ] Introduce to the team
|
||||
- [ ] Read all docs in `/docs/maintainers/`
|
||||
- [ ] Shadow experienced maintainer for 1 sprint
|
||||
- [ ] First solo PR review (with backup reviewer)
|
||||
- [ ] First solo issue triage
|
||||
- [ ] First sprint planning participation
|
||||
|
||||
### Expectations
|
||||
|
||||
**Time Commitment:**
|
||||
- ~5-10 hours per week
|
||||
- Participate in sprint planning/review
|
||||
- Respond to assigned issues/PRs within SLA
|
||||
|
||||
**Responsibilities:**
|
||||
- Code review
|
||||
- Issue triage
|
||||
- Community support
|
||||
- Documentation maintenance
|
||||
|
||||
---
|
||||
|
||||
## 🏆 Contributor Recognition
|
||||
|
||||
### Monthly Recognition
|
||||
|
||||
**Spotlight in Community Update:**
|
||||
- Top contributor
|
||||
- Best PR of the month
|
||||
- Most helpful community member
|
||||
|
||||
### Quarterly Recognition
|
||||
|
||||
**Contributor Tier System:**
|
||||
- 🥇 **Core Contributor** - 20+ merged PRs
|
||||
- 🥈 **Active Contributor** - 10+ merged PRs
|
||||
- 🥉 **Contributor** - 5+ merged PRs
|
||||
- ⭐ **First Timer** - 1+ merged PR
|
||||
|
||||
**Benefits:**
|
||||
- Recognition in README
|
||||
- Invitation to private Discord
|
||||
- Early access to features
|
||||
- Swag (for Core Contributors)
|
||||
|
||||
---
|
||||
|
||||
## 📚 Resources
|
||||
|
||||
### Internal Docs
|
||||
- [PR Review Guide](PR_REVIEW_GUIDE.md)
|
||||
- [Security Policy](../../SECURITY.md)
|
||||
- [Code of Conduct](../../CODE_OF_CONDUCT.md)
|
||||
|
||||
### External Resources
|
||||
- [GitHub Project Management](https://docs.github.com/en/issues/planning-and-tracking-with-projects)
|
||||
- [Conventional Commits](https://www.conventionalcommits.org/)
|
||||
- [Semantic Versioning](https://semver.org/)
|
||||
|
||||
---
|
||||
|
||||
## 🤔 Questions?
|
||||
|
||||
Reach out in the maintainer channel or open a discussion.
|
||||
|
||||
**Let's build something amazing together! 🚀**
|
||||
398
docs/maintainers/PROJECT_MANAGEMENT.zh-CN.md
Normal file
398
docs/maintainers/PROJECT_MANAGEMENT.zh-CN.md
Normal file
@@ -0,0 +1,398 @@
|
||||
# 📊 项目管理指南
|
||||
|
||||
**语言:** [English](PROJECT_MANAGEMENT.md) | [中文](PROJECT_MANAGEMENT.zh-CN.md)
|
||||
|
||||
本指南解释了我们如何管理 NOFX 项目、跟踪进度和优先级排序。
|
||||
|
||||
---
|
||||
|
||||
## 🎯 项目结构
|
||||
|
||||
### GitHub Projects
|
||||
|
||||
我们使用 **GitHub Projects (Beta)** 和以下看板:
|
||||
|
||||
#### 1. **NOFX 开发看板**
|
||||
|
||||
**列:**
|
||||
```
|
||||
Backlog → Triaged → In Progress → In Review → Done
|
||||
```
|
||||
|
||||
**视图:**
|
||||
- 📋 **所有 Issue** - 所有工作项的看板视图
|
||||
- 🏃 **Sprint** - 当前 Sprint 项(2 周 Sprint)
|
||||
- 🗺️ **路线图** - 按路线图阶段的时间轴视图
|
||||
- 🏷️ **按区域** - 按区域标签分组
|
||||
- 🔥 **优先级** - 按优先级排序(critical/high/medium/low)
|
||||
- 👥 **按分配人** - 按分配的维护者分组
|
||||
|
||||
#### 2. **悬赏计划看板**
|
||||
|
||||
**列:**
|
||||
```
|
||||
Available → Claimed → In Progress → Under Review → Paid
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📅 Sprint 计划(双周)
|
||||
|
||||
### Sprint 时间表
|
||||
|
||||
**Sprint 周期:** 2 周
|
||||
**Sprint 计划:** 每隔一周的星期一
|
||||
**Sprint 回顾:** 每隔一周的星期五
|
||||
|
||||
### 计划流程
|
||||
|
||||
**星期一 - Sprint 计划(1小时):**
|
||||
|
||||
1. **回顾上一个 Sprint**(15分钟)
|
||||
- 完成了什么?
|
||||
- 什么没有完成?为什么?
|
||||
- 指标回顾
|
||||
|
||||
2. **优先级排序 Backlog**(20分钟)
|
||||
- 审查新的 issue/PR
|
||||
- 基于路线图更新优先级
|
||||
- 分配标签
|
||||
|
||||
3. **计划下一个 Sprint**(25分钟)
|
||||
- 选择下一个 Sprint 的项目
|
||||
- 分配给维护者
|
||||
- 设定清晰的验收标准
|
||||
- 估算工作量(S/M/L)
|
||||
|
||||
**星期五 - Sprint 回顾(30分钟):**
|
||||
|
||||
1. **演示已完成的工作**(15分钟)
|
||||
- 展示已合并的 PR
|
||||
- 演示新功能
|
||||
|
||||
2. **复盘**(15分钟)
|
||||
- 什么做得好?
|
||||
- 什么可以改进?
|
||||
- 下一个 Sprint 的行动项
|
||||
|
||||
---
|
||||
|
||||
## 🏷️ Issue 分类流程
|
||||
|
||||
### 每日分类(周一至周五,15分钟)
|
||||
|
||||
审查新的 issue 和 PR:
|
||||
|
||||
1. **验证完整性**
|
||||
- 模板是否正确填写?
|
||||
- 重现步骤清晰吗(对于 bug)?
|
||||
- 使用场景解释清楚吗(对于功能)?
|
||||
|
||||
2. **应用标签**
|
||||
```yaml
|
||||
优先级:
|
||||
- priority: critical # 安全问题、数据丢失、生产环境宕机
|
||||
- priority: high # 主要 bug、高价值功能
|
||||
- priority: medium # 常规 bug、标准功能
|
||||
- priority: low # 可选功能、次要改进
|
||||
|
||||
类型:
|
||||
- type: bug
|
||||
- type: feature
|
||||
- type: enhancement
|
||||
- type: documentation
|
||||
- type: security
|
||||
|
||||
区域:
|
||||
- area: exchange
|
||||
- area: ai
|
||||
- area: frontend
|
||||
- area: backend
|
||||
- area: security
|
||||
- area: ui/ux
|
||||
|
||||
路线图:
|
||||
- roadmap: phase-1 # 核心基础设施
|
||||
- roadmap: phase-2 # 测试与稳定性
|
||||
- roadmap: phase-3 # 通用市场
|
||||
```
|
||||
|
||||
3. **分配或标记讨论**
|
||||
- 可以立即处理?分配给维护者
|
||||
- 需要讨论?标记在下次计划会议
|
||||
- 需要更多信息?从作者处请求
|
||||
|
||||
4. **必要时关闭**
|
||||
- 重复?关闭并链接到原始 issue
|
||||
- 无效?关闭并说明原因
|
||||
- 超出范围?礼貌关闭并说明理由
|
||||
|
||||
---
|
||||
|
||||
## 🎯 优先级决策矩阵
|
||||
|
||||
使用此矩阵决定优先级:
|
||||
|
||||
| 影响/紧急程度 | 高紧急 | 中等紧急 | 低紧急 |
|
||||
|------------------|--------------|----------------|-------------|
|
||||
| **高影响** | 🔴 Critical | 🔴 Critical | 🟡 High |
|
||||
| **中等影响** | 🔴 Critical | 🟡 High | 🟢 Medium |
|
||||
| **低影响** | 🟡 High | 🟢 Medium | ⚪ Low |
|
||||
|
||||
**影响:**
|
||||
- 高:影响核心功能、安全性或许多用户
|
||||
- 中:影响特定功能或中等数量用户
|
||||
- 低:可选功能、次要改进
|
||||
|
||||
**紧急程度:**
|
||||
- 高:需要立即关注
|
||||
- 中:应该尽快处理
|
||||
- 低:可以等待自然包含
|
||||
|
||||
---
|
||||
|
||||
## 📊 路线图对齐
|
||||
|
||||
所有工作应与我们的[路线图](../roadmap/README.zh-CN.md)对齐:
|
||||
|
||||
### Phase 1:核心基础设施(当前重点)
|
||||
|
||||
**必须接受:**
|
||||
- 安全增强
|
||||
- AI 模型集成
|
||||
- 交易所集成(OKX、Bybit、Lighter、EdgeX)
|
||||
- 项目结构重构
|
||||
- UI/UX 改进
|
||||
|
||||
**可以接受:**
|
||||
- 相关 bug 修复
|
||||
- 文档改进
|
||||
- 性能优化
|
||||
|
||||
**应该推迟:**
|
||||
- 通用市场扩展(股票、期货)
|
||||
- 高级 AI 功能(RL、多智能体)
|
||||
- 企业功能
|
||||
|
||||
### Phase 2-5:未来工作
|
||||
|
||||
使用适当的 `roadmap: phase-X` 标签标记并添加到 backlog。
|
||||
|
||||
---
|
||||
|
||||
## 🎫 Issue 模板
|
||||
|
||||
我们有这些 issue 模板:
|
||||
|
||||
### 1. Bug 报告
|
||||
- 用于 bug 和错误
|
||||
- 必须包含重现步骤
|
||||
- 标签:`type: bug`
|
||||
|
||||
### 2. 功能请求
|
||||
- 用于新功能
|
||||
- 必须包含使用场景和好处
|
||||
- 标签:`type: feature`
|
||||
|
||||
### 3. 悬赏认领
|
||||
- 认领悬赏时使用
|
||||
- 必须引用悬赏 issue
|
||||
- 标签:`bounty: claimed`
|
||||
|
||||
### 4. 安全漏洞
|
||||
- 用于安全问题(私密)
|
||||
- 遵循负责任的披露
|
||||
- 标签:`type: security`
|
||||
|
||||
**缺少模板?**
|
||||
- 使用空白 issue
|
||||
- 维护者将转换为适当的模板
|
||||
|
||||
---
|
||||
|
||||
## 📈 我们跟踪的指标
|
||||
|
||||
### 每周指标
|
||||
|
||||
- **PR 指标:**
|
||||
- 打开的 PR 数量
|
||||
- 合并的 PR 数量
|
||||
- 平均首次审核时间
|
||||
- 平均合并时间
|
||||
|
||||
- **Issue 指标:**
|
||||
- 打开的 issue 数量
|
||||
- 关闭的 issue 数量
|
||||
- Issue backlog 大小
|
||||
- 按优先级/类型/区域分类的 issue
|
||||
|
||||
- **社区指标:**
|
||||
- 新贡献者
|
||||
- 活跃贡献者
|
||||
- 社区参与度(评论、反应)
|
||||
|
||||
### 每月指标
|
||||
|
||||
- **路线图进度:**
|
||||
- 每个阶段的完成百分比
|
||||
- 已完成 vs 计划项目
|
||||
- 阻塞因素和风险
|
||||
|
||||
- **代码质量:**
|
||||
- 测试覆盖率
|
||||
- 每个 PR 的代码审核评论数
|
||||
- Bug 修复 vs 功能比率
|
||||
|
||||
- **悬赏计划:**
|
||||
- 创建的悬赏
|
||||
- 认领的悬赏
|
||||
- 支付的悬赏
|
||||
- 平均完成时间
|
||||
|
||||
---
|
||||
|
||||
## 🤖 自动化
|
||||
|
||||
我们使用 GitHub Actions 进行自动化:
|
||||
|
||||
### PR 自动化
|
||||
|
||||
- **基于文件变更的自动标签**
|
||||
- **PR 大小标签**(small/medium/large)
|
||||
- **CI 检查**(测试、linting、构建)
|
||||
- **安全扫描**(Trivy、Gitleaks)
|
||||
- **Conventional commit 验证**
|
||||
|
||||
### Issue 自动化
|
||||
|
||||
- **过期 issue 检测**(30天不活动后关闭)
|
||||
- **使用 "bounty" 关键字时自动悬赏标签**
|
||||
- **使用 issue 相似性的重复检测**
|
||||
|
||||
### 发布自动化
|
||||
|
||||
- **从 conventional commits 生成 Changelog**
|
||||
- **基于 commit 类型的版本升级**
|
||||
- **自动生成发布说明**
|
||||
- **部署到 staging/production**
|
||||
|
||||
---
|
||||
|
||||
## 🔄 定期任务
|
||||
|
||||
### 每日
|
||||
- ✅ 分类新的 issue/PR
|
||||
- ✅ 审查紧急 PR
|
||||
- ✅ 回应社区问题
|
||||
|
||||
### 每周
|
||||
- ✅ Sprint 计划(星期一)
|
||||
- ✅ Sprint 回顾(星期五)
|
||||
- ✅ 审查指标仪表板
|
||||
- ✅ 更新项目看板
|
||||
|
||||
### 每月
|
||||
- ✅ 路线图进度回顾
|
||||
- ✅ 社区更新帖子
|
||||
- ✅ 悬赏计划回顾
|
||||
- ✅ 依赖更新
|
||||
- ✅ 安全审计
|
||||
|
||||
### 每季度
|
||||
- ✅ 路线图更新
|
||||
- ✅ 主要版本规划
|
||||
- ✅ 贡献者表彰
|
||||
- ✅ 文档审计
|
||||
|
||||
---
|
||||
|
||||
## 📞 沟通渠道
|
||||
|
||||
### 内部(维护者)
|
||||
|
||||
- **GitHub Discussions:** 架构决策、RFC
|
||||
- **私人频道:** 敏感讨论、悬赏支付
|
||||
- **每周同步:** Sprint 计划和回顾
|
||||
|
||||
### 外部(社区)
|
||||
|
||||
- **Telegram:** [@nofx_dev_community](https://t.me/nofx_dev_community)
|
||||
- **GitHub Issues:** Bug 报告、功能请求
|
||||
- **GitHub Discussions:** 一般问题、想法
|
||||
- **Twitter:** [@nofx_ai](https://x.com/nofx_ai) - 公告
|
||||
|
||||
---
|
||||
|
||||
## 🎓 新维护者入职
|
||||
|
||||
### 新维护者检查清单
|
||||
|
||||
- [ ] 添加到 GitHub 组织
|
||||
- [ ] 授予仓库写入权限
|
||||
- [ ] 添加到私人维护者频道
|
||||
- [ ] 介绍给团队
|
||||
- [ ] 阅读 `/docs/maintainers/` 中的所有文档
|
||||
- [ ] 跟随有经验的维护者 1 个 Sprint
|
||||
- [ ] 首次单独 PR 审核(有备份审核者)
|
||||
- [ ] 首次单独 issue 分类
|
||||
- [ ] 首次参与 Sprint 计划
|
||||
|
||||
### 期望
|
||||
|
||||
**时间投入:**
|
||||
- 每周约 5-10 小时
|
||||
- 参与 Sprint 计划/回顾
|
||||
- 在 SLA 内回应分配的 issue/PR
|
||||
|
||||
**职责:**
|
||||
- 代码审核
|
||||
- Issue 分类
|
||||
- 社区支持
|
||||
- 文档维护
|
||||
|
||||
---
|
||||
|
||||
## 🏆 贡献者表彰
|
||||
|
||||
### 每月表彰
|
||||
|
||||
**在社区更新中聚焦:**
|
||||
- 顶级贡献者
|
||||
- 本月最佳 PR
|
||||
- 最有帮助的社区成员
|
||||
|
||||
### 每季度表彰
|
||||
|
||||
**贡献者等级系统:**
|
||||
- 🥇 **核心贡献者** - 20+ 个已合并 PR
|
||||
- 🥈 **活跃贡献者** - 10+ 个已合并 PR
|
||||
- 🥉 **贡献者** - 5+ 个已合并 PR
|
||||
- ⭐ **首次贡献者** - 1+ 个已合并 PR
|
||||
|
||||
**福利:**
|
||||
- 在 README 中表彰
|
||||
- 邀请加入私人 Discord
|
||||
- 早期访问功能
|
||||
- 周边商品(核心贡献者)
|
||||
|
||||
---
|
||||
|
||||
## 📚 资源
|
||||
|
||||
### 内部文档
|
||||
- [PR 审核指南](PR_REVIEW_GUIDE.zh-CN.md)
|
||||
- [安全政策](../../SECURITY.md)
|
||||
- [行为准则](../../CODE_OF_CONDUCT.md)
|
||||
|
||||
### 外部资源
|
||||
- [GitHub 项目管理](https://docs.github.com/en/issues/planning-and-tracking-with-projects)
|
||||
- [Conventional Commits](https://www.conventionalcommits.org/)
|
||||
- [语义化版本](https://semver.org/)
|
||||
|
||||
---
|
||||
|
||||
## 🤔 问题?
|
||||
|
||||
在维护者频道联系我们或开启讨论。
|
||||
|
||||
**让我们一起构建令人惊叹的产品!🚀**
|
||||
458
docs/maintainers/PR_REVIEW_GUIDE.md
Normal file
458
docs/maintainers/PR_REVIEW_GUIDE.md
Normal file
@@ -0,0 +1,458 @@
|
||||
# 🔍 PR Review Guide for Maintainers
|
||||
|
||||
**Language:** [English](PR_REVIEW_GUIDE.md) | [中文](PR_REVIEW_GUIDE.zh-CN.md)
|
||||
|
||||
This guide is for NOFX maintainers reviewing pull requests.
|
||||
|
||||
---
|
||||
|
||||
## 📋 Review Checklist
|
||||
|
||||
### 1. Initial Triage (Within 24 hours)
|
||||
|
||||
- [ ] **Check PR alignment with roadmap**
|
||||
- Does it fit into our current priorities?
|
||||
- Is it in the [roadmap](../roadmap/README.md)?
|
||||
- If not, should we accept it anyway?
|
||||
|
||||
- [ ] **Verify PR completeness**
|
||||
- All sections of PR template filled?
|
||||
- Clear description of changes?
|
||||
- Related issues linked?
|
||||
- Screenshots/demo for UI changes?
|
||||
|
||||
- [ ] **Apply appropriate labels**
|
||||
- Priority: critical/high/medium/low
|
||||
- Type: bug/feature/enhancement/docs
|
||||
- Area: frontend/backend/exchange/ai/security
|
||||
- Status: needs review/needs changes
|
||||
|
||||
- [ ] **Assign reviewers**
|
||||
- Assign based on area of expertise
|
||||
- At least 1 maintainer review required
|
||||
|
||||
### 2. Code Review
|
||||
|
||||
#### A. Functionality Review
|
||||
|
||||
```markdown
|
||||
✅ **Questions to Ask:**
|
||||
|
||||
- Does it solve the stated problem?
|
||||
- Are edge cases handled?
|
||||
- Will this break existing functionality?
|
||||
- Is the approach correct for our architecture?
|
||||
- Are there better alternatives?
|
||||
```
|
||||
|
||||
**Testing:**
|
||||
- [ ] All CI checks passed?
|
||||
- [ ] Manual testing performed by contributor?
|
||||
- [ ] Test coverage adequate?
|
||||
- [ ] Tests are meaningful (not just for coverage)?
|
||||
|
||||
#### B. Code Quality Review
|
||||
|
||||
**Go Backend Code:**
|
||||
|
||||
```go
|
||||
// ❌ Bad - Reject
|
||||
func GetData(a, b string) interface{} {
|
||||
d := doSomething(a, b)
|
||||
return d
|
||||
}
|
||||
|
||||
// ✅ Good - Approve
|
||||
func GetAccountBalance(apiKey, secretKey string) (*Balance, error) {
|
||||
if apiKey == "" || secretKey == "" {
|
||||
return nil, fmt.Errorf("API credentials required")
|
||||
}
|
||||
|
||||
balance, err := client.FetchBalance(apiKey, secretKey)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to fetch balance: %w", err)
|
||||
}
|
||||
|
||||
return balance, nil
|
||||
}
|
||||
```
|
||||
|
||||
**Check for:**
|
||||
- [ ] Meaningful variable/function names
|
||||
- [ ] Proper error handling (no ignored errors)
|
||||
- [ ] Comments for complex logic
|
||||
- [ ] No hardcoded values (use constants/config)
|
||||
- [ ] Follows Go idioms and conventions
|
||||
- [ ] No unnecessary complexity
|
||||
|
||||
**TypeScript/React Frontend Code:**
|
||||
|
||||
```typescript
|
||||
// ❌ Bad - Reject
|
||||
const getData = (data: any) => {
|
||||
return data.map(d => <div>{d.name}</div>)
|
||||
}
|
||||
|
||||
// ✅ Good - Approve
|
||||
interface Trader {
|
||||
id: string;
|
||||
name: string;
|
||||
status: 'running' | 'stopped';
|
||||
}
|
||||
|
||||
const TraderList: React.FC<{ traders: Trader[] }> = ({ traders }) => {
|
||||
return (
|
||||
<div className="trader-list">
|
||||
{traders.map(trader => (
|
||||
<TraderCard key={trader.id} trader={trader} />
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
**Check for:**
|
||||
- [ ] Type safety (no `any` unless absolutely necessary)
|
||||
- [ ] Proper React patterns (hooks, functional components)
|
||||
- [ ] Component reusability
|
||||
- [ ] Accessibility (a11y) considerations
|
||||
- [ ] Performance optimizations (memoization where needed)
|
||||
|
||||
#### C. Security Review
|
||||
|
||||
**Critical Checks:**
|
||||
|
||||
```go
|
||||
// 🚨 REJECT - Security Issue
|
||||
func Login(username, password string) {
|
||||
query := "SELECT * FROM users WHERE username='" + username + "'" // SQL Injection!
|
||||
db.Query(query)
|
||||
}
|
||||
|
||||
// ✅ APPROVE - Secure
|
||||
func Login(username, password string) error {
|
||||
query := "SELECT * FROM users WHERE username = ?"
|
||||
row := db.QueryRow(query, username) // Parameterized query
|
||||
// ... proper password verification with bcrypt
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] No SQL injection vulnerabilities
|
||||
- [ ] No XSS vulnerabilities in frontend
|
||||
- [ ] API keys/secrets not hardcoded
|
||||
- [ ] User inputs properly validated
|
||||
- [ ] Authentication/authorization properly handled
|
||||
- [ ] No sensitive data in logs
|
||||
- [ ] Dependencies have no known vulnerabilities
|
||||
|
||||
#### D. Performance Review
|
||||
|
||||
- [ ] No obvious performance issues
|
||||
- [ ] Database queries optimized (indexes, no N+1 queries)
|
||||
- [ ] No unnecessary API calls
|
||||
- [ ] Proper caching where applicable
|
||||
- [ ] No memory leaks
|
||||
|
||||
### 3. Documentation Review
|
||||
|
||||
- [ ] Code comments for complex logic
|
||||
- [ ] README updated if needed
|
||||
- [ ] API documentation updated (if API changes)
|
||||
- [ ] Migration guide for breaking changes
|
||||
- [ ] Changelog entry (for significant changes)
|
||||
|
||||
### 4. Testing Review
|
||||
|
||||
- [ ] Unit tests for new functions
|
||||
- [ ] Integration tests for new features
|
||||
- [ ] Tests actually test the functionality (not just coverage)
|
||||
- [ ] Test names are descriptive
|
||||
- [ ] Mock data is realistic
|
||||
|
||||
---
|
||||
|
||||
## 🏷️ Label Management
|
||||
|
||||
### Priority Assignment
|
||||
|
||||
Use these criteria to assign priority:
|
||||
|
||||
**Critical:**
|
||||
- Security vulnerabilities
|
||||
- Production-breaking bugs
|
||||
- Data loss issues
|
||||
|
||||
**High:**
|
||||
- Major bugs affecting many users
|
||||
- High-priority roadmap features
|
||||
- Performance issues
|
||||
|
||||
**Medium:**
|
||||
- Regular bug fixes
|
||||
- Standard feature requests
|
||||
- Refactoring
|
||||
|
||||
**Low:**
|
||||
- Minor improvements
|
||||
- Code style changes
|
||||
- Non-urgent documentation
|
||||
|
||||
### Status Workflow
|
||||
|
||||
```
|
||||
needs review → in review → needs changes → needs review → approved → merged
|
||||
↓
|
||||
on hold
|
||||
```
|
||||
|
||||
**Status Labels:**
|
||||
- `status: needs review` - Ready for initial review
|
||||
- `status: in progress` - Being actively reviewed
|
||||
- `status: needs changes` - Reviewer requested changes
|
||||
- `status: on hold` - Waiting for discussion/decision
|
||||
- `status: blocked` - Blocked by another PR/issue
|
||||
|
||||
---
|
||||
|
||||
## 💬 Providing Feedback
|
||||
|
||||
### Writing Good Review Comments
|
||||
|
||||
**❌ Bad Comments:**
|
||||
```
|
||||
This is wrong.
|
||||
Change this.
|
||||
Why did you do this?
|
||||
```
|
||||
|
||||
**✅ Good Comments:**
|
||||
```
|
||||
This approach might cause issues with concurrent requests.
|
||||
Consider using a mutex or atomic operations here.
|
||||
|
||||
Suggestion: Extract this logic into a separate function for better testability:
|
||||
```go
|
||||
func validateTraderConfig(config *TraderConfig) error {
|
||||
// validation logic
|
||||
}
|
||||
```
|
||||
|
||||
Question: Have you considered using the existing `ExchangeClient` interface
|
||||
instead of creating a new one? This would maintain consistency with the rest
|
||||
of the codebase.
|
||||
```
|
||||
|
||||
### Comment Types
|
||||
|
||||
**🔴 Blocking (must be addressed):**
|
||||
```markdown
|
||||
**BLOCKING:** This introduces a SQL injection vulnerability.
|
||||
Please use parameterized queries instead.
|
||||
```
|
||||
|
||||
**🟡 Non-blocking (suggestions):**
|
||||
```markdown
|
||||
**Suggestion:** Consider using `strings.Builder` here for better performance
|
||||
when concatenating many strings.
|
||||
```
|
||||
|
||||
**🟢 Praise (encourage good practices):**
|
||||
```markdown
|
||||
**Nice!** Great use of context for timeout handling. This is exactly what
|
||||
we want to see.
|
||||
```
|
||||
|
||||
### Questions vs Directives
|
||||
|
||||
**❌ Directive (can feel demanding):**
|
||||
```
|
||||
Change this to use the factory pattern.
|
||||
Add tests for this function.
|
||||
```
|
||||
|
||||
**✅ Question (more collaborative):**
|
||||
```
|
||||
Would the factory pattern be a better fit here? It might make testing easier.
|
||||
Could you add a test case for the error path? I want to make sure we handle
|
||||
failures gracefully.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ⏱️ Response Time Guidelines
|
||||
|
||||
| PR Type | Initial Review | Follow-up | Merge Decision |
|
||||
|---------|---------------|-----------|----------------|
|
||||
| **Critical Bug** | 4 hours | 2 hours | Same day |
|
||||
| **Bounty PR** | 24 hours | 12 hours | 2-3 days |
|
||||
| **Feature** | 2-3 days | 1-2 days | 3-5 days |
|
||||
| **Documentation** | 2-3 days | 1-2 days | 3-5 days |
|
||||
| **Large PR** | 3-5 days | 2-3 days | 5-7 days |
|
||||
|
||||
---
|
||||
|
||||
## ✅ Approval Criteria
|
||||
|
||||
A PR should be approved when:
|
||||
|
||||
1. **Functionality**
|
||||
- ✅ Solves the stated problem
|
||||
- ✅ No regression in existing features
|
||||
- ✅ Edge cases handled
|
||||
|
||||
2. **Quality**
|
||||
- ✅ Follows code standards
|
||||
- ✅ Well-structured and readable
|
||||
- ✅ Adequate test coverage
|
||||
|
||||
3. **Security**
|
||||
- ✅ No security vulnerabilities
|
||||
- ✅ Inputs validated
|
||||
- ✅ Secrets properly managed
|
||||
|
||||
4. **Documentation**
|
||||
- ✅ Code commented where needed
|
||||
- ✅ Docs updated if applicable
|
||||
|
||||
5. **Process**
|
||||
- ✅ All CI checks pass
|
||||
- ✅ All review comments addressed
|
||||
- ✅ Rebased on latest dev branch
|
||||
|
||||
---
|
||||
|
||||
## 🚫 Rejection Criteria
|
||||
|
||||
Reject a PR if:
|
||||
|
||||
**Immediate Rejection:**
|
||||
- 🔴 Introduces security vulnerabilities
|
||||
- 🔴 Contains malicious code
|
||||
- 🔴 Violates Code of Conduct
|
||||
- 🔴 Contains plagiarized code
|
||||
- 🔴 Hardcoded API keys or secrets
|
||||
|
||||
**Request Changes:**
|
||||
- 🟡 Poor code quality (after feedback ignored)
|
||||
- 🟡 No tests for new features
|
||||
- 🟡 Breaking changes without migration path
|
||||
- 🟡 Doesn't align with roadmap (without prior discussion)
|
||||
- 🟡 Incomplete (missing critical parts)
|
||||
|
||||
**Close with Explanation:**
|
||||
- 🟠 Duplicate functionality
|
||||
- 🟠 Out of scope for project
|
||||
- 🟠 Better alternative already exists
|
||||
- 🟠 Contributor unresponsive for >2 weeks
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Special Case Reviews
|
||||
|
||||
### Bounty PRs
|
||||
|
||||
Extra care needed:
|
||||
|
||||
- [ ] All acceptance criteria met?
|
||||
- [ ] Demo video/screenshots provided?
|
||||
- [ ] Working as specified in bounty issue?
|
||||
- [ ] Payment info discussed privately?
|
||||
- [ ] Priority review (24h turnaround)
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
- [ ] Migration guide provided?
|
||||
- [ ] Deprecation warnings added?
|
||||
- [ ] Version bump planned?
|
||||
- [ ] Backward compatibility considered?
|
||||
- [ ] RFC (Request for Comments) created for major changes?
|
||||
|
||||
### Security PRs
|
||||
|
||||
- [ ] Verified by security-focused reviewer?
|
||||
- [ ] No public disclosure of vulnerability?
|
||||
- [ ] Coordinated disclosure if needed?
|
||||
- [ ] Security advisory prepared?
|
||||
- [ ] Patch release planned?
|
||||
|
||||
---
|
||||
|
||||
## 🔄 Merge Guidelines
|
||||
|
||||
### When to Merge
|
||||
|
||||
Merge when:
|
||||
- ✅ At least 1 approval from maintainer
|
||||
- ✅ All CI checks passing
|
||||
- ✅ All conversations resolved
|
||||
- ✅ No requested changes pending
|
||||
- ✅ Rebased on latest target branch
|
||||
|
||||
### Merge Strategy
|
||||
|
||||
**Squash Merge** (default for most PRs):
|
||||
- Small bug fixes
|
||||
- Single-feature PRs
|
||||
- Documentation updates
|
||||
- Keeps git history clean
|
||||
|
||||
**Merge Commit** (for complex PRs):
|
||||
- Multi-commit features with logical commits
|
||||
- Preserve commit history
|
||||
- Large refactoring with atomic commits
|
||||
|
||||
**Rebase and Merge** (rarely):
|
||||
- When linear history is important
|
||||
- Commits are already well-structured
|
||||
|
||||
### Merge Commit Message
|
||||
|
||||
Format:
|
||||
```
|
||||
<type>(<scope>): <PR title> (#123)
|
||||
|
||||
Brief description of changes.
|
||||
|
||||
- Key change 1
|
||||
- Key change 2
|
||||
|
||||
Co-authored-by: Contributor Name <email@example.com>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 Review Metrics to Track
|
||||
|
||||
Monitor these metrics monthly:
|
||||
|
||||
- Average time to first review
|
||||
- Average time to merge
|
||||
- PR acceptance rate
|
||||
- Number of PRs by type (bug/feature/docs)
|
||||
- Number of PRs by area (frontend/backend/exchange)
|
||||
- Contributor retention rate
|
||||
|
||||
---
|
||||
|
||||
## 🙋 Questions?
|
||||
|
||||
If unsure about a PR:
|
||||
|
||||
1. **Ask other maintainers** in private channel
|
||||
2. **Request more context** from contributor
|
||||
3. **Mark as "on hold"** and add to next maintainer sync
|
||||
4. **When in doubt, be conservative** - better to ask than approve something risky
|
||||
|
||||
---
|
||||
|
||||
## 🔗 Related Resources
|
||||
|
||||
- [Contributing Guide](../../CONTRIBUTING.md)
|
||||
- [Code of Conduct](../../CODE_OF_CONDUCT.md)
|
||||
- [Security Policy](../../SECURITY.md)
|
||||
- [Project Roadmap](../roadmap/README.md)
|
||||
|
||||
---
|
||||
|
||||
**Remember:** Reviews should be **respectful**, **constructive**, and **educational**.
|
||||
We're building a community, not just code. 🚀
|
||||
457
docs/maintainers/PR_REVIEW_GUIDE.zh-CN.md
Normal file
457
docs/maintainers/PR_REVIEW_GUIDE.zh-CN.md
Normal file
@@ -0,0 +1,457 @@
|
||||
# 🔍 维护者 PR 审核指南
|
||||
|
||||
**语言:** [English](PR_REVIEW_GUIDE.md) | [中文](PR_REVIEW_GUIDE.zh-CN.md)
|
||||
|
||||
本指南适用于审核 pull request 的 NOFX 维护者。
|
||||
|
||||
---
|
||||
|
||||
## 📋 审核清单
|
||||
|
||||
### 1. 初步分类(24小时内)
|
||||
|
||||
- [ ] **检查 PR 与路线图的一致性**
|
||||
- 是否符合我们当前的优先级?
|
||||
- 是否在[路线图](../roadmap/README.zh-CN.md)中?
|
||||
- 如果不在,我们是否应该接受它?
|
||||
|
||||
- [ ] **验证 PR 完整性**
|
||||
- PR 模板的所有部分都已填写?
|
||||
- 变更描述清晰?
|
||||
- 相关 issue 已链接?
|
||||
- UI 变更有截图/演示?
|
||||
|
||||
- [ ] **应用适当的标签**
|
||||
- 优先级:critical/high/medium/low
|
||||
- 类型:bug/feature/enhancement/docs
|
||||
- 区域:frontend/backend/exchange/ai/security
|
||||
- 状态:needs review/needs changes
|
||||
|
||||
- [ ] **分配审核者**
|
||||
- 根据专业领域分配
|
||||
- 至少需要 1 个维护者审核
|
||||
|
||||
### 2. 代码审核
|
||||
|
||||
#### A. 功能审核
|
||||
|
||||
```markdown
|
||||
✅ **要问的问题:**
|
||||
|
||||
- 是否解决了所述问题?
|
||||
- 边界情况是否处理?
|
||||
- 是否会破坏现有功能?
|
||||
- 方法是否适合我们的架构?
|
||||
- 是否有更好的替代方案?
|
||||
```
|
||||
|
||||
**测试:**
|
||||
- [ ] 所有 CI 检查都通过?
|
||||
- [ ] 贡献者进行了手动测试?
|
||||
- [ ] 测试覆盖率足够?
|
||||
- [ ] 测试有意义(不只是为了覆盖率)?
|
||||
|
||||
#### B. 代码质量审核
|
||||
|
||||
**Go 后端代码:**
|
||||
|
||||
```go
|
||||
// ❌ 差 - 拒绝
|
||||
func GetData(a, b string) interface{} {
|
||||
d := doSomething(a, b)
|
||||
return d
|
||||
}
|
||||
|
||||
// ✅ 好 - 批准
|
||||
func GetAccountBalance(apiKey, secretKey string) (*Balance, error) {
|
||||
if apiKey == "" || secretKey == "" {
|
||||
return nil, fmt.Errorf("API credentials required")
|
||||
}
|
||||
|
||||
balance, err := client.FetchBalance(apiKey, secretKey)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to fetch balance: %w", err)
|
||||
}
|
||||
|
||||
return balance, nil
|
||||
}
|
||||
```
|
||||
|
||||
**检查项:**
|
||||
- [ ] 有意义的变量/函数名
|
||||
- [ ] 正确的错误处理(没有忽略错误)
|
||||
- [ ] 复杂逻辑有注释
|
||||
- [ ] 没有硬编码值(使用常量/配置)
|
||||
- [ ] 遵循 Go 习惯用法和约定
|
||||
- [ ] 没有不必要的复杂性
|
||||
|
||||
**TypeScript/React 前端代码:**
|
||||
|
||||
```typescript
|
||||
// ❌ 差 - 拒绝
|
||||
const getData = (data: any) => {
|
||||
return data.map(d => <div>{d.name}</div>)
|
||||
}
|
||||
|
||||
// ✅ 好 - 批准
|
||||
interface Trader {
|
||||
id: string;
|
||||
name: string;
|
||||
status: 'running' | 'stopped';
|
||||
}
|
||||
|
||||
const TraderList: React.FC<{ traders: Trader[] }> = ({ traders }) => {
|
||||
return (
|
||||
<div className="trader-list">
|
||||
{traders.map(trader => (
|
||||
<TraderCard key={trader.id} trader={trader} />
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
**检查项:**
|
||||
- [ ] 类型安全(除非绝对必要,否则不使用 `any`)
|
||||
- [ ] 正确的 React 模式(hooks、函数式组件)
|
||||
- [ ] 组件可重用性
|
||||
- [ ] 可访问性(a11y)考虑
|
||||
- [ ] 性能优化(需要时使用 memoization)
|
||||
|
||||
#### C. 安全审核
|
||||
|
||||
**关键检查:**
|
||||
|
||||
```go
|
||||
// 🚨 拒绝 - 安全问题
|
||||
func Login(username, password string) {
|
||||
query := "SELECT * FROM users WHERE username='" + username + "'" // SQL 注入!
|
||||
db.Query(query)
|
||||
}
|
||||
|
||||
// ✅ 批准 - 安全
|
||||
func Login(username, password string) error {
|
||||
query := "SELECT * FROM users WHERE username = ?"
|
||||
row := db.QueryRow(query, username) // 参数化查询
|
||||
// ... 使用 bcrypt 进行正确的密码验证
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] 没有 SQL 注入漏洞
|
||||
- [ ] 前端没有 XSS 漏洞
|
||||
- [ ] API 密钥/密码没有硬编码
|
||||
- [ ] 用户输入已正确验证
|
||||
- [ ] 认证/授权正确处理
|
||||
- [ ] 日志中没有敏感数据
|
||||
- [ ] 依赖项没有已知漏洞
|
||||
|
||||
#### D. 性能审核
|
||||
|
||||
- [ ] 没有明显的性能问题
|
||||
- [ ] 数据库查询已优化(索引、没有 N+1 查询)
|
||||
- [ ] 没有不必要的 API 调用
|
||||
- [ ] 适当的缓存
|
||||
- [ ] 没有内存泄漏
|
||||
|
||||
### 3. 文档审核
|
||||
|
||||
- [ ] 复杂逻辑有代码注释
|
||||
- [ ] 如果需要,README 已更新
|
||||
- [ ] API 文档已更新(如有 API 变更)
|
||||
- [ ] 破坏性变更有迁移指南
|
||||
- [ ] Changelog 条目(对于重大变更)
|
||||
|
||||
### 4. 测试审核
|
||||
|
||||
- [ ] 新函数有单元测试
|
||||
- [ ] 新功能有集成测试
|
||||
- [ ] 测试确实测试了功能(不只是覆盖率)
|
||||
- [ ] 测试名称具有描述性
|
||||
- [ ] 模拟数据真实
|
||||
|
||||
---
|
||||
|
||||
## 🏷️ 标签管理
|
||||
|
||||
### 优先级分配
|
||||
|
||||
使用这些标准来分配优先级:
|
||||
|
||||
**Critical(严重):**
|
||||
- 安全漏洞
|
||||
- 生产环境破坏性 bug
|
||||
- 数据丢失问题
|
||||
|
||||
**High(高):**
|
||||
- 影响许多用户的重大 bug
|
||||
- 高优先级路线图功能
|
||||
- 性能问题
|
||||
|
||||
**Medium(中):**
|
||||
- 常规 bug 修复
|
||||
- 标准功能请求
|
||||
- 重构
|
||||
|
||||
**Low(低):**
|
||||
- 次要改进
|
||||
- 代码风格变更
|
||||
- 非紧急文档
|
||||
|
||||
### 状态工作流
|
||||
|
||||
```
|
||||
needs review → in review → needs changes → needs review → approved → merged
|
||||
↓
|
||||
on hold
|
||||
```
|
||||
|
||||
**状态标签:**
|
||||
- `status: needs review` - 准备初次审核
|
||||
- `status: in progress` - 正在积极审核
|
||||
- `status: needs changes` - 审核者请求更改
|
||||
- `status: on hold` - 等待讨论/决定
|
||||
- `status: blocked` - 被另一个 PR/issue 阻塞
|
||||
|
||||
---
|
||||
|
||||
## 💬 提供反馈
|
||||
|
||||
### 编写好的审核评论
|
||||
|
||||
**❌ 差的评论:**
|
||||
```
|
||||
这是错的。
|
||||
改这个。
|
||||
你为什么这样做?
|
||||
```
|
||||
|
||||
**✅ 好的评论:**
|
||||
```
|
||||
这种方法可能会导致并发请求的问题。
|
||||
考虑在这里使用互斥锁或原子操作。
|
||||
|
||||
建议:将此逻辑提取到单独的函数中以提高可测试性:
|
||||
```go
|
||||
func validateTraderConfig(config *TraderConfig) error {
|
||||
// 验证逻辑
|
||||
}
|
||||
```
|
||||
|
||||
问题:你是否考虑过使用现有的 `ExchangeClient` 接口
|
||||
而不是创建新接口?这将与代码库的其余部分保持一致。
|
||||
```
|
||||
|
||||
### 评论类型
|
||||
|
||||
**🔴 阻塞性(必须解决):**
|
||||
```markdown
|
||||
**阻塞性:** 这引入了 SQL 注入漏洞。
|
||||
请改用参数化查询。
|
||||
```
|
||||
|
||||
**🟡 非阻塞性(建议):**
|
||||
```markdown
|
||||
**建议:** 考虑在这里使用 `strings.Builder` 以提高
|
||||
连接多个字符串时的性能。
|
||||
```
|
||||
|
||||
**🟢 赞扬(鼓励好的做法):**
|
||||
```markdown
|
||||
**很好!** 很好地使用 context 进行超时处理。这正是
|
||||
我们想看到的。
|
||||
```
|
||||
|
||||
### 问题 vs 指令
|
||||
|
||||
**❌ 指令(可能感觉强硬):**
|
||||
```
|
||||
改用工厂模式。
|
||||
为这个函数添加测试。
|
||||
```
|
||||
|
||||
**✅ 问题(更协作):**
|
||||
```
|
||||
工厂模式在这里会更合适吗?它可能会使测试更容易。
|
||||
你能为错误路径添加一个测试用例吗?我想确保我们
|
||||
优雅地处理失败。
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ⏱️ 响应时间指南
|
||||
|
||||
| PR 类型 | 初次审核 | 后续审核 | 合并决定 |
|
||||
|---------|----------|----------|----------|
|
||||
| **严重 Bug** | 4 小时 | 2 小时 | 当天 |
|
||||
| **悬赏 PR** | 24 小时 | 12 小时 | 2-3 天 |
|
||||
| **功能** | 2-3 天 | 1-2 天 | 3-5 天 |
|
||||
| **文档** | 2-3 天 | 1-2 天 | 3-5 天 |
|
||||
| **大型 PR** | 3-5 天 | 2-3 天 | 5-7 天 |
|
||||
|
||||
---
|
||||
|
||||
## ✅ 批准标准
|
||||
|
||||
PR 应在以下情况下批准:
|
||||
|
||||
1. **功能性**
|
||||
- ✅ 解决了所述问题
|
||||
- ✅ 现有功能没有退化
|
||||
- ✅ 边界情况已处理
|
||||
|
||||
2. **质量**
|
||||
- ✅ 遵循代码标准
|
||||
- ✅ 结构良好且可读
|
||||
- ✅ 测试覆盖率足够
|
||||
|
||||
3. **安全性**
|
||||
- ✅ 没有安全漏洞
|
||||
- ✅ 输入已验证
|
||||
- ✅ 密钥管理正确
|
||||
|
||||
4. **文档**
|
||||
- ✅ 需要的地方有代码注释
|
||||
- ✅ 文档已更新(如适用)
|
||||
|
||||
5. **流程**
|
||||
- ✅ 所有 CI 检查通过
|
||||
- ✅ 所有审核评论已处理
|
||||
- ✅ 已基于最新 dev 分支 rebase
|
||||
|
||||
---
|
||||
|
||||
## 🚫 拒绝标准
|
||||
|
||||
在以下情况下拒绝 PR:
|
||||
|
||||
**立即拒绝:**
|
||||
- 🔴 引入安全漏洞
|
||||
- 🔴 包含恶意代码
|
||||
- 🔴 违反行为准则
|
||||
- 🔴 包含抄袭代码
|
||||
- 🔴 硬编码 API 密钥或密码
|
||||
|
||||
**请求更改:**
|
||||
- 🟡 代码质量差(反馈被忽略后)
|
||||
- 🟡 新功能没有测试
|
||||
- 🟡 没有迁移路径的破坏性变更
|
||||
- 🟡 与路线图不一致(未经事先讨论)
|
||||
- 🟡 不完整(缺少关键部分)
|
||||
|
||||
**关闭并说明:**
|
||||
- 🟠 重复功能
|
||||
- 🟠 超出项目范围
|
||||
- 🟠 已存在更好的替代方案
|
||||
- 🟠 贡献者 >2 周无响应
|
||||
|
||||
---
|
||||
|
||||
## 🎯 特殊情况审核
|
||||
|
||||
### 悬赏 PR
|
||||
|
||||
需要额外注意:
|
||||
|
||||
- [ ] 所有验收标准都满足?
|
||||
- [ ] 提供了演示视频/截图?
|
||||
- [ ] 按悬赏 issue 中的规定工作?
|
||||
- [ ] 私下讨论了付款信息?
|
||||
- [ ] 优先审核(24小时周转)
|
||||
|
||||
### 破坏性变更
|
||||
|
||||
- [ ] 提供了迁移指南?
|
||||
- [ ] 添加了弃用警告?
|
||||
- [ ] 计划了版本升级?
|
||||
- [ ] 考虑了向后兼容性?
|
||||
- [ ] 为重大变更创建了 RFC?
|
||||
|
||||
### 安全 PR
|
||||
|
||||
- [ ] 由专注于安全的审核者验证?
|
||||
- [ ] 没有公开披露漏洞?
|
||||
- [ ] 如需要,协调披露?
|
||||
- [ ] 准备了安全公告?
|
||||
- [ ] 计划了补丁发布?
|
||||
|
||||
---
|
||||
|
||||
## 🔄 合并指南
|
||||
|
||||
### 何时合并
|
||||
|
||||
满足以下条件时合并:
|
||||
- ✅ 至少 1 个维护者批准
|
||||
- ✅ 所有 CI 检查通过
|
||||
- ✅ 所有对话已解决
|
||||
- ✅ 没有待处理的请求更改
|
||||
- ✅ 已基于最新目标分支 rebase
|
||||
|
||||
### 合并策略
|
||||
|
||||
**Squash Merge**(大多数 PR 的默认策略):
|
||||
- 小型 bug 修复
|
||||
- 单功能 PR
|
||||
- 文档更新
|
||||
- 保持 git 历史清洁
|
||||
|
||||
**Merge Commit**(复杂 PR):
|
||||
- 具有逻辑提交的多提交功能
|
||||
- 保留提交历史
|
||||
- 具有原子提交的大型重构
|
||||
|
||||
**Rebase and Merge**(很少使用):
|
||||
- 线性历史很重要时
|
||||
- 提交已经结构良好
|
||||
|
||||
### 合并提交信息
|
||||
|
||||
格式:
|
||||
```
|
||||
<type>(<scope>): <PR 标题> (#123)
|
||||
|
||||
变更的简要描述。
|
||||
|
||||
- 关键变更 1
|
||||
- 关键变更 2
|
||||
|
||||
Co-authored-by: 贡献者姓名 <email@example.com>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 要跟踪的审核指标
|
||||
|
||||
每月监控这些指标:
|
||||
|
||||
- 平均首次审核时间
|
||||
- 平均合并时间
|
||||
- PR 接受率
|
||||
- 按类型分类的 PR 数量(bug/feature/docs)
|
||||
- 按区域分类的 PR 数量(frontend/backend/exchange)
|
||||
- 贡献者留存率
|
||||
|
||||
---
|
||||
|
||||
## 🙋 问题?
|
||||
|
||||
如果对 PR 不确定:
|
||||
|
||||
1. **询问其他维护者**在私人频道
|
||||
2. **向贡献者请求更多上下文**
|
||||
3. **标记为"on hold"**并添加到下次维护者同步
|
||||
4. **如有疑问,保守一点** - 问比批准有风险的东西更好
|
||||
|
||||
---
|
||||
|
||||
## 🔗 相关资源
|
||||
|
||||
- [贡献指南](../../CONTRIBUTING.md)
|
||||
- [行为准则](../../CODE_OF_CONDUCT.md)
|
||||
- [安全政策](../../SECURITY.md)
|
||||
- [项目路线图](../roadmap/README.zh-CN.md)
|
||||
|
||||
---
|
||||
|
||||
**记住:** 审核应该是**尊重的**、**建设性的**和**教育性的**。
|
||||
我们在构建社区,而不仅仅是代码。🚀
|
||||
51
docs/maintainers/README.md
Normal file
51
docs/maintainers/README.md
Normal file
@@ -0,0 +1,51 @@
|
||||
# 📚 Maintainer Documentation
|
||||
|
||||
**Language:** [English](README.md) | [中文](README.zh-CN.md)
|
||||
|
||||
This directory contains documentation for NOFX project maintainers and contributors who want to understand our processes.
|
||||
|
||||
---
|
||||
|
||||
## 📖 Documentation
|
||||
|
||||
| Document | Description |
|
||||
|----------|-------------|
|
||||
| [PR_REVIEW_GUIDE.md](PR_REVIEW_GUIDE.md) | Guide for reviewing pull requests |
|
||||
| [PROJECT_MANAGEMENT.md](PROJECT_MANAGEMENT.md) | Project management workflow and processes |
|
||||
| [SETUP_GUIDE.md](SETUP_GUIDE.md) | Setup guide for the PR management system |
|
||||
|
||||
**Available in:** 🇬🇧 English | 🇨🇳 中文
|
||||
|
||||
---
|
||||
|
||||
## 🎯 For New Maintainers
|
||||
|
||||
If you're a new maintainer, start here:
|
||||
|
||||
1. **Read the documentation** (listed above) to understand the review process
|
||||
2. **Shadow an experienced maintainer** for 1-2 weeks
|
||||
3. **Start with simple reviews** before handling complex PRs
|
||||
4. **Ask questions** in the maintainer channel
|
||||
|
||||
---
|
||||
|
||||
## 🤝 For Contributors
|
||||
|
||||
These documents are also helpful for contributors who want to:
|
||||
- Understand our review standards
|
||||
- Learn our project management workflow
|
||||
- See how we prioritize work
|
||||
|
||||
Everything here is transparent and designed to help you contribute successfully!
|
||||
|
||||
---
|
||||
|
||||
## 📞 Questions?
|
||||
|
||||
- **Public questions:** Use [GitHub Discussions](https://github.com/tinkle-community/nofx/discussions)
|
||||
- **Maintainer questions:** Use the maintainer channel
|
||||
- **Migration questions:** See [Migration Announcement](../community/MIGRATION_ANNOUNCEMENT.md)
|
||||
|
||||
---
|
||||
|
||||
**Remember:** We're building an open, welcoming community. Documentation should empower contributors while maintaining project quality. 🚀
|
||||
51
docs/maintainers/README.zh-CN.md
Normal file
51
docs/maintainers/README.zh-CN.md
Normal file
@@ -0,0 +1,51 @@
|
||||
# 📚 维护者文档
|
||||
|
||||
**语言:** [English](README.md) | [中文](README.zh-CN.md)
|
||||
|
||||
此目录包含 NOFX 项目维护者和想要了解我们流程的贡献者的文档。
|
||||
|
||||
---
|
||||
|
||||
## 📖 文档
|
||||
|
||||
| 文档 | 描述 |
|
||||
|------|------|
|
||||
| [PR_REVIEW_GUIDE.md](PR_REVIEW_GUIDE.md) | PR 审核指南 |
|
||||
| [PROJECT_MANAGEMENT.md](PROJECT_MANAGEMENT.md) | 项目管理工作流程和流程 |
|
||||
| [SETUP_GUIDE.md](SETUP_GUIDE.md) | PR 管理系统设置指南 |
|
||||
|
||||
**可用语言:** 🇬🇧 English | 🇨🇳 中文
|
||||
|
||||
---
|
||||
|
||||
## 🎯 对于新维护者
|
||||
|
||||
如果你是新维护者,从这里开始:
|
||||
|
||||
1. **阅读文档**(上面列出的)以了解审核流程
|
||||
2. **跟随有经验的维护者** 1-2 周
|
||||
3. **从简单的审核开始**,然后再处理复杂的 PR
|
||||
4. **在维护者频道提问**
|
||||
|
||||
---
|
||||
|
||||
## 🤝 对于贡献者
|
||||
|
||||
这些文档对想要以下内容的贡献者也很有帮助:
|
||||
- 了解我们的审核标准
|
||||
- 学习我们的项目管理工作流程
|
||||
- 了解我们如何排定工作优先级
|
||||
|
||||
这里的一切都是透明的,旨在帮助你成功贡献!
|
||||
|
||||
---
|
||||
|
||||
## 📞 问题?
|
||||
|
||||
- **公开问题:** 使用 [GitHub Discussions](https://github.com/tinkle-community/nofx/discussions)
|
||||
- **维护者问题:** 使用维护者频道
|
||||
- **迁移问题:** 查看[迁移公告](../community/MIGRATION_ANNOUNCEMENT.zh-CN.md)
|
||||
|
||||
---
|
||||
|
||||
**记住:** 我们正在建立一个开放、热情的社区。文档应该赋能贡献者,同时保持项目质量。🚀
|
||||
381
docs/maintainers/SETUP_GUIDE.md
Normal file
381
docs/maintainers/SETUP_GUIDE.md
Normal file
@@ -0,0 +1,381 @@
|
||||
# 🚀 PR Management System Setup Guide
|
||||
|
||||
**Language:** [English](SETUP_GUIDE.md) | [中文](SETUP_GUIDE.zh-CN.md)
|
||||
|
||||
This guide will help you set up and activate the complete PR management system for NOFX.
|
||||
|
||||
---
|
||||
|
||||
## 📦 What's Included
|
||||
|
||||
The PR management system includes:
|
||||
|
||||
### 1. **Documentation**
|
||||
- ✅ `CONTRIBUTING.md` - Contributor guidelines
|
||||
- ✅ `docs/maintainers/PR_REVIEW_GUIDE.md` - Reviewer guidelines
|
||||
- ✅ `docs/maintainers/PROJECT_MANAGEMENT.md` - Project management workflow
|
||||
- ✅ `docs/maintainers/SETUP_GUIDE.md` - This file
|
||||
|
||||
### 2. **GitHub Configuration**
|
||||
- ✅ `.github/PULL_REQUEST_TEMPLATE.md` - PR template (already exists)
|
||||
- ✅ `.github/labels.yml` - Label definitions
|
||||
- ✅ `.github/labeler.yml` - Auto-labeling rules
|
||||
- ✅ `.github/workflows/pr-checks.yml` - Automated PR checks
|
||||
|
||||
### 3. **Automation**
|
||||
- ✅ Automatic PR labeling
|
||||
- ✅ PR size checking
|
||||
- ✅ CI/CD tests
|
||||
- ✅ Security scanning
|
||||
- ✅ Commit message validation
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Setup Steps
|
||||
|
||||
### Step 1: Sync GitHub Labels
|
||||
|
||||
Create the labels defined in `.github/labels.yml`:
|
||||
|
||||
```bash
|
||||
# Option 1: Using gh CLI (recommended)
|
||||
gh label list # See current labels
|
||||
gh label delete <label-name> # Remove old labels if needed
|
||||
gh label create "priority: critical" --color "d73a4a" --description "Critical priority"
|
||||
# ... repeat for all labels in labels.yml
|
||||
|
||||
# Option 2: Use GitHub Labeler Action (automated)
|
||||
# The workflow will sync labels automatically on push
|
||||
```
|
||||
|
||||
**Or use the GitHub Labeler Action** (add to `.github/workflows/sync-labels.yml`):
|
||||
|
||||
```yaml
|
||||
name: Sync Labels
|
||||
on:
|
||||
push:
|
||||
branches: [main, dev]
|
||||
paths:
|
||||
- '.github/labels.yml'
|
||||
|
||||
jobs:
|
||||
labels:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: crazy-max/ghaction-github-labeler@v5
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
yaml-file: .github/labels.yml
|
||||
```
|
||||
|
||||
### Step 2: Enable GitHub Actions
|
||||
|
||||
1. Go to **Settings → Actions → General**
|
||||
2. Enable **"Allow all actions and reusable workflows"**
|
||||
3. Set **Workflow permissions** to **"Read and write permissions"**
|
||||
4. Check **"Allow GitHub Actions to create and approve pull requests"**
|
||||
|
||||
### Step 3: Set Up Branch Protection Rules
|
||||
|
||||
**For `main` branch:**
|
||||
|
||||
1. Go to **Settings → Branches → Add rule**
|
||||
2. Branch name pattern: `main`
|
||||
3. Configure:
|
||||
- ✅ Require a pull request before merging
|
||||
- ✅ Require approvals: **1**
|
||||
- ✅ Require status checks to pass before merging
|
||||
- Select: `Backend Tests (Go)`
|
||||
- Select: `Frontend Tests (React/TypeScript)`
|
||||
- Select: `Security Scan`
|
||||
- ✅ Require conversation resolution before merging
|
||||
- ✅ Do not allow bypassing the above settings
|
||||
- ❌ Allow force pushes (disabled)
|
||||
- ❌ Allow deletions (disabled)
|
||||
|
||||
**For `dev` branch:**
|
||||
|
||||
1. Same as above, but with:
|
||||
- Require approvals: **1**
|
||||
- Less strict (allow maintainers to bypass if needed)
|
||||
|
||||
### Step 4: Create GitHub Projects
|
||||
|
||||
1. Go to **Projects → New project**
|
||||
2. Create **"NOFX Development"** board
|
||||
- Template: Board
|
||||
- Add columns: `Backlog`, `Triaged`, `In Progress`, `In Review`, `Done`
|
||||
- Add views: Sprint, Roadmap, By Area, Priority
|
||||
|
||||
3. Create **"Bounty Program"** board
|
||||
- Template: Board
|
||||
- Add columns: `Available`, `Claimed`, `In Progress`, `Under Review`, `Paid`
|
||||
|
||||
### Step 5: Enable Discussions (Optional but Recommended)
|
||||
|
||||
1. Go to **Settings → General → Features**
|
||||
2. Enable **"Discussions"**
|
||||
3. Create categories:
|
||||
- 💬 **General** - General discussions
|
||||
- 💡 **Ideas** - Feature ideas and suggestions
|
||||
- 🙏 **Q&A** - Questions and answers
|
||||
- 📢 **Announcements** - Important updates
|
||||
- 🗳️ **Polls** - Community polls
|
||||
|
||||
### Step 6: Configure Issue Templates
|
||||
|
||||
The templates already exist in `.github/ISSUE_TEMPLATE/`. Verify they're working:
|
||||
|
||||
1. Go to **Issues → New issue**
|
||||
2. You should see:
|
||||
- 🐛 Bug Report
|
||||
- ✨ Feature Request
|
||||
- 💰 Bounty Claim
|
||||
|
||||
If not showing, check files are properly formatted YAML with frontmatter.
|
||||
|
||||
### Step 7: Set Up Code Owners (Optional)
|
||||
|
||||
Create `.github/CODEOWNERS`:
|
||||
|
||||
```
|
||||
# Global owners
|
||||
* @tinkle @zack
|
||||
|
||||
# Frontend
|
||||
/web/ @frontend-lead
|
||||
|
||||
# Exchange integrations
|
||||
/internal/exchange/ @exchange-lead
|
||||
|
||||
# AI components
|
||||
/internal/ai/ @ai-lead
|
||||
|
||||
# Documentation
|
||||
/docs/ @tinkle @zack
|
||||
*.md @tinkle @zack
|
||||
```
|
||||
|
||||
### Step 8: Configure Notifications
|
||||
|
||||
**For Maintainers:**
|
||||
|
||||
1. Go to **Settings → Notifications**
|
||||
2. Enable:
|
||||
- ✅ Pull request reviews
|
||||
- ✅ Pull request pushes
|
||||
- ✅ Comments on issues and PRs
|
||||
- ✅ New issues
|
||||
- ✅ Security alerts
|
||||
|
||||
3. Set up email filters to organize notifications
|
||||
|
||||
**For Repository:**
|
||||
|
||||
1. Go to **Settings → Webhooks** (if integrating with Slack/Discord)
|
||||
2. Add webhook for notifications
|
||||
|
||||
---
|
||||
|
||||
## 📋 Post-Setup Checklist
|
||||
|
||||
After setup, verify:
|
||||
|
||||
- [ ] Labels are created and visible
|
||||
- [ ] Branch protection rules are active
|
||||
- [ ] GitHub Actions workflows run on new PR
|
||||
- [ ] Auto-labeling works (create a test PR)
|
||||
- [ ] PR template shows when creating PR
|
||||
- [ ] Issue templates show when creating issue
|
||||
- [ ] Projects boards are accessible
|
||||
- [ ] CONTRIBUTING.md is linked in README
|
||||
|
||||
---
|
||||
|
||||
## 🎯 How to Use the System
|
||||
|
||||
### For Contributors
|
||||
|
||||
1. **Read** [CONTRIBUTING.md](../../../CONTRIBUTING.md)
|
||||
2. **Check** [Roadmap](../../roadmap/README.md) for priorities
|
||||
3. **Open issue** or find existing one
|
||||
4. **Create PR** using the template
|
||||
5. **Address review feedback**
|
||||
6. **Celebrate** when merged! 🎉
|
||||
|
||||
### For Maintainers
|
||||
|
||||
1. **Daily:** Triage new issues/PRs (15 min)
|
||||
2. **Daily:** Review assigned PRs
|
||||
3. **Weekly:** Sprint planning (Monday) and review (Friday)
|
||||
4. **Follow:** [PR Review Guide](PR_REVIEW_GUIDE.md)
|
||||
5. **Follow:** [Project Management Guide](PROJECT_MANAGEMENT.md)
|
||||
|
||||
### For Bounty Hunters
|
||||
|
||||
1. **Check** bounty issues with `bounty` label
|
||||
2. **Claim** by commenting on issue
|
||||
3. **Complete** within deadline
|
||||
4. **Submit PR** with bounty claim section filled
|
||||
5. **Get paid** after merge
|
||||
|
||||
---
|
||||
|
||||
## 🔍 Testing the System
|
||||
|
||||
### Test 1: Create a Test PR
|
||||
|
||||
```bash
|
||||
# Create a test branch
|
||||
git checkout -b test/pr-system-check
|
||||
|
||||
# Make a small change
|
||||
echo "# Test" >> TEST.md
|
||||
|
||||
# Commit and push
|
||||
git add TEST.md
|
||||
git commit -m "test: verify PR automation system"
|
||||
git push origin test/pr-system-check
|
||||
|
||||
# Create PR on GitHub
|
||||
# Verify:
|
||||
# - PR template loads
|
||||
# - Auto-labels are applied
|
||||
# - CI checks run
|
||||
# - Size label is added
|
||||
```
|
||||
|
||||
### Test 2: Create a Test Issue
|
||||
|
||||
1. Go to **Issues → New issue**
|
||||
2. Select **Bug Report**
|
||||
3. Fill in template
|
||||
4. Submit
|
||||
5. Verify:
|
||||
- Template renders correctly
|
||||
- Issue can be labeled
|
||||
- Issue appears in project board
|
||||
|
||||
### Test 3: Test Auto-Labeling
|
||||
|
||||
Create PRs that change files in different areas:
|
||||
|
||||
```bash
|
||||
# Test 1: Frontend changes
|
||||
git checkout -b test/frontend-label
|
||||
touch web/src/test.tsx
|
||||
git add . && git commit -m "test: frontend labeling"
|
||||
git push origin test/frontend-label
|
||||
# Should get "area: frontend" label
|
||||
|
||||
# Test 2: Backend changes
|
||||
git checkout -b test/backend-label
|
||||
touch internal/test.go
|
||||
git add . && git commit -m "test: backend labeling"
|
||||
git push origin test/backend-label
|
||||
# Should get "area: backend" label
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🐛 Troubleshooting
|
||||
|
||||
### Issue: Labels not syncing
|
||||
|
||||
**Solution:**
|
||||
```bash
|
||||
# Delete all existing labels first
|
||||
gh label list --json name --jq '.[].name' | xargs -I {} gh label delete "{}" --yes
|
||||
|
||||
# Then create from labels.yml manually or via action
|
||||
```
|
||||
|
||||
### Issue: GitHub Actions not running
|
||||
|
||||
**Check:**
|
||||
1. Actions are enabled in repository settings
|
||||
2. Workflow files are in `.github/workflows/`
|
||||
3. YAML syntax is valid
|
||||
4. Permissions are set correctly
|
||||
|
||||
**Debug:**
|
||||
```bash
|
||||
# Validate workflow locally
|
||||
act pull_request # Using 'act' tool
|
||||
```
|
||||
|
||||
### Issue: Branch protection blocking PRs
|
||||
|
||||
**Check:**
|
||||
1. Required checks are defined in workflow
|
||||
2. Check names match exactly
|
||||
3. Checks are completing (not stuck)
|
||||
|
||||
**Temporary fix:**
|
||||
- Maintainers can bypass if urgent
|
||||
- Adjust protection rules if too strict
|
||||
|
||||
### Issue: Auto-labeler not working
|
||||
|
||||
**Check:**
|
||||
1. `.github/labeler.yml` exists and valid YAML
|
||||
2. Labels defined in labeler.yml exist in repository
|
||||
3. Workflow has `pull-requests: write` permission
|
||||
|
||||
---
|
||||
|
||||
## 📊 Monitoring and Maintenance
|
||||
|
||||
### Weekly Review
|
||||
|
||||
Check these metrics every week:
|
||||
|
||||
```bash
|
||||
# Using gh CLI
|
||||
gh pr list --state all --json number,createdAt,closedAt
|
||||
gh issue list --state all --json number,createdAt,closedAt
|
||||
|
||||
# Or use GitHub Insights
|
||||
# Repository → Insights → Pulse, Contributors, Traffic
|
||||
```
|
||||
|
||||
### Monthly Maintenance
|
||||
|
||||
- [ ] Review and update labels if needed
|
||||
- [ ] Check for outdated dependencies in workflows
|
||||
- [ ] Update CONTRIBUTING.md if processes change
|
||||
- [ ] Review automation effectiveness
|
||||
- [ ] Gather community feedback
|
||||
|
||||
---
|
||||
|
||||
## 🎓 Training Resources
|
||||
|
||||
### For New Contributors
|
||||
|
||||
- [First Contributions Guide](https://github.com/firstcontributions/first-contributions)
|
||||
- [How to Write a Git Commit Message](https://chris.beams.io/posts/git-commit/)
|
||||
- [Conventional Commits](https://www.conventionalcommits.org/)
|
||||
|
||||
### For Maintainers
|
||||
|
||||
- [The Art of Code Review](https://google.github.io/eng-practices/review/)
|
||||
- [GitHub Project Management](https://docs.github.com/en/issues/planning-and-tracking-with-projects)
|
||||
- [Maintainer Community](https://maintainers.github.com/)
|
||||
|
||||
---
|
||||
|
||||
## 🎉 You're All Set!
|
||||
|
||||
The PR management system is now ready to:
|
||||
|
||||
✅ Guide contributors with clear guidelines
|
||||
✅ Automate repetitive tasks
|
||||
✅ Maintain code quality
|
||||
✅ Track progress systematically
|
||||
✅ Scale the community
|
||||
|
||||
**Questions?** Reach out in the maintainer channel or open a discussion.
|
||||
|
||||
**Let's build an amazing community! 🚀**
|
||||
381
docs/maintainers/SETUP_GUIDE.zh-CN.md
Normal file
381
docs/maintainers/SETUP_GUIDE.zh-CN.md
Normal file
@@ -0,0 +1,381 @@
|
||||
# 🚀 PR 管理系统设置指南
|
||||
|
||||
**语言:** [English](SETUP_GUIDE.md) | [中文](SETUP_GUIDE.zh-CN.md)
|
||||
|
||||
本指南将帮助你为 NOFX 设置和激活完整的 PR 管理系统。
|
||||
|
||||
---
|
||||
|
||||
## 📦 包含内容
|
||||
|
||||
PR 管理系统包括:
|
||||
|
||||
### 1. **文档**
|
||||
- ✅ `CONTRIBUTING.md` - 贡献者指南
|
||||
- ✅ `docs/maintainers/PR_REVIEW_GUIDE.md` - 审核者指南
|
||||
- ✅ `docs/maintainers/PROJECT_MANAGEMENT.md` - 项目管理工作流程
|
||||
- ✅ `docs/maintainers/SETUP_GUIDE.md` - 本文件
|
||||
|
||||
### 2. **GitHub 配置**
|
||||
- ✅ `.github/PULL_REQUEST_TEMPLATE.md` - PR 模板(已存在)
|
||||
- ✅ `.github/labels.yml` - 标签定义
|
||||
- ✅ `.github/labeler.yml` - 自动标签规则
|
||||
- ✅ `.github/workflows/pr-checks.yml` - 自动化 PR 检查
|
||||
|
||||
### 3. **自动化**
|
||||
- ✅ 自动 PR 标签
|
||||
- ✅ PR 大小检查
|
||||
- ✅ CI/CD 测试
|
||||
- ✅ 安全扫描
|
||||
- ✅ Commit 信息验证
|
||||
|
||||
---
|
||||
|
||||
## 🔧 设置步骤
|
||||
|
||||
### 步骤 1:同步 GitHub 标签
|
||||
|
||||
创建 `.github/labels.yml` 中定义的标签:
|
||||
|
||||
```bash
|
||||
# 选项 1:使用 gh CLI(推荐)
|
||||
gh label list # 查看当前标签
|
||||
gh label delete <label-name> # 如需要,删除旧标签
|
||||
gh label create "priority: critical" --color "d73a4a" --description "Critical priority"
|
||||
# ... 为 labels.yml 中的所有标签重复
|
||||
|
||||
# 选项 2:使用 GitHub Labeler Action(自动化)
|
||||
# 工作流将在推送时自动同步标签
|
||||
```
|
||||
|
||||
**或使用 GitHub Labeler Action**(添加到 `.github/workflows/sync-labels.yml`):
|
||||
|
||||
```yaml
|
||||
name: Sync Labels
|
||||
on:
|
||||
push:
|
||||
branches: [main, dev]
|
||||
paths:
|
||||
- '.github/labels.yml'
|
||||
|
||||
jobs:
|
||||
labels:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: crazy-max/ghaction-github-labeler@v5
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
yaml-file: .github/labels.yml
|
||||
```
|
||||
|
||||
### 步骤 2:启用 GitHub Actions
|
||||
|
||||
1. 前往 **Settings → Actions → General**
|
||||
2. 启用 **"Allow all actions and reusable workflows"**
|
||||
3. 设置 **Workflow permissions** 为 **"Read and write permissions"**
|
||||
4. 勾选 **"Allow GitHub Actions to create and approve pull requests"**
|
||||
|
||||
### 步骤 3:设置分支保护规则
|
||||
|
||||
**对于 `main` 分支:**
|
||||
|
||||
1. 前往 **Settings → Branches → Add rule**
|
||||
2. 分支名称模式:`main`
|
||||
3. 配置:
|
||||
- ✅ Require a pull request before merging
|
||||
- ✅ Require approvals: **1**
|
||||
- ✅ Require status checks to pass before merging
|
||||
- 选择:`Backend Tests (Go)`
|
||||
- 选择:`Frontend Tests (React/TypeScript)`
|
||||
- 选择:`Security Scan`
|
||||
- ✅ Require conversation resolution before merging
|
||||
- ✅ Do not allow bypassing the above settings
|
||||
- ❌ Allow force pushes(禁用)
|
||||
- ❌ Allow deletions(禁用)
|
||||
|
||||
**对于 `dev` 分支:**
|
||||
|
||||
1. 与上面相同,但:
|
||||
- Require approvals: **1**
|
||||
- 宽松一些(如需要允许维护者绕过)
|
||||
|
||||
### 步骤 4:创建 GitHub Projects
|
||||
|
||||
1. 前往 **Projects → New project**
|
||||
2. 创建 **"NOFX Development"** 看板
|
||||
- 模板:Board
|
||||
- 添加列:`Backlog`、`Triaged`、`In Progress`、`In Review`、`Done`
|
||||
- 添加视图:Sprint、Roadmap、By Area、Priority
|
||||
|
||||
3. 创建 **"Bounty Program"** 看板
|
||||
- 模板:Board
|
||||
- 添加列:`Available`、`Claimed`、`In Progress`、`Under Review`、`Paid`
|
||||
|
||||
### 步骤 5:启用 Discussions(可选但推荐)
|
||||
|
||||
1. 前往 **Settings → General → Features**
|
||||
2. 启用 **"Discussions"**
|
||||
3. 创建分类:
|
||||
- 💬 **General** - 一般讨论
|
||||
- 💡 **Ideas** - 功能想法和建议
|
||||
- 🙏 **Q&A** - 问答
|
||||
- 📢 **Announcements** - 重要更新
|
||||
- 🗳️ **Polls** - 社区投票
|
||||
|
||||
### 步骤 6:配置 Issue 模板
|
||||
|
||||
模板已存在于 `.github/ISSUE_TEMPLATE/` 中。验证它们是否正常工作:
|
||||
|
||||
1. 前往 **Issues → New issue**
|
||||
2. 你应该看到:
|
||||
- 🐛 Bug Report
|
||||
- ✨ Feature Request
|
||||
- 💰 Bounty Claim
|
||||
|
||||
如果没有显示,检查文件是否为正确格式的 YAML 和 frontmatter。
|
||||
|
||||
### 步骤 7:设置 Code Owners(可选)
|
||||
|
||||
创建 `.github/CODEOWNERS`:
|
||||
|
||||
```
|
||||
# 全局所有者
|
||||
* @tinkle @zack
|
||||
|
||||
# 前端
|
||||
/web/ @frontend-lead
|
||||
|
||||
# 交易所集成
|
||||
/internal/exchange/ @exchange-lead
|
||||
|
||||
# AI 组件
|
||||
/internal/ai/ @ai-lead
|
||||
|
||||
# 文档
|
||||
/docs/ @tinkle @zack
|
||||
*.md @tinkle @zack
|
||||
```
|
||||
|
||||
### 步骤 8:配置通知
|
||||
|
||||
**对于维护者:**
|
||||
|
||||
1. 前往 **Settings → Notifications**
|
||||
2. 启用:
|
||||
- ✅ Pull request reviews
|
||||
- ✅ Pull request pushes
|
||||
- ✅ Comments on issues and PRs
|
||||
- ✅ New issues
|
||||
- ✅ Security alerts
|
||||
|
||||
3. 设置电子邮件过滤器来组织通知
|
||||
|
||||
**对于仓库:**
|
||||
|
||||
1. 前往 **Settings → Webhooks**(如果与 Slack/Discord 集成)
|
||||
2. 添加通知 webhook
|
||||
|
||||
---
|
||||
|
||||
## 📋 设置后检查清单
|
||||
|
||||
设置后,验证:
|
||||
|
||||
- [ ] 标签已创建并可见
|
||||
- [ ] 分支保护规则已激活
|
||||
- [ ] GitHub Actions 工作流在新 PR 上运行
|
||||
- [ ] 自动标签工作(创建测试 PR)
|
||||
- [ ] 创建 PR 时显示 PR 模板
|
||||
- [ ] 创建 issue 时显示 issue 模板
|
||||
- [ ] Projects 看板可访问
|
||||
- [ ] CONTRIBUTING.md 在 README 中链接
|
||||
|
||||
---
|
||||
|
||||
## 🎯 如何使用系统
|
||||
|
||||
### 对于贡献者
|
||||
|
||||
1. **阅读** [CONTRIBUTING.md](../../../CONTRIBUTING.md)
|
||||
2. **查看** [路线图](../../roadmap/README.zh-CN.md)了解优先级
|
||||
3. **开启 issue** 或找到现有的
|
||||
4. **使用模板创建 PR**
|
||||
5. **处理审核反馈**
|
||||
6. **庆祝** 当合并时!🎉
|
||||
|
||||
### 对于维护者
|
||||
|
||||
1. **每日:** 分类新 issue/PR(15分钟)
|
||||
2. **每日:** 审查分配的 PR
|
||||
3. **每周:** Sprint 计划(周一)和回顾(周五)
|
||||
4. **遵循:** [PR 审核指南](PR_REVIEW_GUIDE.zh-CN.md)
|
||||
5. **遵循:** [项目管理指南](PROJECT_MANAGEMENT.zh-CN.md)
|
||||
|
||||
### 对于悬赏猎人
|
||||
|
||||
1. **查看** 带有 `bounty` 标签的悬赏 issue
|
||||
2. **通过评论认领** issue
|
||||
3. **在截止日期前完成**
|
||||
4. **提交 PR** 并填写悬赏认领部分
|
||||
5. **合并后获得报酬**
|
||||
|
||||
---
|
||||
|
||||
## 🔍 测试系统
|
||||
|
||||
### 测试 1:创建测试 PR
|
||||
|
||||
```bash
|
||||
# 创建测试分支
|
||||
git checkout -b test/pr-system-check
|
||||
|
||||
# 进行小改动
|
||||
echo "# Test" >> TEST.md
|
||||
|
||||
# 提交并推送
|
||||
git add TEST.md
|
||||
git commit -m "test: verify PR automation system"
|
||||
git push origin test/pr-system-check
|
||||
|
||||
# 在 GitHub 上创建 PR
|
||||
# 验证:
|
||||
# - PR 模板加载
|
||||
# - 应用了自动标签
|
||||
# - CI 检查运行
|
||||
# - 添加了大小标签
|
||||
```
|
||||
|
||||
### 测试 2:创建测试 Issue
|
||||
|
||||
1. 前往 **Issues → New issue**
|
||||
2. 选择 **Bug Report**
|
||||
3. 填写模板
|
||||
4. 提交
|
||||
5. 验证:
|
||||
- 模板正确渲染
|
||||
- Issue 可以被标签
|
||||
- Issue 出现在项目看板中
|
||||
|
||||
### 测试 3:测试自动标签
|
||||
|
||||
创建改动不同区域文件的 PR:
|
||||
|
||||
```bash
|
||||
# 测试 1:前端变更
|
||||
git checkout -b test/frontend-label
|
||||
touch web/src/test.tsx
|
||||
git add . && git commit -m "test: frontend labeling"
|
||||
git push origin test/frontend-label
|
||||
# 应该得到 "area: frontend" 标签
|
||||
|
||||
# 测试 2:后端变更
|
||||
git checkout -b test/backend-label
|
||||
touch internal/test.go
|
||||
git add . && git commit -m "test: backend labeling"
|
||||
git push origin test/backend-label
|
||||
# 应该得到 "area: backend" 标签
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🐛 故障排除
|
||||
|
||||
### 问题:标签未同步
|
||||
|
||||
**解决方案:**
|
||||
```bash
|
||||
# 首先删除所有现有标签
|
||||
gh label list --json name --jq '.[].name' | xargs -I {} gh label delete "{}" --yes
|
||||
|
||||
# 然后从 labels.yml 手动创建或通过 action 创建
|
||||
```
|
||||
|
||||
### 问题:GitHub Actions 未运行
|
||||
|
||||
**检查:**
|
||||
1. 仓库设置中启用了 Actions
|
||||
2. 工作流文件在 `.github/workflows/` 中
|
||||
3. YAML 语法有效
|
||||
4. 权限设置正确
|
||||
|
||||
**调试:**
|
||||
```bash
|
||||
# 本地验证工作流
|
||||
act pull_request # 使用 'act' 工具
|
||||
```
|
||||
|
||||
### 问题:分支保护阻止 PR
|
||||
|
||||
**检查:**
|
||||
1. 必需的检查在工作流中定义
|
||||
2. 检查名称完全匹配
|
||||
3. 检查正在完成(没有卡住)
|
||||
|
||||
**临时修复:**
|
||||
- 维护者可以在紧急情况下绕过
|
||||
- 如果太严格,调整保护规则
|
||||
|
||||
### 问题:自动标签器不工作
|
||||
|
||||
**检查:**
|
||||
1. `.github/labeler.yml` 存在且为有效 YAML
|
||||
2. labeler.yml 中定义的标签在仓库中存在
|
||||
3. 工作流有 `pull-requests: write` 权限
|
||||
|
||||
---
|
||||
|
||||
## 📊 监控和维护
|
||||
|
||||
### 每周回顾
|
||||
|
||||
每周检查这些指标:
|
||||
|
||||
```bash
|
||||
# 使用 gh CLI
|
||||
gh pr list --state all --json number,createdAt,closedAt
|
||||
gh issue list --state all --json number,createdAt,closedAt
|
||||
|
||||
# 或使用 GitHub Insights
|
||||
# Repository → Insights → Pulse, Contributors, Traffic
|
||||
```
|
||||
|
||||
### 每月维护
|
||||
|
||||
- [ ] 如需要审查和更新标签
|
||||
- [ ] 检查工作流中的过期依赖
|
||||
- [ ] 如果流程变更更新 CONTRIBUTING.md
|
||||
- [ ] 审查自动化效果
|
||||
- [ ] 收集社区反馈
|
||||
|
||||
---
|
||||
|
||||
## 🎓 培训资源
|
||||
|
||||
### 对于新贡献者
|
||||
|
||||
- [首次贡献指南](https://github.com/firstcontributions/first-contributions)
|
||||
- [如何写 Git Commit 信息](https://chris.beams.io/posts/git-commit/)
|
||||
- [Conventional Commits](https://www.conventionalcommits.org/)
|
||||
|
||||
### 对于维护者
|
||||
|
||||
- [代码审核的艺术](https://google.github.io/eng-practices/review/)
|
||||
- [GitHub 项目管理](https://docs.github.com/en/issues/planning-and-tracking-with-projects)
|
||||
- [维护者社区](https://maintainers.github.com/)
|
||||
|
||||
---
|
||||
|
||||
## 🎉 一切就绪!
|
||||
|
||||
PR 管理系统现在已准备好:
|
||||
|
||||
✅ 用清晰的指南引导贡献者
|
||||
✅ 自动化重复任务
|
||||
✅ 保持代码质量
|
||||
✅ 系统性地跟踪进度
|
||||
✅ 扩展社区
|
||||
|
||||
**有问题?** 在维护者频道联系我们或开启讨论。
|
||||
|
||||
**让我们构建令人惊叹的社区!🚀**
|
||||
292
docs/roadmap/README.md
Normal file
292
docs/roadmap/README.md
Normal file
@@ -0,0 +1,292 @@
|
||||
# 🗺️ NOFX Roadmap
|
||||
|
||||
**Language:** [English](README.md) | [中文](README.zh-CN.md)
|
||||
|
||||
Strategic plan for NOFX development and universal market expansion.
|
||||
|
||||
---
|
||||
|
||||
## 📋 Overview
|
||||
|
||||
NOFX is on a mission to become the **Universal AI Trading Operating System** for all financial markets. Our proven infrastructure on crypto markets is being extended to stocks, futures, options, forex, and beyond.
|
||||
|
||||
**Vision:** Same architecture. Same agent framework. All markets.
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Short-Term Roadmap
|
||||
|
||||
### Phase 1: Core Infrastructure Enhancement
|
||||
|
||||
#### 1.1 Security Enhancements
|
||||
**Goal:** Protect sensitive data and reduce security vulnerabilities
|
||||
|
||||
- **Credential Management**
|
||||
- [ ] Implement AES-256 encryption for API keys in database
|
||||
- [ ] Add encryption for private keys (Hyperliquid, Aster)
|
||||
- [ ] Use hardware security module (HSM) support for production
|
||||
- [ ] Implement key rotation mechanism
|
||||
- [ ] Add audit logging for all credential access
|
||||
|
||||
- **Application Security**
|
||||
- [ ] Input validation and sanitization (prevent SQL injection, XSS)
|
||||
- [ ] Rate limiting for API endpoints
|
||||
- [ ] CORS policy configuration
|
||||
- [ ] JWT token expiration and refresh mechanism
|
||||
- [ ] Implement RBAC (Role-Based Access Control) for multi-user support
|
||||
- [ ] Add IP whitelisting for API access
|
||||
- [ ] Security headers (CSP, HSTS, X-Frame-Options)
|
||||
|
||||
- **Operational Security**
|
||||
- [ ] Secure password hashing (bcrypt with salt)
|
||||
- [ ] 2FA enhancement (backup codes, multiple TOTP devices)
|
||||
- [ ] Session management (auto-logout, concurrent session limits)
|
||||
- [ ] Secrets management (environment variables, vault integration)
|
||||
- [ ] Regular dependency vulnerability scanning
|
||||
|
||||
#### 1.2 Enhanced AI Capabilities
|
||||
**Goal:** Richer prompts, flexible configuration, support for more AI models
|
||||
|
||||
- **Prompt System Overhaul**
|
||||
- [ ] Template engine for dynamic prompt generation
|
||||
- [ ] Multi-language prompt support (chain-of-thought, few-shot, zero-shot)
|
||||
- [ ] Market condition-based prompt switching (bull, bear, sideways)
|
||||
- [ ] Historical performance feedback integration in prompts
|
||||
- [ ] Prompt versioning and A/B testing framework
|
||||
- [ ] User-customizable prompt templates via web interface
|
||||
|
||||
- **AI Model Integration**
|
||||
- [ ] OpenAI GPT-4/GPT-4 Turbo support
|
||||
- [ ] Anthropic Claude 3 (Opus, Sonnet, Haiku) integration
|
||||
- [ ] Google Gemini Pro support
|
||||
- [ ] Local LLM support (Llama, Mistral via Ollama)
|
||||
- [ ] Multi-model ensemble (voting, weighted average)
|
||||
- [ ] Model performance tracking and auto-selection
|
||||
- [ ] Fallback mechanism when primary model fails
|
||||
|
||||
- **AI Decision Engine**
|
||||
- [ ] Confidence scoring for each decision
|
||||
- [ ] Explanation generation (why this trade?)
|
||||
- [ ] Risk assessment integration in AI reasoning
|
||||
- [ ] Market regime detection (trend, mean-reversion, high volatility)
|
||||
- [ ] Cross-validation with technical indicators
|
||||
|
||||
#### 1.3 Exchange Integration Expansion
|
||||
**Goal:** Support more CEX and popular perp-DEX, both spot and futures
|
||||
|
||||
- **Centralized Exchanges (CEX)**
|
||||
- [ ] **OKX** - Futures + Spot trading
|
||||
- [ ] **Bybit** - Futures + Spot trading
|
||||
- [ ] **Bitget** - Futures + Spot trading
|
||||
- [ ] **Gate.io** - Futures + Spot trading
|
||||
- [ ] **KuCoin** - Futures + Spot trading
|
||||
- [ ] Unified CEX interface for easy addition of new exchanges
|
||||
|
||||
- **Decentralized Perpetual Exchanges (Perp-DEX)**
|
||||
- [x] **Hyperliquid** (Ethereum L1) - High-performance orderbook DEX (✅ Supported)
|
||||
- [x] **Aster** (Multi-chain) - Binance-compatible API DEX (✅ Supported)
|
||||
- [ ] **Lighter** (Arbitrum) - Gasless orderbook DEX with off-chain matching
|
||||
- [ ] **EdgeX** (Multi-chain) - Professional derivatives DEX
|
||||
- [ ] Unified DEX interface for consistent integration
|
||||
- [ ] Enhanced Hyperliquid integration (testnet support, advanced order types)
|
||||
- [ ] Enhanced Aster integration (cross-chain support, wallet management)
|
||||
|
||||
- **Spot + Futures Support**
|
||||
- [ ] Dual-mode trading (spot arbitrage, futures hedging)
|
||||
- [ ] Cross-exchange arbitrage detection
|
||||
- [ ] Unified position tracking across spot and futures
|
||||
- [ ] Auto-conversion between spot and perpetual strategies
|
||||
|
||||
- **Exchange Infrastructure**
|
||||
- [ ] **Trading Data Analysis API Integration** (In-house developed)
|
||||
- [ ] AI500 integration - In-house AI-powered coin selection model
|
||||
- [ ] OI (Open Interest) Analysis - Real-time open interest tracking and anomaly detection
|
||||
- [ ] NetFlow Analysis - On-chain fund flow analysis for market sentiment
|
||||
- [ ] Market sentiment aggregator - Combine multiple data sources for enhanced AI decision making
|
||||
- [ ] Custom indicator API - Support for proprietary technical indicators
|
||||
- [ ] Automatic precision handling (quantity, price decimals)
|
||||
- [ ] Order type abstraction (market, limit, stop-loss, take-profit)
|
||||
- [ ] Unified error handling and retry logic
|
||||
- [ ] WebSocket support for real-time data
|
||||
- [ ] Rate limit management per exchange
|
||||
|
||||
#### 1.4 Project Structure Refactoring
|
||||
**Goal:** Clear hierarchy, high cohesion, low coupling, easy to extend and maintain
|
||||
|
||||
- **Architecture Redesign**
|
||||
- [ ] Implement layered architecture (Presentation → Business Logic → Data Access)
|
||||
- [ ] Apply SOLID principles (especially Liskov Substitution Principle for exchange adapters)
|
||||
- [ ] Extract common interfaces for all exchange implementations
|
||||
- [ ] Separate concerns: trading logic, data fetching, decision making, execution
|
||||
- [ ] Implement dependency injection for better testability
|
||||
|
||||
- **Code Organization**
|
||||
- [ ] Refactor monolithic modules into smaller, focused packages
|
||||
- [ ] Create abstract base classes for traders, exchanges, AI models
|
||||
- [ ] Implement factory pattern for exchange/AI model creation
|
||||
- [ ] Standardize error handling and logging across all modules
|
||||
- [ ] Remove circular dependencies and improve import structure
|
||||
|
||||
- **Configuration Management**
|
||||
- [ ] Centralize all configuration in structured config files
|
||||
- [ ] Implement hot-reload for non-critical configuration changes
|
||||
- [ ] Validate configurations at startup with clear error messages
|
||||
- [ ] Support environment-specific configs (dev/staging/production)
|
||||
|
||||
#### 1.5 User Experience Improvements
|
||||
**Goal:** Enhanced web interface, better monitoring, and alerting system
|
||||
|
||||
- **Web Interface Enhancements**
|
||||
- [ ] Mobile-responsive design (tablet and phone support)
|
||||
- [ ] Dark/Light theme toggle with user preference saving
|
||||
- [ ] Advanced charting with TradingView widget integration
|
||||
- [ ] Real-time WebSocket updates (replace polling for positions/orders)
|
||||
- [ ] Drag-and-drop dashboard customization
|
||||
- [ ] Multi-language support (EN, CN, RU, UK)
|
||||
|
||||
- **Configuration Interface**
|
||||
- [ ] Visual strategy builder (no-code flow diagram)
|
||||
- [ ] Live configuration preview before saving
|
||||
- [ ] Configuration templates for common strategies
|
||||
- [ ] Bulk trader management (start/stop multiple traders)
|
||||
- [ ] Exchange credential testing (verify before saving)
|
||||
- [ ] AI model testing interface (test prompts before deployment)
|
||||
|
||||
- **Monitoring & Analytics**
|
||||
- [ ] Real-time performance dashboard with key metrics
|
||||
- [ ] Equity curve visualization (per trader, per exchange, overall)
|
||||
- [ ] Drawdown analysis and risk metrics
|
||||
- [ ] Trade history with filtering and search
|
||||
- [ ] P&L breakdown by symbol, time period, strategy
|
||||
- [ ] Comparison view (multiple traders side-by-side)
|
||||
- [ ] Export functionality (CSV, JSON, PDF reports)
|
||||
|
||||
- **Alert & Notification System**
|
||||
- [ ] Multi-channel alerts (Email, Telegram, Discord, Webhook)
|
||||
- [ ] Configurable alert rules (profit threshold, loss limit, error detection)
|
||||
- [ ] Alert priority levels (critical, warning, info)
|
||||
- [ ] Alert history and acknowledgment tracking
|
||||
- [ ] Daily/Weekly performance summary emails
|
||||
- [ ] System health monitoring (API connectivity, database status)
|
||||
|
||||
### Phase 2: Testing & Stability
|
||||
|
||||
#### 2.1 Quality Assurance
|
||||
- [ ] Comprehensive unit test coverage (>80%)
|
||||
- [ ] Integration tests for all exchange adapters
|
||||
- [ ] Load testing (100+ concurrent traders)
|
||||
- [ ] Security audit (API key encryption, SQL injection prevention)
|
||||
|
||||
#### 2.2 Documentation
|
||||
- [ ] Complete API reference documentation
|
||||
- [ ] Video tutorials for beginners
|
||||
- [ ] Strategy development guide
|
||||
- [ ] Troubleshooting playbook
|
||||
|
||||
#### 2.3 Community Features
|
||||
- [ ] Public strategy marketplace (share/sell strategies)
|
||||
- [ ] Leaderboard with verified performance
|
||||
- [ ] Community forum integration
|
||||
- [ ] Bug bounty program
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Long-Term Roadmap
|
||||
|
||||
### Phase 3: Universal Market Expansion
|
||||
|
||||
**Goal:** Extend the proven crypto trading infrastructure to all major financial markets.
|
||||
|
||||
#### 3.1 Stock Markets
|
||||
- [ ] US Equities (Interactive Brokers, Alpaca Markets)
|
||||
- [ ] Asian Markets (A-shares, Hong Kong, Japan)
|
||||
- [ ] Fundamental analysis integration (earnings, P/E, dividends)
|
||||
- [ ] AI-powered stock screening
|
||||
|
||||
#### 3.2 Futures Markets
|
||||
- [ ] Commodity Futures (Energy, Metals, Agriculture)
|
||||
- [ ] Index Futures (S&P 500, NASDAQ, Dow Jones, VIX)
|
||||
- [ ] Rollover management and spread trading
|
||||
|
||||
#### 3.3 Options Trading
|
||||
- [ ] Options chain data and Greeks calculation
|
||||
- [ ] Equity, Index, and Crypto options
|
||||
- [ ] Options strategy builder
|
||||
|
||||
#### 3.4 Forex Markets
|
||||
- [ ] Major currency pairs and exotic pairs
|
||||
- [ ] Interest rate analysis and carry trade support
|
||||
|
||||
---
|
||||
|
||||
### Phase 4: Advanced AI & Automation
|
||||
|
||||
**Goal:** Implement cutting-edge AI technologies for autonomous trading.
|
||||
|
||||
- [ ] Multi-Agent orchestration (specialized agents with dynamic coordination)
|
||||
- [ ] Reinforcement Learning (DQN, PPO, transfer learning)
|
||||
- [ ] Alternative data integration (social sentiment, news, on-chain analytics)
|
||||
|
||||
---
|
||||
|
||||
### Phase 5: Enterprise & Scaling
|
||||
|
||||
**Goal:** Scale infrastructure for institutional use and high-volume trading.
|
||||
|
||||
- [ ] Database migration (PostgreSQL/MySQL, Redis, TimescaleDB)
|
||||
- [ ] Microservices architecture with Kubernetes deployment
|
||||
- [ ] Multi-user RBAC and white-label solutions
|
||||
- [ ] Advanced analytics and compliance reporting
|
||||
|
||||
---
|
||||
|
||||
## 📊 Key Metrics & Milestones
|
||||
|
||||
### Short-Term Targets
|
||||
- [ ] **100+** supported trading pairs across all exchanges
|
||||
- [ ] **10,000+** active trader instances
|
||||
- [ ] **5+** new exchange integrations
|
||||
- [ ] **80%+** test coverage
|
||||
- [ ] **99.9%** uptime
|
||||
|
||||
### Long-Term Targets
|
||||
- [ ] **All major asset classes** supported (crypto, stocks, futures, options, forex)
|
||||
- [ ] **50,000+** active users
|
||||
- [ ] **Enterprise tier** launched
|
||||
- [ ] **Institutional partnerships** established
|
||||
|
||||
---
|
||||
|
||||
## 🤝 Community Involvement
|
||||
|
||||
We welcome community contributions to accelerate our roadmap:
|
||||
|
||||
- **Vote on Features**: Join our [Telegram community](https://t.me/nofx_dev_community) to vote on priority features
|
||||
- **Contribute Code**: Check our [Contributing Guide](../../CONTRIBUTING.md)
|
||||
- **Bug Bounties**: Report issues and earn rewards
|
||||
- **Strategy Sharing**: Share your successful strategies
|
||||
|
||||
---
|
||||
|
||||
## 📝 Roadmap Updates
|
||||
|
||||
This roadmap is reviewed and updated quarterly based on:
|
||||
- Community feedback
|
||||
- Market demands
|
||||
- Technical feasibility
|
||||
- Resource availability
|
||||
|
||||
**Last Updated:** 2025-11-01
|
||||
|
||||
---
|
||||
|
||||
## 📚 Related Documentation
|
||||
|
||||
- [Architecture Documentation](../architecture/README.md) - Technical architecture details
|
||||
- [Getting Started](../getting-started/README.md) - Setup and deployment
|
||||
- [Contributing Guide](../../CONTRIBUTING.md) - How to contribute
|
||||
- [Changelog](../../CHANGELOG.md) - Version history
|
||||
|
||||
---
|
||||
|
||||
[← Back to Documentation Home](../README.md)
|
||||
292
docs/roadmap/README.zh-CN.md
Normal file
292
docs/roadmap/README.zh-CN.md
Normal file
@@ -0,0 +1,292 @@
|
||||
# 🗺️ NOFX 路线图
|
||||
|
||||
**语言:** [English](README.md) | [中文](README.zh-CN.md)
|
||||
|
||||
NOFX 发展和通用市场扩展的战略规划。
|
||||
|
||||
---
|
||||
|
||||
## 📋 概述
|
||||
|
||||
NOFX 的使命是成为所有金融市场的**通用 AI 交易操作系统**。我们在加密货币市场上经过验证的基础设施正在扩展到股票、期货、期权、外汇等领域。
|
||||
|
||||
**愿景:** 相同架构。相同智能体框架。所有市场。
|
||||
|
||||
---
|
||||
|
||||
## 🎯 短期路线图
|
||||
|
||||
### 阶段1: 核心基础设施增强
|
||||
|
||||
#### 1.1 安全性增强
|
||||
**目标:** 保护敏感数据,减少安全漏洞
|
||||
|
||||
- **凭证管理**
|
||||
- [ ] 为数据库中的API密钥实现AES-256加密
|
||||
- [ ] 为私钥(Hyperliquid、Aster)添加加密
|
||||
- [ ] 为生产环境支持硬件安全模块(HSM)
|
||||
- [ ] 实现密钥轮换机制
|
||||
- [ ] 为所有凭证访问添加审计日志
|
||||
|
||||
- **应用安全**
|
||||
- [ ] 输入验证和清理(防止SQL注入、XSS攻击)
|
||||
- [ ] API端点的速率限制
|
||||
- [ ] CORS策略配置
|
||||
- [ ] JWT令牌过期和刷新机制
|
||||
- [ ] 实现RBAC(基于角色的访问控制)支持多用户
|
||||
- [ ] 添加API访问的IP白名单
|
||||
- [ ] 安全头部(CSP、HSTS、X-Frame-Options)
|
||||
|
||||
- **运营安全**
|
||||
- [ ] 安全密码哈希(bcrypt加盐)
|
||||
- [ ] 2FA增强(备份码、多个TOTP设备)
|
||||
- [ ] 会话管理(自动登出、并发会话限制)
|
||||
- [ ] 密钥管理(环境变量、vault集成)
|
||||
- [ ] 定期依赖项漏洞扫描
|
||||
|
||||
#### 1.2 增强AI能力
|
||||
**目标:** 更丰富的prompts、灵活配置、支持更多AI模型
|
||||
|
||||
- **Prompt系统全面改造**
|
||||
- [ ] 动态prompt生成的模板引擎
|
||||
- [ ] 多语言prompt支持(思维链、few-shot、zero-shot)
|
||||
- [ ] 基于市场状况的prompt切换(牛市、熊市、震荡)
|
||||
- [ ] 在prompts中集成历史绩效反馈
|
||||
- [ ] Prompt版本控制和A/B测试框架
|
||||
- [ ] 通过Web界面自定义prompt模板
|
||||
|
||||
- **AI模型集成**
|
||||
- [ ] OpenAI GPT-4/GPT-4 Turbo支持
|
||||
- [ ] Anthropic Claude 3(Opus、Sonnet、Haiku)集成
|
||||
- [ ] Google Gemini Pro支持
|
||||
- [ ] 本地LLM支持(通过Ollama的Llama、Mistral)
|
||||
- [ ] 多模型集成(投票、加权平均)
|
||||
- [ ] 模型性能跟踪和自动选择
|
||||
- [ ] 主模型失败时的降级机制
|
||||
|
||||
- **AI决策引擎**
|
||||
- [ ] 每个决策的置信度评分
|
||||
- [ ] 解释生成(为什么做这笔交易?)
|
||||
- [ ] AI推理中的风险评估集成
|
||||
- [ ] 市场状态检测(趋势、均值回归、高波动)
|
||||
- [ ] 与技术指标的交叉验证
|
||||
|
||||
#### 1.3 交易所集成扩展
|
||||
**目标:** 支持更多CEX和流行的perp-DEX,现货和合约
|
||||
|
||||
- **中心化交易所(CEX)**
|
||||
- [ ] **OKX** - 合约 + 现货交易
|
||||
- [ ] **Bybit** - 合约 + 现货交易
|
||||
- [ ] **Bitget** - 合约 + 现货交易
|
||||
- [ ] **Gate.io** - 合约 + 现货交易
|
||||
- [ ] **KuCoin** - 合约 + 现货交易
|
||||
- [ ] 统一的CEX接口,便于添加新交易所
|
||||
|
||||
- **去中心化永续交易所(Perp-DEX)**
|
||||
- [x] **Hyperliquid**(Ethereum L1)- 高性能订单簿DEX(✅ 已支持)
|
||||
- [x] **Aster**(多链)- Binance兼容API的DEX(✅ 已支持)
|
||||
- [ ] **Lighter**(Arbitrum)- 无Gas订单簿DEX,链下撮合
|
||||
- [ ] **EdgeX**(多链)- 专业衍生品DEX
|
||||
- [ ] 统一的DEX接口,保证集成一致性
|
||||
- [ ] 增强Hyperliquid集成(测试网支持、高级订单类型)
|
||||
- [ ] 增强Aster集成(跨链支持、钱包管理)
|
||||
|
||||
- **现货 + 合约支持**
|
||||
- [ ] 双模式交易(现货套利、合约对冲)
|
||||
- [ ] 跨交易所套利检测
|
||||
- [ ] 现货和合约的统一持仓跟踪
|
||||
- [ ] 现货和永续策略之间的自动转换
|
||||
|
||||
- **交易所基础设施**
|
||||
- [ ] **交易数据分析API集成**(自研)
|
||||
- [ ] AI500集成 - 自研AI选币模型
|
||||
- [ ] OI(持仓量)分析 - 实时持仓量跟踪和异常检测
|
||||
- [ ] NetFlow分析 - 链上资金流向分析,用于市场情绪判断
|
||||
- [ ] 市场情绪聚合器 - 整合多个数据源,增强AI决策能力
|
||||
- [ ] 自定义指标API - 支持专有技术指标
|
||||
- [ ] 自动精度处理(数量、价格小数位)
|
||||
- [ ] 订单类型抽象(市价、限价、止损、止盈)
|
||||
- [ ] 统一的错误处理和重试逻辑
|
||||
- [ ] 实时数据的WebSocket支持
|
||||
- [ ] 每个交易所的速率限制管理
|
||||
|
||||
#### 1.4 项目结构重构
|
||||
**目标:** 清晰层次、高内聚低耦合、易于扩展和维护
|
||||
|
||||
- **架构重新设计**
|
||||
- [ ] 实现分层架构(表现层 → 业务逻辑层 → 数据访问层)
|
||||
- [ ] 应用SOLID原则(特别是里氏替换原则用于交易所适配器)
|
||||
- [ ] 为所有交易所实现提取通用接口
|
||||
- [ ] 分离关注点:交易逻辑、数据获取、决策制定、执行
|
||||
- [ ] 实现依赖注入以提高可测试性
|
||||
|
||||
- **代码组织**
|
||||
- [ ] 将单体模块重构为更小、更专注的包
|
||||
- [ ] 为traders、exchanges、AI模型创建抽象基类
|
||||
- [ ] 实现工厂模式用于交易所/AI模型的创建
|
||||
- [ ] 标准化所有模块的错误处理和日志记录
|
||||
- [ ] 消除循环依赖并改进导入结构
|
||||
|
||||
- **配置管理**
|
||||
- [ ] 将所有配置集中到结构化配置文件中
|
||||
- [ ] 实现非关键配置的热重载
|
||||
- [ ] 启动时验证配置并提供清晰的错误消息
|
||||
- [ ] 支持环境特定配置(dev/staging/production)
|
||||
|
||||
#### 1.5 用户体验改进
|
||||
**目标:** 增强Web界面、更好的监控和告警系统
|
||||
|
||||
- **Web界面增强**
|
||||
- [ ] 移动端响应式设计(平板和手机支持)
|
||||
- [ ] 深色/浅色主题切换并保存用户偏好
|
||||
- [ ] TradingView小部件集成的高级图表
|
||||
- [ ] 实时WebSocket更新(替代持仓/订单的轮询)
|
||||
- [ ] 拖拽式仪表板自定义
|
||||
- [ ] 多语言支持(EN、CN、RU、UK)
|
||||
|
||||
- **配置界面**
|
||||
- [ ] 可视化策略构建器(无代码流程图)
|
||||
- [ ] 保存前的实时配置预览
|
||||
- [ ] 常用策略的配置模板
|
||||
- [ ] 批量trader管理(启动/停止多个traders)
|
||||
- [ ] 交易所凭证测试(保存前验证)
|
||||
- [ ] AI模型测试界面(部署前测试prompts)
|
||||
|
||||
- **监控与分析**
|
||||
- [ ] 实时性能仪表板和关键指标
|
||||
- [ ] 权益曲线可视化(每个trader、每个交易所、总体)
|
||||
- [ ] 回撤分析和风险指标
|
||||
- [ ] 带过滤和搜索的交易历史
|
||||
- [ ] 按币种、时间段、策略的盈亏分解
|
||||
- [ ] 比较视图(多个traders并排)
|
||||
- [ ] 导出功能(CSV、JSON、PDF报告)
|
||||
|
||||
- **告警与通知系统**
|
||||
- [ ] 多渠道告警(Email、Telegram、Discord、Webhook)
|
||||
- [ ] 可配置的告警规则(利润阈值、亏损限制、错误检测)
|
||||
- [ ] 告警优先级(严重、警告、信息)
|
||||
- [ ] 告警历史和确认跟踪
|
||||
- [ ] 每日/每周性能摘要邮件
|
||||
- [ ] 系统健康监控(API连接、数据库状态)
|
||||
|
||||
### 阶段2: 测试与稳定性
|
||||
|
||||
#### 2.1 质量保证
|
||||
- [ ] 全面的单元测试覆盖率(>80%)
|
||||
- [ ] 所有交易所适配器的集成测试
|
||||
- [ ] 负载测试(100+并发交易者)
|
||||
- [ ] 安全审计(API密钥加密、SQL注入防护)
|
||||
|
||||
#### 2.2 文档
|
||||
- [ ] 完整的API参考文档
|
||||
- [ ] 新手视频教程
|
||||
- [ ] 策略开发指南
|
||||
- [ ] 故障排查手册
|
||||
|
||||
#### 2.3 社区功能
|
||||
- [ ] 公开策略市场(分享/出售策略)
|
||||
- [ ] 经过验证的绩效排行榜
|
||||
- [ ] 社区论坛集成
|
||||
- [ ] 漏洞赏金计划
|
||||
|
||||
---
|
||||
|
||||
## 🚀 长期路线图
|
||||
|
||||
### 阶段3: 通用市场扩展
|
||||
|
||||
**目标:** 将经过验证的加密货币交易基础设施扩展到所有主要金融市场。
|
||||
|
||||
#### 3.1 股票市场
|
||||
- [ ] 美股(Interactive Brokers、Alpaca Markets)
|
||||
- [ ] 亚洲市场(A股、香港、日本)
|
||||
- [ ] 基本面分析集成(财报、市盈率、股息)
|
||||
- [ ] AI驱动的股票筛选
|
||||
|
||||
#### 3.2 期货市场
|
||||
- [ ] 商品期货(能源、金属、农产品)
|
||||
- [ ] 指数期货(标普500、纳斯达克、道琼斯、VIX)
|
||||
- [ ] 展期管理和价差交易
|
||||
|
||||
#### 3.3 期权交易
|
||||
- [ ] 期权链数据和Greeks计算
|
||||
- [ ] 股票、指数和加密期权
|
||||
- [ ] 期权策略构建器
|
||||
|
||||
#### 3.4 外汇市场
|
||||
- [ ] 主要货币对和稀有货币对
|
||||
- [ ] 利率分析和套息交易支持
|
||||
|
||||
---
|
||||
|
||||
### 阶段4: 高级AI与自动化
|
||||
|
||||
**目标:** 实现前沿AI技术用于自主交易。
|
||||
|
||||
- [ ] 多智能体编排(专业化智能体与动态协调)
|
||||
- [ ] 强化学习(DQN、PPO、迁移学习)
|
||||
- [ ] 替代数据集成(社交情绪、新闻、链上分析)
|
||||
|
||||
---
|
||||
|
||||
### 阶段5: 企业级与扩展
|
||||
|
||||
**目标:** 扩展基础设施以支持机构使用和高频交易。
|
||||
|
||||
- [ ] 数据库迁移(PostgreSQL/MySQL、Redis、TimescaleDB)
|
||||
- [ ] 微服务架构与Kubernetes部署
|
||||
- [ ] 多用户RBAC和白标解决方案
|
||||
- [ ] 高级分析和合规报告
|
||||
|
||||
---
|
||||
|
||||
## 📊 关键指标与里程碑
|
||||
|
||||
### 短期目标
|
||||
- [ ] 所有交易所支持**100+**交易对
|
||||
- [ ] **10,000+**活跃交易者实例
|
||||
- [ ] **5+**新交易所集成
|
||||
- [ ] **80%+**测试覆盖率
|
||||
- [ ] **99.9%**正常运行时间
|
||||
|
||||
### 长期目标
|
||||
- [ ] 支持**所有主要资产类别**(加密、股票、期货、期权、外汇)
|
||||
- [ ] **50,000+**活跃用户
|
||||
- [ ] **企业级**版本发布
|
||||
- [ ] 建立**机构合作伙伴关系**
|
||||
|
||||
---
|
||||
|
||||
## 🤝 社区参与
|
||||
|
||||
我们欢迎社区贡献来加速我们的路线图:
|
||||
|
||||
- **功能投票**: 加入我们的[Telegram社区](https://t.me/nofx_dev_community)投票优先功能
|
||||
- **贡献代码**: 查看我们的[贡献指南](../../CONTRIBUTING.md)
|
||||
- **漏洞赏金**: 报告问题并获得奖励
|
||||
- **策略分享**: 分享你的成功策略
|
||||
|
||||
---
|
||||
|
||||
## 📝 路线图更新
|
||||
|
||||
本路线图根据以下因素每季度审查和更新:
|
||||
- 社区反馈
|
||||
- 市场需求
|
||||
- 技术可行性
|
||||
- 资源可用性
|
||||
|
||||
**最后更新:** 2025-11-01
|
||||
|
||||
---
|
||||
|
||||
## 📚 相关文档
|
||||
|
||||
- [架构文档](../architecture/README.zh-CN.md) - 技术架构详情
|
||||
- [快速开始](../getting-started/README.zh-CN.md) - 设置和部署
|
||||
- [贡献指南](../../CONTRIBUTING.md) - 如何贡献
|
||||
- [更新日志](../../CHANGELOG.zh-CN.md) - 版本历史
|
||||
|
||||
---
|
||||
|
||||
[← 返回文档主页](../README.md)
|
||||
221
generate_beta_code.sh
Executable file
221
generate_beta_code.sh
Executable file
@@ -0,0 +1,221 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 内测码生成脚本
|
||||
# 生成6位不重复的内测码并写入 beta_codes.txt
|
||||
|
||||
BETA_CODES_FILE="beta_codes.txt"
|
||||
COUNT=1
|
||||
LIST_ONLY=false
|
||||
CODE_LENGTH=6
|
||||
|
||||
# 字符集(避免易混淆字符:0/O, 1/I/l)
|
||||
CHARSET="23456789abcdefghjkmnpqrstuvwxyz"
|
||||
|
||||
# 显示帮助信息
|
||||
show_help() {
|
||||
cat << EOF
|
||||
用法: $0 [选项]
|
||||
|
||||
选项:
|
||||
-c COUNT 生成内测码数量 (默认: 1)
|
||||
-l 列出现有内测码
|
||||
-f FILE 内测码文件路径 (默认: beta_codes.txt)
|
||||
-h 显示此帮助信息
|
||||
|
||||
示例:
|
||||
$0 -c 10 # 生成10个内测码
|
||||
$0 -l # 列出现有内测码
|
||||
$0 -f custom.txt -c 5 # 在自定义文件中生成5个内测码
|
||||
EOF
|
||||
}
|
||||
|
||||
# 生成随机内测码
|
||||
generate_beta_code() {
|
||||
local length="$1"
|
||||
local charset="$2"
|
||||
local code=""
|
||||
|
||||
for ((i=0; i<length; i++)); do
|
||||
local random_index=$((RANDOM % ${#charset}))
|
||||
code+="${charset:$random_index:1}"
|
||||
done
|
||||
|
||||
echo "$code"
|
||||
}
|
||||
|
||||
# 读取现有内测码
|
||||
read_existing_codes() {
|
||||
local file="$1"
|
||||
if [ -f "$file" ]; then
|
||||
grep -v '^$' "$file" 2>/dev/null | tr -d ' \t' | grep -v '^#' || true
|
||||
fi
|
||||
}
|
||||
|
||||
# 检查内测码是否已存在
|
||||
code_exists() {
|
||||
local code="$1"
|
||||
local file="$2"
|
||||
if [ -f "$file" ]; then
|
||||
grep -Fxq "$code" "$file" 2>/dev/null
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 添加内测码到文件
|
||||
add_code_to_file() {
|
||||
local code="$1"
|
||||
local file="$2"
|
||||
echo "$code" >> "$file"
|
||||
}
|
||||
|
||||
# 验证内测码格式
|
||||
validate_code() {
|
||||
local code="$1"
|
||||
# 检查长度
|
||||
if [ ${#code} -ne $CODE_LENGTH ]; then
|
||||
return 1
|
||||
fi
|
||||
# 检查字符是否都在允许的字符集中
|
||||
if [[ ! "$code" =~ ^[$CHARSET]+$ ]]; then
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# 去重并排序内测码
|
||||
dedupe_and_sort_codes() {
|
||||
local file="$1"
|
||||
if [ -f "$file" ]; then
|
||||
# 过滤空行和注释,去重并排序
|
||||
grep -v '^$' "$file" | grep -v '^#' | sort -u > "${file}.tmp" && mv "${file}.tmp" "$file"
|
||||
fi
|
||||
}
|
||||
|
||||
# 解析命令行参数
|
||||
while getopts "c:lf:h" opt; do
|
||||
case $opt in
|
||||
c)
|
||||
COUNT="$OPTARG"
|
||||
if ! [[ "$COUNT" =~ ^[0-9]+$ ]] || [ "$COUNT" -lt 1 ]; then
|
||||
echo "错误: count 必须是正整数" >&2
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
l)
|
||||
LIST_ONLY=true
|
||||
;;
|
||||
f)
|
||||
BETA_CODES_FILE="$OPTARG"
|
||||
;;
|
||||
h)
|
||||
show_help
|
||||
exit 0
|
||||
;;
|
||||
\?)
|
||||
echo "无效选项: -$OPTARG" >&2
|
||||
echo "使用 -h 查看帮助信息" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# 如果是列出现有内测码
|
||||
if [ "$LIST_ONLY" = true ]; then
|
||||
if [ -f "$BETA_CODES_FILE" ]; then
|
||||
existing_codes=$(read_existing_codes "$BETA_CODES_FILE")
|
||||
if [ -z "$existing_codes" ]; then
|
||||
echo "内测码列表为空"
|
||||
else
|
||||
count=$(echo "$existing_codes" | wc -l | tr -d ' ')
|
||||
echo "当前内测码 ($count 个):"
|
||||
echo "$existing_codes" | nl -w3 -s'. '
|
||||
fi
|
||||
else
|
||||
echo "内测码文件不存在: $BETA_CODES_FILE"
|
||||
fi
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# 读取现有内测码
|
||||
existing_codes=$(read_existing_codes "$BETA_CODES_FILE")
|
||||
|
||||
# 生成新内测码
|
||||
new_codes=()
|
||||
max_attempts=1000 # 防止无限循环
|
||||
|
||||
echo "正在生成 $COUNT 个内测码..."
|
||||
|
||||
for ((i=1; i<=COUNT; i++)); do
|
||||
attempts=0
|
||||
while [ $attempts -lt $max_attempts ]; do
|
||||
code=$(generate_beta_code $CODE_LENGTH "$CHARSET")
|
||||
|
||||
# 验证格式
|
||||
if ! validate_code "$code"; then
|
||||
((attempts++))
|
||||
continue
|
||||
fi
|
||||
|
||||
# 检查是否已存在
|
||||
if code_exists "$code" "$BETA_CODES_FILE"; then
|
||||
((attempts++))
|
||||
continue
|
||||
fi
|
||||
|
||||
# 检查是否与本次生成的重复
|
||||
duplicate=false
|
||||
for existing_code in "${new_codes[@]}"; do
|
||||
if [ "$code" = "$existing_code" ]; then
|
||||
duplicate=true
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "$duplicate" = false ]; then
|
||||
new_codes+=("$code")
|
||||
break
|
||||
fi
|
||||
|
||||
((attempts++))
|
||||
done
|
||||
|
||||
if [ $attempts -eq $max_attempts ]; then
|
||||
echo "警告: 生成第 $i 个内测码时达到最大尝试次数,可能字符空间不足" >&2
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
# 检查是否成功生成了内测码
|
||||
if [ ${#new_codes[@]} -eq 0 ]; then
|
||||
echo "未能生成任何新的内测码"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 添加到文件
|
||||
for code in "${new_codes[@]}"; do
|
||||
add_code_to_file "$code" "$BETA_CODES_FILE"
|
||||
done
|
||||
|
||||
# 去重并排序
|
||||
dedupe_and_sort_codes "$BETA_CODES_FILE"
|
||||
|
||||
echo "成功生成 ${#new_codes[@]} 个内测码:"
|
||||
printf ' %s\n' "${new_codes[@]}"
|
||||
echo
|
||||
echo "内测码文件: $BETA_CODES_FILE"
|
||||
|
||||
# 显示当前总数
|
||||
if [ -f "$BETA_CODES_FILE" ]; then
|
||||
total_count=$(read_existing_codes "$BETA_CODES_FILE" | wc -l | tr -d ' ')
|
||||
echo "当前内测码总计: $total_count 个"
|
||||
fi
|
||||
|
||||
# 显示文件头部信息(如果是新文件)
|
||||
if [ ! -s "$BETA_CODES_FILE" ] || [ $(wc -l < "$BETA_CODES_FILE") -eq ${#new_codes[@]} ]; then
|
||||
echo
|
||||
echo "内测码规则:"
|
||||
echo "- 长度: $CODE_LENGTH 位"
|
||||
echo "- 字符集: 数字 2-9, 小写字母 a-z (排除 0,1,i,l,o 避免混淆)"
|
||||
echo "- 每个内测码唯一且不重复"
|
||||
fi
|
||||
42
main.go
42
main.go
@@ -25,6 +25,7 @@ type LeverageConfig struct {
|
||||
// ConfigFile 配置文件结构,只包含需要同步到数据库的字段
|
||||
type ConfigFile struct {
|
||||
AdminMode bool `json:"admin_mode"`
|
||||
BetaMode bool `json:"beta_mode"`
|
||||
APIServerPort int `json:"api_server_port"`
|
||||
UseDefaultCoins bool `json:"use_default_coins"`
|
||||
DefaultCoins []string `json:"default_coins"`
|
||||
@@ -62,6 +63,7 @@ func syncConfigToDatabase(database *config.Database) error {
|
||||
// 同步各配置项到数据库
|
||||
configs := map[string]string{
|
||||
"admin_mode": fmt.Sprintf("%t", configFile.AdminMode),
|
||||
"beta_mode": fmt.Sprintf("%t", configFile.BetaMode),
|
||||
"api_server_port": strconv.Itoa(configFile.APIServerPort),
|
||||
"use_default_coins": fmt.Sprintf("%t", configFile.UseDefaultCoins),
|
||||
"coin_pool_api_url": configFile.CoinPoolAPIURL,
|
||||
@@ -105,6 +107,41 @@ func syncConfigToDatabase(database *config.Database) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// loadBetaCodesToDatabase 加载内测码文件到数据库
|
||||
func loadBetaCodesToDatabase(database *config.Database) error {
|
||||
betaCodeFile := "beta_codes.txt"
|
||||
|
||||
// 检查内测码文件是否存在
|
||||
if _, err := os.Stat(betaCodeFile); os.IsNotExist(err) {
|
||||
log.Printf("📄 内测码文件 %s 不存在,跳过加载", betaCodeFile)
|
||||
return nil
|
||||
}
|
||||
|
||||
// 获取文件信息
|
||||
fileInfo, err := os.Stat(betaCodeFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("获取内测码文件信息失败: %w", err)
|
||||
}
|
||||
|
||||
log.Printf("🔄 发现内测码文件 %s (%.1f KB),开始加载...", betaCodeFile, float64(fileInfo.Size())/1024)
|
||||
|
||||
// 加载内测码到数据库
|
||||
err = database.LoadBetaCodesFromFile(betaCodeFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("加载内测码失败: %w", err)
|
||||
}
|
||||
|
||||
// 显示统计信息
|
||||
total, used, err := database.GetBetaCodeStats()
|
||||
if err != nil {
|
||||
log.Printf("⚠️ 获取内测码统计失败: %v", err)
|
||||
} else {
|
||||
log.Printf("✅ 内测码加载完成: 总计 %d 个,已使用 %d 个,剩余 %d 个", total, used, total-used)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
fmt.Println("╔════════════════════════════════════════════════════════════╗")
|
||||
fmt.Println("║ 🤖 AI多模型交易系统 - 支持 DeepSeek & Qwen ║")
|
||||
@@ -129,6 +166,11 @@ func main() {
|
||||
log.Printf("⚠️ 同步config.json到数据库失败: %v", err)
|
||||
}
|
||||
|
||||
// 加载内测码到数据库
|
||||
if err := loadBetaCodesToDatabase(database); err != nil {
|
||||
log.Printf("⚠️ 加载内测码到数据库失败: %v", err)
|
||||
}
|
||||
|
||||
// 获取系统配置
|
||||
useDefaultCoinsStr, _ := database.GetSystemConfig("use_default_coins")
|
||||
useDefaultCoins := useDefaultCoinsStr == "true"
|
||||
|
||||
413
scripts/pr-check.sh
Executable file
413
scripts/pr-check.sh
Executable file
@@ -0,0 +1,413 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 🔍 PR Health Check Script
|
||||
# Analyzes your PR and gives suggestions on how to meet the new standards
|
||||
# This script only analyzes and suggests - it won't modify your code
|
||||
|
||||
set -e
|
||||
|
||||
# Colors
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
CYAN='\033[0;36m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Counters
|
||||
ISSUES_FOUND=0
|
||||
WARNINGS_FOUND=0
|
||||
PASSED_CHECKS=0
|
||||
|
||||
# Helper functions
|
||||
log_section() {
|
||||
echo ""
|
||||
echo -e "${CYAN}═══════════════════════════════════════════${NC}"
|
||||
echo -e "${CYAN} $1${NC}"
|
||||
echo -e "${CYAN}═══════════════════════════════════════════${NC}"
|
||||
}
|
||||
|
||||
log_check() {
|
||||
echo -e "${BLUE}🔍 Checking: $1${NC}"
|
||||
}
|
||||
|
||||
log_pass() {
|
||||
echo -e "${GREEN}✅ PASS: $1${NC}"
|
||||
((PASSED_CHECKS++))
|
||||
}
|
||||
|
||||
log_warning() {
|
||||
echo -e "${YELLOW}⚠️ WARNING: $1${NC}"
|
||||
((WARNINGS_FOUND++))
|
||||
}
|
||||
|
||||
log_error() {
|
||||
echo -e "${RED}❌ ISSUE: $1${NC}"
|
||||
((ISSUES_FOUND++))
|
||||
}
|
||||
|
||||
log_suggestion() {
|
||||
echo -e "${CYAN}💡 Suggestion: $1${NC}"
|
||||
}
|
||||
|
||||
log_command() {
|
||||
echo -e "${GREEN} Run: ${NC}$1"
|
||||
}
|
||||
|
||||
# Welcome
|
||||
echo ""
|
||||
echo "╔═══════════════════════════════════════════╗"
|
||||
echo "║ NOFX PR Health Check ║"
|
||||
echo "║ Analyze your PR and get suggestions ║"
|
||||
echo "╚═══════════════════════════════════════════╝"
|
||||
echo ""
|
||||
|
||||
# Check if we're in a git repo
|
||||
if ! git rev-parse --is-inside-work-tree > /dev/null 2>&1; then
|
||||
log_error "Not a git repository"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Get current branch
|
||||
CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD)
|
||||
echo -e "${BLUE}Current branch: ${GREEN}$CURRENT_BRANCH${NC}"
|
||||
|
||||
if [ "$CURRENT_BRANCH" = "main" ] || [ "$CURRENT_BRANCH" = "dev" ]; then
|
||||
log_error "You're on the $CURRENT_BRANCH branch. Please switch to your PR branch."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if upstream exists
|
||||
if ! git remote | grep -q "^upstream$"; then
|
||||
log_warning "Upstream remote not found"
|
||||
log_suggestion "Add upstream remote:"
|
||||
log_command "git remote add upstream https://github.com/tinkle-community/nofx.git"
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# ═══════════════════════════════════════════
|
||||
# 1. GIT BRANCH CHECKS
|
||||
# ═══════════════════════════════════════════
|
||||
log_section "1. Git Branch Status"
|
||||
|
||||
# Check if branch is up to date with upstream
|
||||
log_check "Is branch based on latest upstream/dev?"
|
||||
if git remote | grep -q "^upstream$"; then
|
||||
git fetch upstream -q 2>/dev/null || true
|
||||
|
||||
if git merge-base --is-ancestor upstream/dev HEAD 2>/dev/null; then
|
||||
log_pass "Branch is up to date with upstream/dev"
|
||||
else
|
||||
log_error "Branch is not based on latest upstream/dev"
|
||||
log_suggestion "Rebase your branch:"
|
||||
log_command "git fetch upstream && git rebase upstream/dev"
|
||||
echo ""
|
||||
fi
|
||||
else
|
||||
log_warning "Cannot check - upstream remote not configured"
|
||||
fi
|
||||
|
||||
# Check for merge conflicts
|
||||
log_check "Any merge conflicts?"
|
||||
if git diff --check > /dev/null 2>&1; then
|
||||
log_pass "No merge conflicts detected"
|
||||
else
|
||||
log_error "Merge conflicts detected"
|
||||
log_suggestion "Resolve conflicts and commit"
|
||||
fi
|
||||
|
||||
# ═══════════════════════════════════════════
|
||||
# 2. COMMIT MESSAGE CHECKS
|
||||
# ═══════════════════════════════════════════
|
||||
log_section "2. Commit Messages"
|
||||
|
||||
# Get commits in this branch (not in upstream/dev)
|
||||
if git remote | grep -q "^upstream$"; then
|
||||
COMMITS=$(git log upstream/dev..HEAD --oneline 2>/dev/null || git log --oneline -10)
|
||||
else
|
||||
COMMITS=$(git log --oneline -10)
|
||||
fi
|
||||
|
||||
COMMIT_COUNT=$(echo "$COMMITS" | wc -l | tr -d ' ')
|
||||
echo -e "${BLUE}Found $COMMIT_COUNT commit(s) in your branch${NC}"
|
||||
echo ""
|
||||
|
||||
# Check each commit message
|
||||
echo "$COMMITS" | while read -r line; do
|
||||
COMMIT_MSG=$(echo "$line" | cut -d' ' -f2-)
|
||||
|
||||
# Check if follows conventional commits
|
||||
if echo "$COMMIT_MSG" | grep -qE "^(feat|fix|docs|style|refactor|perf|test|chore|ci|security)(\(.+\))?: .+"; then
|
||||
log_pass "\"$COMMIT_MSG\""
|
||||
else
|
||||
log_warning "\"$COMMIT_MSG\""
|
||||
log_suggestion "Should follow format: type(scope): description"
|
||||
echo " Examples:"
|
||||
echo " - feat(exchange): add OKX integration"
|
||||
echo " - fix(trader): resolve position bug"
|
||||
echo ""
|
||||
fi
|
||||
done
|
||||
|
||||
# Suggest PR title based on commits
|
||||
echo ""
|
||||
log_check "Suggested PR title:"
|
||||
SUGGESTED_TITLE=$(git log --pretty=%s upstream/dev..HEAD 2>/dev/null | head -1 || git log --pretty=%s -1)
|
||||
echo -e "${GREEN} \"$SUGGESTED_TITLE\"${NC}"
|
||||
echo ""
|
||||
|
||||
# ═══════════════════════════════════════════
|
||||
# 3. CODE QUALITY - BACKEND (Go)
|
||||
# ═══════════════════════════════════════════
|
||||
if find . -name "*.go" -not -path "./vendor/*" -not -path "./.git/*" | grep -q .; then
|
||||
log_section "3. Backend Code Quality (Go)"
|
||||
|
||||
# Check if Go is installed
|
||||
if ! command -v go &> /dev/null; then
|
||||
log_warning "Go not installed - skipping backend checks"
|
||||
log_suggestion "Install Go: https://go.dev/doc/install"
|
||||
else
|
||||
# Check go fmt
|
||||
log_check "Go code formatting (go fmt)"
|
||||
UNFORMATTED=$(gofmt -l . 2>/dev/null | grep -v vendor || true)
|
||||
if [ -z "$UNFORMATTED" ]; then
|
||||
log_pass "All Go files are formatted"
|
||||
else
|
||||
log_error "Some files need formatting:"
|
||||
echo "$UNFORMATTED" | head -5 | while read -r file; do
|
||||
echo " - $file"
|
||||
done
|
||||
log_suggestion "Format your code:"
|
||||
log_command "go fmt ./..."
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# Check go vet
|
||||
log_check "Go static analysis (go vet)"
|
||||
if go vet ./... > /tmp/vet-output.txt 2>&1; then
|
||||
log_pass "No issues found by go vet"
|
||||
else
|
||||
log_error "Go vet found issues:"
|
||||
head -10 /tmp/vet-output.txt | sed 's/^/ /'
|
||||
log_suggestion "Fix the issues above"
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# Check tests exist
|
||||
log_check "Do tests exist?"
|
||||
TEST_FILES=$(find . -name "*_test.go" -not -path "./vendor/*" | wc -l)
|
||||
if [ "$TEST_FILES" -gt 0 ]; then
|
||||
log_pass "Found $TEST_FILES test file(s)"
|
||||
else
|
||||
log_warning "No test files found"
|
||||
log_suggestion "Add tests for your changes"
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# Run tests
|
||||
log_check "Running Go tests..."
|
||||
if go test ./... -v > /tmp/test-output.txt 2>&1; then
|
||||
log_pass "All tests passed"
|
||||
else
|
||||
log_error "Some tests failed:"
|
||||
grep -E "FAIL|ERROR" /tmp/test-output.txt | head -10 | sed 's/^/ /' || true
|
||||
log_suggestion "Fix failing tests:"
|
||||
log_command "go test ./... -v"
|
||||
echo ""
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# ═══════════════════════════════════════════
|
||||
# 4. CODE QUALITY - FRONTEND
|
||||
# ═══════════════════════════════════════════
|
||||
if [ -d "web" ]; then
|
||||
log_section "4. Frontend Code Quality"
|
||||
|
||||
# Check if npm is installed
|
||||
if ! command -v npm &> /dev/null; then
|
||||
log_warning "npm not installed - skipping frontend checks"
|
||||
log_suggestion "Install Node.js: https://nodejs.org/"
|
||||
else
|
||||
cd web
|
||||
|
||||
# Check if node_modules exists
|
||||
if [ ! -d "node_modules" ]; then
|
||||
log_warning "Dependencies not installed"
|
||||
log_suggestion "Install dependencies:"
|
||||
log_command "cd web && npm install"
|
||||
cd ..
|
||||
else
|
||||
# Check linting
|
||||
log_check "Frontend linting"
|
||||
if npm run lint > /tmp/lint-output.txt 2>&1; then
|
||||
log_pass "No linting issues"
|
||||
else
|
||||
log_error "Linting issues found:"
|
||||
tail -20 /tmp/lint-output.txt | sed 's/^/ /' || true
|
||||
log_suggestion "Fix linting issues:"
|
||||
log_command "cd web && npm run lint -- --fix"
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# Check type errors
|
||||
log_check "TypeScript type checking"
|
||||
if npm run type-check > /tmp/typecheck-output.txt 2>&1; then
|
||||
log_pass "No type errors"
|
||||
else
|
||||
log_error "Type errors found:"
|
||||
tail -20 /tmp/typecheck-output.txt | sed 's/^/ /' || true
|
||||
log_suggestion "Fix type errors in your code"
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# Check build
|
||||
log_check "Frontend build"
|
||||
if npm run build > /tmp/build-output.txt 2>&1; then
|
||||
log_pass "Build successful"
|
||||
else
|
||||
log_error "Build failed:"
|
||||
tail -20 /tmp/build-output.txt | sed 's/^/ /' || true
|
||||
log_suggestion "Fix build errors"
|
||||
echo ""
|
||||
fi
|
||||
fi
|
||||
|
||||
cd ..
|
||||
fi
|
||||
fi
|
||||
|
||||
# ═══════════════════════════════════════════
|
||||
# 5. PR SIZE CHECK
|
||||
# ═══════════════════════════════════════════
|
||||
log_section "5. PR Size"
|
||||
|
||||
if git remote | grep -q "^upstream$"; then
|
||||
ADDED=$(git diff --numstat upstream/dev...HEAD | awk '{sum+=$1} END {print sum+0}')
|
||||
DELETED=$(git diff --numstat upstream/dev...HEAD | awk '{sum+=$2} END {print sum+0}')
|
||||
TOTAL=$((ADDED + DELETED))
|
||||
FILES_CHANGED=$(git diff --name-only upstream/dev...HEAD | wc -l)
|
||||
|
||||
echo -e "${BLUE}Lines changed: ${GREEN}+$ADDED ${RED}-$DELETED ${NC}(total: $TOTAL)"
|
||||
echo -e "${BLUE}Files changed: ${GREEN}$FILES_CHANGED${NC}"
|
||||
echo ""
|
||||
|
||||
if [ "$TOTAL" -lt 100 ]; then
|
||||
log_pass "Small PR (<100 lines) - ideal for quick review"
|
||||
elif [ "$TOTAL" -lt 500 ]; then
|
||||
log_pass "Medium PR (100-500 lines) - reasonable size"
|
||||
elif [ "$TOTAL" -lt 1000 ]; then
|
||||
log_warning "Large PR (500-1000 lines) - consider splitting"
|
||||
log_suggestion "Breaking into smaller PRs makes review faster"
|
||||
else
|
||||
log_error "Very large PR (>1000 lines) - strongly consider splitting"
|
||||
log_suggestion "Split into multiple smaller PRs, each with a focused change"
|
||||
echo ""
|
||||
fi
|
||||
fi
|
||||
|
||||
# ═══════════════════════════════════════════
|
||||
# 6. DOCUMENTATION CHECK
|
||||
# ═══════════════════════════════════════════
|
||||
log_section "6. Documentation"
|
||||
|
||||
# Check if README or docs were updated
|
||||
log_check "Documentation updates"
|
||||
if git remote | grep -q "^upstream$"; then
|
||||
DOC_CHANGES=$(git diff --name-only upstream/dev...HEAD | grep -E "\.(md|txt)$" || true)
|
||||
|
||||
if [ -n "$DOC_CHANGES" ]; then
|
||||
log_pass "Documentation files updated"
|
||||
echo "$DOC_CHANGES" | sed 's/^/ - /'
|
||||
else
|
||||
# Check if this is a feature/fix that might need docs
|
||||
COMMIT_TYPES=$(git log --pretty=%s upstream/dev..HEAD | grep -oE "^(feat|fix)" || true)
|
||||
if [ -n "$COMMIT_TYPES" ]; then
|
||||
log_warning "No documentation updates found"
|
||||
log_suggestion "Consider updating docs if your changes affect usage"
|
||||
echo ""
|
||||
else
|
||||
log_pass "No documentation update needed"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# ═══════════════════════════════════════════
|
||||
# 7. ROADMAP ALIGNMENT
|
||||
# ═══════════════════════════════════════════
|
||||
log_section "7. Roadmap Alignment"
|
||||
|
||||
log_check "Does your PR align with the roadmap?"
|
||||
echo ""
|
||||
echo "Current priorities (Phase 1):"
|
||||
echo " ✅ Security enhancements"
|
||||
echo " ✅ AI model integrations"
|
||||
echo " ✅ Exchange integrations (OKX, Bybit, Lighter, EdgeX)"
|
||||
echo " ✅ UI/UX improvements"
|
||||
echo " ✅ Performance optimizations"
|
||||
echo " ✅ Bug fixes"
|
||||
echo ""
|
||||
log_suggestion "Check roadmap: https://github.com/tinkle-community/nofx/blob/dev/docs/roadmap/README.md"
|
||||
echo ""
|
||||
|
||||
# ═══════════════════════════════════════════
|
||||
# FINAL REPORT
|
||||
# ═══════════════════════════════════════════
|
||||
log_section "Summary Report"
|
||||
|
||||
echo ""
|
||||
echo -e "${GREEN}✅ Passed checks: $PASSED_CHECKS${NC}"
|
||||
echo -e "${YELLOW}⚠️ Warnings: $WARNINGS_FOUND${NC}"
|
||||
echo -e "${RED}❌ Issues found: $ISSUES_FOUND${NC}"
|
||||
echo ""
|
||||
|
||||
# Overall assessment
|
||||
if [ "$ISSUES_FOUND" -eq 0 ] && [ "$WARNINGS_FOUND" -eq 0 ]; then
|
||||
echo "╔═══════════════════════════════════════════╗"
|
||||
echo "║ 🎉 Excellent! Your PR looks great! ║"
|
||||
echo "║ Ready to submit or update your PR ║"
|
||||
echo "╚═══════════════════════════════════════════╝"
|
||||
elif [ "$ISSUES_FOUND" -eq 0 ]; then
|
||||
echo "╔═══════════════════════════════════════════╗"
|
||||
echo "║ 👍 Good! Minor warnings found ║"
|
||||
echo "║ Consider addressing warnings ║"
|
||||
echo "╚═══════════════════════════════════════════╝"
|
||||
elif [ "$ISSUES_FOUND" -le 3 ]; then
|
||||
echo "╔═══════════════════════════════════════════╗"
|
||||
echo "║ ⚠️ Issues found - Please fix ║"
|
||||
echo "║ See suggestions above ║"
|
||||
echo "╚═══════════════════════════════════════════╝"
|
||||
else
|
||||
echo "╔═══════════════════════════════════════════╗"
|
||||
echo "║ ❌ Multiple issues found ║"
|
||||
echo "║ Please address issues before submitting ║"
|
||||
echo "╚═══════════════════════════════════════════╝"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "📖 Next steps:"
|
||||
echo ""
|
||||
|
||||
if [ "$ISSUES_FOUND" -gt 0 ] || [ "$WARNINGS_FOUND" -gt 0 ]; then
|
||||
echo "1. Fix the issues and warnings listed above"
|
||||
echo "2. Run this script again to verify: ./scripts/pr-check.sh"
|
||||
echo "3. Commit your fixes"
|
||||
echo "4. Push to your PR: git push origin $CURRENT_BRANCH"
|
||||
else
|
||||
echo "1. Push your changes: git push origin $CURRENT_BRANCH"
|
||||
echo "2. Create or update your PR on GitHub"
|
||||
echo "3. Wait for automated CI checks"
|
||||
echo "4. Address reviewer feedback"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "📚 Resources:"
|
||||
echo " - Contributing Guide: https://github.com/tinkle-community/nofx/blob/dev/CONTRIBUTING.md"
|
||||
echo " - Migration Guide: https://github.com/tinkle-community/nofx/blob/dev/docs/community/MIGRATION_ANNOUNCEMENT.md"
|
||||
echo ""
|
||||
|
||||
# Cleanup temp files
|
||||
rm -f /tmp/vet-output.txt /tmp/test-output.txt /tmp/lint-output.txt /tmp/typecheck-output.txt /tmp/build-output.txt
|
||||
|
||||
echo "✨ Analysis complete! Good luck with your PR! 🚀"
|
||||
echo ""
|
||||
335
scripts/pr-fix.sh
Executable file
335
scripts/pr-fix.sh
Executable file
@@ -0,0 +1,335 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 🔄 PR Migration Script for Contributors
|
||||
# This script helps you migrate your PR to the new format
|
||||
# Run this in your local fork to update your PR automatically
|
||||
|
||||
set -e
|
||||
|
||||
# Colors
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Helper functions
|
||||
log_info() {
|
||||
echo -e "${BLUE}ℹ️ $1${NC}"
|
||||
}
|
||||
|
||||
log_success() {
|
||||
echo -e "${GREEN}✅ $1${NC}"
|
||||
}
|
||||
|
||||
log_warning() {
|
||||
echo -e "${YELLOW}⚠️ $1${NC}"
|
||||
}
|
||||
|
||||
log_error() {
|
||||
echo -e "${RED}❌ $1${NC}"
|
||||
}
|
||||
|
||||
confirm() {
|
||||
read -p "$(echo -e ${YELLOW}"$1 (y/N): "${NC})" -n 1 -r
|
||||
echo
|
||||
[[ $REPLY =~ ^[Yy]$ ]]
|
||||
}
|
||||
|
||||
# Welcome message
|
||||
echo ""
|
||||
echo "╔═══════════════════════════════════════════╗"
|
||||
echo "║ NOFX PR Migration Tool ║"
|
||||
echo "║ Migrate your PR to the new format ║"
|
||||
echo "╚═══════════════════════════════════════════╝"
|
||||
echo ""
|
||||
|
||||
# Check if we're in a git repo
|
||||
if ! git rev-parse --is-inside-work-tree > /dev/null 2>&1; then
|
||||
log_error "Not a git repository. Please run this from your NOFX fork."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check current branch
|
||||
CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD)
|
||||
log_info "Current branch: $CURRENT_BRANCH"
|
||||
|
||||
if [ "$CURRENT_BRANCH" = "main" ] || [ "$CURRENT_BRANCH" = "dev" ]; then
|
||||
log_warning "You're on the $CURRENT_BRANCH branch."
|
||||
log_info "This script should be run on your PR branch."
|
||||
|
||||
# List branches
|
||||
log_info "Your branches:"
|
||||
git branch
|
||||
|
||||
echo ""
|
||||
read -p "Enter your PR branch name: " PR_BRANCH
|
||||
|
||||
if [ -z "$PR_BRANCH" ]; then
|
||||
log_error "No branch specified. Exiting."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
git checkout "$PR_BRANCH" || {
|
||||
log_error "Failed to checkout branch $PR_BRANCH"
|
||||
exit 1
|
||||
}
|
||||
|
||||
CURRENT_BRANCH="$PR_BRANCH"
|
||||
fi
|
||||
|
||||
log_success "Working on branch: $CURRENT_BRANCH"
|
||||
|
||||
echo ""
|
||||
log_info "What this script will do:"
|
||||
echo " 1. ✅ Verify you're rebased on latest upstream/dev"
|
||||
echo " 2. ✅ Check and format Go code (go fmt)"
|
||||
echo " 3. ✅ Run Go linting (go vet)"
|
||||
echo " 4. ✅ Run Go tests"
|
||||
echo " 5. ✅ Check frontend code (if modified)"
|
||||
echo " 6. ✅ Give you feedback and suggestions"
|
||||
echo ""
|
||||
log_warning "Make sure you've already run: git fetch upstream && git rebase upstream/dev"
|
||||
echo ""
|
||||
|
||||
if ! confirm "Continue with migration?"; then
|
||||
log_info "Migration cancelled"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Step 1: Verify upstream sync
|
||||
echo ""
|
||||
log_info "Step 1: Verifying upstream sync..."
|
||||
|
||||
# Check if upstream remote exists
|
||||
if ! git remote | grep -q "^upstream$"; then
|
||||
log_warning "Upstream remote not found. Adding it..."
|
||||
git remote add upstream https://github.com/tinkle-community/nofx.git
|
||||
git fetch upstream
|
||||
log_success "Added upstream remote"
|
||||
fi
|
||||
|
||||
# Check if we're up to date with upstream/dev
|
||||
if git merge-base --is-ancestor upstream/dev HEAD; then
|
||||
log_success "Your branch is up to date with upstream/dev"
|
||||
else
|
||||
log_warning "Your branch is not based on latest upstream/dev"
|
||||
log_info "Please run first: git fetch upstream && git rebase upstream/dev"
|
||||
|
||||
if confirm "Try to rebase now?"; then
|
||||
git fetch upstream
|
||||
if git rebase upstream/dev; then
|
||||
log_success "Successfully rebased on upstream/dev"
|
||||
else
|
||||
log_error "Rebase failed. Please resolve conflicts manually."
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
log_warning "Skipping rebase. Results may not be accurate."
|
||||
fi
|
||||
fi
|
||||
|
||||
# Step 2: Backend checks (if Go files exist)
|
||||
if find . -name "*.go" -not -path "./vendor/*" | grep -q .; then
|
||||
echo ""
|
||||
log_info "Step 2: Running backend checks..."
|
||||
|
||||
# Check if Go is installed
|
||||
if ! command -v go &> /dev/null; then
|
||||
log_warning "Go not found. Skipping backend checks."
|
||||
log_info "Install Go: https://go.dev/doc/install"
|
||||
else
|
||||
# Format Go code
|
||||
log_info "Formatting Go code..."
|
||||
if go fmt ./...; then
|
||||
log_success "Go code formatted"
|
||||
|
||||
# Check if there are changes
|
||||
if ! git diff --quiet; then
|
||||
log_info "Formatting created changes. Committing..."
|
||||
git add .
|
||||
git commit -m "chore: format Go code with go fmt" || true
|
||||
fi
|
||||
else
|
||||
log_warning "Go formatting had issues (non-critical)"
|
||||
fi
|
||||
|
||||
# Run go vet
|
||||
log_info "Running go vet..."
|
||||
if go vet ./...; then
|
||||
log_success "Go vet passed"
|
||||
else
|
||||
log_warning "Go vet found issues. Please review them."
|
||||
if confirm "Continue anyway?"; then
|
||||
log_info "Continuing..."
|
||||
else
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Run tests
|
||||
log_info "Running Go tests..."
|
||||
if go test ./...; then
|
||||
log_success "All Go tests passed"
|
||||
else
|
||||
log_warning "Some tests failed. Please fix them before pushing."
|
||||
if confirm "Continue anyway?"; then
|
||||
log_info "Continuing..."
|
||||
else
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
else
|
||||
log_info "Step 2: No Go files found, skipping backend checks"
|
||||
fi
|
||||
|
||||
# Step 3: Frontend checks (if web directory exists)
|
||||
if [ -d "web" ]; then
|
||||
echo ""
|
||||
log_info "Step 3: Running frontend checks..."
|
||||
|
||||
# Check if npm is installed
|
||||
if ! command -v npm &> /dev/null; then
|
||||
log_warning "npm not found. Skipping frontend checks."
|
||||
log_info "Install Node.js: https://nodejs.org/"
|
||||
else
|
||||
cd web
|
||||
|
||||
# Install dependencies if needed
|
||||
if [ ! -d "node_modules" ]; then
|
||||
log_info "Installing dependencies..."
|
||||
npm install
|
||||
fi
|
||||
|
||||
# Run linter
|
||||
log_info "Running linter..."
|
||||
if npm run lint; then
|
||||
log_success "Linting passed"
|
||||
else
|
||||
log_warning "Linting found issues"
|
||||
log_info "Attempting to auto-fix..."
|
||||
npm run lint -- --fix || true
|
||||
|
||||
# Commit fixes if any
|
||||
if ! git diff --quiet; then
|
||||
git add .
|
||||
git commit -m "chore: fix linting issues" || true
|
||||
fi
|
||||
fi
|
||||
|
||||
# Type check
|
||||
log_info "Running type check..."
|
||||
if npm run type-check; then
|
||||
log_success "Type checking passed"
|
||||
else
|
||||
log_warning "Type checking found issues. Please fix them."
|
||||
fi
|
||||
|
||||
# Build
|
||||
log_info "Testing build..."
|
||||
if npm run build; then
|
||||
log_success "Build successful"
|
||||
else
|
||||
log_error "Build failed. Please fix build errors."
|
||||
cd ..
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd ..
|
||||
fi
|
||||
else
|
||||
log_info "Step 3: No frontend changes, skipping frontend checks"
|
||||
fi
|
||||
|
||||
# Step 4: Check PR title format
|
||||
echo ""
|
||||
log_info "Step 4: Checking PR title format..."
|
||||
|
||||
# Get the commit messages to suggest a title
|
||||
COMMITS=$(git log upstream/dev..HEAD --oneline)
|
||||
COMMIT_COUNT=$(echo "$COMMITS" | wc -l | tr -d ' ')
|
||||
|
||||
log_info "Found $COMMIT_COUNT commit(s) in your PR"
|
||||
|
||||
if [ "$COMMIT_COUNT" -eq 1 ]; then
|
||||
SUGGESTED_TITLE=$(git log -1 --pretty=%s)
|
||||
else
|
||||
SUGGESTED_TITLE=$(git log --pretty=%s upstream/dev..HEAD | head -1)
|
||||
fi
|
||||
|
||||
log_info "Current/suggested title: $SUGGESTED_TITLE"
|
||||
|
||||
# Check if it follows conventional commits
|
||||
if echo "$SUGGESTED_TITLE" | grep -qE "^(feat|fix|docs|style|refactor|perf|test|chore|ci|security)(\(.+\))?: .+"; then
|
||||
log_success "Title follows Conventional Commits format"
|
||||
else
|
||||
log_warning "Title doesn't follow Conventional Commits format"
|
||||
echo ""
|
||||
echo "Conventional Commits format:"
|
||||
echo " <type>(<scope>): <description>"
|
||||
echo ""
|
||||
echo "Types: feat, fix, docs, style, refactor, perf, test, chore, ci, security"
|
||||
echo ""
|
||||
echo "Examples:"
|
||||
echo " feat(exchange): add OKX integration"
|
||||
echo " fix(trader): resolve position tracking bug"
|
||||
echo " docs(readme): update installation guide"
|
||||
echo ""
|
||||
|
||||
read -p "Enter new title (or press Enter to keep current): " NEW_TITLE
|
||||
|
||||
if [ -n "$NEW_TITLE" ]; then
|
||||
log_info "You can update the PR title on GitHub after pushing"
|
||||
log_info "Suggested title: $NEW_TITLE"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Step 5: Push changes
|
||||
echo ""
|
||||
log_info "Step 5: Ready to push changes"
|
||||
|
||||
# Check if there are changes to push
|
||||
if git diff upstream/dev..HEAD --quiet; then
|
||||
log_info "No changes to push"
|
||||
else
|
||||
log_info "Changes ready to push to origin/$CURRENT_BRANCH"
|
||||
|
||||
if confirm "Push changes now?"; then
|
||||
log_info "Pushing to origin/$CURRENT_BRANCH..."
|
||||
if git push -f origin "$CURRENT_BRANCH"; then
|
||||
log_success "Successfully pushed changes!"
|
||||
else
|
||||
log_error "Failed to push. You may need to push manually:"
|
||||
echo " git push -f origin $CURRENT_BRANCH"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
log_info "Skipped push. You can push manually later:"
|
||||
echo " git push -f origin $CURRENT_BRANCH"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Summary
|
||||
echo ""
|
||||
echo "╔═══════════════════════════════════════════╗"
|
||||
echo "║ ✅ Migration Complete! ║"
|
||||
echo "╚═══════════════════════════════════════════╝"
|
||||
echo ""
|
||||
|
||||
log_success "Your PR has been migrated!"
|
||||
|
||||
echo ""
|
||||
log_info "Next steps:"
|
||||
echo " 1. Check your PR on GitHub"
|
||||
echo " 2. Update PR title if needed (Conventional Commits format)"
|
||||
echo " 3. Wait for CI checks to run"
|
||||
echo " 4. Address any reviewer feedback"
|
||||
echo ""
|
||||
|
||||
log_info "Need help? Ask in the PR comments or Telegram!"
|
||||
log_info "Telegram: https://t.me/nofx_dev_community"
|
||||
|
||||
echo ""
|
||||
log_success "Thank you for contributing to NOFX! 🚀"
|
||||
echo ""
|
||||
107
web/package-lock.json
generated
107
web/package-lock.json
generated
@@ -8,13 +8,17 @@
|
||||
"name": "nofx-web",
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-slot": "^1.2.3",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"date-fns": "^4.1.0",
|
||||
"framer-motion": "^12.23.24",
|
||||
"lucide-react": "^0.552.0",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"recharts": "^2.15.2",
|
||||
"swr": "^2.2.5",
|
||||
"tailwind-merge": "^3.3.1",
|
||||
"zustand": "^5.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -834,6 +838,39 @@
|
||||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-compose-refs": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmmirror.com/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz",
|
||||
"integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-slot": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmmirror.com/@radix-ui/react-slot/-/react-slot-1.2.3.tgz",
|
||||
"integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-compose-refs": "1.1.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/pluginutils": {
|
||||
"version": "1.0.0-beta.27",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz",
|
||||
@@ -1504,6 +1541,18 @@
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/class-variance-authority": {
|
||||
"version": "0.7.1",
|
||||
"resolved": "https://registry.npmmirror.com/class-variance-authority/-/class-variance-authority-0.7.1.tgz",
|
||||
"integrity": "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"clsx": "^2.1.1"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://polar.sh/cva"
|
||||
}
|
||||
},
|
||||
"node_modules/clsx": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
|
||||
@@ -1905,6 +1954,33 @@
|
||||
"url": "https://github.com/sponsors/rawify"
|
||||
}
|
||||
},
|
||||
"node_modules/framer-motion": {
|
||||
"version": "12.23.24",
|
||||
"resolved": "https://registry.npmmirror.com/framer-motion/-/framer-motion-12.23.24.tgz",
|
||||
"integrity": "sha512-HMi5HRoRCTou+3fb3h9oTLyJGBxHfW+HnNE25tAXOvVx/IvwMHK0cx7IR4a2ZU6sh3IX1Z+4ts32PcYBOqka8w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"motion-dom": "^12.23.23",
|
||||
"motion-utils": "^12.23.6",
|
||||
"tslib": "^2.4.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@emotion/is-prop-valid": "*",
|
||||
"react": "^18.0.0 || ^19.0.0",
|
||||
"react-dom": "^18.0.0 || ^19.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@emotion/is-prop-valid": {
|
||||
"optional": true
|
||||
},
|
||||
"react": {
|
||||
"optional": true
|
||||
},
|
||||
"react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/fsevents": {
|
||||
"version": "2.3.3",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
||||
@@ -2212,6 +2288,21 @@
|
||||
"node": ">=16 || 14 >=14.17"
|
||||
}
|
||||
},
|
||||
"node_modules/motion-dom": {
|
||||
"version": "12.23.23",
|
||||
"resolved": "https://registry.npmmirror.com/motion-dom/-/motion-dom-12.23.23.tgz",
|
||||
"integrity": "sha512-n5yolOs0TQQBRUFImrRfs/+6X4p3Q4n1dUEqt/H58Vx7OW6RF+foWEgmTVDhIWJIMXOuNNL0apKH2S16en9eiA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"motion-utils": "^12.23.6"
|
||||
}
|
||||
},
|
||||
"node_modules/motion-utils": {
|
||||
"version": "12.23.6",
|
||||
"resolved": "https://registry.npmmirror.com/motion-utils/-/motion-utils-12.23.6.tgz",
|
||||
"integrity": "sha512-eAWoPgr4eFEOFfg2WjIsMoqJTW6Z8MTUCgn/GZ3VRpClWBdnbjryiA3ZSNLyxCTmCQx4RmYX6jX1iWHbenUPNQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
@@ -2970,6 +3061,16 @@
|
||||
"react": "^16.11.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/tailwind-merge": {
|
||||
"version": "3.3.1",
|
||||
"resolved": "https://registry.npmmirror.com/tailwind-merge/-/tailwind-merge-3.3.1.tgz",
|
||||
"integrity": "sha512-gBXpgUm/3rp1lMZZrM/w7D8GKqshif0zAymAhbCyIt8KMe+0v9DQ7cdYLR4FHH/cKpdTXb+A/tKKU3eolfsI+g==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/dcastil"
|
||||
}
|
||||
},
|
||||
"node_modules/tailwindcss": {
|
||||
"version": "3.4.18",
|
||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.18.tgz",
|
||||
@@ -3096,6 +3197,12 @@
|
||||
"integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/tslib": {
|
||||
"version": "2.8.1",
|
||||
"resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.8.1.tgz",
|
||||
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
|
||||
"license": "0BSD"
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "5.9.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
|
||||
|
||||
@@ -8,13 +8,17 @@
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@radix-ui/react-slot": "^1.2.3",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"date-fns": "^4.1.0",
|
||||
"framer-motion": "^12.23.24",
|
||||
"lucide-react": "^0.552.0",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"recharts": "^2.15.2",
|
||||
"swr": "^2.2.5",
|
||||
"tailwind-merge": "^3.3.1",
|
||||
"zustand": "^5.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
BIN
web/public/images/hand-bg.png
Normal file
BIN
web/public/images/hand-bg.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 175 KiB |
BIN
web/public/images/hand.png
Normal file
BIN
web/public/images/hand.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.4 MiB |
Binary file not shown.
|
Before Width: | Height: | Size: 39 KiB |
BIN
web/public/images/main.png
Normal file
BIN
web/public/images/main.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 676 KiB |
261
web/src/App.tsx
261
web/src/App.tsx
@@ -6,6 +6,8 @@ import { AITradersPage } from './components/AITradersPage';
|
||||
import { LoginPage } from './components/LoginPage';
|
||||
import { RegisterPage } from './components/RegisterPage';
|
||||
import { CompetitionPage } from './components/CompetitionPage';
|
||||
import { LandingPage } from './pages/LandingPage';
|
||||
import HeaderBar from './components/landing/HeaderBar';
|
||||
import AILearning from './components/AILearning';
|
||||
import { LanguageProvider, useLanguage } from './contexts/LanguageContext';
|
||||
import { AuthProvider, useAuth } from './contexts/AuthContext';
|
||||
@@ -42,29 +44,42 @@ function App() {
|
||||
const { config: systemConfig, loading: configLoading } = useSystemConfig();
|
||||
const [route, setRoute] = useState(window.location.pathname);
|
||||
|
||||
// 从URL hash读取初始页面状态(支持刷新保持页面)
|
||||
// 从URL路径读取初始页面状态(支持刷新保持页面)
|
||||
const getInitialPage = (): Page => {
|
||||
const path = window.location.pathname;
|
||||
const hash = window.location.hash.slice(1); // 去掉 #
|
||||
return hash === 'trader' || hash === 'details' ? 'trader' : 'competition';
|
||||
|
||||
if (path === '/traders' || hash === 'traders') return 'traders';
|
||||
if (path === '/dashboard' || hash === 'trader' || hash === 'details') return 'trader';
|
||||
return 'competition'; // 默认为竞赛页面
|
||||
};
|
||||
|
||||
const [currentPage, setCurrentPage] = useState<Page>(getInitialPage());
|
||||
const [selectedTraderId, setSelectedTraderId] = useState<string | undefined>();
|
||||
const [lastUpdate, setLastUpdate] = useState<string>('--:--:--');
|
||||
|
||||
// 监听URL hash变化,同步页面状态
|
||||
// 监听URL变化,同步页面状态
|
||||
useEffect(() => {
|
||||
const handleHashChange = () => {
|
||||
const handleRouteChange = () => {
|
||||
const path = window.location.pathname;
|
||||
const hash = window.location.hash.slice(1);
|
||||
if (hash === 'trader' || hash === 'details') {
|
||||
|
||||
if (path === '/traders' || hash === 'traders') {
|
||||
setCurrentPage('traders');
|
||||
} else if (path === '/dashboard' || hash === 'trader' || hash === 'details') {
|
||||
setCurrentPage('trader');
|
||||
} else if (hash === 'competition' || hash === '') {
|
||||
} else if (path === '/competition' || hash === 'competition' || hash === '') {
|
||||
setCurrentPage('competition');
|
||||
}
|
||||
setRoute(path);
|
||||
};
|
||||
|
||||
window.addEventListener('hashchange', handleHashChange);
|
||||
return () => window.removeEventListener('hashchange', handleHashChange);
|
||||
window.addEventListener('hashchange', handleRouteChange);
|
||||
window.addEventListener('popstate', handleRouteChange);
|
||||
return () => {
|
||||
window.removeEventListener('hashchange', handleRouteChange);
|
||||
window.removeEventListener('popstate', handleRouteChange);
|
||||
};
|
||||
}, []);
|
||||
|
||||
// 切换页面时更新URL hash (当前通过按钮直接调用setCurrentPage,这个函数暂时保留用于未来扩展)
|
||||
@@ -164,151 +179,137 @@ function App() {
|
||||
return () => window.removeEventListener('popstate', handlePopState);
|
||||
}, []);
|
||||
|
||||
// Set current page based on route for consistent navigation state
|
||||
useEffect(() => {
|
||||
if (route === '/competition') {
|
||||
setCurrentPage('competition');
|
||||
} else if (route === '/traders') {
|
||||
setCurrentPage('traders');
|
||||
} else if (route === '/dashboard') {
|
||||
setCurrentPage('trader');
|
||||
}
|
||||
}, [route]);
|
||||
|
||||
// Show loading spinner while checking auth or config
|
||||
if (isLoading || configLoading) {
|
||||
return (
|
||||
<div className="min-h-screen flex items-center justify-center" style={{ background: '#0B0E11' }}>
|
||||
<div className="text-center">
|
||||
<div className="w-16 h-16 rounded-full mx-auto mb-4 flex items-center justify-center text-3xl animate-spin"
|
||||
style={{ background: 'linear-gradient(135deg, #F0B90B 0%, #FCD535 100%)' }}>
|
||||
⚡
|
||||
</div>
|
||||
<img src="/icons/nofx.svg" alt="NoFx Logo" className="w-16 h-16 mx-auto mb-4 animate-pulse" />
|
||||
<p style={{ color: '#EAECEF' }}>{t('loading', language)}</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// If not in admin mode and not authenticated, show login/register pages
|
||||
if (!systemConfig?.admin_mode && (!user || !token)) {
|
||||
if (route === '/register') {
|
||||
return <RegisterPage />;
|
||||
}
|
||||
// Handle specific routes regardless of authentication
|
||||
if (route === '/login') {
|
||||
return <LoginPage />;
|
||||
}
|
||||
if (route === '/register') {
|
||||
return <RegisterPage />;
|
||||
}
|
||||
if (route === '/competition') {
|
||||
return (
|
||||
<div className="min-h-screen" style={{ background: '#000000', color: '#EAECEF' }}>
|
||||
<HeaderBar
|
||||
|
||||
isLoggedIn={!!user}
|
||||
currentPage="competition"
|
||||
language={language}
|
||||
onLanguageChange={setLanguage}
|
||||
user={user}
|
||||
onLogout={logout}
|
||||
isAdminMode={systemConfig?.admin_mode}
|
||||
onPageChange={(page) => {
|
||||
console.log('Competition page onPageChange called with:', page);
|
||||
console.log('Current route:', route, 'Current page:', currentPage);
|
||||
|
||||
if (page === 'competition') {
|
||||
console.log('Navigating to competition');
|
||||
window.history.pushState({}, '', '/competition');
|
||||
setRoute('/competition');
|
||||
setCurrentPage('competition');
|
||||
} else if (page === 'traders') {
|
||||
console.log('Navigating to traders');
|
||||
window.history.pushState({}, '', '/traders');
|
||||
setRoute('/traders');
|
||||
setCurrentPage('traders');
|
||||
} else if (page === 'trader') {
|
||||
console.log('Navigating to trader/dashboard');
|
||||
window.history.pushState({}, '', '/dashboard');
|
||||
setRoute('/dashboard');
|
||||
setCurrentPage('trader');
|
||||
}
|
||||
|
||||
console.log('After navigation - route:', route, 'currentPage:', currentPage);
|
||||
}}
|
||||
/>
|
||||
<main className="max-w-[1920px] mx-auto px-6 py-6 pt-24">
|
||||
<CompetitionPage />
|
||||
</main>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// Show landing page for root route
|
||||
if (route === '/' || route === '') {
|
||||
return <LandingPage />;
|
||||
}
|
||||
|
||||
// Show main app for authenticated users on other routes
|
||||
if (!systemConfig?.admin_mode && (!user || !token)) {
|
||||
// Default to landing page when not authenticated and no specific route
|
||||
return <LandingPage />;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="min-h-screen" style={{ background: '#0B0E11', color: '#EAECEF' }}>
|
||||
{/* Header - Binance Style */}
|
||||
<header className="glass sticky top-0 z-50 backdrop-blur-xl">
|
||||
<div className="max-w-[1920px] mx-auto px-6 py-4">
|
||||
<div className="relative flex items-center">
|
||||
{/* Left - Logo and Title */}
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="w-8 h-8 flex items-center justify-center">
|
||||
<img src="/icons/nofx.svg?v=2" alt="NOFX" className="w-8 h-8" />
|
||||
</div>
|
||||
<div>
|
||||
<h1 className="text-xl font-bold" style={{ color: '#EAECEF' }}>
|
||||
{t('appTitle', language)}
|
||||
</h1>
|
||||
<p className="text-xs mono" style={{ color: '#848E9C' }}>
|
||||
{t('subtitle', language)}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Center - Page Toggle (absolutely positioned) */}
|
||||
<div className="absolute left-1/2 transform -translate-x-1/2 flex gap-1 rounded p-1" style={{ background: '#1E2329' }}>
|
||||
<button
|
||||
onClick={() => setCurrentPage('competition')}
|
||||
className={`px-3 py-2 rounded text-sm font-semibold transition-all`}
|
||||
style={currentPage === 'competition'
|
||||
? { background: '#F0B90B', color: '#000' }
|
||||
: { background: 'transparent', color: '#848E9C' }
|
||||
}
|
||||
>
|
||||
{t('aiCompetition', language)}
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setCurrentPage('traders')}
|
||||
className={`px-3 py-2 rounded text-sm font-semibold transition-all`}
|
||||
style={currentPage === 'traders'
|
||||
? { background: '#F0B90B', color: '#000' }
|
||||
: { background: 'transparent', color: '#848E9C' }
|
||||
}
|
||||
>
|
||||
{t('aiTraders', language)}
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setCurrentPage('trader')}
|
||||
className={`px-3 py-2 rounded text-sm font-semibold transition-all`}
|
||||
style={currentPage === 'trader'
|
||||
? { background: '#F0B90B', color: '#000' }
|
||||
: { background: 'transparent', color: '#848E9C' }
|
||||
}
|
||||
>
|
||||
{t('tradingPanel', language)}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Right - Actions */}
|
||||
<div className="ml-auto flex items-center gap-3">
|
||||
|
||||
{/* User Info - Only show if not in admin mode */}
|
||||
{!systemConfig?.admin_mode && user && (
|
||||
<div className="flex items-center gap-2 px-3 py-2 rounded" style={{ background: '#1E2329', border: '1px solid #2B3139' }}>
|
||||
<div className="w-6 h-6 rounded-full flex items-center justify-center text-xs font-bold" style={{ background: '#F0B90B', color: '#000' }}>
|
||||
{user.email[0].toUpperCase()}
|
||||
</div>
|
||||
<span className="text-sm" style={{ color: '#EAECEF' }}>{user.email}</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Admin Mode Indicator */}
|
||||
{systemConfig?.admin_mode && (
|
||||
<div className="flex items-center gap-2 px-3 py-2 rounded" style={{ background: '#1E2329', border: '1px solid #2B3139' }}>
|
||||
<span className="text-sm font-semibold" style={{ color: '#F0B90B' }}>⚡ {t('adminMode', language)}</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Language Toggle */}
|
||||
<div className="flex gap-1 rounded p-1" style={{ background: '#1E2329' }}>
|
||||
<button
|
||||
onClick={() => setLanguage('zh')}
|
||||
className="px-3 py-1.5 rounded text-xs font-semibold transition-all"
|
||||
style={language === 'zh'
|
||||
? { background: '#F0B90B', color: '#000' }
|
||||
: { background: 'transparent', color: '#848E9C' }
|
||||
}
|
||||
>
|
||||
中文
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setLanguage('en')}
|
||||
className="px-3 py-1.5 rounded text-xs font-semibold transition-all"
|
||||
style={language === 'en'
|
||||
? { background: '#F0B90B', color: '#000' }
|
||||
: { background: 'transparent', color: '#848E9C' }
|
||||
}
|
||||
>
|
||||
EN
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Logout Button - Only show if not in admin mode */}
|
||||
{!systemConfig?.admin_mode && (
|
||||
<button
|
||||
onClick={logout}
|
||||
className="px-3 py-2 rounded text-sm font-semibold transition-all hover:scale-105"
|
||||
style={{ background: 'rgba(246, 70, 93, 0.1)', color: '#F6465D', border: '1px solid rgba(246, 70, 93, 0.2)' }}
|
||||
>
|
||||
{t('logout', language)}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<div className="min-h-screen" style={{ background: 'var(--brand-black)', color: 'var(--brand-light-gray)' }}>
|
||||
<HeaderBar
|
||||
|
||||
isLoggedIn={!!user}
|
||||
isHomePage={false}
|
||||
currentPage={currentPage}
|
||||
language={language}
|
||||
onLanguageChange={setLanguage}
|
||||
user={user}
|
||||
onLogout={logout}
|
||||
isAdminMode={systemConfig?.admin_mode}
|
||||
onPageChange={(page) => {
|
||||
console.log('App.tsx onPageChange called with:', page);
|
||||
console.log('Current route:', route, 'Current page:', currentPage);
|
||||
|
||||
if (page === 'competition') {
|
||||
console.log('Navigating to competition');
|
||||
window.history.pushState({}, '', '/competition');
|
||||
setRoute('/competition');
|
||||
setCurrentPage('competition');
|
||||
} else if (page === 'traders') {
|
||||
console.log('Navigating to traders');
|
||||
window.history.pushState({}, '', '/traders');
|
||||
setRoute('/traders');
|
||||
setCurrentPage('traders');
|
||||
} else if (page === 'trader') {
|
||||
console.log('Navigating to trader/dashboard');
|
||||
window.history.pushState({}, '', '/dashboard');
|
||||
setRoute('/dashboard');
|
||||
setCurrentPage('trader');
|
||||
}
|
||||
|
||||
console.log('After navigation - route:', route, 'currentPage:', currentPage);
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* Main Content */}
|
||||
<main className="max-w-[1920px] mx-auto px-6 py-6">
|
||||
<main className="max-w-[1920px] mx-auto px-6 py-6 pt-24">
|
||||
{currentPage === 'competition' ? (
|
||||
<CompetitionPage />
|
||||
) : currentPage === 'traders' ? (
|
||||
<AITradersPage
|
||||
onTraderSelect={(traderId) => {
|
||||
setSelectedTraderId(traderId);
|
||||
window.history.pushState({}, '', '/dashboard');
|
||||
setRoute('/dashboard');
|
||||
setCurrentPage('trader');
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -7,7 +7,7 @@ import { t, type Language } from '../i18n/translations';
|
||||
import { getExchangeIcon } from './ExchangeIcons';
|
||||
import { getModelIcon } from './ModelIcons';
|
||||
import { TraderConfigModal } from './TraderConfigModal';
|
||||
import { Bot, Brain, Landmark, BarChart3, Trash2, Plus, Users } from 'lucide-react';
|
||||
import { Bot, Brain, Landmark, BarChart3, Trash2, Plus, Users, AlertTriangle } from 'lucide-react';
|
||||
|
||||
// 获取友好的AI模型名称
|
||||
function getModelDisplayName(modelId: string): string {
|
||||
@@ -1427,7 +1427,7 @@ function ExchangeConfigModal({
|
||||
|
||||
<div className="p-4 rounded" style={{ background: 'rgba(240, 185, 11, 0.1)', border: '1px solid rgba(240, 185, 11, 0.2)' }}>
|
||||
<div className="text-sm font-semibold mb-2" style={{ color: '#F0B90B' }}>
|
||||
⚠️ {t('securityWarning', language)}
|
||||
<span className="inline-flex items-center gap-1"><AlertTriangle className="w-4 h-4" /> {t('securityWarning', language)}</span>
|
||||
</div>
|
||||
<div className="text-xs space-y-1" style={{ color: '#848E9C' }}>
|
||||
<div>{t('exchangeConfigWarning1', language)}</div>
|
||||
@@ -1467,4 +1467,4 @@ function ExchangeConfigModal({
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ import type { CompetitionTraderData } from '../types';
|
||||
import { getTraderColor } from '../utils/traderColors';
|
||||
import { useLanguage } from '../contexts/LanguageContext';
|
||||
import { t } from '../i18n/translations';
|
||||
import { BarChart3 } from 'lucide-react';
|
||||
|
||||
interface ComparisonChartProps {
|
||||
traders: CompetitionTraderData[];
|
||||
@@ -136,7 +137,7 @@ export function ComparisonChart({ traders }: ComparisonChartProps) {
|
||||
if (combinedData.length === 0) {
|
||||
return (
|
||||
<div className="text-center py-16" style={{ color: '#848E9C' }}>
|
||||
<div className="text-6xl mb-4 opacity-50">📊</div>
|
||||
<BarChart3 className="w-12 h-12 mx-auto mb-4 opacity-60" />
|
||||
<div className="text-lg font-semibold mb-2">{t('noHistoricalData', language)}</div>
|
||||
<div className="text-sm">{t('dataWillAppear', language)}</div>
|
||||
</div>
|
||||
@@ -338,4 +339,4 @@ export function ComparisonChart({ traders }: ComparisonChartProps) {
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { useState } from 'react';
|
||||
import { Trophy, Medal } from 'lucide-react';
|
||||
import useSWR from 'swr';
|
||||
import { api } from '../lib/api';
|
||||
import type { CompetitionData } from '../types';
|
||||
@@ -30,6 +31,8 @@ export function CompetitionPage() {
|
||||
setIsModalOpen(true);
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch trader config:', error);
|
||||
// 对于未登录用户,不显示详细配置,这是正常行为
|
||||
// 竞赛页面主要用于查看排行榜和基本信息
|
||||
}
|
||||
};
|
||||
|
||||
@@ -74,11 +77,8 @@ export function CompetitionPage() {
|
||||
{/* Competition Header - 精简版 */}
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="w-12 h-12 rounded-xl flex items-center justify-center text-2xl" style={{
|
||||
background: 'linear-gradient(135deg, #F0B90B 0%, #FCD535 100%)',
|
||||
boxShadow: '0 4px 14px rgba(240, 185, 11, 0.4)'
|
||||
}}>
|
||||
🏆
|
||||
<div className="w-12 h-12 rounded-xl flex items-center justify-center" style={{ background: 'rgba(240, 185, 11, 0.15)', border: '1px solid rgba(240,185,11,0.3)' }}>
|
||||
<Trophy className="w-6 h-6" style={{ color: '#F0B90B' }} />
|
||||
</div>
|
||||
<div>
|
||||
<h1 className="text-2xl font-bold flex items-center gap-2" style={{ color: '#EAECEF' }}>
|
||||
@@ -145,8 +145,8 @@ export function CompetitionPage() {
|
||||
<div className="flex items-center justify-between">
|
||||
{/* Rank & Name */}
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="text-2xl w-6">
|
||||
{index === 0 ? '🥇' : index === 1 ? '🥈' : '🥉'}
|
||||
<div className="w-6 flex items-center justify-center">
|
||||
<Medal className="w-5 h-5" style={{ color: index === 0 ? '#F0B90B' : index === 1 ? '#C0C0C0' : '#CD7F32' }} />
|
||||
</div>
|
||||
<div>
|
||||
<div className="font-bold text-sm" style={{ color: '#EAECEF' }}>{trader.trader_name}</div>
|
||||
@@ -281,4 +281,4 @@ export function CompetitionPage() {
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
115
web/src/components/CryptoFeatureCard.tsx
Normal file
115
web/src/components/CryptoFeatureCard.tsx
Normal file
@@ -0,0 +1,115 @@
|
||||
import * as React from "react";
|
||||
import { motion } from "framer-motion";
|
||||
import { Check } from "lucide-react";
|
||||
import { cn } from "../lib/utils";
|
||||
|
||||
interface CryptoFeatureCardProps {
|
||||
icon: React.ReactNode;
|
||||
title: string;
|
||||
description: string;
|
||||
features: string[];
|
||||
className?: string;
|
||||
delay?: number;
|
||||
}
|
||||
|
||||
export const CryptoFeatureCard = React.forwardRef<HTMLDivElement, CryptoFeatureCardProps>(
|
||||
({ icon, title, description, features, className, delay = 0 }, ref) => {
|
||||
const [isHovered, setIsHovered] = React.useState(false);
|
||||
|
||||
return (
|
||||
<motion.div
|
||||
ref={ref}
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.5, delay }}
|
||||
onHoverStart={() => setIsHovered(true)}
|
||||
onHoverEnd={() => setIsHovered(false)}
|
||||
className="relative h-full"
|
||||
>
|
||||
<div
|
||||
className={cn(
|
||||
"relative h-full overflow-hidden border-2 transition-all duration-300 rounded-xl",
|
||||
"bg-gradient-to-br from-[#000000] to-[#0A0A0A]",
|
||||
"border-[#1A1A1A] hover:border-[#F0B90B]/50",
|
||||
isHovered && "shadow-[0_0_20px_rgba(240,185,11,0.2)]",
|
||||
className
|
||||
)}
|
||||
>
|
||||
{/* Animated glow border effect */}
|
||||
<motion.div
|
||||
className="absolute inset-0 opacity-0 pointer-events-none"
|
||||
animate={{
|
||||
opacity: isHovered ? 1 : 0,
|
||||
}}
|
||||
transition={{ duration: 0.3 }}
|
||||
>
|
||||
<div className="absolute inset-0 bg-gradient-to-r from-transparent via-[#F0B90B]/20 to-transparent animate-[shimmer_2s_infinite]" />
|
||||
</motion.div>
|
||||
|
||||
{/* Background pattern */}
|
||||
<div className="absolute inset-0 opacity-5">
|
||||
<div
|
||||
className="absolute inset-0"
|
||||
style={{
|
||||
backgroundImage: `radial-gradient(circle at 2px 2px, #F0B90B 1px, transparent 0)`,
|
||||
backgroundSize: "32px 32px",
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="relative z-10 p-8 flex flex-col h-full">
|
||||
{/* Icon container */}
|
||||
<motion.div
|
||||
className="mb-6 inline-flex items-center justify-center w-16 h-16 rounded-xl"
|
||||
style={{
|
||||
background: 'linear-gradient(135deg, rgba(240, 185, 11, 0.2) 0%, rgba(240, 185, 11, 0.05) 100%)',
|
||||
border: '1px solid rgba(240, 185, 11, 0.3)'
|
||||
}}
|
||||
animate={{
|
||||
scale: isHovered ? 1.1 : 1,
|
||||
boxShadow: isHovered
|
||||
? "0 0 20px rgba(240, 185, 11, 0.4)"
|
||||
: "0 0 0px rgba(240, 185, 11, 0)",
|
||||
}}
|
||||
transition={{ duration: 0.3 }}
|
||||
>
|
||||
<div style={{ color: 'var(--brand-yellow)' }}>{icon}</div>
|
||||
</motion.div>
|
||||
|
||||
{/* Title */}
|
||||
<h3 className="text-2xl font-bold mb-3" style={{ color: 'var(--brand-light-gray)' }}>{title}</h3>
|
||||
|
||||
{/* Description */}
|
||||
<p className="mb-6 flex-grow leading-relaxed" style={{ color: 'var(--text-secondary)' }}>{description}</p>
|
||||
|
||||
{/* Features list */}
|
||||
<div className="space-y-3 mb-6">
|
||||
{features.map((feature, index) => (
|
||||
<motion.div
|
||||
key={index}
|
||||
initial={{ opacity: 0, x: -10 }}
|
||||
whileInView={{ opacity: 1, x: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ delay: delay + index * 0.1 }}
|
||||
className="flex items-start gap-3"
|
||||
>
|
||||
<div className="mt-0.5 flex-shrink-0">
|
||||
<div className="w-5 h-5 rounded-full flex items-center justify-center" style={{ background: 'rgba(240, 185, 11, 0.2)' }}>
|
||||
<Check className="w-3 h-3" style={{ color: 'var(--brand-yellow)' }} />
|
||||
</div>
|
||||
</div>
|
||||
<span className="text-sm" style={{ color: 'var(--brand-light-gray)' }}>{feature}</span>
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</motion.div>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
CryptoFeatureCard.displayName = "CryptoFeatureCard";
|
||||
@@ -15,7 +15,7 @@ export function Header({ simple = false }: HeaderProps) {
|
||||
{/* Left - Logo and Title */}
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="flex items-center justify-center">
|
||||
<img src="/icons/nofx.svg?v=2" alt="NOFX" className="h-10 w-auto" />
|
||||
<img src="/icons/nofx.svg" alt="NoFx Logo" className="w-8 h-8" />
|
||||
</div>
|
||||
<div>
|
||||
<h1 className="text-xl font-bold" style={{ color: '#EAECEF' }}>
|
||||
@@ -56,4 +56,4 @@ export function Header({ simple = false }: HeaderProps) {
|
||||
</div>
|
||||
</header>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import React, { useState } from 'react';
|
||||
import { useAuth } from '../contexts/AuthContext';
|
||||
import { useLanguage } from '../contexts/LanguageContext';
|
||||
import { t } from '../i18n/translations';
|
||||
import { Header } from './Header';
|
||||
import HeaderBar from './landing/HeaderBar';
|
||||
|
||||
export function LoginPage() {
|
||||
const { language } = useLanguage();
|
||||
@@ -50,30 +50,44 @@ export function LoginPage() {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="min-h-screen" style={{ background: '#0B0E11' }}>
|
||||
<Header simple />
|
||||
|
||||
<div className="flex items-center justify-center" style={{ minHeight: 'calc(100vh - 80px)' }}>
|
||||
<div className="min-h-screen" style={{ background: 'var(--brand-black)' }}>
|
||||
<HeaderBar
|
||||
onLoginClick={() => {}}
|
||||
isLoggedIn={false}
|
||||
isHomePage={false}
|
||||
currentPage="login"
|
||||
language={language}
|
||||
onLanguageChange={() => {}}
|
||||
onPageChange={(page) => {
|
||||
console.log('LoginPage onPageChange called with:', page);
|
||||
if (page === 'competition') {
|
||||
window.location.href = '/competition';
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
||||
<div className="flex items-center justify-center pt-20" style={{ minHeight: 'calc(100vh - 80px)' }}>
|
||||
<div className="w-full max-w-md">
|
||||
|
||||
{/* Logo */}
|
||||
<div className="text-center mb-8">
|
||||
<div className="w-16 h-16 mx-auto mb-4 flex items-center justify-center">
|
||||
<img src="/icons/nofx.svg?v=2" alt="NOFX" className="w-16 h-16" />
|
||||
<img src="/icons/nofx.svg" alt="NoFx Logo" className="w-16 h-16 object-contain" />
|
||||
</div>
|
||||
<h1 className="text-2xl font-bold" style={{ color: '#EAECEF' }}>
|
||||
{t('loginTitle', language)}
|
||||
<h1 className="text-2xl font-bold" style={{ color: 'var(--brand-light-gray)' }}>
|
||||
登录 NOFX
|
||||
</h1>
|
||||
<p className="text-sm mt-2" style={{ color: '#848E9C' }}>
|
||||
{step === 'login' ? t('loginTitle', language) : t('enterOTPCode', language)}
|
||||
<p className="text-sm mt-2" style={{ color: 'var(--text-secondary)' }}>
|
||||
{step === 'login' ? '请输入您的邮箱和密码' : '请输入两步验证码'}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Login Form */}
|
||||
<div className="rounded-lg p-6" style={{ background: '#1E2329', border: '1px solid #2B3139' }}>
|
||||
<div className="rounded-lg p-6" style={{ background: 'var(--panel-bg)', border: '1px solid var(--panel-border)' }}>
|
||||
{step === 'login' ? (
|
||||
<form onSubmit={handleLogin} className="space-y-4">
|
||||
<div>
|
||||
<label className="block text-sm font-semibold mb-2" style={{ color: '#EAECEF' }}>
|
||||
<label className="block text-sm font-semibold mb-2" style={{ color: 'var(--brand-light-gray)' }}>
|
||||
{t('email', language)}
|
||||
</label>
|
||||
<input
|
||||
@@ -81,14 +95,14 @@ export function LoginPage() {
|
||||
value={email}
|
||||
onChange={(e) => setEmail(e.target.value)}
|
||||
className="w-full px-3 py-2 rounded"
|
||||
style={{ background: '#0B0E11', border: '1px solid #2B3139', color: '#EAECEF' }}
|
||||
style={{ background: 'var(--brand-black)', border: '1px solid var(--panel-border)', color: 'var(--brand-light-gray)' }}
|
||||
placeholder={t('emailPlaceholder', language)}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-semibold mb-2" style={{ color: '#EAECEF' }}>
|
||||
<label className="block text-sm font-semibold mb-2" style={{ color: 'var(--brand-light-gray)' }}>
|
||||
{t('password', language)}
|
||||
</label>
|
||||
<input
|
||||
@@ -96,14 +110,14 @@ export function LoginPage() {
|
||||
value={password}
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
className="w-full px-3 py-2 rounded"
|
||||
style={{ background: '#0B0E11', border: '1px solid #2B3139', color: '#EAECEF' }}
|
||||
style={{ background: 'var(--brand-black)', border: '1px solid var(--panel-border)', color: 'var(--brand-light-gray)' }}
|
||||
placeholder={t('passwordPlaceholder', language)}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
{error && (
|
||||
<div className="text-sm px-3 py-2 rounded" style={{ background: 'rgba(246, 70, 93, 0.1)', color: '#F6465D' }}>
|
||||
<div className="text-sm px-3 py-2 rounded" style={{ background: 'var(--binance-red-bg)', color: 'var(--binance-red)' }}>
|
||||
{error}
|
||||
</div>
|
||||
)}
|
||||
@@ -112,7 +126,7 @@ export function LoginPage() {
|
||||
type="submit"
|
||||
disabled={loading}
|
||||
className="w-full px-4 py-2 rounded text-sm font-semibold transition-all hover:scale-105 disabled:opacity-50"
|
||||
style={{ background: '#F0B90B', color: '#000' }}
|
||||
style={{ background: 'var(--brand-yellow)', color: 'var(--brand-black)' }}
|
||||
>
|
||||
{loading ? t('loading', language) : t('loginButton', language)}
|
||||
</button>
|
||||
@@ -128,7 +142,7 @@ export function LoginPage() {
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-semibold mb-2" style={{ color: '#EAECEF' }}>
|
||||
<label className="block text-sm font-semibold mb-2" style={{ color: 'var(--brand-light-gray)' }}>
|
||||
{t('otpCode', language)}
|
||||
</label>
|
||||
<input
|
||||
@@ -136,7 +150,7 @@ export function LoginPage() {
|
||||
value={otpCode}
|
||||
onChange={(e) => setOtpCode(e.target.value.replace(/\D/g, '').slice(0, 6))}
|
||||
className="w-full px-3 py-2 rounded text-center text-2xl font-mono"
|
||||
style={{ background: '#0B0E11', border: '1px solid #2B3139', color: '#EAECEF' }}
|
||||
style={{ background: 'var(--brand-black)', border: '1px solid var(--panel-border)', color: 'var(--brand-light-gray)' }}
|
||||
placeholder={t('otpPlaceholder', language)}
|
||||
maxLength={6}
|
||||
required
|
||||
@@ -144,7 +158,7 @@ export function LoginPage() {
|
||||
</div>
|
||||
|
||||
{error && (
|
||||
<div className="text-sm px-3 py-2 rounded" style={{ background: 'rgba(246, 70, 93, 0.1)', color: '#F6465D' }}>
|
||||
<div className="text-sm px-3 py-2 rounded" style={{ background: 'var(--binance-red-bg)', color: 'var(--binance-red)' }}>
|
||||
{error}
|
||||
</div>
|
||||
)}
|
||||
@@ -154,7 +168,7 @@ export function LoginPage() {
|
||||
type="button"
|
||||
onClick={() => setStep('login')}
|
||||
className="flex-1 px-4 py-2 rounded text-sm font-semibold"
|
||||
style={{ background: '#2B3139', color: '#848E9C' }}
|
||||
style={{ background: 'var(--panel-bg-hover)', color: 'var(--text-secondary)' }}
|
||||
>
|
||||
{t('back', language)}
|
||||
</button>
|
||||
@@ -173,17 +187,17 @@ export function LoginPage() {
|
||||
|
||||
{/* Register Link */}
|
||||
<div className="text-center mt-6">
|
||||
<p className="text-sm" style={{ color: '#848E9C' }}>
|
||||
{t('noAccount', language)}{' '}
|
||||
<p className="text-sm" style={{ color: 'var(--text-secondary)' }}>
|
||||
还没有账户?{' '}
|
||||
<button
|
||||
onClick={() => {
|
||||
window.history.pushState({}, '', '/register');
|
||||
window.dispatchEvent(new PopStateEvent('popstate'));
|
||||
}}
|
||||
className="font-semibold hover:underline"
|
||||
style={{ color: '#F0B90B' }}
|
||||
className="font-semibold hover:underline transition-colors"
|
||||
style={{ color: 'var(--brand-yellow)' }}
|
||||
>
|
||||
{t('registerNow', language)}
|
||||
立即注册
|
||||
</button>
|
||||
</p>
|
||||
</div>
|
||||
@@ -191,4 +205,4 @@ export function LoginPage() {
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import React, { useState } from 'react';
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { useAuth } from '../contexts/AuthContext';
|
||||
import { useLanguage } from '../contexts/LanguageContext';
|
||||
import { t } from '../i18n/translations';
|
||||
import { getSystemConfig } from '../lib/config';
|
||||
import HeaderBar from './landing/HeaderBar';
|
||||
|
||||
export function RegisterPage() {
|
||||
const { language } = useLanguage();
|
||||
@@ -10,6 +12,8 @@ export function RegisterPage() {
|
||||
const [email, setEmail] = useState('');
|
||||
const [password, setPassword] = useState('');
|
||||
const [confirmPassword, setConfirmPassword] = useState('');
|
||||
const [betaCode, setBetaCode] = useState('');
|
||||
const [betaMode, setBetaMode] = useState(false);
|
||||
const [otpCode, setOtpCode] = useState('');
|
||||
const [userID, setUserID] = useState('');
|
||||
const [otpSecret, setOtpSecret] = useState('');
|
||||
@@ -17,6 +21,15 @@ export function RegisterPage() {
|
||||
const [error, setError] = useState('');
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
// 获取系统配置,检查是否开启内测模式
|
||||
getSystemConfig().then(config => {
|
||||
setBetaMode(config.beta_mode || false);
|
||||
}).catch(err => {
|
||||
console.error('Failed to fetch system config:', err);
|
||||
});
|
||||
}, []);
|
||||
|
||||
const handleRegister = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
setError('');
|
||||
@@ -31,9 +44,14 @@ export function RegisterPage() {
|
||||
return;
|
||||
}
|
||||
|
||||
if (betaMode && !betaCode.trim()) {
|
||||
setError('内测期间,注册需要提供内测码');
|
||||
return;
|
||||
}
|
||||
|
||||
setLoading(true);
|
||||
|
||||
const result = await register(email, password);
|
||||
const result = await register(email, password, betaCode.trim() || undefined);
|
||||
|
||||
if (result.success && result.userID) {
|
||||
setUserID(result.userID);
|
||||
@@ -71,12 +89,28 @@ export function RegisterPage() {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="min-h-screen flex items-center justify-center" style={{ background: '#0B0E11' }}>
|
||||
<div className="w-full max-w-md">
|
||||
{/* Logo */}
|
||||
<div className="text-center mb-8">
|
||||
<div className="min-h-screen" style={{ background: 'var(--brand-black)' }}>
|
||||
<HeaderBar
|
||||
isLoggedIn={false}
|
||||
isHomePage={false}
|
||||
currentPage="register"
|
||||
language={language}
|
||||
onLanguageChange={() => {}}
|
||||
onPageChange={(page) => {
|
||||
console.log('RegisterPage onPageChange called with:', page);
|
||||
if (page === 'competition') {
|
||||
window.location.href = '/competition';
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
||||
<div className="flex items-center justify-center pt-20" style={{ minHeight: 'calc(100vh - 80px)' }}>
|
||||
<div className="w-full max-w-md">
|
||||
|
||||
{/* Logo */}
|
||||
<div className="text-center mb-8">
|
||||
<div className="w-16 h-16 mx-auto mb-4 flex items-center justify-center">
|
||||
<img src="/icons/nofx.svg?v=2" alt="NOFX" className="w-16 h-16" />
|
||||
<img src="/icons/nofx.svg" alt="NoFx Logo" className="w-16 h-16 object-contain" />
|
||||
</div>
|
||||
<h1 className="text-2xl font-bold" style={{ color: '#EAECEF' }}>
|
||||
{t('appTitle', language)}
|
||||
@@ -89,11 +123,11 @@ export function RegisterPage() {
|
||||
</div>
|
||||
|
||||
{/* Registration Form */}
|
||||
<div className="rounded-lg p-6" style={{ background: '#1E2329', border: '1px solid #2B3139' }}>
|
||||
<div className="rounded-lg p-6" style={{ background: 'var(--panel-bg)', border: '1px solid var(--panel-border)' }}>
|
||||
{step === 'register' && (
|
||||
<form onSubmit={handleRegister} className="space-y-4">
|
||||
<div>
|
||||
<label className="block text-sm font-semibold mb-2" style={{ color: '#EAECEF' }}>
|
||||
<label className="block text-sm font-semibold mb-2" style={{ color: 'var(--brand-light-gray)' }}>
|
||||
{t('email', language)}
|
||||
</label>
|
||||
<input
|
||||
@@ -101,14 +135,14 @@ export function RegisterPage() {
|
||||
value={email}
|
||||
onChange={(e) => setEmail(e.target.value)}
|
||||
className="w-full px-3 py-2 rounded"
|
||||
style={{ background: '#0B0E11', border: '1px solid #2B3139', color: '#EAECEF' }}
|
||||
style={{ background: 'var(--brand-black)', border: '1px solid var(--panel-border)', color: 'var(--brand-light-gray)' }}
|
||||
placeholder={t('emailPlaceholder', language)}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-semibold mb-2" style={{ color: '#EAECEF' }}>
|
||||
<label className="block text-sm font-semibold mb-2" style={{ color: 'var(--brand-light-gray)' }}>
|
||||
{t('password', language)}
|
||||
</label>
|
||||
<input
|
||||
@@ -116,14 +150,14 @@ export function RegisterPage() {
|
||||
value={password}
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
className="w-full px-3 py-2 rounded"
|
||||
style={{ background: '#0B0E11', border: '1px solid #2B3139', color: '#EAECEF' }}
|
||||
style={{ background: 'var(--brand-black)', border: '1px solid var(--panel-border)', color: 'var(--brand-light-gray)' }}
|
||||
placeholder={t('passwordPlaceholder', language)}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-semibold mb-2" style={{ color: '#EAECEF' }}>
|
||||
<label className="block text-sm font-semibold mb-2" style={{ color: 'var(--brand-light-gray)' }}>
|
||||
{t('confirmPassword', language)}
|
||||
</label>
|
||||
<input
|
||||
@@ -131,23 +165,44 @@ export function RegisterPage() {
|
||||
value={confirmPassword}
|
||||
onChange={(e) => setConfirmPassword(e.target.value)}
|
||||
className="w-full px-3 py-2 rounded"
|
||||
style={{ background: '#0B0E11', border: '1px solid #2B3139', color: '#EAECEF' }}
|
||||
style={{ background: 'var(--brand-black)', border: '1px solid var(--panel-border)', color: 'var(--brand-light-gray)' }}
|
||||
placeholder={t('confirmPasswordPlaceholder', language)}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
{betaMode && (
|
||||
<div>
|
||||
<label className="block text-sm font-semibold mb-2" style={{ color: '#EAECEF' }}>
|
||||
内测码 *
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
value={betaCode}
|
||||
onChange={(e) => setBetaCode(e.target.value.replace(/[^a-z0-9]/gi, '').toLowerCase())}
|
||||
className="w-full px-3 py-2 rounded font-mono"
|
||||
style={{ background: '#0B0E11', border: '1px solid #2B3139', color: '#EAECEF' }}
|
||||
placeholder="请输入6位内测码"
|
||||
maxLength={6}
|
||||
required={betaMode}
|
||||
/>
|
||||
<p className="text-xs mt-1" style={{ color: '#848E9C' }}>
|
||||
内测码由6位字母数字组成,区分大小写
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{error && (
|
||||
<div className="text-sm px-3 py-2 rounded" style={{ background: 'rgba(246, 70, 93, 0.1)', color: '#F6465D' }}>
|
||||
<div className="text-sm px-3 py-2 rounded" style={{ background: 'var(--binance-red-bg)', color: 'var(--binance-red)' }}>
|
||||
{error}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
disabled={loading}
|
||||
disabled={loading || (betaMode && !betaCode.trim())}
|
||||
className="w-full px-4 py-2 rounded text-sm font-semibold transition-all hover:scale-105 disabled:opacity-50"
|
||||
style={{ background: '#F0B90B', color: '#000' }}
|
||||
style={{ background: 'var(--brand-yellow)', color: 'var(--brand-black)' }}
|
||||
>
|
||||
{loading ? t('loading', language) : t('registerButton', language)}
|
||||
</button>
|
||||
@@ -167,21 +222,21 @@ export function RegisterPage() {
|
||||
</div>
|
||||
|
||||
<div className="space-y-3">
|
||||
<div className="p-3 rounded" style={{ background: '#0B0E11', border: '1px solid #2B3139' }}>
|
||||
<p className="text-sm font-semibold mb-2" style={{ color: '#EAECEF' }}>
|
||||
{t('step1Title', language)}
|
||||
<div className="p-3 rounded" style={{ background: 'var(--brand-black)', border: '1px solid var(--panel-border)' }}>
|
||||
<p className="text-sm font-semibold mb-2" style={{ color: 'var(--brand-light-gray)' }}>
|
||||
{t('authStep1Title', language)}
|
||||
</p>
|
||||
<p className="text-xs" style={{ color: '#848E9C' }}>
|
||||
{t('step1Desc', language)}
|
||||
<p className="text-xs" style={{ color: 'var(--text-secondary)' }}>
|
||||
{t('authStep1Desc', language)}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="p-3 rounded" style={{ background: '#0B0E11', border: '1px solid #2B3139' }}>
|
||||
<p className="text-sm font-semibold mb-2" style={{ color: '#EAECEF' }}>
|
||||
{t('step2Title', language)}
|
||||
<div className="p-3 rounded" style={{ background: 'var(--brand-black)', border: '1px solid var(--panel-border)' }}>
|
||||
<p className="text-sm font-semibold mb-2" style={{ color: 'var(--brand-light-gray)' }}>
|
||||
{t('authStep2Title', language)}
|
||||
</p>
|
||||
<p className="text-xs mb-2" style={{ color: '#848E9C' }}>
|
||||
{t('step2Desc', language)}
|
||||
{t('authStep2Desc', language)}
|
||||
</p>
|
||||
|
||||
{qrCodeURL && (
|
||||
@@ -198,13 +253,13 @@ export function RegisterPage() {
|
||||
<p className="text-xs mb-1" style={{ color: '#848E9C' }}>{t('otpSecret', language)}</p>
|
||||
<div className="flex items-center gap-2">
|
||||
<code className="flex-1 px-2 py-1 text-xs rounded font-mono"
|
||||
style={{ background: '#2B3139', color: '#EAECEF' }}>
|
||||
style={{ background: 'var(--panel-bg-hover)', color: 'var(--brand-light-gray)' }}>
|
||||
{otpSecret}
|
||||
</code>
|
||||
<button
|
||||
onClick={() => copyToClipboard(otpSecret)}
|
||||
className="px-2 py-1 text-xs rounded"
|
||||
style={{ background: '#F0B90B', color: '#000' }}
|
||||
style={{ background: 'var(--brand-yellow)', color: 'var(--brand-black)' }}
|
||||
>
|
||||
{t('copy', language)}
|
||||
</button>
|
||||
@@ -212,12 +267,12 @@ export function RegisterPage() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="p-3 rounded" style={{ background: '#0B0E11', border: '1px solid #2B3139' }}>
|
||||
<p className="text-sm font-semibold mb-2" style={{ color: '#EAECEF' }}>
|
||||
{t('step3Title', language)}
|
||||
<div className="p-3 rounded" style={{ background: 'var(--brand-black)', border: '1px solid var(--panel-border)' }}>
|
||||
<p className="text-sm font-semibold mb-2" style={{ color: 'var(--brand-light-gray)' }}>
|
||||
{t('authStep3Title', language)}
|
||||
</p>
|
||||
<p className="text-xs" style={{ color: '#848E9C' }}>
|
||||
{t('step3Desc', language)}
|
||||
<p className="text-xs" style={{ color: 'var(--text-secondary)' }}>
|
||||
{t('authStep3Desc', language)}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -243,7 +298,7 @@ export function RegisterPage() {
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-semibold mb-2" style={{ color: '#EAECEF' }}>
|
||||
<label className="block text-sm font-semibold mb-2" style={{ color: 'var(--brand-light-gray)' }}>
|
||||
{t('otpCode', language)}
|
||||
</label>
|
||||
<input
|
||||
@@ -251,7 +306,7 @@ export function RegisterPage() {
|
||||
value={otpCode}
|
||||
onChange={(e) => setOtpCode(e.target.value.replace(/\D/g, '').slice(0, 6))}
|
||||
className="w-full px-3 py-2 rounded text-center text-2xl font-mono"
|
||||
style={{ background: '#0B0E11', border: '1px solid #2B3139', color: '#EAECEF' }}
|
||||
style={{ background: 'var(--brand-black)', border: '1px solid var(--panel-border)', color: 'var(--brand-light-gray)' }}
|
||||
placeholder={t('otpPlaceholder', language)}
|
||||
maxLength={6}
|
||||
required
|
||||
@@ -259,7 +314,7 @@ export function RegisterPage() {
|
||||
</div>
|
||||
|
||||
{error && (
|
||||
<div className="text-sm px-3 py-2 rounded" style={{ background: 'rgba(246, 70, 93, 0.1)', color: '#F6465D' }}>
|
||||
<div className="text-sm px-3 py-2 rounded" style={{ background: 'var(--binance-red-bg)', color: 'var(--binance-red)' }}>
|
||||
{error}
|
||||
</div>
|
||||
)}
|
||||
@@ -269,7 +324,7 @@ export function RegisterPage() {
|
||||
type="button"
|
||||
onClick={() => setStep('setup-otp')}
|
||||
className="flex-1 px-4 py-2 rounded text-sm font-semibold"
|
||||
style={{ background: '#2B3139', color: '#848E9C' }}
|
||||
style={{ background: 'var(--panel-bg-hover)', color: 'var(--text-secondary)' }}
|
||||
>
|
||||
{t('back', language)}
|
||||
</button>
|
||||
@@ -289,22 +344,23 @@ export function RegisterPage() {
|
||||
{/* Login Link */}
|
||||
{step === 'register' && (
|
||||
<div className="text-center mt-6">
|
||||
<p className="text-sm" style={{ color: '#848E9C' }}>
|
||||
<p className="text-sm" style={{ color: 'var(--text-secondary)' }}>
|
||||
已有账户?{' '}
|
||||
<button
|
||||
onClick={() => {
|
||||
window.history.pushState({}, '', '/login');
|
||||
window.dispatchEvent(new PopStateEvent('popstate'));
|
||||
}}
|
||||
className="font-semibold hover:underline"
|
||||
style={{ color: '#F0B90B' }}
|
||||
className="font-semibold hover:underline transition-colors"
|
||||
style={{ color: 'var(--brand-yellow)' }}
|
||||
>
|
||||
立即登录
|
||||
</button>
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -453,7 +453,7 @@ export function TraderConfigModal({
|
||||
className="w-4 h-4"
|
||||
/>
|
||||
<label className="text-sm text-[#EAECEF]">覆盖默认提示词</label>
|
||||
<span className="text-xs text-[#F0B90B]">⚠️ 启用后将完全替换默认策略</span>
|
||||
<span className="text-xs text-[#F0B90B] inline-flex items-center gap-1"><svg xmlns="http://www.w3.org/2000/svg" className="w-3.5 h-3.5" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0Z"/><line x1="12" x2="12" y1="9" y2="13"/><line x1="12" x2="12.01" y1="17" y2="17"/></svg> 启用后将完全替换默认策略</span>
|
||||
</div>
|
||||
<div>
|
||||
<label className="text-sm text-[#EAECEF] block mb-2">
|
||||
@@ -491,4 +491,4 @@ export function TraderConfigModal({
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
73
web/src/components/Typewriter.tsx
Normal file
73
web/src/components/Typewriter.tsx
Normal file
@@ -0,0 +1,73 @@
|
||||
import { useEffect, useMemo, useRef, useState } from 'react'
|
||||
|
||||
interface TypewriterProps {
|
||||
lines: string[]
|
||||
typingSpeed?: number // 毫秒/字符
|
||||
lineDelay?: number // 每行结束的额外等待
|
||||
className?: string
|
||||
style?: React.CSSProperties
|
||||
}
|
||||
|
||||
export default function Typewriter({
|
||||
lines,
|
||||
typingSpeed = 50,
|
||||
lineDelay = 600,
|
||||
className,
|
||||
style,
|
||||
}: TypewriterProps) {
|
||||
const [typedLines, setTypedLines] = useState<string[]>([''])
|
||||
const [showCursor, setShowCursor] = useState(true)
|
||||
const lineIndexRef = useRef(0)
|
||||
const charIndexRef = useRef(0)
|
||||
const timerRef = useRef<number | null>(null)
|
||||
const blinkRef = useRef<number | null>(null)
|
||||
const sanitizedLines = useMemo(() => lines.map((l) => String(l ?? '')), [lines])
|
||||
|
||||
useEffect(() => {
|
||||
function typeNext() {
|
||||
const currentLine = sanitizedLines[lineIndexRef.current] ?? ''
|
||||
if (charIndexRef.current < currentLine.length) {
|
||||
setTypedLines((prev) => {
|
||||
const next = [...prev]
|
||||
const ch = currentLine.charAt(charIndexRef.current)
|
||||
next[next.length - 1] = (next[next.length - 1] || '') + ch
|
||||
return next
|
||||
})
|
||||
charIndexRef.current += 1
|
||||
timerRef.current = window.setTimeout(typeNext, typingSpeed)
|
||||
} else {
|
||||
// 行结束
|
||||
if (lineIndexRef.current < sanitizedLines.length - 1) {
|
||||
lineIndexRef.current += 1
|
||||
charIndexRef.current = 0
|
||||
setTypedLines((prev) => [...prev, ''])
|
||||
timerRef.current = window.setTimeout(typeNext, lineDelay)
|
||||
} else {
|
||||
// 最后一行输入完毕
|
||||
timerRef.current = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
typeNext()
|
||||
|
||||
// 光标闪烁
|
||||
blinkRef.current = window.setInterval(() => {
|
||||
setShowCursor((v) => !v)
|
||||
}, 500)
|
||||
|
||||
return () => {
|
||||
if (timerRef.current) window.clearTimeout(timerRef.current)
|
||||
if (blinkRef.current) window.clearInterval(blinkRef.current)
|
||||
}
|
||||
}, [lines, typingSpeed, lineDelay])
|
||||
|
||||
const displayText = useMemo(() => typedLines.join('\n').replace(/undefined/g, ''), [typedLines])
|
||||
|
||||
return (
|
||||
<pre className={className} style={{ whiteSpace: 'pre-wrap', ...style }}>
|
||||
{displayText}
|
||||
<span style={{ opacity: showCursor ? 1 : 0 }}> ▍</span>
|
||||
</pre>
|
||||
)
|
||||
}
|
||||
124
web/src/components/landing/AboutSection.tsx
Normal file
124
web/src/components/landing/AboutSection.tsx
Normal file
@@ -0,0 +1,124 @@
|
||||
import { motion } from 'framer-motion'
|
||||
import { Shield, Target } from 'lucide-react'
|
||||
import AnimatedSection from './AnimatedSection'
|
||||
import Typewriter from '../Typewriter'
|
||||
import { t, Language } from '../../i18n/translations'
|
||||
|
||||
interface AboutSectionProps {
|
||||
language: Language
|
||||
}
|
||||
|
||||
export default function AboutSection({ language }: AboutSectionProps) {
|
||||
return (
|
||||
<AnimatedSection id='about' backgroundColor='var(--brand-dark-gray)'>
|
||||
<div className='max-w-7xl mx-auto'>
|
||||
<div className='grid lg:grid-cols-2 gap-12 items-center'>
|
||||
<motion.div
|
||||
className='space-y-6'
|
||||
initial={{ opacity: 0, x: -50 }}
|
||||
whileInView={{ opacity: 1, x: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.6 }}
|
||||
>
|
||||
<motion.div
|
||||
className='inline-flex items-center gap-2 px-4 py-2 rounded-full'
|
||||
style={{
|
||||
background: 'rgba(240, 185, 11, 0.1)',
|
||||
border: '1px solid rgba(240, 185, 11, 0.2)',
|
||||
}}
|
||||
whileHover={{ scale: 1.05 }}
|
||||
>
|
||||
<Target
|
||||
className='w-4 h-4'
|
||||
style={{ color: 'var(--brand-yellow)' }}
|
||||
/>
|
||||
<span
|
||||
className='text-sm font-semibold'
|
||||
style={{ color: 'var(--brand-yellow)' }}
|
||||
>
|
||||
{t('aboutNofx', language)}
|
||||
</span>
|
||||
</motion.div>
|
||||
|
||||
<h2
|
||||
className='text-4xl font-bold'
|
||||
style={{ color: 'var(--brand-light-gray)' }}
|
||||
>
|
||||
{t('whatIsNofx', language)}
|
||||
</h2>
|
||||
<p
|
||||
className='text-lg leading-relaxed'
|
||||
style={{ color: 'var(--text-secondary)' }}
|
||||
>
|
||||
{t('nofxNotAnotherBot', language)} {t('nofxDescription1', language)} {t('nofxDescription2', language)}
|
||||
</p>
|
||||
<p
|
||||
className='text-lg leading-relaxed'
|
||||
style={{ color: 'var(--text-secondary)' }}
|
||||
>
|
||||
{t('nofxDescription3', language)} {t('nofxDescription4', language)} {t('nofxDescription5', language)}
|
||||
</p>
|
||||
<motion.div
|
||||
className='flex items-center gap-3 pt-4'
|
||||
whileHover={{ x: 5 }}
|
||||
>
|
||||
<div
|
||||
className='w-12 h-12 rounded-full flex items-center justify-center'
|
||||
style={{ background: 'rgba(240, 185, 11, 0.1)' }}
|
||||
>
|
||||
<Shield
|
||||
className='w-6 h-6'
|
||||
style={{ color: 'var(--brand-yellow)' }}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
className='font-semibold'
|
||||
style={{ color: 'var(--brand-light-gray)' }}
|
||||
>
|
||||
{t('youFullControl', language)}
|
||||
</div>
|
||||
<div
|
||||
className='text-sm'
|
||||
style={{ color: 'var(--text-secondary)' }}
|
||||
>
|
||||
{t('fullControlDesc', language)}
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
|
||||
<div className='relative'>
|
||||
<div
|
||||
className='rounded-2xl p-8'
|
||||
style={{
|
||||
background: 'var(--brand-black)',
|
||||
border: '1px solid var(--panel-border)',
|
||||
}}
|
||||
>
|
||||
<Typewriter
|
||||
lines={[
|
||||
'$ git clone https://github.com/tinkle-community/nofx.git',
|
||||
'$ cd nofx',
|
||||
'$ chmod +x start.sh',
|
||||
'$ ./start.sh start --build',
|
||||
t('startupMessages1', language),
|
||||
t('startupMessages2', language),
|
||||
t('startupMessages3', language),
|
||||
]}
|
||||
typingSpeed={70}
|
||||
lineDelay={900}
|
||||
className='text-sm font-mono'
|
||||
style={{
|
||||
color: '#00FF88',
|
||||
textShadow: '0 0 8px rgba(0,255,136,0.4)',
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</AnimatedSection>
|
||||
)
|
||||
}
|
||||
|
||||
30
web/src/components/landing/AnimatedSection.tsx
Normal file
30
web/src/components/landing/AnimatedSection.tsx
Normal file
@@ -0,0 +1,30 @@
|
||||
import { useRef } from 'react'
|
||||
import { motion, useInView } from 'framer-motion'
|
||||
|
||||
export default function AnimatedSection({
|
||||
children,
|
||||
id,
|
||||
backgroundColor = 'var(--brand-black)',
|
||||
}: {
|
||||
children: React.ReactNode
|
||||
id?: string
|
||||
backgroundColor?: string
|
||||
}) {
|
||||
const ref = useRef(null)
|
||||
const isInView = useInView(ref, { once: true, margin: '-100px' })
|
||||
|
||||
return (
|
||||
<motion.section
|
||||
id={id}
|
||||
ref={ref}
|
||||
className='py-20 px-4'
|
||||
style={{ background: backgroundColor }}
|
||||
initial={{ opacity: 0 }}
|
||||
animate={isInView ? { opacity: 1 } : { opacity: 0 }}
|
||||
transition={{ duration: 0.6 }}
|
||||
>
|
||||
{children}
|
||||
</motion.section>
|
||||
)
|
||||
}
|
||||
|
||||
42
web/src/components/landing/CommunitySection.tsx
Normal file
42
web/src/components/landing/CommunitySection.tsx
Normal file
@@ -0,0 +1,42 @@
|
||||
import { motion } from 'framer-motion'
|
||||
import AnimatedSection from './AnimatedSection'
|
||||
|
||||
function TestimonialCard({ quote, author, delay }: any) {
|
||||
return (
|
||||
<motion.div
|
||||
className='p-6 rounded-xl'
|
||||
style={{ background: 'var(--brand-dark-gray)', border: '1px solid rgba(240, 185, 11, 0.1)' }}
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ delay }}
|
||||
whileHover={{ scale: 1.05 }}
|
||||
>
|
||||
<p className='text-lg mb-4' style={{ color: 'var(--brand-light-gray)' }}>
|
||||
"{quote}"
|
||||
</p>
|
||||
<div className='flex items-center gap-2'>
|
||||
<div className='w-8 h-8 rounded-full' style={{ background: 'var(--binance-yellow)' }} />
|
||||
<span className='text-sm font-semibold' style={{ color: 'var(--text-secondary)' }}>
|
||||
{author}
|
||||
</span>
|
||||
</div>
|
||||
</motion.div>
|
||||
)
|
||||
}
|
||||
|
||||
export default function CommunitySection() {
|
||||
const staggerContainer = { animate: { transition: { staggerChildren: 0.1 } } }
|
||||
return (
|
||||
<AnimatedSection>
|
||||
<div className='max-w-7xl mx-auto'>
|
||||
<motion.div className='grid md:grid-cols-3 gap-6' variants={staggerContainer} initial='initial' whileInView='animate' viewport={{ once: true }}>
|
||||
<TestimonialCard quote='跑了一晚上 NOFX,开源的 AI 自动交易,太有意思了,一晚上赚了 6% 收益!' author='@DIYgod' delay={0} />
|
||||
<TestimonialCard quote='所有成功人士都在用 NOFX。IYKYK。' author='@SexyMichill' delay={0.1} />
|
||||
<TestimonialCard quote='NOFX 复兴了传奇 Alpha Arena,AI 驱动的加密期货战场。' author='@hqmank' delay={0.2} />
|
||||
</motion.div>
|
||||
</div>
|
||||
</AnimatedSection>
|
||||
)
|
||||
}
|
||||
|
||||
76
web/src/components/landing/FeaturesSection.tsx
Normal file
76
web/src/components/landing/FeaturesSection.tsx
Normal file
@@ -0,0 +1,76 @@
|
||||
import { motion } from 'framer-motion'
|
||||
import AnimatedSection from './AnimatedSection'
|
||||
import { CryptoFeatureCard } from '../CryptoFeatureCard'
|
||||
import { Code, Cpu, Lock, Rocket } from 'lucide-react'
|
||||
import { t, Language } from '../../i18n/translations'
|
||||
|
||||
interface FeaturesSectionProps {
|
||||
language: Language
|
||||
}
|
||||
|
||||
export default function FeaturesSection({ language }: FeaturesSectionProps) {
|
||||
return (
|
||||
<AnimatedSection id='features'>
|
||||
<div className='max-w-7xl mx-auto'>
|
||||
<motion.div className='text-center mb-16' initial={{ opacity: 0, y: 30 }} whileInView={{ opacity: 1, y: 0 }} viewport={{ once: true }}>
|
||||
<motion.div
|
||||
className='inline-flex items-center gap-2 px-4 py-2 rounded-full mb-6'
|
||||
style={{ background: 'rgba(240, 185, 11, 0.1)', border: '1px solid rgba(240, 185, 11, 0.2)' }}
|
||||
whileHover={{ scale: 1.05 }}
|
||||
>
|
||||
<Rocket className='w-4 h-4' style={{ color: 'var(--brand-yellow)' }} />
|
||||
<span className='text-sm font-semibold' style={{ color: 'var(--brand-yellow)' }}>
|
||||
{t('coreFeatures', language)}
|
||||
</span>
|
||||
</motion.div>
|
||||
<h2 className='text-4xl font-bold mb-4' style={{ color: 'var(--brand-light-gray)' }}>
|
||||
{t('whyChooseNofx', language)}
|
||||
</h2>
|
||||
<p className='text-lg' style={{ color: 'var(--text-secondary)' }}>
|
||||
{t('openCommunityDriven', language)}
|
||||
</p>
|
||||
</motion.div>
|
||||
|
||||
<div className='grid md:grid-cols-2 lg:grid-cols-3 gap-8 max-w-7xl mx-auto'>
|
||||
<CryptoFeatureCard
|
||||
icon={<Code className='w-8 h-8' />}
|
||||
title={t('openSourceSelfHosted', language)}
|
||||
description={t('openSourceDesc', language)}
|
||||
features={[
|
||||
t('openSourceFeatures1', language),
|
||||
t('openSourceFeatures2', language),
|
||||
t('openSourceFeatures3', language),
|
||||
t('openSourceFeatures4', language)
|
||||
]}
|
||||
delay={0}
|
||||
/>
|
||||
<CryptoFeatureCard
|
||||
icon={<Cpu className='w-8 h-8' />}
|
||||
title={t('multiAgentCompetition', language)}
|
||||
description={t('multiAgentDesc', language)}
|
||||
features={[
|
||||
t('multiAgentFeatures1', language),
|
||||
t('multiAgentFeatures2', language),
|
||||
t('multiAgentFeatures3', language),
|
||||
t('multiAgentFeatures4', language)
|
||||
]}
|
||||
delay={0.1}
|
||||
/>
|
||||
<CryptoFeatureCard
|
||||
icon={<Lock className='w-8 h-8' />}
|
||||
title={t('secureReliableTrading', language)}
|
||||
description={t('secureDesc', language)}
|
||||
features={[
|
||||
t('secureFeatures1', language),
|
||||
t('secureFeatures2', language),
|
||||
t('secureFeatures3', language),
|
||||
t('secureFeatures4', language)
|
||||
]}
|
||||
delay={0.2}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</AnimatedSection>
|
||||
)
|
||||
}
|
||||
|
||||
171
web/src/components/landing/FooterSection.tsx
Normal file
171
web/src/components/landing/FooterSection.tsx
Normal file
@@ -0,0 +1,171 @@
|
||||
import { t, Language } from '../../i18n/translations'
|
||||
|
||||
interface FooterSectionProps {
|
||||
language: Language
|
||||
}
|
||||
|
||||
export default function FooterSection({ language }: FooterSectionProps) {
|
||||
return (
|
||||
<footer style={{ borderTop: '1px solid var(--panel-border)', background: 'var(--brand-dark-gray)' }}>
|
||||
<div className='max-w-[1200px] mx-auto px-6 py-10'>
|
||||
{/* Brand */}
|
||||
<div className='flex items-center gap-3 mb-8'>
|
||||
<img src='/icons/nofx.svg' alt='NOFX Logo' className='w-8 h-8' />
|
||||
<div>
|
||||
<div className='text-lg font-bold' style={{ color: '#EAECEF' }}>
|
||||
NOFX
|
||||
</div>
|
||||
<div className='text-xs' style={{ color: '#848E9C' }}>
|
||||
{t('futureStandardAI', language)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Multi-link columns */}
|
||||
<div className='grid grid-cols-2 sm:grid-cols-3 md:grid-cols-3 gap-8'>
|
||||
<div>
|
||||
<h3
|
||||
className='text-sm font-semibold mb-3'
|
||||
style={{ color: '#EAECEF' }}
|
||||
>
|
||||
{t('links', language)}
|
||||
</h3>
|
||||
<ul className='space-y-2 text-sm' style={{ color: '#848E9C' }}>
|
||||
<li>
|
||||
<a
|
||||
className='hover:text-[#F0B90B]'
|
||||
href='https://github.com/tinkle-community/nofx'
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
>
|
||||
GitHub
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
className='hover:text-[#F0B90B]'
|
||||
href='https://t.me/nofx_dev_community'
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
>
|
||||
Telegram
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
className='hover:text-[#F0B90B]'
|
||||
href='https://x.com/nofx_ai'
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
>
|
||||
X (Twitter)
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3
|
||||
className='text-sm font-semibold mb-3'
|
||||
style={{ color: '#EAECEF' }}
|
||||
>
|
||||
{t('resources', language)}
|
||||
</h3>
|
||||
<ul className='space-y-2 text-sm' style={{ color: '#848E9C' }}>
|
||||
<li>
|
||||
<a
|
||||
className='hover:text-[#F0B90B]'
|
||||
href='https://github.com/tinkle-community/nofx/blob/main/README.md'
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
>
|
||||
{t('documentation', language)}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
className='hover:text-[#F0B90B]'
|
||||
href='https://github.com/tinkle-community/nofx/issues'
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
>
|
||||
Issues
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
className='hover:text-[#F0B90B]'
|
||||
href='https://github.com/tinkle-community/nofx/pulls'
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
>
|
||||
Pull Requests
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3
|
||||
className='text-sm font-semibold mb-3'
|
||||
style={{ color: '#EAECEF' }}
|
||||
>
|
||||
{t('supporters', language)}
|
||||
</h3>
|
||||
<ul className='space-y-2 text-sm' style={{ color: '#848E9C' }}>
|
||||
<li>
|
||||
<a
|
||||
className='hover:text-[#F0B90B]'
|
||||
href='https://asterdex.com/'
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
>
|
||||
Aster DEX
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
className='hover:text-[#F0B90B]'
|
||||
href='https://www.binance.com/'
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
>
|
||||
Binance
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
className='hover:text-[#F0B90B]'
|
||||
href='https://hyperliquid.xyz/'
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
>
|
||||
Hyperliquid
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
className='hover:text-[#F0B90B]'
|
||||
href='https://amber.ac/'
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
>
|
||||
Amber.ac <span className='opacity-70'>{t('strategicInvestment', language)}</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Bottom note (kept subtle) */}
|
||||
<div
|
||||
className='pt-6 mt-8 text-center text-xs'
|
||||
style={{ color: 'var(--text-tertiary)', borderTop: '1px solid var(--panel-border)' }}
|
||||
>
|
||||
<p>{t('footerTitle', language)}</p>
|
||||
<p className='mt-1'>{t('footerWarning', language)}</p>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
)
|
||||
}
|
||||
615
web/src/components/landing/HeaderBar.tsx
Normal file
615
web/src/components/landing/HeaderBar.tsx
Normal file
@@ -0,0 +1,615 @@
|
||||
import { useState, useEffect, useRef } from 'react'
|
||||
import { motion } from 'framer-motion'
|
||||
import { Menu, X, ChevronDown } from 'lucide-react'
|
||||
import { t, type Language } from '../../i18n/translations'
|
||||
|
||||
interface HeaderBarProps {
|
||||
onLoginClick?: () => void
|
||||
isLoggedIn?: boolean
|
||||
isHomePage?: boolean
|
||||
currentPage?: string
|
||||
language?: Language
|
||||
onLanguageChange?: (lang: Language) => void
|
||||
user?: { email: string } | null
|
||||
onLogout?: () => void
|
||||
isAdminMode?: boolean
|
||||
onPageChange?: (page: string) => void
|
||||
}
|
||||
|
||||
export default function HeaderBar({ isLoggedIn = false, isHomePage = false, currentPage, language = 'zh' as Language, onLanguageChange, user, onLogout, isAdminMode = false, onPageChange }: HeaderBarProps) {
|
||||
const [mobileMenuOpen, setMobileMenuOpen] = useState(false)
|
||||
const [languageDropdownOpen, setLanguageDropdownOpen] = useState(false)
|
||||
const [userDropdownOpen, setUserDropdownOpen] = useState(false)
|
||||
const dropdownRef = useRef<HTMLDivElement>(null)
|
||||
const userDropdownRef = useRef<HTMLDivElement>(null)
|
||||
|
||||
// Close dropdown when clicking outside
|
||||
useEffect(() => {
|
||||
function handleClickOutside(event: MouseEvent) {
|
||||
if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) {
|
||||
setLanguageDropdownOpen(false)
|
||||
}
|
||||
if (userDropdownRef.current && !userDropdownRef.current.contains(event.target as Node)) {
|
||||
setUserDropdownOpen(false)
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener('mousedown', handleClickOutside)
|
||||
return () => {
|
||||
document.removeEventListener('mousedown', handleClickOutside)
|
||||
}
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<nav className='fixed top-0 w-full z-50 header-bar'>
|
||||
<div className='max-w-7xl mx-auto px-4 sm:px-6 lg:px-8'>
|
||||
<div className='flex items-center justify-between h-16'>
|
||||
{/* Logo */}
|
||||
<a href='/' className='flex items-center gap-3 hover:opacity-80 transition-opacity cursor-pointer'>
|
||||
<img src='/icons/nofx.svg' alt='NOFX Logo' className='w-8 h-8' />
|
||||
<span className='text-xl font-bold' style={{ color: 'var(--brand-yellow)' }}>
|
||||
NOFX
|
||||
</span>
|
||||
<span className='text-sm hidden sm:block' style={{ color: 'var(--text-secondary)' }}>
|
||||
Agentic Trading OS
|
||||
</span>
|
||||
</a>
|
||||
|
||||
{/* Desktop Menu */}
|
||||
<div className='hidden md:flex items-center justify-between flex-1 ml-8'>
|
||||
{/* Left Side - Navigation Tabs */}
|
||||
<div className='flex items-center gap-4'>
|
||||
{isLoggedIn ? (
|
||||
// Main app navigation when logged in
|
||||
<>
|
||||
<button
|
||||
onClick={() => {
|
||||
console.log('实时 button clicked, onPageChange:', onPageChange);
|
||||
onPageChange?.('competition');
|
||||
}}
|
||||
className='text-sm font-bold transition-all duration-300 relative focus:outline-2 focus:outline-yellow-500'
|
||||
style={{
|
||||
color: currentPage === 'competition' ? 'var(--brand-yellow)' : 'var(--brand-light-gray)',
|
||||
padding: '8px 16px',
|
||||
borderRadius: '8px',
|
||||
position: 'relative'
|
||||
}}
|
||||
onMouseEnter={(e) => {
|
||||
if (currentPage !== 'competition') {
|
||||
e.currentTarget.style.color = 'var(--brand-yellow)';
|
||||
}
|
||||
}}
|
||||
onMouseLeave={(e) => {
|
||||
if (currentPage !== 'competition') {
|
||||
e.currentTarget.style.color = 'var(--brand-light-gray)';
|
||||
}
|
||||
}}
|
||||
>
|
||||
{/* Background for selected state */}
|
||||
{currentPage === 'competition' && (
|
||||
<span
|
||||
className="absolute inset-0 rounded-lg"
|
||||
style={{
|
||||
background: 'rgba(240, 185, 11, 0.15)',
|
||||
zIndex: -1
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
{t('realtimeNav', language)}
|
||||
</button>
|
||||
|
||||
<button
|
||||
onClick={() => {
|
||||
console.log('配置 button clicked, onPageChange:', onPageChange);
|
||||
onPageChange?.('traders');
|
||||
}}
|
||||
className='text-sm font-bold transition-all duration-300 relative focus:outline-2 focus:outline-yellow-500'
|
||||
style={{
|
||||
color: currentPage === 'traders' ? 'var(--brand-yellow)' : 'var(--brand-light-gray)',
|
||||
padding: '8px 16px',
|
||||
borderRadius: '8px',
|
||||
position: 'relative'
|
||||
}}
|
||||
onMouseEnter={(e) => {
|
||||
if (currentPage !== 'traders') {
|
||||
e.currentTarget.style.color = 'var(--brand-yellow)';
|
||||
}
|
||||
}}
|
||||
onMouseLeave={(e) => {
|
||||
if (currentPage !== 'traders') {
|
||||
e.currentTarget.style.color = 'var(--brand-light-gray)';
|
||||
}
|
||||
}}
|
||||
>
|
||||
{/* Background for selected state */}
|
||||
{currentPage === 'traders' && (
|
||||
<span
|
||||
className="absolute inset-0 rounded-lg"
|
||||
style={{
|
||||
background: 'rgba(240, 185, 11, 0.15)',
|
||||
zIndex: -1
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
{t('configNav', language)}
|
||||
</button>
|
||||
|
||||
<button
|
||||
onClick={() => {
|
||||
console.log('看板 button clicked, onPageChange:', onPageChange);
|
||||
onPageChange?.('trader');
|
||||
}}
|
||||
className='text-sm font-bold transition-all duration-300 relative focus:outline-2 focus:outline-yellow-500'
|
||||
style={{
|
||||
color: currentPage === 'trader' ? 'var(--brand-yellow)' : 'var(--brand-light-gray)',
|
||||
padding: '8px 16px',
|
||||
borderRadius: '8px',
|
||||
position: 'relative'
|
||||
}}
|
||||
onMouseEnter={(e) => {
|
||||
if (currentPage !== 'trader') {
|
||||
e.currentTarget.style.color = 'var(--brand-yellow)';
|
||||
}
|
||||
}}
|
||||
onMouseLeave={(e) => {
|
||||
if (currentPage !== 'trader') {
|
||||
e.currentTarget.style.color = 'var(--brand-light-gray)';
|
||||
}
|
||||
}}
|
||||
>
|
||||
{/* Background for selected state */}
|
||||
{currentPage === 'trader' && (
|
||||
<span
|
||||
className="absolute inset-0 rounded-lg"
|
||||
style={{
|
||||
background: 'rgba(240, 185, 11, 0.15)',
|
||||
zIndex: -1
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
{t('dashboardNav', language)}
|
||||
</button>
|
||||
</>
|
||||
) : (
|
||||
// Landing page navigation when not logged in
|
||||
<a
|
||||
href='/competition'
|
||||
className='text-sm font-bold transition-all duration-300 relative focus:outline-2 focus:outline-yellow-500'
|
||||
style={{
|
||||
color: currentPage === 'competition' ? 'var(--brand-yellow)' : 'var(--brand-light-gray)',
|
||||
padding: '8px 16px',
|
||||
borderRadius: '8px',
|
||||
position: 'relative'
|
||||
}}
|
||||
onMouseEnter={(e) => {
|
||||
if (currentPage !== 'competition') {
|
||||
e.currentTarget.style.color = 'var(--brand-yellow)';
|
||||
}
|
||||
}}
|
||||
onMouseLeave={(e) => {
|
||||
if (currentPage !== 'competition') {
|
||||
e.currentTarget.style.color = 'var(--brand-light-gray)';
|
||||
}
|
||||
}}
|
||||
>
|
||||
{/* Background for selected state */}
|
||||
{currentPage === 'competition' && (
|
||||
<span
|
||||
className="absolute inset-0 rounded-lg"
|
||||
style={{
|
||||
background: 'rgba(240, 185, 11, 0.15)',
|
||||
zIndex: -1
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
{t('realtimeNav', language)}
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Right Side - Original Navigation Items and Login */}
|
||||
<div className='flex items-center gap-6'>
|
||||
{/* Only show original navigation items on home page */}
|
||||
{isHomePage && [
|
||||
{ key: 'features', label: t('features', language) },
|
||||
{ key: 'howItWorks', label: t('howItWorks', language) },
|
||||
{ key: 'GitHub', label: 'GitHub' },
|
||||
{ key: 'community', label: t('community', language) }
|
||||
].map((item) => (
|
||||
<a
|
||||
key={item.key}
|
||||
href={
|
||||
item.key === 'GitHub'
|
||||
? 'https://github.com/tinkle-community/nofx'
|
||||
: item.key === 'community'
|
||||
? 'https://t.me/nofx_dev_community'
|
||||
: `#${item.key === 'features' ? 'features' : 'how-it-works'}`
|
||||
}
|
||||
target={item.key === 'GitHub' || item.key === 'community' ? '_blank' : undefined}
|
||||
rel={item.key === 'GitHub' || item.key === 'community' ? 'noopener noreferrer' : undefined}
|
||||
className='text-sm transition-colors relative group'
|
||||
style={{ color: 'var(--brand-light-gray)' }}
|
||||
>
|
||||
{item.label}
|
||||
<span
|
||||
className='absolute -bottom-1 left-0 w-0 h-0.5 group-hover:w-full transition-all duration-300'
|
||||
style={{ background: 'var(--brand-yellow)' }}
|
||||
/>
|
||||
</a>
|
||||
))}
|
||||
|
||||
{/* User Info and Actions */}
|
||||
{isLoggedIn && user ? (
|
||||
<div className='flex items-center gap-3'>
|
||||
{/* User Info with Dropdown */}
|
||||
<div className='relative' ref={userDropdownRef}>
|
||||
<button
|
||||
onClick={() => setUserDropdownOpen(!userDropdownOpen)}
|
||||
className='flex items-center gap-2 px-3 py-2 rounded transition-colors'
|
||||
style={{ background: 'var(--panel-bg)', border: '1px solid var(--panel-border)' }}
|
||||
onMouseEnter={(e) => e.currentTarget.style.background = 'rgba(255, 255, 255, 0.05)'}
|
||||
onMouseLeave={(e) => e.currentTarget.style.background = 'var(--panel-bg)'}
|
||||
>
|
||||
<div className='w-6 h-6 rounded-full flex items-center justify-center text-xs font-bold' style={{ background: 'var(--brand-yellow)', color: 'var(--brand-black)' }}>
|
||||
{user.email[0].toUpperCase()}
|
||||
</div>
|
||||
<span className='text-sm' style={{ color: 'var(--brand-light-gray)' }}>{user.email}</span>
|
||||
<ChevronDown className='w-4 h-4' style={{ color: 'var(--brand-light-gray)' }} />
|
||||
</button>
|
||||
|
||||
{userDropdownOpen && (
|
||||
<div className='absolute right-0 top-full mt-2 w-48 rounded-lg shadow-lg overflow-hidden z-50' style={{ background: 'var(--brand-dark-gray)', border: '1px solid var(--panel-border)' }}>
|
||||
<div className='px-3 py-2 border-b' style={{ borderColor: 'var(--panel-border)' }}>
|
||||
<div className='text-xs' style={{ color: 'var(--text-secondary)' }}>{t('loggedInAs', language)}</div>
|
||||
<div className='text-sm font-medium' style={{ color: 'var(--brand-light-gray)' }}>{user.email}</div>
|
||||
</div>
|
||||
{!isAdminMode && onLogout && (
|
||||
<button
|
||||
onClick={() => {
|
||||
onLogout()
|
||||
setUserDropdownOpen(false)
|
||||
}}
|
||||
className='w-full px-3 py-2 text-sm font-semibold transition-colors hover:opacity-80 text-center'
|
||||
style={{ background: 'var(--binance-red-bg)', color: 'var(--binance-red)' }}
|
||||
>
|
||||
{t('exitLogin', language)}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
/* Show login/register buttons when not logged in and not on login/register pages */
|
||||
currentPage !== 'login' && currentPage !== 'register' && (
|
||||
<div className='flex items-center gap-3'>
|
||||
<a
|
||||
href='/login'
|
||||
className='px-3 py-2 text-sm font-medium transition-colors rounded'
|
||||
style={{ color: 'var(--brand-light-gray)' }}
|
||||
>
|
||||
{t('signIn', language)}
|
||||
</a>
|
||||
<a
|
||||
href='/register'
|
||||
className='px-4 py-2 rounded font-semibold text-sm transition-colors hover:opacity-90'
|
||||
style={{ background: 'var(--brand-yellow)', color: 'var(--brand-black)' }}
|
||||
>
|
||||
{t('signUp', language)}
|
||||
</a>
|
||||
</div>
|
||||
)
|
||||
)}
|
||||
|
||||
{/* Language Toggle - Always at the rightmost */}
|
||||
<div className='relative' ref={dropdownRef}>
|
||||
<button
|
||||
onClick={() => setLanguageDropdownOpen(!languageDropdownOpen)}
|
||||
className='flex items-center gap-2 px-3 py-2 rounded transition-colors'
|
||||
style={{ color: 'var(--brand-light-gray)' }}
|
||||
onMouseEnter={(e) => e.currentTarget.style.background = 'rgba(255, 255, 255, 0.05)'}
|
||||
onMouseLeave={(e) => e.currentTarget.style.background = 'transparent'}
|
||||
>
|
||||
<span className='text-lg'>
|
||||
{language === 'zh' ? '🇨🇳' : '🇺🇸'}
|
||||
</span>
|
||||
<ChevronDown className='w-4 h-4' />
|
||||
</button>
|
||||
|
||||
{languageDropdownOpen && (
|
||||
<div className='absolute right-0 top-full mt-2 w-32 rounded-lg shadow-lg overflow-hidden z-50' style={{ background: 'var(--brand-dark-gray)', border: '1px solid var(--panel-border)' }}>
|
||||
<button
|
||||
onClick={() => {
|
||||
onLanguageChange?.('zh')
|
||||
setLanguageDropdownOpen(false)
|
||||
}}
|
||||
className={`w-full flex items-center gap-2 px-3 py-2 transition-colors ${
|
||||
language === 'zh' ? '' : 'hover:opacity-80'
|
||||
}`}
|
||||
style={{
|
||||
color: 'var(--brand-light-gray)',
|
||||
background: language === 'zh' ? 'rgba(240, 185, 11, 0.1)' : 'transparent'
|
||||
}}
|
||||
>
|
||||
<span className='text-base'>🇨🇳</span>
|
||||
<span className='text-sm'>中文</span>
|
||||
</button>
|
||||
<button
|
||||
onClick={() => {
|
||||
onLanguageChange?.('en')
|
||||
setLanguageDropdownOpen(false)
|
||||
}}
|
||||
className={`w-full flex items-center gap-2 px-3 py-2 transition-colors ${
|
||||
language === 'en' ? '' : 'hover:opacity-80'
|
||||
}`}
|
||||
style={{
|
||||
color: 'var(--brand-light-gray)',
|
||||
background: language === 'en' ? 'rgba(240, 185, 11, 0.1)' : 'transparent'
|
||||
}}
|
||||
>
|
||||
<span className='text-base'>🇺🇸</span>
|
||||
<span className='text-sm'>English</span>
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Mobile Menu Button */}
|
||||
<motion.button
|
||||
onClick={() => setMobileMenuOpen(!mobileMenuOpen)}
|
||||
className='md:hidden'
|
||||
style={{ color: 'var(--brand-light-gray)' }}
|
||||
whileTap={{ scale: 0.9 }}
|
||||
>
|
||||
{mobileMenuOpen ? <X className='w-6 h-6' /> : <Menu className='w-6 h-6' />}
|
||||
</motion.button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Mobile Menu */}
|
||||
<motion.div
|
||||
initial={false}
|
||||
animate={mobileMenuOpen ? { height: 'auto', opacity: 1 } : { height: 0, opacity: 0 }}
|
||||
transition={{ duration: 0.3 }}
|
||||
className='md:hidden overflow-hidden'
|
||||
style={{ background: 'var(--brand-dark-gray)', borderTop: '1px solid rgba(240, 185, 11, 0.1)' }}
|
||||
>
|
||||
<div className='px-4 py-4 space-y-3'>
|
||||
{/* New Navigation Tabs */}
|
||||
{isLoggedIn ? (
|
||||
<button
|
||||
onClick={() => {
|
||||
console.log('移动端 实时 button clicked, onPageChange:', onPageChange);
|
||||
onPageChange?.('competition')
|
||||
setMobileMenuOpen(false)
|
||||
}}
|
||||
className='block text-sm font-bold transition-all duration-300 relative focus:outline-2 focus:outline-yellow-500'
|
||||
style={{
|
||||
color: currentPage === 'competition' ? 'var(--brand-yellow)' : 'var(--brand-light-gray)',
|
||||
padding: '12px 16px',
|
||||
borderRadius: '8px',
|
||||
position: 'relative',
|
||||
width: '100%',
|
||||
textAlign: 'left'
|
||||
}}
|
||||
>
|
||||
{/* Background for selected state */}
|
||||
{currentPage === 'competition' && (
|
||||
<span
|
||||
className="absolute inset-0 rounded-lg"
|
||||
style={{
|
||||
background: 'rgba(240, 185, 11, 0.15)',
|
||||
zIndex: -1
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
{t('realtimeNav', language)}
|
||||
</button>
|
||||
) : (
|
||||
<a
|
||||
href='/competition'
|
||||
className='block text-sm font-bold transition-all duration-300 relative focus:outline-2 focus:outline-yellow-500'
|
||||
style={{
|
||||
color: currentPage === 'competition' ? 'var(--brand-yellow)' : 'var(--brand-light-gray)',
|
||||
padding: '12px 16px',
|
||||
borderRadius: '8px',
|
||||
position: 'relative'
|
||||
}}
|
||||
>
|
||||
{/* Background for selected state */}
|
||||
{currentPage === 'competition' && (
|
||||
<span
|
||||
className="absolute inset-0 rounded-lg"
|
||||
style={{
|
||||
background: 'rgba(240, 185, 11, 0.15)',
|
||||
zIndex: -1
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
{t('realtimeNav', language)}
|
||||
</a>
|
||||
)}
|
||||
{/* Only show 配置 and 看板 when logged in */}
|
||||
{isLoggedIn && (
|
||||
<>
|
||||
<button
|
||||
onClick={() => {
|
||||
console.log('移动端 配置 button clicked, onPageChange:', onPageChange);
|
||||
onPageChange?.('traders')
|
||||
setMobileMenuOpen(false)
|
||||
}}
|
||||
className='block text-sm font-bold transition-all duration-300 relative focus:outline-2 focus:outline-yellow-500 hover:text-yellow-500'
|
||||
style={{
|
||||
color: currentPage === 'traders' ? 'var(--brand-yellow)' : 'var(--brand-light-gray)',
|
||||
padding: '12px 16px',
|
||||
borderRadius: '8px',
|
||||
position: 'relative',
|
||||
width: '100%',
|
||||
textAlign: 'left'
|
||||
}}
|
||||
>
|
||||
{/* Background for selected state */}
|
||||
{currentPage === 'traders' && (
|
||||
<span
|
||||
className="absolute inset-0 rounded-lg"
|
||||
style={{
|
||||
background: 'rgba(240, 185, 11, 0.15)',
|
||||
zIndex: -1
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
{t('configNav', language)}
|
||||
</button>
|
||||
<button
|
||||
onClick={() => {
|
||||
console.log('移动端 看板 button clicked, onPageChange:', onPageChange);
|
||||
onPageChange?.('trader')
|
||||
setMobileMenuOpen(false)
|
||||
}}
|
||||
className='block text-sm font-bold transition-all duration-300 relative focus:outline-2 focus:outline-yellow-500 hover:text-yellow-500'
|
||||
style={{
|
||||
color: currentPage === 'trader' ? 'var(--brand-yellow)' : 'var(--brand-light-gray)',
|
||||
padding: '12px 16px',
|
||||
borderRadius: '8px',
|
||||
position: 'relative',
|
||||
width: '100%',
|
||||
textAlign: 'left'
|
||||
}}
|
||||
>
|
||||
{/* Background for selected state */}
|
||||
{currentPage === 'trader' && (
|
||||
<span
|
||||
className="absolute inset-0 rounded-lg"
|
||||
style={{
|
||||
background: 'rgba(240, 185, 11, 0.15)',
|
||||
zIndex: -1
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
{t('dashboardNav', language)}
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* Original Navigation Items - Only on home page */}
|
||||
{isHomePage && [
|
||||
{ key: 'features', label: t('features', language) },
|
||||
{ key: 'howItWorks', label: t('howItWorks', language) },
|
||||
{ key: 'GitHub', label: 'GitHub' },
|
||||
{ key: 'community', label: t('community', language) }
|
||||
].map((item) => (
|
||||
<a
|
||||
key={item.key}
|
||||
href={
|
||||
item.key === 'GitHub'
|
||||
? 'https://github.com/tinkle-community/nofx'
|
||||
: item.key === 'community'
|
||||
? 'https://t.me/nofx_dev_community'
|
||||
: `#${item.key === 'features' ? 'features' : 'how-it-works'}`
|
||||
}
|
||||
target={item.key === 'GitHub' || item.key === 'community' ? '_blank' : undefined}
|
||||
rel={item.key === 'GitHub' || item.key === 'community' ? 'noopener noreferrer' : undefined}
|
||||
className='block text-sm py-2'
|
||||
style={{ color: 'var(--brand-light-gray)' }}
|
||||
>
|
||||
{item.label}
|
||||
</a>
|
||||
))}
|
||||
|
||||
{/* Language Toggle */}
|
||||
<div className='py-2'>
|
||||
<div className='flex items-center gap-2 mb-2'>
|
||||
<span className='text-xs' style={{ color: 'var(--brand-light-gray)' }}>{t('language', language)}:</span>
|
||||
</div>
|
||||
<div className='space-y-1'>
|
||||
<button
|
||||
onClick={() => {
|
||||
onLanguageChange?.('zh')
|
||||
setMobileMenuOpen(false)
|
||||
}}
|
||||
className={`w-full flex items-center gap-3 px-3 py-2 rounded transition-colors ${
|
||||
language === 'zh' ? 'bg-yellow-500 text-black' : 'text-gray-400 hover:text-white'
|
||||
}`}
|
||||
>
|
||||
<span className='text-lg'>🇨🇳</span>
|
||||
<span className='text-sm'>中文</span>
|
||||
</button>
|
||||
<button
|
||||
onClick={() => {
|
||||
onLanguageChange?.('en')
|
||||
setMobileMenuOpen(false)
|
||||
}}
|
||||
className={`w-full flex items-center gap-3 px-3 py-2 rounded transition-colors ${
|
||||
language === 'en' ? 'bg-yellow-500 text-black' : 'text-gray-400 hover:text-white'
|
||||
}`}
|
||||
>
|
||||
<span className='text-lg'>🇺🇸</span>
|
||||
<span className='text-sm'>English</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* User info and logout for mobile when logged in */}
|
||||
{isLoggedIn && user && (
|
||||
<div className='mt-4 pt-4' style={{ borderTop: '1px solid var(--panel-border)' }}>
|
||||
<div className='flex items-center gap-2 px-3 py-2 mb-2 rounded' style={{ background: 'var(--panel-bg)' }}>
|
||||
<div className='w-6 h-6 rounded-full flex items-center justify-center text-xs font-bold' style={{ background: 'var(--brand-yellow)', color: 'var(--brand-black)' }}>
|
||||
{user.email[0].toUpperCase()}
|
||||
</div>
|
||||
<div>
|
||||
<div className='text-xs' style={{ color: 'var(--text-secondary)' }}>{t('loggedInAs', language)}</div>
|
||||
<div className='text-sm' style={{ color: 'var(--brand-light-gray)' }}>{user.email}</div>
|
||||
</div>
|
||||
</div>
|
||||
{!isAdminMode && onLogout && (
|
||||
<button
|
||||
onClick={() => {
|
||||
onLogout()
|
||||
setMobileMenuOpen(false)
|
||||
}}
|
||||
className='w-full px-4 py-2 rounded text-sm font-semibold transition-colors text-center'
|
||||
style={{ background: 'var(--binance-red-bg)', color: 'var(--binance-red)' }}
|
||||
>
|
||||
{t('exitLogin', language)}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Show login/register buttons when not logged in and not on login/register pages */}
|
||||
{!isLoggedIn && currentPage !== 'login' && currentPage !== 'register' && (
|
||||
<div className='space-y-2 mt-2'>
|
||||
<a
|
||||
href='/login'
|
||||
className='block w-full px-4 py-2 rounded text-sm font-medium text-center transition-colors'
|
||||
style={{ color: 'var(--brand-light-gray)', border: '1px solid var(--brand-light-gray)' }}
|
||||
onClick={() => setMobileMenuOpen(false)}
|
||||
>
|
||||
{t('signIn', language)}
|
||||
</a>
|
||||
<a
|
||||
href='/register'
|
||||
className='block w-full px-4 py-2 rounded font-semibold text-sm text-center transition-colors'
|
||||
style={{ background: 'var(--brand-yellow)', color: 'var(--brand-black)' }}
|
||||
onClick={() => setMobileMenuOpen(false)}
|
||||
>
|
||||
{t('signUp', language)}
|
||||
</a>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</motion.div>
|
||||
</nav>
|
||||
)
|
||||
}
|
||||
|
||||
137
web/src/components/landing/HeroSection.tsx
Normal file
137
web/src/components/landing/HeroSection.tsx
Normal file
@@ -0,0 +1,137 @@
|
||||
import { motion, useScroll, useTransform, useAnimation } from 'framer-motion'
|
||||
import { Sparkles } from 'lucide-react'
|
||||
import { t, Language } from '../../i18n/translations'
|
||||
|
||||
interface HeroSectionProps {
|
||||
language: Language
|
||||
}
|
||||
|
||||
export default function HeroSection({ language }: HeroSectionProps) {
|
||||
const { scrollYProgress } = useScroll()
|
||||
const opacity = useTransform(scrollYProgress, [0, 0.2], [1, 0])
|
||||
const scale = useTransform(scrollYProgress, [0, 0.2], [1, 0.8])
|
||||
const handControls = useAnimation()
|
||||
|
||||
const fadeInUp = {
|
||||
initial: { opacity: 0, y: 60 },
|
||||
animate: { opacity: 1, y: 0 },
|
||||
transition: { duration: 0.6, ease: [0.6, -0.05, 0.01, 0.99] },
|
||||
}
|
||||
const staggerContainer = { animate: { transition: { staggerChildren: 0.1 } } }
|
||||
|
||||
return (
|
||||
<section className='relative pt-32 pb-20 px-4'>
|
||||
<div className='max-w-7xl mx-auto'>
|
||||
<div className='grid lg:grid-cols-2 gap-12 items-center'>
|
||||
{/* Left Content */}
|
||||
<motion.div className='space-y-6 relative z-10' style={{ opacity, scale }} initial='initial' animate='animate' variants={staggerContainer}>
|
||||
<motion.div variants={fadeInUp}>
|
||||
<motion.div
|
||||
className='inline-flex items-center gap-2 px-4 py-2 rounded-full mb-6'
|
||||
style={{ background: 'rgba(240, 185, 11, 0.1)', border: '1px solid rgba(240, 185, 11, 0.2)' }}
|
||||
whileHover={{ scale: 1.05, boxShadow: '0 0 20px rgba(240, 185, 11, 0.2)' }}
|
||||
>
|
||||
<Sparkles className='w-4 h-4' style={{ color: 'var(--brand-yellow)' }} />
|
||||
<span className='text-sm font-semibold' style={{ color: 'var(--brand-yellow)' }}>
|
||||
{t('githubStarsInDays', language)}
|
||||
</span>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
|
||||
<h1 className='text-5xl lg:text-7xl font-bold leading-tight' style={{ color: 'var(--brand-light-gray)' }}>
|
||||
{t('heroTitle1', language)}
|
||||
<br />
|
||||
<span style={{ color: 'var(--brand-yellow)' }}>{t('heroTitle2', language)}</span>
|
||||
</h1>
|
||||
|
||||
<motion.p className='text-xl leading-relaxed' style={{ color: 'var(--text-secondary)' }} variants={fadeInUp}>
|
||||
{t('heroDescription', language)}
|
||||
</motion.p>
|
||||
|
||||
<div className='flex items-center gap-3 flex-wrap'>
|
||||
<motion.a href='https://github.com/tinkle-community/nofx' target='_blank' rel='noopener noreferrer' whileHover={{ scale: 1.05 }} transition={{ type: 'spring', stiffness: 400 }}>
|
||||
<img
|
||||
src='https://img.shields.io/github/stars/tinkle-community/nofx?style=for-the-badge&logo=github&logoColor=white&color=F0B90B&labelColor=0A0A0A'
|
||||
alt='GitHub Stars'
|
||||
className='h-7'
|
||||
/>
|
||||
</motion.a>
|
||||
<motion.a href='https://github.com/tinkle-community/nofx/network/members' target='_blank' rel='noopener noreferrer' whileHover={{ scale: 1.05 }} transition={{ type: 'spring', stiffness: 400 }}>
|
||||
<img
|
||||
src='https://img.shields.io/github/forks/tinkle-community/nofx?style=for-the-badge&logo=github&logoColor=white&color=F0B90B&labelColor=0A0A0A'
|
||||
alt='GitHub Forks'
|
||||
className='h-7'
|
||||
/>
|
||||
</motion.a>
|
||||
<motion.a href='https://github.com/tinkle-community/nofx/graphs/contributors' target='_blank' rel='noopener noreferrer' whileHover={{ scale: 1.05 }} transition={{ type: 'spring', stiffness: 400 }}>
|
||||
<img
|
||||
src='https://img.shields.io/github/contributors/tinkle-community/nofx?style=for-the-badge&logo=github&logoColor=white&color=F0B90B&labelColor=0A0A0A'
|
||||
alt='GitHub Contributors'
|
||||
className='h-7'
|
||||
/>
|
||||
</motion.a>
|
||||
</div>
|
||||
|
||||
<motion.p className='text-xs pt-4' style={{ color: 'var(--text-tertiary)' }} variants={fadeInUp}>
|
||||
{t('poweredBy', language)}
|
||||
</motion.p>
|
||||
</motion.div>
|
||||
|
||||
{/* Right Visual - Interactive Robot */}
|
||||
<div
|
||||
className='relative w-full cursor-pointer'
|
||||
onMouseEnter={() => {
|
||||
handControls.start({
|
||||
y: [-8, 8, -8],
|
||||
rotate: [-3, 3, -3],
|
||||
x: [-2, 2, -2],
|
||||
transition: {
|
||||
duration: 2.5,
|
||||
repeat: Infinity,
|
||||
ease: "easeInOut",
|
||||
times: [0, 0.5, 1]
|
||||
}
|
||||
})
|
||||
}}
|
||||
onMouseLeave={() => {
|
||||
handControls.start({
|
||||
y: 0,
|
||||
rotate: 0,
|
||||
x: 0,
|
||||
transition: {
|
||||
duration: 0.6,
|
||||
ease: "easeOut"
|
||||
}
|
||||
})
|
||||
}}
|
||||
>
|
||||
{/* Background Layer */}
|
||||
<motion.img
|
||||
src='/images/hand-bg.png'
|
||||
alt='NOFX Platform Background'
|
||||
className='w-full opacity-90'
|
||||
style={{ opacity, scale }}
|
||||
whileHover={{ scale: 1.02 }}
|
||||
transition={{ type: 'spring', stiffness: 300 }}
|
||||
/>
|
||||
|
||||
{/* Hand Layer - Animated */}
|
||||
<motion.img
|
||||
src='/images/hand.png'
|
||||
alt='Robot Hand'
|
||||
className='absolute top-0 left-0 w-full'
|
||||
style={{ opacity }}
|
||||
animate={handControls}
|
||||
initial={{ y: 0, rotate: 0, x: 0 }}
|
||||
whileHover={{
|
||||
scale: 1.05,
|
||||
transition: { type: 'spring', stiffness: 400 }
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
79
web/src/components/landing/HowItWorksSection.tsx
Normal file
79
web/src/components/landing/HowItWorksSection.tsx
Normal file
@@ -0,0 +1,79 @@
|
||||
import { motion } from 'framer-motion'
|
||||
import AnimatedSection from './AnimatedSection'
|
||||
import { t, Language } from '../../i18n/translations'
|
||||
|
||||
function StepCard({ number, title, description, delay }: any) {
|
||||
return (
|
||||
<motion.div className='flex gap-6 items-start' initial={{ opacity: 0, x: -50 }} whileInView={{ opacity: 1, x: 0 }} viewport={{ once: true }} transition={{ delay }} whileHover={{ x: 10 }}>
|
||||
<motion.div
|
||||
className='flex-shrink-0 w-14 h-14 rounded-full flex items-center justify-center font-bold text-2xl'
|
||||
style={{ background: 'var(--binance-yellow)', color: 'var(--brand-black)' }}
|
||||
whileHover={{ scale: 1.2, rotate: 360 }}
|
||||
transition={{ type: 'spring', stiffness: 260, damping: 20 }}
|
||||
>
|
||||
{number}
|
||||
</motion.div>
|
||||
<div>
|
||||
<h3 className='text-2xl font-semibold mb-2' style={{ color: 'var(--brand-light-gray)' }}>
|
||||
{title}
|
||||
</h3>
|
||||
<p className='text-lg leading-relaxed' style={{ color: 'var(--text-secondary)' }}>
|
||||
{description}
|
||||
</p>
|
||||
</div>
|
||||
</motion.div>
|
||||
)
|
||||
}
|
||||
|
||||
interface HowItWorksSectionProps {
|
||||
language: Language
|
||||
}
|
||||
|
||||
export default function HowItWorksSection({ language }: HowItWorksSectionProps) {
|
||||
return (
|
||||
<AnimatedSection id='how-it-works' backgroundColor='var(--brand-dark-gray)'>
|
||||
<div className='max-w-7xl mx-auto'>
|
||||
<motion.div className='text-center mb-16' initial={{ opacity: 0, y: 30 }} whileInView={{ opacity: 1, y: 0 }} viewport={{ once: true }}>
|
||||
<h2 className='text-4xl font-bold mb-4' style={{ color: 'var(--brand-light-gray)' }}>
|
||||
{t('howToStart', language)}
|
||||
</h2>
|
||||
<p className='text-lg' style={{ color: 'var(--text-secondary)' }}>
|
||||
{t('fourSimpleSteps', language)}
|
||||
</p>
|
||||
</motion.div>
|
||||
|
||||
<div className='space-y-8'>
|
||||
{[
|
||||
{ number: 1, title: t('step1Title', language), description: t('step1Desc', language) },
|
||||
{ number: 2, title: t('step2Title', language), description: t('step2Desc', language) },
|
||||
{ number: 3, title: t('step3Title', language), description: t('step3Desc', language) },
|
||||
{ number: 4, title: t('step4Title', language), description: t('step4Desc', language) },
|
||||
].map((step, index) => (
|
||||
<StepCard key={step.number} {...step} delay={index * 0.1} />
|
||||
))}
|
||||
</div>
|
||||
|
||||
<motion.div
|
||||
className='mt-12 p-6 rounded-xl flex items-start gap-4'
|
||||
style={{ background: 'rgba(246, 70, 93, 0.1)', border: '1px solid rgba(246, 70, 93, 0.3)' }}
|
||||
initial={{ opacity: 0, scale: 0.9 }}
|
||||
whileInView={{ opacity: 1, scale: 1 }}
|
||||
viewport={{ once: true }}
|
||||
whileHover={{ scale: 1.02 }}
|
||||
>
|
||||
<div className='w-10 h-10 rounded-full flex items-center justify-center flex-shrink-0' style={{ background: 'rgba(246, 70, 93, 0.2)', color: '#F6465D' }}>
|
||||
<svg xmlns='http://www.w3.org/2000/svg' className='w-6 h-6' viewBox='0 0 24 24' fill='none' stroke='currentColor' strokeWidth='2' strokeLinecap='round' strokeLinejoin='round'><path d='M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0Z'/><line x1='12' x2='12' y1='9' y2='13'/><line x1='12' x2='12.01' y1='17' y2='17'/></svg>
|
||||
</div>
|
||||
<div>
|
||||
<div className='font-semibold mb-2' style={{ color: '#F6465D' }}>
|
||||
{t('importantRiskWarning', language)}
|
||||
</div>
|
||||
<p className='text-sm' style={{ color: 'var(--text-secondary)' }}>
|
||||
{t('riskWarningText', language)}
|
||||
</p>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
</AnimatedSection>
|
||||
)
|
||||
}
|
||||
69
web/src/components/landing/LoginModal.tsx
Normal file
69
web/src/components/landing/LoginModal.tsx
Normal file
@@ -0,0 +1,69 @@
|
||||
import { motion } from 'framer-motion'
|
||||
import { X } from 'lucide-react'
|
||||
import { t, Language } from '../../i18n/translations'
|
||||
|
||||
interface LoginModalProps {
|
||||
onClose: () => void
|
||||
language: Language
|
||||
}
|
||||
|
||||
export default function LoginModal({ onClose, language }: LoginModalProps) {
|
||||
return (
|
||||
<motion.div
|
||||
className='fixed inset-0 z-50 flex items-center justify-center p-4'
|
||||
style={{ background: 'rgba(0, 0, 0, 0.8)' }}
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
exit={{ opacity: 0 }}
|
||||
onClick={onClose}
|
||||
>
|
||||
<motion.div
|
||||
className='relative max-w-md w-full rounded-2xl p-8'
|
||||
style={{ background: 'var(--brand-dark-gray)', border: '1px solid rgba(240, 185, 11, 0.2)' }}
|
||||
initial={{ scale: 0.9, y: 50 }}
|
||||
animate={{ scale: 1, y: 0 }}
|
||||
exit={{ scale: 0.9, y: 50 }}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
<motion.button onClick={onClose} className='absolute top-4 right-4' style={{ color: 'var(--text-secondary)' }} whileHover={{ scale: 1.1, rotate: 90 }} whileTap={{ scale: 0.9 }}>
|
||||
<X className='w-6 h-6' />
|
||||
</motion.button>
|
||||
<h2 className='text-2xl font-bold mb-6' style={{ color: 'var(--brand-light-gray)' }}>
|
||||
{t('accessNofxPlatform', language)}
|
||||
</h2>
|
||||
<p className='text-sm mb-6' style={{ color: 'var(--text-secondary)' }}>
|
||||
{t('loginRegisterPrompt', language)}
|
||||
</p>
|
||||
<div className='space-y-3'>
|
||||
<motion.button
|
||||
onClick={() => {
|
||||
window.history.pushState({}, '', '/login')
|
||||
window.dispatchEvent(new PopStateEvent('popstate'))
|
||||
onClose()
|
||||
}}
|
||||
className='block w-full px-6 py-3 rounded-lg font-semibold text-center'
|
||||
style={{ background: 'var(--brand-yellow)', color: 'var(--brand-black)' }}
|
||||
whileHover={{ scale: 1.05, boxShadow: '0 10px 30px rgba(240, 185, 11, 0.4)' }}
|
||||
whileTap={{ scale: 0.95 }}
|
||||
>
|
||||
{t('signIn', language)}
|
||||
</motion.button>
|
||||
<motion.button
|
||||
onClick={() => {
|
||||
window.history.pushState({}, '', '/register')
|
||||
window.dispatchEvent(new PopStateEvent('popstate'))
|
||||
onClose()
|
||||
}}
|
||||
className='block w-full px-6 py-3 rounded-lg font-semibold text-center'
|
||||
style={{ background: 'var(--brand-dark-gray)', color: 'var(--brand-light-gray)', border: '1px solid rgba(240, 185, 11, 0.2)' }}
|
||||
whileHover={{ scale: 1.05, borderColor: 'var(--brand-yellow)' }}
|
||||
whileTap={{ scale: 0.95 }}
|
||||
>
|
||||
{t('registerNewAccount', language)}
|
||||
</motion.button>
|
||||
</div>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ interface AuthContextType {
|
||||
user: User | null;
|
||||
token: string | null;
|
||||
login: (email: string, password: string) => Promise<{ success: boolean; message?: string; userID?: string; requiresOTP?: boolean }>;
|
||||
register: (email: string, password: string) => Promise<{ success: boolean; message?: string; userID?: string; otpSecret?: string; qrCodeURL?: string }>;
|
||||
register: (email: string, password: string, betaCode?: string) => Promise<{ success: boolean; message?: string; userID?: string; otpSecret?: string; qrCodeURL?: string }>;
|
||||
verifyOTP: (userID: string, otpCode: string) => Promise<{ success: boolean; message?: string }>;
|
||||
completeRegistration: (userID: string, otpCode: string) => Promise<{ success: boolean; message?: string }>;
|
||||
logout: () => void;
|
||||
@@ -89,14 +89,19 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
|
||||
return { success: false, message: '未知错误' };
|
||||
};
|
||||
|
||||
const register = async (email: string, password: string) => {
|
||||
const register = async (email: string, password: string, betaCode?: string) => {
|
||||
try {
|
||||
const requestBody: { email: string; password: string; beta_code?: string } = { email, password };
|
||||
if (betaCode) {
|
||||
requestBody.beta_code = betaCode;
|
||||
}
|
||||
|
||||
const response = await fetch('/api/register', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({ email, password }),
|
||||
body: JSON.stringify(requestBody),
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
@@ -15,6 +15,11 @@ export const translations = {
|
||||
logout: 'Logout',
|
||||
switchTrader: 'Switch Trader:',
|
||||
view: 'View',
|
||||
|
||||
// Navigation
|
||||
realtimeNav: 'Live',
|
||||
configNav: 'Config',
|
||||
dashboardNav: 'Dashboard',
|
||||
|
||||
// Footer
|
||||
footerTitle: 'NOFX - AI Trading System',
|
||||
@@ -296,12 +301,12 @@ export const translations = {
|
||||
scanQRCodeInstructions: 'Scan this QR code with Google Authenticator or Authy',
|
||||
otpSecret: 'Or enter this secret manually:',
|
||||
qrCodeHint: 'QR code (if scanning fails, use the secret below):',
|
||||
step1Title: 'Step 1: Install Google Authenticator',
|
||||
step1Desc: 'Download and install Google Authenticator from your app store',
|
||||
step2Title: 'Step 2: Add account',
|
||||
step2Desc: 'Tap "+", then choose "Scan QR code" or "Enter a setup key"',
|
||||
step3Title: 'Step 3: Verify setup',
|
||||
step3Desc: 'After setup, continue to enter the 6-digit code',
|
||||
authStep1Title: 'Step 1: Install Google Authenticator',
|
||||
authStep1Desc: 'Download and install Google Authenticator from your app store',
|
||||
authStep2Title: 'Step 2: Add account',
|
||||
authStep2Desc: 'Tap "+", then choose "Scan QR code" or "Enter a setup key"',
|
||||
authStep3Title: 'Step 3: Verify setup',
|
||||
authStep3Desc: 'After setup, continue to enter the 6-digit code',
|
||||
setupCompleteContinue: 'I have completed setup, continue',
|
||||
copy: 'Copy',
|
||||
completeRegistration: 'Complete Registration',
|
||||
@@ -317,6 +322,96 @@ export const translations = {
|
||||
passwordRequired: 'Password is required',
|
||||
invalidEmail: 'Invalid email format',
|
||||
passwordTooShort: 'Password must be at least 6 characters',
|
||||
|
||||
// Landing Page
|
||||
features: 'Features',
|
||||
howItWorks: 'How it Works',
|
||||
community: 'Community',
|
||||
language: 'Language',
|
||||
loggedInAs: 'Logged in as',
|
||||
exitLogin: 'Sign Out',
|
||||
signIn: 'Sign In',
|
||||
signUp: 'Sign Up',
|
||||
|
||||
// Hero Section
|
||||
githubStarsInDays: '2.5K+ GitHub Stars in 3 days',
|
||||
heroTitle1: 'Read the Market.',
|
||||
heroTitle2: 'Write the Trade.',
|
||||
heroDescription: 'NOFX is the future standard for AI trading — an open, community-driven agentic trading OS. Supporting Binance, Aster DEX and other exchanges, self-hosted, multi-agent competition, let AI automatically make decisions, execute and optimize trades for you.',
|
||||
poweredBy: 'Powered by Aster DEX and Binance, strategically invested by Amber.ac.',
|
||||
|
||||
// Landing Page CTA
|
||||
readyToDefine: 'Ready to define the future of AI trading?',
|
||||
startWithCrypto: 'Starting with crypto markets, expanding to TradFi. NOFX is the infrastructure of AgentFi.',
|
||||
getStartedNow: 'Get Started Now',
|
||||
viewSourceCode: 'View Source Code',
|
||||
|
||||
// Features Section
|
||||
coreFeatures: 'Core Features',
|
||||
whyChooseNofx: 'Why Choose NOFX?',
|
||||
openCommunityDriven: 'Open source, transparent, community-driven AI trading OS',
|
||||
openSourceSelfHosted: '100% Open Source & Self-Hosted',
|
||||
openSourceDesc: 'Your framework, your rules. Non-black box, supports custom prompts and multi-models.',
|
||||
openSourceFeatures1: 'Fully open source code',
|
||||
openSourceFeatures2: 'Self-hosting deployment support',
|
||||
openSourceFeatures3: 'Custom AI prompts',
|
||||
openSourceFeatures4: 'Multi-model support (DeepSeek, Qwen)',
|
||||
multiAgentCompetition: 'Multi-Agent Intelligent Competition',
|
||||
multiAgentDesc: 'AI strategies battle at high speed in sandbox, survival of the fittest, achieving strategy evolution.',
|
||||
multiAgentFeatures1: 'Multiple AI agents running in parallel',
|
||||
multiAgentFeatures2: 'Automatic strategy optimization',
|
||||
multiAgentFeatures3: 'Sandbox security testing',
|
||||
multiAgentFeatures4: 'Cross-market strategy porting',
|
||||
secureReliableTrading: 'Secure and Reliable Trading',
|
||||
secureDesc: 'Enterprise-grade security, complete control over your funds and trading strategies.',
|
||||
secureFeatures1: 'Local private key management',
|
||||
secureFeatures2: 'Fine-grained API permission control',
|
||||
secureFeatures3: 'Real-time risk monitoring',
|
||||
secureFeatures4: 'Trading log auditing',
|
||||
|
||||
// About Section
|
||||
aboutNofx: 'About NOFX',
|
||||
whatIsNofx: 'What is NOFX?',
|
||||
nofxNotAnotherBot: "NOFX is not another trading bot, but the 'Linux' of AI trading —",
|
||||
nofxDescription1: 'a transparent, trustworthy open source OS that provides a unified',
|
||||
nofxDescription2: "'decision-risk-execution' layer, supporting all asset classes.",
|
||||
nofxDescription3: 'Starting with crypto markets (24/7, high volatility perfect testing ground), future expansion to stocks, futures, forex. Core: open architecture, AI',
|
||||
nofxDescription4: 'Darwinism (multi-agent self-competition, strategy evolution), CodeFi',
|
||||
nofxDescription5: 'flywheel (developers get point rewards for PR contributions).',
|
||||
youFullControl: 'You 100% Control',
|
||||
fullControlDesc: 'Complete control over AI prompts and funds',
|
||||
startupMessages1: 'Starting automated trading system...',
|
||||
startupMessages2: 'API server started on port 8080',
|
||||
startupMessages3: 'Web console http://localhost:3000',
|
||||
|
||||
// How It Works Section
|
||||
howToStart: 'How to Get Started with NOFX',
|
||||
fourSimpleSteps: 'Four simple steps to start your AI automated trading journey',
|
||||
step1Title: 'Clone GitHub Repository',
|
||||
step1Desc: 'git clone https://github.com/tinkle-community/nofx and switch to dev branch to test new features.',
|
||||
step2Title: 'Configure Environment',
|
||||
step2Desc: 'Frontend setup for exchange APIs (like Binance, Hyperliquid), AI models and custom prompts.',
|
||||
step3Title: 'Deploy & Run',
|
||||
step3Desc: 'One-click Docker deployment, start AI agents. Note: High-risk market, only test with money you can afford to lose.',
|
||||
step4Title: 'Optimize & Contribute',
|
||||
step4Desc: 'Monitor trading, submit PRs to improve framework. Join Telegram to share strategies.',
|
||||
importantRiskWarning: 'Important Risk Warning',
|
||||
riskWarningText: 'Dev branch is unstable, do not use funds you cannot afford to lose. NOFX is non-custodial, no official strategies. Trading involves risks, invest carefully.',
|
||||
|
||||
// Community Section (testimonials are kept as-is since they are quotes)
|
||||
|
||||
// Footer Section
|
||||
futureStandardAI: 'The future standard of AI trading',
|
||||
links: 'Links',
|
||||
resources: 'Resources',
|
||||
documentation: 'Documentation',
|
||||
supporters: 'Supporters',
|
||||
strategicInvestment: '(Strategic Investment)',
|
||||
|
||||
// Login Modal
|
||||
accessNofxPlatform: 'Access NOFX Platform',
|
||||
loginRegisterPrompt: 'Please login or register to access the full AI trading platform',
|
||||
registerNewAccount: 'Register New Account',
|
||||
},
|
||||
zh: {
|
||||
// Header
|
||||
@@ -332,6 +427,11 @@ export const translations = {
|
||||
logout: '退出',
|
||||
switchTrader: '切换交易员:',
|
||||
view: '查看',
|
||||
|
||||
// Navigation
|
||||
realtimeNav: '实时',
|
||||
configNav: '配置',
|
||||
dashboardNav: '看板',
|
||||
|
||||
// Footer
|
||||
footerTitle: 'NOFX - AI交易系统',
|
||||
@@ -613,12 +713,12 @@ export const translations = {
|
||||
scanQRCodeInstructions: '使用Google Authenticator或Authy扫描此二维码',
|
||||
otpSecret: '或手动输入此密钥:',
|
||||
qrCodeHint: '二维码(如果无法扫描,请使用下方密钥):',
|
||||
step1Title: '步骤1:下载Google Authenticator',
|
||||
step1Desc: '在手机应用商店下载并安装Google Authenticator应用',
|
||||
step2Title: '步骤2:添加账户',
|
||||
step2Desc: '在应用中点击“+”,选择“扫描二维码”或“手动输入密钥”',
|
||||
step3Title: '步骤3:验证设置',
|
||||
step3Desc: '设置完成后,点击下方按钮输入6位验证码',
|
||||
authStep1Title: '步骤1:下载Google Authenticator',
|
||||
authStep1Desc: '在手机应用商店下载并安装Google Authenticator应用',
|
||||
authStep2Title: '步骤2:添加账户',
|
||||
authStep2Desc: '在应用中点击“+”,选择“扫描二维码”或“手动输入密钥”',
|
||||
authStep3Title: '步骤3:验证设置',
|
||||
authStep3Desc: '设置完成后,点击下方按钮输入6位验证码',
|
||||
setupCompleteContinue: '我已完成设置,继续',
|
||||
copy: '复制',
|
||||
completeRegistration: '完成注册',
|
||||
@@ -634,6 +734,96 @@ export const translations = {
|
||||
passwordRequired: '请输入密码',
|
||||
invalidEmail: '邮箱格式不正确',
|
||||
passwordTooShort: '密码至少需要6个字符',
|
||||
|
||||
// Landing Page
|
||||
features: '功能',
|
||||
howItWorks: '如何运作',
|
||||
community: '社区',
|
||||
language: '语言',
|
||||
loggedInAs: '已登录为',
|
||||
exitLogin: '退出登录',
|
||||
signIn: '登录',
|
||||
signUp: '注册',
|
||||
|
||||
// Hero Section
|
||||
githubStarsInDays: '3 天内 2.5K+ GitHub Stars',
|
||||
heroTitle1: 'Read the Market.',
|
||||
heroTitle2: 'Write the Trade.',
|
||||
heroDescription: 'NOFX 是 AI 交易的未来标准——一个开放、社区驱动的代理式交易操作系统。支持 Binance、Aster DEX 等交易所,自托管、多代理竞争,让 AI 为你自动决策、执行和优化交易。',
|
||||
poweredBy: '由 Aster DEX 和 Binance 提供支持,Amber.ac 战略投资。',
|
||||
|
||||
// Landing Page CTA
|
||||
readyToDefine: '准备好定义 AI 交易的未来吗?',
|
||||
startWithCrypto: '从加密市场起步,扩展到 TradFi。NOFX 是 AgentFi 的基础架构。',
|
||||
getStartedNow: '立即开始',
|
||||
viewSourceCode: '查看源码',
|
||||
|
||||
// Features Section
|
||||
coreFeatures: '核心功能',
|
||||
whyChooseNofx: '为什么选择 NOFX?',
|
||||
openCommunityDriven: '开源、透明、社区驱动的 AI 交易操作系统',
|
||||
openSourceSelfHosted: '100% 开源与自托管',
|
||||
openSourceDesc: '你的框架,你的规则。非黑箱,支持自定义提示词和多模型。',
|
||||
openSourceFeatures1: '完全开源代码',
|
||||
openSourceFeatures2: '支持自托管部署',
|
||||
openSourceFeatures3: '自定义 AI 提示词',
|
||||
openSourceFeatures4: '多模型支持(DeepSeek、Qwen)',
|
||||
multiAgentCompetition: '多代理智能竞争',
|
||||
multiAgentDesc: 'AI 策略在沙盒中高速战斗,最优者生存,实现策略进化。',
|
||||
multiAgentFeatures1: '多 AI 代理并行运行',
|
||||
multiAgentFeatures2: '策略自动优化',
|
||||
multiAgentFeatures3: '沙盒安全测试',
|
||||
multiAgentFeatures4: '跨市场策略移植',
|
||||
secureReliableTrading: '安全可靠交易',
|
||||
secureDesc: '企业级安全保障,完全掌控你的资金和交易策略。',
|
||||
secureFeatures1: '本地私钥管理',
|
||||
secureFeatures2: 'API 权限精细控制',
|
||||
secureFeatures3: '实时风险监控',
|
||||
secureFeatures4: '交易日志审计',
|
||||
|
||||
// About Section
|
||||
aboutNofx: '关于 NOFX',
|
||||
whatIsNofx: '什么是 NOFX?',
|
||||
nofxNotAnotherBot: 'NOFX 不是另一个交易机器人,而是 AI 交易的 \'Linux\' ——',
|
||||
nofxDescription1: '一个透明、可信任的开源 OS,提供统一的 \'决策-风险-执行\'',
|
||||
nofxDescription2: '层,支持所有资产类别。',
|
||||
nofxDescription3: '从加密市场起步(24/7、高波动性完美测试场),未来扩展到股票、期货、外汇。核心:开放架构、AI',
|
||||
nofxDescription4: '达尔文主义(多代理自竞争、策略进化)、CodeFi 飞轮(开发者 PR',
|
||||
nofxDescription5: '贡献获积分奖励)。',
|
||||
youFullControl: '你 100% 掌控',
|
||||
fullControlDesc: '完全掌控 AI 提示词和资金',
|
||||
startupMessages1: ' 启动自动交易系统...',
|
||||
startupMessages2: ' API服务器启动在端口 8080',
|
||||
startupMessages3: ' Web 控制台 http://localhost:3000',
|
||||
|
||||
// How It Works Section
|
||||
howToStart: '如何开始使用 NOFX',
|
||||
fourSimpleSteps: '四个简单步骤,开启 AI 自动交易之旅',
|
||||
step1Title: '拉取 GitHub 仓库',
|
||||
step1Desc: 'git clone https://github.com/tinkle-community/nofx 并切换到 dev 分支测试新功能。',
|
||||
step2Title: '配置环境',
|
||||
step2Desc: '前端设置交易所 API(如 Binance、Hyperliquid)、AI 模型和自定义提示词。',
|
||||
step3Title: '部署与运行',
|
||||
step3Desc: '一键 Docker 部署,启动 AI 代理。注意:高风险市场,仅用闲钱测试。',
|
||||
step4Title: '优化与贡献',
|
||||
step4Desc: '监控交易,提交 PR 改进框架。加入 Telegram 分享策略。',
|
||||
importantRiskWarning: '重要风险提示',
|
||||
riskWarningText: 'dev 分支不稳定,勿用无法承受损失的资金。NOFX 非托管,无官方策略。交易有风险,投资需谨慎。',
|
||||
|
||||
// Community Section (testimonials are kept as-is since they are quotes)
|
||||
|
||||
// Footer Section
|
||||
futureStandardAI: 'AI 交易的未来标准',
|
||||
links: '链接',
|
||||
resources: '资源',
|
||||
documentation: '文档',
|
||||
supporters: '支持方',
|
||||
strategicInvestment: '(战略投资)',
|
||||
|
||||
// Login Modal
|
||||
accessNofxPlatform: '访问 NOFX 平台',
|
||||
loginRegisterPrompt: '请选择登录或注册以访问完整的 AI 交易平台',
|
||||
registerNewAccount: '注册新账号',
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -5,20 +5,34 @@
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
/* 强制显示滚动条以确保所有页面布局一致 */
|
||||
html {
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
:root {
|
||||
/* Binance Brand Colors */
|
||||
--brand-yellow: #F0B90B;
|
||||
--brand-black: #000000;
|
||||
--brand-dark-gray: #0A0A0A;
|
||||
--brand-light-gray: #EAECEF;
|
||||
--brand-almost-white: #FAFAFA;
|
||||
--brand-white: #FFFFFF;
|
||||
|
||||
/* Binance Theme Colors */
|
||||
--binance-yellow: #F0B90B;
|
||||
--binance-yellow-dark: #C99400;
|
||||
--binance-yellow-light: #FCD535;
|
||||
--binance-yellow-glow: rgba(240, 185, 11, 0.2);
|
||||
|
||||
--background: #0B0E11;
|
||||
--background-elevated: #181A20;
|
||||
--background: #000000; /* Binance body bg */
|
||||
--header-bg: #000000; /* Binance header bg */
|
||||
--background-elevated: #000000;
|
||||
--foreground: #EAECEF;
|
||||
--panel-bg: #1E2329;
|
||||
--panel-bg-hover: #252930;
|
||||
--panel-border: #2B3139;
|
||||
--panel-border-hover: #474D57;
|
||||
--panel-bg: #0A0A0A;
|
||||
--panel-bg-hover: #111111;
|
||||
--panel-border: #1A1A1A;
|
||||
--panel-border-hover: #2A2A2A;
|
||||
|
||||
/* Binance Signature Colors */
|
||||
--binance-green: #0ECB81;
|
||||
@@ -35,7 +49,7 @@
|
||||
--text-disabled: #474D57;
|
||||
|
||||
/* Chart Colors */
|
||||
--grid-stroke: #2B3139;
|
||||
--grid-stroke: #1A1A1A;
|
||||
--axis-tick: #5E6673;
|
||||
--ref-line: #474D57;
|
||||
|
||||
@@ -138,10 +152,10 @@ body {
|
||||
|
||||
@keyframes shimmer {
|
||||
0% {
|
||||
background-position: -200% 0;
|
||||
transform: translateX(-100%);
|
||||
}
|
||||
100% {
|
||||
background-position: 200% 0;
|
||||
transform: translateX(100%);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,12 +185,9 @@ body {
|
||||
}
|
||||
|
||||
/* Glass effect - Binance header style */
|
||||
.glass {
|
||||
background: var(--background-elevated);
|
||||
backdrop-filter: blur(12px);
|
||||
-webkit-backdrop-filter: blur(12px);
|
||||
.header-bar {
|
||||
background: var(--header-bg);
|
||||
border-bottom: 1px solid var(--panel-border);
|
||||
box-shadow: var(--shadow-sm);
|
||||
}
|
||||
|
||||
/* Monospace numbers */
|
||||
|
||||
@@ -32,13 +32,20 @@ function getAuthHeaders(): Record<string, string> {
|
||||
export const api = {
|
||||
// AI交易员管理接口
|
||||
async getTraders(): Promise<TraderInfo[]> {
|
||||
const res = await fetch(`${API_BASE}/traders`, {
|
||||
const res = await fetch(`${API_BASE}/my-traders`, {
|
||||
headers: getAuthHeaders(),
|
||||
});
|
||||
if (!res.ok) throw new Error('获取trader列表失败');
|
||||
return res.json();
|
||||
},
|
||||
|
||||
// 获取公开的交易员列表(无需认证)
|
||||
async getPublicTraders(): Promise<any[]> {
|
||||
const res = await fetch(`${API_BASE}/traders`);
|
||||
if (!res.ok) throw new Error('获取公开trader列表失败');
|
||||
return res.json();
|
||||
},
|
||||
|
||||
async createTrader(request: CreateTraderRequest): Promise<TraderInfo> {
|
||||
const res = await fetch(`${API_BASE}/traders`, {
|
||||
method: 'POST',
|
||||
@@ -252,11 +259,9 @@ export const api = {
|
||||
return res.json();
|
||||
},
|
||||
|
||||
// 获取竞赛数据
|
||||
// 获取竞赛数据(无需认证)
|
||||
async getCompetition(): Promise<CompetitionData> {
|
||||
const res = await fetch(`${API_BASE}/competition`, {
|
||||
headers: getAuthHeaders(),
|
||||
});
|
||||
const res = await fetch(`${API_BASE}/competition`);
|
||||
if (!res.ok) throw new Error('获取竞赛数据失败');
|
||||
return res.json();
|
||||
},
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
export interface SystemConfig {
|
||||
admin_mode: boolean;
|
||||
beta_mode: boolean;
|
||||
}
|
||||
|
||||
let configPromise: Promise<SystemConfig> | null = null;
|
||||
|
||||
6
web/src/lib/utils.ts
Normal file
6
web/src/lib/utils.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import { clsx, type ClassValue } from "clsx";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
|
||||
export function cn(...inputs: ClassValue[]) {
|
||||
return twMerge(clsx(inputs));
|
||||
}
|
||||
80
web/src/pages/LandingPage.tsx
Normal file
80
web/src/pages/LandingPage.tsx
Normal file
@@ -0,0 +1,80 @@
|
||||
import { useState } from 'react'
|
||||
import { motion } from 'framer-motion'
|
||||
import { ArrowRight } from 'lucide-react'
|
||||
import HeaderBar from '../components/landing/HeaderBar'
|
||||
import HeroSection from '../components/landing/HeroSection'
|
||||
import AboutSection from '../components/landing/AboutSection'
|
||||
import FeaturesSection from '../components/landing/FeaturesSection'
|
||||
import HowItWorksSection from '../components/landing/HowItWorksSection'
|
||||
import CommunitySection from '../components/landing/CommunitySection'
|
||||
import AnimatedSection from '../components/landing/AnimatedSection'
|
||||
import LoginModal from '../components/landing/LoginModal'
|
||||
import FooterSection from '../components/landing/FooterSection'
|
||||
import { useAuth } from '../contexts/AuthContext'
|
||||
import { useLanguage } from '../contexts/LanguageContext'
|
||||
import { t } from '../i18n/translations'
|
||||
|
||||
export function LandingPage() {
|
||||
const [showLoginModal, setShowLoginModal] = useState(false)
|
||||
const { user, logout } = useAuth()
|
||||
const { language, setLanguage } = useLanguage()
|
||||
const isLoggedIn = !!user
|
||||
|
||||
console.log('LandingPage - user:', user, 'isLoggedIn:', isLoggedIn);
|
||||
return (
|
||||
<>
|
||||
<HeaderBar
|
||||
onLoginClick={() => setShowLoginModal(true)}
|
||||
isLoggedIn={isLoggedIn}
|
||||
isHomePage={true}
|
||||
language={language}
|
||||
onLanguageChange={setLanguage}
|
||||
user={user}
|
||||
onLogout={logout}
|
||||
onPageChange={(page) => {
|
||||
console.log('LandingPage onPageChange called with:', page);
|
||||
if (page === 'competition') {
|
||||
window.location.href = '/competition';
|
||||
} else if (page === 'traders') {
|
||||
window.location.href = '/traders';
|
||||
} else if (page === 'trader') {
|
||||
window.location.href = '/dashboard';
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<div className='min-h-screen px-4 sm:px-6 lg:px-8' style={{ background: 'var(--brand-black)', color: 'var(--brand-light-gray)' }}>
|
||||
<HeroSection language={language} />
|
||||
<AboutSection language={language} />
|
||||
<FeaturesSection language={language} />
|
||||
<HowItWorksSection language={language} />
|
||||
<CommunitySection />
|
||||
|
||||
{/* CTA */}
|
||||
<AnimatedSection backgroundColor='var(--panel-bg)'>
|
||||
<div className='max-w-4xl mx-auto text-center'>
|
||||
<motion.h2 className='text-5xl font-bold mb-6' style={{ color: 'var(--brand-light-gray)' }} initial={{ opacity: 0, y: 30 }} whileInView={{ opacity: 1, y: 0 }} viewport={{ once: true }}>
|
||||
{t('readyToDefine', language)}
|
||||
</motion.h2>
|
||||
<motion.p className='text-xl mb-12' style={{ color: 'var(--text-secondary)' }} initial={{ opacity: 0, y: 30 }} whileInView={{ opacity: 1, y: 0 }} viewport={{ once: true }} transition={{ delay: 0.1 }}>
|
||||
{t('startWithCrypto', language)}
|
||||
</motion.p>
|
||||
<div className='flex flex-wrap justify-center gap-4'>
|
||||
<motion.button onClick={() => setShowLoginModal(true)} className='flex items-center gap-2 px-10 py-4 rounded-lg font-semibold text-lg' style={{ background: 'var(--brand-yellow)', color: 'var(--brand-black)' }} whileHover={{ scale: 1.05 }} whileTap={{ scale: 0.95 }}>
|
||||
{t('getStartedNow', language)}
|
||||
<motion.div animate={{ x: [0, 5, 0] }} transition={{ duration: 1.5, repeat: Infinity }}>
|
||||
<ArrowRight className='w-5 h-5' />
|
||||
</motion.div>
|
||||
</motion.button>
|
||||
<motion.a href='https://github.com/tinkle-community/nofx/tree/dev' target='_blank' rel='noopener noreferrer' className='flex items-center gap-2 px-10 py-4 rounded-lg font-semibold text-lg' style={{ background: 'transparent', color: 'var(--brand-light-gray)', border: '2px solid var(--brand-yellow)' }} whileHover={{ scale: 1.05, backgroundColor: 'rgba(240, 185, 11, 0.1)' }} whileTap={{ scale: 0.95 }}>
|
||||
{t('viewSourceCode', language)}
|
||||
</motion.a>
|
||||
</div>
|
||||
</div>
|
||||
</AnimatedSection>
|
||||
|
||||
{showLoginModal && <LoginModal onClose={() => setShowLoginModal(false)} language={language} />}
|
||||
<FooterSection language={language} />
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user