A template project for developing, researching, and backtesting trading signals.
- Click the Button: At the top of this repository page, click the green "Use this template" button and select "Create a new repository."
- Configure:
- Choose an Owner (your account).
- Give your new repository a Name, "sf-research-{signal_name}"
- Create: Click "Create repository from template."
- Clone: Once your new repo is ready, clone it to your local machine:
git clone https://github.com/your-username/your-new-repo.gitThis template includes automatic syncing to keep your repository up-to-date with the latest improvements, bug fixes, and security patches.
- Every Monday at midnight UTC, GitHub automatically checks for template updates
- If new changes are available, a pull request is created in your repository
- You'll be notified via GitHub, and can review the changes at your convenience
- Updates include version bumps, changelog updates, and framework improvements
When you first receive an update PR, you'll need to configure GitHub Actions permissions (one-time only):
- Go to Settings β Actions β General
- Under "Workflow permissions," select "Read and write permissions"
- Check "Allow GitHub Actions to create and approve pull requests"
After this, updates will flow in automatically. You can always merge, ignore, or customize the updates as needed for your specific project.
Before running any commands, you need to configure your environment:
- Copy the environment template:
cp .env.example .env- Edit
.envwith your settings:
# Update these values:
SIGNAL_PATH=data/signal.parquet # Where to save your signal
WEIGHT_DIR=data/weights # Where backtest results go
LOG_DIR=logs # Where logs go
SIGNAL_NAME="Your Signal Name" # Name your signal
GAMMA=50 # Risk aversion parameter
EMAIL=your-netid@byu.edu # Your BYU email
CONSTRAINTS=["ZeroBeta", "ZeroInvestment"] # Portfolio constraints
# Optional: Customize SLURM settings for cluster jobs
SLURM_N_CPUS=8 # Number of CPUs
SLURM_MEM=32G # Memory allocation
SLURM_TIME=03:00:00 # Time limitThe .env file is not tracked in git (see .gitignore), so each user can have their own settings.
sf-signal/
βββ src/
β βββ framework/
β β βββ ew_dash.py # Equal-weight dashboard (do not edit)
β β βββ opt_dash.py # Optimal portfolio dashboard (do not edit)
β β βββ run_backtest.py # Run the backtest (edit config only)
β βββ signal/
β βββ create_signal.py # Your signal implementation (edit this)
βββ data/
β βββ signal.parquet # Output: Your signal
β βββ weights/ # Output: Backtest weights
βββ README.md
date: Date column barrid: Asset identifier alpha: Alpha signal values predicted_beta: Predicted beta values signal: orignal signal values (name can be changed)
- Customize date ranges, data columns, and calculation logic
- Develop your signal logic
- Saves signal to
data/signal.parquet
make create-signal- Compare your signal against an equal-weight baseline
- Analyze signal characteristics
- Visualize signal properties and performance
make ew-dash- Run MVO-based backtest on your signal
- Generates optimal portfolio weights
- Saves results to
data/weights.parquet
make run-backtest- View optimized portfolio performance
- Analyze backtest returns, drawdowns, and metrics
make opt-dashAll data files are stored in the data/ directory:
-
data/signal.parquet: Output fromcreate_signal.py- Columns:
date,barrid,alpha(your signal),signal - Format: Parquet (AlphaSchema)
- Columns:
-
data/weights/*.parquet: Output from backtest- Contains: Portfolio weights and performance data
- Format: Parquet
# 1. Implement your signal
# Edit src/signal/create_signal.py with your logic
make create-signal
# 2. View equal-weight performance
make ew-dash
# 3. Run backtest
make run-backtest
# 4. View optimized performance
make opt-dashThe following files are templates and should not be modified:
src/framework/ew_dash.py- Equal-weight comparison dashboardsrc/framework/opt_dash.py- Optimized portfolio dashboardsrc/framework/run_backtest.py- Backtest runner
If you want to edit the marimo notebooks use:
uv run marimo edit src/framework/{}_dash.pyAll signal customization happens in src/signal/create_signal.py.
All configuration is managed through the .env file (copied from .env.example):
SIGNAL_PATH: Where to save your generated signal (relative or absolute path)WEIGHT_DIR: Where backtest results will be savedLOG_DIR: Where backtest logs will be savedSIGNAL_NAME: Name for your signalGAMMA: Risk aversion / transaction cost parameterEMAIL: Your BYU email for job notificationsCONSTRAINTS: Portfolio constraints as JSON array (e.g.,["ZeroBeta", "ZeroInvestment"])SLURM_N_CPUS: Number of CPU cores for cluster jobsSLURM_MEM: Memory allocation for cluster jobsSLURM_TIME: Time limit for cluster jobsSLURM_MAIL_TYPE: Email notifications (BEGIN, END, FAIL)SLURM_MAX_CONCURRENT_JOBS: Maximum parallel jobs
Note: Do not edit src/framework/run_backtest.py directly. All configuration comes from .env.
- Implement your signal logic in
src/signal/create_signal.py - Run
make create-signalto generate your signal - Compare against baseline with
make ew-dash - Run backtest with
make run-backtest - Analyze optimized results with
make opt-dash - Iterate and refine your approach
If you're maintaining the template repository and need to release updates:
-
Update the VERSION file with the new semantic version (e.g.,
1.0.1for bug fixes,1.1.0for new features)- Follow Semantic Versioning:
MAJOR.MINOR.PATCH
- Follow Semantic Versioning:
-
Update CHANGELOG.md with what changed
- Use the format: Added, Changed, Deprecated, Removed, Fixed, Security
-
Commit and push your changes to the main branch
git add VERSION CHANGELOG.md [other files] git commit -m "chore: release v1.0.1" git push
- The template sync workflow automatically runs every Monday
- All repositories created from this template will receive a pull request with the updates
- Users can review, merge, or customize the changes as needed
For more details, see CHANGELOG.md.
Note: This is a template project. Customize src/signal/create_signal.py with your unique signal logic, then use the workflow above to backtest your ideas.