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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# CODEOWNERS — auto-assign reviewers for PRs
# https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners

# Default: repo owner reviews everything
* @NeuZhou

# Evolution engine — core, needs careful review
stratevo/evolution/ @NeuZhou
stratevo/fitness_plugins/ @NeuZhou

# Factors — community contributions welcome
stratevo/factor_registry/builtin/ @NeuZhou

# CI & Infrastructure
.github/ @NeuZhou

# Trading — sensitive, needs extra scrutiny
stratevo/trading/ @NeuZhou
39 changes: 39 additions & 0 deletions .github/workflows/stale.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
name: Stale

on:
schedule:
- cron: '30 1 * * *' # daily at 01:30 UTC
workflow_dispatch:

permissions:
issues: write
pull-requests: write

jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v9
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
days-before-stale: 30
days-before-close: 14
stale-issue-label: stale
stale-pr-label: stale
stale-issue-message: >
This issue has been automatically marked as stale because it has not had
recent activity. It will be closed in 14 days if no further activity occurs.
If this is still relevant, please leave a comment or remove the stale label.
stale-pr-message: >
This pull request has been automatically marked as stale because it has not had
recent activity. It will be closed in 14 days if no further activity occurs.
If you're still working on this, please leave a comment or push a new commit.
close-issue-message: >
This issue was closed because it has been stale for 14 days with no activity.
Feel free to reopen if this is still relevant.
close-pr-message: >
This PR was closed because it has been stale for 14 days with no activity.
Feel free to reopen if you'd like to continue working on it.
exempt-issue-labels: 'pinned,priority,in-progress'
exempt-pr-labels: 'pinned,priority,in-progress'
exempt-all-milestones: true
10 changes: 6 additions & 4 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ Thanks for your interest in contributing! StratEvo is an AI-native quantitative

```bash
# 1. Clone the repo
git clone https://github.com/NeuZhou/finclaw.git
cd finclaw
git clone https://github.com/NeuZhou/stratevo.git
cd stratevo

# 2. Install in development mode (with pre-commit hooks)
make dev
Expand Down Expand Up @@ -41,8 +41,8 @@ make check

| Area | Description |
|------|-------------|
| 🐛 Bug reports | Found something broken? [Open an issue](https://github.com/NeuZhou/finclaw/issues/new?template=bug_report.yml) |
| ✨ Features | Have an idea? [Request a feature](https://github.com/NeuZhou/finclaw/issues/new?template=feature_request.yml) |
| 🐛 Bug reports | Found something broken? [Open an issue](https://github.com/NeuZhou/stratevo/issues/new?template=bug_report.yml) |
| ✨ Features | Have an idea? [Request a feature](https://github.com/NeuZhou/stratevo/issues/new?template=feature_request.yml) |
| 📈 Factors | Add a new alpha factor to the evolution engine |
| 🏋️ Fitness Functions | Implement a new fitness function for strategy evaluation |
| 📡 Data Sources | Connect a new data provider |
Expand Down Expand Up @@ -164,6 +164,8 @@ All of the following must pass before a PR can be merged:
- `ruff check .` — linting
- No regressions in existing tests

> **Note for first-time contributors:** GitHub requires a maintainer to approve CI runs on your first PR from a fork. This is a security measure. Don't worry — we'll approve it quickly!

## Issue Labels

| Label | Description |
Expand Down
3 changes: 2 additions & 1 deletion SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@

| Version | Supported |
| ------- | ------------------ |
| 5.x.x | ✅ |
| 6.x.x | ✅ |
| 5.x.x | ✅ (security only) |
| < 5.0 | ❌ |

## Reporting a Vulnerability
Expand Down
37 changes: 32 additions & 5 deletions stratevo/cli/commands/scaffold.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,16 +188,44 @@ def test_supported_symbols(self):


# ─── scaffold commands ──────────────────────────────────────────────
def _find_repo_root() -> Optional[str]:
"""Walk up from CWD to find the repo root (contains stratevo/ package)."""
cur = os.path.abspath(".")
for _ in range(10):
if os.path.isdir(os.path.join(cur, "stratevo", "factor_registry")):
return cur
parent = os.path.dirname(cur)
if parent == cur:
break
cur = parent
return None


def scaffold_factor(
name: str,
category: str = "custom",
output_dir: Optional[str] = None,
) -> tuple[str, str]:
"""Generate a factor file and its companion test. Returns tuple of paths."""
class_name = _to_class_name(name)
base = output_dir or "."
src_path = os.path.join(base, f"{name}_factor.py")
test_path = os.path.join(base, f"test_{name}_factor.py")

# Auto-detect correct placement when output_dir is not given
if output_dir is None:
repo_root = _find_repo_root()
if repo_root is not None:
src_dir = os.path.join(
repo_root, "stratevo", "factor_registry", "builtin",
)
test_dir = os.path.join(repo_root, "tests")
else:
src_dir = "."
test_dir = "."
else:
src_dir = output_dir
test_dir = output_dir

src_path = os.path.join(src_dir, f"{name}_factor.py")
test_path = os.path.join(test_dir, f"test_{name}_factor.py")

_write_file(src_path, _factor_template(name, category, class_name))
_write_file(test_path, _factor_test_template(name, category, class_name))
Expand Down Expand Up @@ -251,8 +279,7 @@ def cmd_scaffold(args: object) -> None:
print(" Next steps:")
print(f" 1. Open {src} and implement compute()")
print(f" 2. Run tests: python -m pytest {test} -v")
print(" 3. Move into stratevo/factor_registry/builtin/<category>/ when ready")
print(" 4. Submit a PR!")
print(" 3. Submit a PR!")

elif scaffold_type == "fitness":
name = args.name # type: ignore[attr-defined]
Expand Down
Loading