Everything on this page is published for educational and informational purposes only. Nothing here is investment, financial, legal, tax, or trading advice, a recommendation to buy or sell any security or contract, or a solicitation of any kind. Trading futures, options, equities, and crypto involves substantial risk of loss and is not suitable for every investor. Past performance — including any backtests, demos, or examples shown — does not guarantee future results. Consult a licensed professional before acting on anything you read here.
Code, terminal, Git. The floor every automator stands on.
Trading automation tutorials skip the boring stuff: which language, which shell, which Git command. This module starts at zero and gets you to a working environment, a clean commit, and the eight failure modes you will absolutely hit. No paywall, no upsell, no login.
Four languages. One task. The same five concepts.
Every automation language hits the same five concepts: variable, conditional, broker call, position size, logging. Once you see the pattern in one, the rest are just different syntax for the same shape.
One task. Four languages. Same five concepts.
Buy when RSI < 30, exit when RSI > 70. Compare the syntax — then read the bottom table to confirm the concepts are the same in all four.
import logging
from alpaca.trading.client import TradingClient
from alpaca.trading.requests import MarketOrderRequest
from alpaca.trading.enums import OrderSide, TimeInForce
import pandas as pd
log = logging.getLogger("rsi-strategy")
client = TradingClient(API_KEY, API_SECRET, paper=True)
def rsi(series: pd.Series, period: int = 14) -> float:
delta = series.diff()
gain = delta.clip(lower=0).rolling(period).mean()
loss = -delta.clip(upper=0).rolling(period).mean()
rs = gain / loss
return float(100 - (100 / (1 + rs.iloc[-1])))
def on_bar(symbol: str, closes: pd.Series) -> None:
value = rsi(closes)
pos_qty = get_position_qty(symbol) # 0 if flat
if value < 30 and pos_qty == 0:
log.info("rsi_buy", extra={"symbol": symbol, "rsi": value})
client.submit_order(MarketOrderRequest(
symbol=symbol, qty=100,
side=OrderSide.BUY,
time_in_force=TimeInForce.DAY,
))
elif value > 70 and pos_qty > 0:
log.info("rsi_exit", extra={"symbol": symbol, "rsi": value})
client.submit_order(MarketOrderRequest(
symbol=symbol, qty=pos_qty,
side=OrderSide.SELL,
time_in_force=TimeInForce.DAY,
))You want one language for research, backtesting, and live trading. The richest ecosystem for data science and the cleanest broker SDKs in 2026.
You need sub-millisecond execution or you live inside a chart-first platform like NinjaTrader.
| concept | Python | Pine | C# | MQL5 |
|---|---|---|---|---|
| Variable | x = 10 | x = 10 | int x = 10; | int x = 10; |
| Conditional | if rsi < 30: | if value < 30 | if (value < 30) { | if (value < 30) { |
| Buy order | client.submit_order(MarketOrderRequest(...)) | strategy.entry("Long", strategy.long) | EnterLong(100, "tag"); | trade.Buy(0.10, _Symbol); |
| Position size | qty=100 | default_qty_value=100 | EnterLong(100, ...) | input double Lots = 0.10; |
| Logging | log.info('rsi_buy', extra=...) | alert("rsi_buy", ...) | Print($"rsi_buy ..."); | PrintFormat("rsi_buy ..."); |
The shell. Stop being afraid of the black box.
Six categories, fifty commands. Each one has a one-line explanation written for someone who has never opened a terminal. Filter, search, copy — it is built to live in a second monitor while you work.
50 terminal commands every automator should know
Every command is copy-able. Every one has a one-line explanation written for someone who has never opened a shell. Filter or search to find what you need.
$ pwdPrint your current working directory. Where am I?
$ ls -lahList every file in the current directory, hidden ones included, with size and date.
$ cd ~/projects/botMove into a folder. `~` is your home directory.
→ cd ~ goes home; cd .. goes up one.
$ cd -Jump back to the previous directory you were in. Saves a lot of typing.
$ tree -L 2Show a folder tree two levels deep. Best way to understand a new repo.
→ Install on macOS: brew install tree
$ open .Open the current folder in Finder (macOS) — useful when you live in the terminal but need to drop a file.
$ cat strategy.pyDump the whole file to the screen. Fine for short configs, awful for logs.
$ less strategy.pyScroll through a file one page at a time. Press q to quit, / to search.
$ head -n 50 trades.csvShow the first 50 lines of a file. Use `tail` for the last 50.
$ tail -f bot.logWatch a log file grow in real time. Best command in this whole list for live debugging.
$ grep 'ERROR' bot.logFind every line containing ERROR. Add -r to search a whole folder.
$ find . -name '*.py'Find every Python file in this folder and its subfolders.
$ wc -l trades.csvCount the lines in a file. Use to sanity-check 'did all 1000 trades export?'
$ diff a.json b.jsonShow what changed between two files. Add -u for the unified diff format devs are used to.
$ cp config.example.yaml config.yamlCopy a file. `cp -r src/ backup/` copies a whole folder.
$ mv old.py new.pyRename or move a file. Same command for both.
$ rm trades.csvDelete a file. No undo. No trash can.
⚠ rm -rf is permanent and ruthless. Type the path twice before you press enter.
$ python bot.pyRun a Python script in the foreground. Ctrl+C stops it.
$ python bot.py &Run a Python script in the background. The shell prints a job number.
$ nohup python bot.py > bot.log 2>&1 &Run a script in the background AND keep it running after you log out. Output goes to bot.log.
$ ps aux | grep pythonList every Python process running on this machine. Great for 'is my bot actually alive?'
$ kill 12345Stop process 12345 politely. If it refuses, use `kill -9 12345` to force-stop.
$ topLive dashboard of CPU and memory by process. q to quit. `htop` is the prettier modern version.
$ watch -n 1 'curl -s localhost:8000/health'Re-run a command every second. Excellent for watching a healthcheck during deploys.
$ tmux new -s botOpen a persistent terminal session called 'bot'. Detach with Ctrl+b then d. Reattach later with `tmux attach -t bot`.
$ curl https://api.alpaca.markets/v2/clockFire a single HTTP request and print the response. The Swiss army knife of API testing.
$ curl -X POST -H 'Content-Type: application/json' -d '{...}' URLPOST JSON to an endpoint. The shape every webhook handler should respond to.
$ curl -i URLInclude response headers. Use when you want to see status codes, rate limits, or Content-Type.
$ lsof -i :8000Which process is holding port 8000? Indispensable when a server won't start.
$ netstat -an | grep LISTENList every port your machine is listening on. The honest answer to 'what services do I have running?'
$ ping api.alpaca.marketsMeasure round-trip latency to a host. Stop the test with Ctrl+C.
$ dig api.alpaca.marketsResolve a domain to its IP and see TTL. Helpful when DNS is the bug.
$ ssh ubuntu@your-vpsConnect to a remote machine. Set up SSH keys first; never type the password over and over.
$ scp bot.py ubuntu@vps:~/bot/Copy a file to a remote server over SSH. Same syntax in reverse to pull files down.
$ git statusWhat changed since the last commit? The command you run twenty times an hour.
$ git diffShow every unstaged change line by line. Add `--cached` to see staged changes.
$ git add -pStage changes one hunk at a time, accepting or rejecting each. The grown-up way to commit.
$ git commit -m 'risk: cap daily loss at 2%'Save a snapshot with a message. Keep messages short, present tense, and scoped.
$ git log --oneline -20Show the last 20 commits, one per line. The fastest way to remember what you shipped.
$ git checkout -b feat/new-strategyCreate and switch to a new branch. Always branch before risky changes.
$ git stashSet aside uncommitted changes so you can switch branches cleanly. `git stash pop` brings them back.
$ git pull --rebaseFetch and replay your commits on top of the remote. Cleaner history than a default merge pull.
$ python --versionConfirm which Python you are about to use. Surprises here cause hours of debugging.
$ python -m venv .venvCreate an isolated environment in the current folder. Always per-project, never global.
$ source .venv/bin/activateActivate the venv. Your prompt usually shows the env name when it worked.
$ pip install -r requirements.txtInstall every dependency listed in requirements.txt into the active env.
$ pip freeze > requirements.txtWrite every installed package into requirements.txt so the env is reproducible.
$ python -m pip install --upgrade pipUpdate pip itself. Do this before installing anything else after creating a venv.
$ python -m pytest tests/Run the test suite. Run tests before pushing — every time.
$ python -m ipythonOpen a much better Python REPL. Tab completion, history, and rich tracebacks.
Ten steps from clean main to merged PR. The only workflow you need.
You only need ten commands to ship safely. Memorize the order. Internalize the rationale. The cheat sheet covers the other ninety-nine percent of day-to-day work.
One feature, ten commands, from clean main to merged PR
This is the only Git workflow you need to memorize. Click any step to see what it does and why it matters. The cheat sheet below covers the other 99% of day-to-day commands.
Sync main
$ git checkout main && git pull --rebaseStart from a clean, up-to-date `main` branch.
If you branch off a stale main, you fight merge conflicts later for no reason.
Always use --rebase on main so your local merges do not pollute history.
The 20 commands you will actually run
| category | command | what it does |
|---|---|---|
| Setup | git clone <url> | Download a repo for the first time. |
| Setup | git config user.email 'you@example.com' | Set the email attached to every commit you make in this repo. |
| Daily | git status | What has changed since the last commit? |
| Daily | git diff | Line-by-line view of unstaged changes. |
| Daily | git add <file> | Stage one file. `git add -p` stages by hunk. |
| Daily | git commit -m '...' | Snapshot the staged changes. |
| Daily | git push | Send commits to the remote. |
| Daily | git pull --rebase | Fetch remote and replay your commits on top. |
| Branches | git checkout -b name | Create and switch to a new branch. |
| Branches | git branch -d name | Delete a merged local branch. |
| Branches | git checkout main | Switch back to the main branch. |
| Branches | git merge name | Merge a branch into the current one. |
| History | git log --oneline -20 | Show the last 20 commits, one per line. |
| History | git blame <file> | Who last touched each line, and when? |
| History | git show <sha> | Show the full diff for a commit. |
| Undo | git restore <file> | Throw away unstaged changes to a file. No undo. |
| Undo | git reset HEAD <file> | Unstage a file without losing your edits. |
| Undo | git commit --amend | Edit the last commit. Do NOT amend something you already pushed. |
| Undo | git revert <sha> | Add a new commit that undoes an old one. Safe in shared history. |
| Stash | git stash | Tuck uncommitted work aside so you can switch branches. |
| Stash | git stash pop | Bring back the most recent stash. |
Three environments. From zero to working in under five minutes.
Python venv for 80% of automators. Node + nvm when you build the webhook receiver in JavaScript. Docker Compose when you ship the whole thing as a container. Pick one, copy the commands, verify, move on.
From zero to a working environment in three commands or less
Pick the runtime that matches the stack you chose in the Decision Tree. Every command is copy-able. Every step has a one-line explanation of why it exists.
You write the strategy in Python, run backtests in pandas, and hit the broker REST API directly. Default for 80% of retail automators.
- // step 1
$ mkdir bot && cd botMake a project folder and step into it. Every bot lives in its own folder.
- // step 2
$ python -m venv .venvCreate a virtual environment in `.venv`. The leading dot hides it from `ls`.
- // step 3
$ source .venv/bin/activateActivate the venv. On Windows PowerShell, use `.\.venv\Scripts\Activate.ps1`. Your prompt should now start with `(.venv)`.
- // step 4
$ python -m pip install --upgrade pipUpdate pip itself before installing anything else. Skips a lot of warnings.
- // step 5
$ pip install alpaca-py pandas python-dotenvInstall the bare-minimum dependencies for a US-equities bot. Add more as you need them.
- // step 6
$ pip freeze > requirements.txtPin every installed package into requirements.txt. This file gets committed to Git; the .venv folder does not.
- // step 7
$ echo '.venv\n.env\n__pycache__' > .gitignoreTell Git to ignore your environment, secrets, and Python cache. Do this on day one.
$ python -c 'import alpaca; print(alpaca.__version__)'Prints the installed version. If you see ModuleNotFoundError, your venv is not activated.
- ›macOS or Linux terminal (Windows: use WSL2 or Git Bash)
- ›Python 3.10 or newer installed (`python --version` to check)
- ›A code editor (VS Code is free and excellent)
- `python: command not found`→ On macOS try `python3` instead. On Windows install Python from python.org and check the 'Add to PATH' box during install.
- `pip install` is hung→ Network or DNS. Add `--default-timeout=60` to pip, or switch to a different network. Corporate VPNs frequently block PyPI.
- Activated venv but `pip list` is empty→ You activated, then a hook (oh-my-zsh, conda) re-pointed your shell. Run `which python` — it should be inside `.venv/bin/`.
Eight ways your bot will fail. Every one of them happens.
From years of post-mortems: the symptom you actually see, the root causes ranked by likelihood, the diagnostic command, the canonical fix, and how to prevent it from happening again.
Eight ways your bot fails. Every one of them happens.
For each scenario: the symptom you actually observe, the root causes ranked by likelihood, the diagnostic command, and the canonical fix. Bookmark this page now — you will be back.
2× position, 2× margin, 2× P&L variance. Risk math is now silently wrong.
- 1No idempotency key on the webhook handlerPlatform retries on 5xx or timeout. Without a dedupe key in Redis, both attempts execute.
- 2Strategy fires on both bar-close and tick-closeCommon in TradingView Pine when `process_orders_on_close` is true but alerts also fire intra-bar.
- 3Two instances of the bot runningYou started the bot, restarted it, but never killed the original. `ps aux | grep python` will reveal it.
$ grep -c 'order_submitted' bot.log | headCount should match the number of signal events. If higher, something is firing twice.
Wrap order submission in `SETNX <idem_key> EX 60` in Redis. Reject anything you have already seen in the last 60 seconds. This is the #1 risk gate from the flowchart — wire it first.
Add a unit test that re-submits the same payload twice and asserts the broker is only called once.
Take it offline. 31 pages. No login. Free.
The full Coding Fundamentals module, formatted for print or tablet, with every command, every diagram, and every failure scenario in one PDF. Same content as the web — just takes up less screen real estate when you are coding next to it.
This is one of six modules in the Nexural Automation curriculum. The library page maps every module, shows the dependency graph, and links the master 14-page Curriculum Index PDF.
browse the full PDF library →