Add Linux-native cTrader cBot build/run scaffold
Build cBots in C# and compile them to .algo entirely on Linux via the official cTrader.Automate NuGet package + 'dotnet build' — no Windows and no cTrader desktop app. Run/backtest headless through Spotware's official cTrader console Docker image. Includes: - src/SampleCBot: example SMA-crossover cBot (SDK-style net6.0 class library) - scripts/install-dotnet.sh: root-free local .NET SDK install (~/.dotnet) - scripts/build.sh: dotnet build -> dist/<ProjectName>.algo, with a workaround for cTrader.Automate naming the .algo after the project's parent folder - scripts/run-console.sh: wrapper over ghcr.io/spotware/ctrader-console - docs/research-findings.md: sourced research; .algo verified as a proprietary 'algo'-magic container (not a ZIP); build verified end to end on Linux
This commit is contained in:
+13
@@ -0,0 +1,13 @@
|
|||||||
|
# .NET build output
|
||||||
|
bin/
|
||||||
|
obj/
|
||||||
|
dist/
|
||||||
|
|
||||||
|
# IDE
|
||||||
|
.vs/
|
||||||
|
.vscode/
|
||||||
|
.idea/
|
||||||
|
*.user
|
||||||
|
|
||||||
|
# Local tool installs
|
||||||
|
.dotnet/
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
# cTrader cBot scaffold — project rules
|
||||||
|
|
||||||
|
A Linux-native toolchain for building cTrader cBots in C# and compiling them to
|
||||||
|
`.algo`, plus running/backtesting them headless via Spotware's official cTrader CLI
|
||||||
|
Docker image. No Windows, no cTrader desktop app. See `README.md` and
|
||||||
|
`docs/research-findings.md`.
|
||||||
|
|
||||||
|
## Domain facts (load-bearing, verified)
|
||||||
|
|
||||||
|
- cBots are .NET 6 class libraries referencing the **official** NuGet package
|
||||||
|
`cTrader.Automate` (owner **spotware**). Do **not** use the third-party `cAlgo.API`
|
||||||
|
package — it is not the Spotware SDK.
|
||||||
|
- `dotnet build` emits the `.algo`; the cTrader desktop app is not needed to compile.
|
||||||
|
- `.algo` is a proprietary, encrypted container (file magic = ASCII `algo`), not a ZIP.
|
||||||
|
- `cTrader.Automate` 1.0.17 names the `.algo` after the project's **parent folder**
|
||||||
|
(no override property); `scripts/build.sh` renames artifacts to `<ProjectName>.algo`.
|
||||||
|
- Run/backtest on Linux requires cTrader 5.4+ console image (`ghcr.io/spotware/ctrader-console`).
|
||||||
|
|
||||||
|
## Conventions
|
||||||
|
|
||||||
|
- Everything committed is **English** (code, comments, docs, commit messages).
|
||||||
|
- New cBots go under `src/<BotName>/`, one class-library project each.
|
||||||
|
|
||||||
|
## Skills plugin: project facts
|
||||||
|
|
||||||
|
- **Code roots:** `src/` (cBots/indicators), `scripts/` (toolchain).
|
||||||
|
- **Build command:** `./scripts/build.sh` (wraps `dotnet build -c Release`, collects
|
||||||
|
`dist/<ProjectName>.algo`). Requires the .NET SDK on PATH or in `~/.dotnet`
|
||||||
|
(`./scripts/install-dotnet.sh`).
|
||||||
|
- **Test command:** none yet (no test project). Build success + a valid `.algo`
|
||||||
|
(magic bytes `algo`) is the current acceptance check.
|
||||||
|
- **Run/backtest:** `./scripts/run-console.sh` (Docker, official cTrader console).
|
||||||
|
- **Issue tracker:** none yet.
|
||||||
@@ -0,0 +1,102 @@
|
|||||||
|
# cTrader cBots on Linux — no Windows required
|
||||||
|
|
||||||
|
Build cTrader **cBots** in C#, compile them to `.algo` files, and run/backtest them
|
||||||
|
**entirely on Linux** — no Windows, no Wine, no cTrader desktop GUI.
|
||||||
|
|
||||||
|
This repo is a working scaffold that proves the full toolchain end to end and gives
|
||||||
|
you a starting point. The build was verified on this machine: `dotnet build` against
|
||||||
|
the official `cTrader.Automate` NuGet package produces a valid `.algo` on Linux.
|
||||||
|
|
||||||
|
## TL;DR — is it really possible?
|
||||||
|
|
||||||
|
**Yes**, with two pieces, both officially supported by Spotware:
|
||||||
|
|
||||||
|
1. **Compile on Linux** (since cTrader Desktop 4.2, March 2022). A cBot is an
|
||||||
|
ordinary .NET class library that references the official `cTrader.Automate`
|
||||||
|
NuGet package. `dotnet build` runs the package's MSBuild targets, which emit the
|
||||||
|
`.algo`. No Windows, no desktop app. Spotware's own words: *"write code and
|
||||||
|
compile it on Linux or Mac."*
|
||||||
|
2. **Run/backtest on Linux** (since cTrader 5.4, ~Aug 2025) via the official
|
||||||
|
**cTrader CLI / Console** Docker image `ghcr.io/spotware/ctrader-console`. It
|
||||||
|
runs `.algo` cBots headless — live and backtest — without the desktop GUI.
|
||||||
|
|
||||||
|
The nuance worth knowing: step 2 is *recent*. Before cTrader 5.4 there was no Linux
|
||||||
|
runtime, and Spotware staff said so on the forum as late as Nov 2024. Anyone working
|
||||||
|
from older information will (incorrectly) tell you it's impossible.
|
||||||
|
|
||||||
|
See [`docs/research-findings.md`](docs/research-findings.md) for the sourced details.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- The **.NET SDK** (6.0+). Nothing else is needed to compile.
|
||||||
|
Install it locally without root: `./scripts/install-dotnet.sh`
|
||||||
|
(drops it into `~/.dotnet`).
|
||||||
|
- **Docker** — only if you want to run/backtest via the official console image.
|
||||||
|
|
||||||
|
## Quickstart
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. Install the .NET SDK locally (skip if you already have `dotnet`)
|
||||||
|
./scripts/install-dotnet.sh
|
||||||
|
|
||||||
|
# 2. Compile every cBot in src/ into dist/*.algo
|
||||||
|
./scripts/build.sh
|
||||||
|
|
||||||
|
# 3. Run / backtest headless in the official cTrader console container
|
||||||
|
# (discover the exact flags for your image version first)
|
||||||
|
./scripts/run-console.sh --help
|
||||||
|
```
|
||||||
|
|
||||||
|
After step 2 you get `dist/SampleCBot.algo` — a ready `.algo` you can also import
|
||||||
|
into the cTrader desktop/web app directly.
|
||||||
|
|
||||||
|
## Repo layout
|
||||||
|
|
||||||
|
```
|
||||||
|
src/SampleCBot/ A complete example cBot (SMA crossover)
|
||||||
|
SampleCBot.csproj SDK-style class library referencing cTrader.Automate
|
||||||
|
SmaCrossOverBot.cs The Robot class
|
||||||
|
scripts/
|
||||||
|
install-dotnet.sh Local, root-free .NET SDK install (~/.dotnet)
|
||||||
|
build.sh dotnet build -> collects dist/<ProjectName>.algo
|
||||||
|
run-console.sh Thin wrapper over ghcr.io/spotware/ctrader-console
|
||||||
|
dist/ Built .algo artifacts (gitignored)
|
||||||
|
docs/research-findings.md What the research established, with sources
|
||||||
|
```
|
||||||
|
|
||||||
|
## How it works
|
||||||
|
|
||||||
|
**Build.** A cBot project is a normal `Microsoft.NET.Sdk` class library targeting
|
||||||
|
`net6.0` with a single `<PackageReference Include="cTrader.Automate" />`. The package
|
||||||
|
ships MSBuild `.targets` that, after a successful compile, bundle the assembly into the
|
||||||
|
proprietary, encrypted `.algo` container (file magic: the ASCII bytes `algo`). The
|
||||||
|
`.algo` lands in `bin/<config>/<tfm>/`; `build.sh` collects it into `dist/`.
|
||||||
|
|
||||||
|
**Run.** `run-console.sh` mounts `dist/` into Spotware's official console container at
|
||||||
|
`/mnt/Robots` and forwards your arguments to the cTrader CLI, which hosts the `.algo`
|
||||||
|
live or in backtest without the desktop app.
|
||||||
|
|
||||||
|
## To add your own cBot
|
||||||
|
|
||||||
|
1. `dotnet new classlib --name MyBot --output src/MyBot`
|
||||||
|
2. `cd src/MyBot && dotnet add package cTrader.Automate`
|
||||||
|
3. Write a `class MyBot : Robot` (`using cAlgo.API;`) — see `SmaCrossOverBot.cs`.
|
||||||
|
4. `./scripts/build.sh` → `dist/MyBot.algo`.
|
||||||
|
|
||||||
|
## Known quirk (handled)
|
||||||
|
|
||||||
|
`cTrader.Automate` 1.0.17 names the raw `.algo` after the project's **parent folder**,
|
||||||
|
not the project — so multiple bots would collide on one name. `build.sh` works around
|
||||||
|
this by renaming each collected artifact to `<ProjectName>.algo`. (The bot's name shown
|
||||||
|
inside cTrader comes from the class metadata, not the file name, so this is cosmetic.)
|
||||||
|
|
||||||
|
## Limitations
|
||||||
|
|
||||||
|
- The cTrader **desktop app** itself is Windows/macOS only — but you don't need it for
|
||||||
|
this workflow.
|
||||||
|
- Must be a **modern .NET 6 algo** (cTrader 4.8+). Legacy .NET Framework cAlgo bots
|
||||||
|
must be recompiled.
|
||||||
|
- **Live trading** requires a real broker account + cTrader ID credentials passed to
|
||||||
|
the console.
|
||||||
|
- The `.algo` format is proprietary/encrypted by Spotware; this scaffold goes *through*
|
||||||
|
the official package — there is no independent open-source `.algo` packer.
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 17
|
||||||
|
VisualStudioVersion = 17.0.31903.59
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{49D31EB1-4380-417B-A69E-0F21240EFC29}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SampleCBot", "src\SampleCBot\SampleCBot.csproj", "{CE1934B5-C4C0-474D-874F-575A8436A27C}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{CE1934B5-C4C0-474D-874F-575A8436A27C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{CE1934B5-C4C0-474D-874F-575A8436A27C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{CE1934B5-C4C0-474D-874F-575A8436A27C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{CE1934B5-C4C0-474D-874F-575A8436A27C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(NestedProjects) = preSolution
|
||||||
|
{CE1934B5-C4C0-474D-874F-575A8436A27C} = {49D31EB1-4380-417B-A69E-0F21240EFC29}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
||||||
@@ -0,0 +1,111 @@
|
|||||||
|
# Research: building & running cTrader cBots without Windows
|
||||||
|
|
||||||
|
This documents what was established before building the scaffold in this repo. The two
|
||||||
|
load-bearing claims were each adversarially fact-checked (the verifier was instructed to
|
||||||
|
*refute* them); both came back **CONFIRMED**. Where a fact was verified locally on this
|
||||||
|
machine rather than only from the web, it is marked **[verified locally]**.
|
||||||
|
|
||||||
|
## The claim under test
|
||||||
|
|
||||||
|
> It is possible to create cTrader cBots directly in C# with no Windows, produce `.algo`
|
||||||
|
> files, and run them in a container.
|
||||||
|
|
||||||
|
**Verdict: true**, in two officially-supported halves — but the second half is recent
|
||||||
|
enough that older sources (and people relying on them) say it's impossible.
|
||||||
|
|
||||||
|
## The era split (why answers conflict)
|
||||||
|
|
||||||
|
| Era | Build | Run on Linux |
|
||||||
|
|---|---|---|
|
||||||
|
| Old **cAlgo**, .NET Framework 4.x (≤ cTrader 4.1, pre-2022) | Windows-only `cTrader.exe /compile` (Spotware: *"not actually supported"*) | No |
|
||||||
|
| Modern **cTrader Automate**, .NET 6 (cTrader 4.2+, Mar 2022) | `dotnet build` + `cTrader.Automate` NuGet — cross-platform | Desktop only at first; **Linux Docker since cTrader 5.4 (~Aug 2025)** |
|
||||||
|
|
||||||
|
cTrader Desktop 4.2 (30 Mar 2022) *"removed any dependency from the cTrader application
|
||||||
|
for the build process"* and let developers *"compile cBots and indicators using the
|
||||||
|
'dotnet build' command and even write code and compile it on Linux or Mac."*
|
||||||
|
|
||||||
|
## 1. Compiling `.algo` on Linux — CONFIRMED
|
||||||
|
|
||||||
|
- **Official SDK package:** `cTrader.Automate` on NuGet, owner **spotware**
|
||||||
|
(Spotware Systems Ltd.). Description: *"Provides cTrader Automate SDK to build cBots
|
||||||
|
and Indicators in ALGO format."* Multi-targets **net6.0+** and net40, **no
|
||||||
|
dependencies** → installs and runs fine via `dotnet` on Linux. (Latest seen: 1.0.17,
|
||||||
|
2026-03-27.)
|
||||||
|
- **Mechanism:** the package ships MSBuild `.targets`. Building a class library that
|
||||||
|
references it and contains an algo type (a class deriving from `Robot`/`Indicator`)
|
||||||
|
bundles the compiled assembly into the `.algo`. **[verified locally]** — a clean
|
||||||
|
`dotnet build -c Release` on this Linux box produced a valid `.algo` with **0 errors**.
|
||||||
|
- **What you need on Linux:** just the .NET SDK + NuGet access. No Windows, no Wine, no
|
||||||
|
cTrader desktop.
|
||||||
|
- **Beware the name collision:** there is a *separate* third-party NuGet package
|
||||||
|
`cAlgo.API` (owner `st.alexofgod`, MIT). It is **not** the Spotware SDK. Use
|
||||||
|
`cTrader.Automate`.
|
||||||
|
|
||||||
|
### Build verified, plus a local finding
|
||||||
|
|
||||||
|
- The `.algo` filename quirk: `cTrader.Automate` 1.0.17 names the output after the
|
||||||
|
**parent directory of the project folder** — `_AlgoFileName =
|
||||||
|
GetFileName(GetDirectoryName(MSBuildProjectDirectory))` in its
|
||||||
|
`cTrader.Automate.targets`, with no override property. **[verified locally]** Two bots
|
||||||
|
in one folder collide; this repo renames artifacts in `build.sh`.
|
||||||
|
- **`.algo` format — what it actually is. [verified locally]** A built `.algo` begins
|
||||||
|
with the ASCII magic bytes `algo` (`61 6c 67 6f`) and is **not** a ZIP (no `PK` header,
|
||||||
|
no central directory). So it is Spotware's own proprietary container, not a renamed
|
||||||
|
archive — settling a question the web sources left open. Per Spotware it wraps the
|
||||||
|
compiled assembly (+ referenced DLLs, + optional source/symbols) and is encrypted; the
|
||||||
|
encryption algorithm is undisclosed and there is no public byte-level spec.
|
||||||
|
|
||||||
|
## 2. Running `.algo` headless in a container — CONFIRMED (recent)
|
||||||
|
|
||||||
|
- **Official runner:** **cTrader CLI / Console**, distributed as a Linux Docker image
|
||||||
|
`ghcr.io/spotware/ctrader-console` (repo `spotware/ctrader-console-docker`). Docs:
|
||||||
|
it *"enables traders to manage account and algo-trading operations directly from a
|
||||||
|
console or terminal without launching or relying on the regular cTrader application"*
|
||||||
|
and *"is available as a Linux Docker image … All cTrader CLI features are available
|
||||||
|
when using the Docker image, including backtesting."* Mount `.algo` files to
|
||||||
|
`/mnt/Robots`.
|
||||||
|
- **Recency caveat:** available only in **cTrader 4.8+**, works only with **modern .NET 6
|
||||||
|
algos**, and the Linux image arrived with **cTrader 5.4 (~Aug 2025)**. As late as
|
||||||
|
**Nov 2024** a Spotware moderator wrote *"Unfortunately cTrader CLI is not supported on
|
||||||
|
Linux"*, and DIY Wine/Mono attempts failed. So pre-2025 sources correctly said it was
|
||||||
|
impossible — this is the single most likely source of disagreement.
|
||||||
|
- The runner is a **host, not a compiler** — it runs/backtests `.algo` files; it does not
|
||||||
|
build them. Compilation is the `dotnet build` step above.
|
||||||
|
|
||||||
|
## 3. cTrader Automate vs. Open API (don't conflate)
|
||||||
|
|
||||||
|
Two different products that can both run on headless Linux:
|
||||||
|
|
||||||
|
- **cTrader Automate (cBots / `.algo`)** — the strategy framework (`cAlgo.API`,
|
||||||
|
indicators, backtesting, optimization). Runs *inside* the cTrader runtime / the cTrader
|
||||||
|
CLI. This is what this repo targets.
|
||||||
|
- **cTrader Open API** — a *separate* protocol (Protobuf over TLS/TCP or WebSocket, OAuth2;
|
||||||
|
endpoints `live.ctraderapi.com` / `demo.ctraderapi.com`) for **external** apps that
|
||||||
|
connect to a broker backend. Official SDKs: .NET (`cTrader.OpenAPI.Net`) and Python
|
||||||
|
(`ctrader-open-api`); language-neutral otherwise. It gives you trading + market data +
|
||||||
|
account access, but **no** cBot framework, indicators, or backtesting — you write all
|
||||||
|
strategy logic yourself.
|
||||||
|
|
||||||
|
Choose **Automate + cTrader CLI** to reuse the cBot framework and backtesting on Linux;
|
||||||
|
choose **Open API** for a fully standalone, language-flexible service.
|
||||||
|
|
||||||
|
## Limitations / honesty notes
|
||||||
|
|
||||||
|
- The cTrader **desktop app** is Windows/macOS only — not needed for this workflow, but
|
||||||
|
there is no native Linux *desktop*.
|
||||||
|
- **Live** trading needs a broker account + cTrader ID credentials.
|
||||||
|
- The `.algo` container is proprietary and encrypted; any legitimate Linux build goes
|
||||||
|
*through* the official `cTrader.Automate` package — there is no independent OSS packer.
|
||||||
|
- cTrader's docs/tooling move quickly; version numbers above reflect mid-2026.
|
||||||
|
|
||||||
|
## Key sources
|
||||||
|
|
||||||
|
- cTrader Desktop 4.2 release — https://www.spotware.com/news/ctrader-desktop-4-2/
|
||||||
|
- Use Visual Studio and other IDEs — https://help.ctrader.com/ctrader-algo/documentation/visual-studio-ides/
|
||||||
|
- Compiler (MSBuild properties) — https://help.ctrader.com/ctrader-algo/documentation/all-algos/compiling/
|
||||||
|
- cTrader CLI — https://help.ctrader.com/ctrader-algo/documentation/ctrader-cli/
|
||||||
|
- Console Docker image — https://github.com/spotware/ctrader-console-docker
|
||||||
|
- `cTrader.Automate` package — https://www.nuget.org/packages/cTrader.Automate/
|
||||||
|
- Algo security measures (encryption) — https://help.ctrader.com/ctrader-algo/documentation/protection-measures/
|
||||||
|
- Open API getting started — https://help.ctrader.com/open-api/
|
||||||
|
- Forum: Linux not supported (Nov 2024) — https://community.ctrader.com/forum/ctrader-algo/45395/
|
||||||
Executable
+50
@@ -0,0 +1,50 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# Compile every cBot/indicator project in src/ into .algo files — on Linux, with
|
||||||
|
# no Windows and no cTrader desktop app. The .algo files are collected into dist/.
|
||||||
|
#
|
||||||
|
# Usage: ./scripts/build.sh [Release|Debug] # defaults to Release
|
||||||
|
#
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
|
CONFIG="${1:-Release}"
|
||||||
|
|
||||||
|
# Pick up the locally-installed SDK (see scripts/install-dotnet.sh).
|
||||||
|
export DOTNET_ROOT="${DOTNET_ROOT:-$HOME/.dotnet}"
|
||||||
|
export PATH="$DOTNET_ROOT:$PATH"
|
||||||
|
export DOTNET_CLI_TELEMETRY_OPTOUT=1
|
||||||
|
export DOTNET_NOLOGO=1
|
||||||
|
|
||||||
|
if ! command -v dotnet >/dev/null 2>&1; then
|
||||||
|
echo "dotnet not found. Run ./scripts/install-dotnet.sh first." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
SLN="$REPO_ROOT/cTraderBots.sln"
|
||||||
|
if [[ ! -f "$SLN" ]]; then
|
||||||
|
echo ">> Creating solution and adding projects..."
|
||||||
|
dotnet new sln --name cTraderBots --output "$REPO_ROOT"
|
||||||
|
find "$REPO_ROOT/src" -name '*.csproj' -print0 \
|
||||||
|
| xargs -0 -I{} dotnet sln "$SLN" add {}
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ">> Building ($CONFIG)..."
|
||||||
|
dotnet build "$SLN" --configuration "$CONFIG"
|
||||||
|
|
||||||
|
DIST="$REPO_ROOT/dist"
|
||||||
|
mkdir -p "$DIST"
|
||||||
|
|
||||||
|
# Collect artifacts. cTrader.Automate names the raw .algo after the project's parent
|
||||||
|
# folder (which collides across bots), so rename each to <ProjectName>.algo here.
|
||||||
|
while IFS= read -r -d '' csproj; do
|
||||||
|
name="$(basename "${csproj%.csproj}")"
|
||||||
|
algo="$(find "$(dirname "$csproj")/bin/$CONFIG" -name '*.algo' 2>/dev/null | head -1)"
|
||||||
|
if [[ -n "$algo" ]]; then
|
||||||
|
cp -v "$algo" "$DIST/$name.algo"
|
||||||
|
fi
|
||||||
|
done < <(find "$REPO_ROOT/src" -name '*.csproj' -print0)
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo ">> .algo artifacts in $DIST:"
|
||||||
|
ls -1 "$DIST"/*.algo 2>/dev/null || echo " (none found — check the build output above)"
|
||||||
Executable
+37
@@ -0,0 +1,37 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# Install the .NET SDK locally — no root, no system packages — into ~/.dotnet.
|
||||||
|
# This is the only prerequisite for compiling cBots into .algo files on Linux.
|
||||||
|
#
|
||||||
|
# Usage: ./scripts/install-dotnet.sh [channel] # channel defaults to 8.0
|
||||||
|
#
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
INSTALL_DIR="${DOTNET_ROOT:-$HOME/.dotnet}"
|
||||||
|
CHANNEL="${1:-8.0}"
|
||||||
|
|
||||||
|
if command -v curl >/dev/null 2>&1; then
|
||||||
|
curl -fsSL https://dot.net/v1/dotnet-install.sh -o /tmp/dotnet-install.sh
|
||||||
|
else
|
||||||
|
wget -qO /tmp/dotnet-install.sh https://dot.net/v1/dotnet-install.sh
|
||||||
|
fi
|
||||||
|
|
||||||
|
bash /tmp/dotnet-install.sh --channel "$CHANNEL" --install-dir "$INSTALL_DIR" --no-path
|
||||||
|
|
||||||
|
cat <<EOF
|
||||||
|
|
||||||
|
.NET SDK installed to $INSTALL_DIR
|
||||||
|
|
||||||
|
Add it to your shell so 'dotnet' is on PATH:
|
||||||
|
|
||||||
|
fish:
|
||||||
|
set -gx DOTNET_ROOT $INSTALL_DIR
|
||||||
|
fish_add_path $INSTALL_DIR
|
||||||
|
|
||||||
|
bash / zsh:
|
||||||
|
export DOTNET_ROOT="$INSTALL_DIR"
|
||||||
|
export PATH="\$DOTNET_ROOT:\$PATH"
|
||||||
|
|
||||||
|
(The build script picks up ~/.dotnet automatically, so this is only needed for
|
||||||
|
running 'dotnet' by hand.)
|
||||||
|
EOF
|
||||||
Executable
+38
@@ -0,0 +1,38 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# Run / backtest a compiled .algo headlessly using Spotware's OFFICIAL cTrader CLI
|
||||||
|
# Docker image — no cTrader desktop GUI, no Windows. Available since cTrader 5.4.
|
||||||
|
#
|
||||||
|
# This is a thin wrapper: it mounts your built .algo files (dist/) into the
|
||||||
|
# container at /mnt/Robots and forwards all arguments to the cTrader console.
|
||||||
|
#
|
||||||
|
# Discover the exact subcommands/flags for your image version first:
|
||||||
|
#
|
||||||
|
# ./scripts/run-console.sh --help
|
||||||
|
#
|
||||||
|
# Then backtest or run, e.g. (flag names follow the container's --help output):
|
||||||
|
#
|
||||||
|
# ./scripts/run-console.sh backtest --robot SmaCrossOverBot.algo \
|
||||||
|
# --symbol EURUSD --period h1 --start 2024-01-01 --end 2024-06-01 \
|
||||||
|
# --balance 10000
|
||||||
|
#
|
||||||
|
# Live trading additionally needs cTrader ID credentials passed to the console.
|
||||||
|
#
|
||||||
|
# Official image + documented commands:
|
||||||
|
# https://github.com/spotware/ctrader-console-docker
|
||||||
|
#
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
|
IMAGE="${CTRADER_CONSOLE_IMAGE:-ghcr.io/spotware/ctrader-console:latest}"
|
||||||
|
|
||||||
|
if ! command -v docker >/dev/null 2>&1; then
|
||||||
|
echo "docker not found — install Docker to run the cTrader console image." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
docker pull "$IMAGE"
|
||||||
|
|
||||||
|
exec docker run --rm -it \
|
||||||
|
-v "$REPO_ROOT/dist:/mnt/Robots" \
|
||||||
|
"$IMAGE" "$@"
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<!--
|
||||||
|
net6.0 is the runtime cTrader's algo host expects ("modern .NET 6 algos").
|
||||||
|
A newer SDK can still build for this target; the net6.0 reference pack is
|
||||||
|
restored from NuGet automatically.
|
||||||
|
-->
|
||||||
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
|
<LangVersion>latest</LangVersion>
|
||||||
|
<Nullable>disable</Nullable>
|
||||||
|
<ImplicitUsings>disable</ImplicitUsings>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
The cTrader.Automate MSBuild targets normally copy the produced .algo into
|
||||||
|
~/Documents/cAlgo/Sources/... — a Windows-only path. Turn that publish step
|
||||||
|
off; the .algo is still emitted into bin/<config>/<tfm>/.
|
||||||
|
-->
|
||||||
|
<AlgoPublish>false</AlgoPublish>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
NOTE on the .algo file name: cTrader.Automate 1.0.17 names the produced .algo
|
||||||
|
after the PARENT directory of the project folder (see its cTrader.Automate.targets:
|
||||||
|
_AlgoFileName = GetFileName(GetDirectoryName(MSBuildProjectDirectory))). There is
|
||||||
|
no public property to override it, and two bots under the same folder would collide.
|
||||||
|
The bot's name shown inside cTrader comes from the class/metadata, not the file name,
|
||||||
|
so this is cosmetic — but to get clean, non-colliding artifacts, scripts/build.sh
|
||||||
|
renames each collected .algo to <ProjectName>.algo when copying into dist/.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<!--
|
||||||
|
The official Spotware SDK. Its MSBuild targets are what package the compiled
|
||||||
|
assembly into the encrypted .algo container during `dotnet build`.
|
||||||
|
Owner on nuget.org must be "spotware" (do not confuse with the third-party
|
||||||
|
"cAlgo.API" package). The "1.*-*" range matches the official samples and
|
||||||
|
includes pre-release SDK builds.
|
||||||
|
-->
|
||||||
|
<PackageReference Include="cTrader.Automate" Version="1.*-*" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
using cAlgo.API;
|
||||||
|
using cAlgo.API.Indicators;
|
||||||
|
|
||||||
|
namespace SampleCBot
|
||||||
|
{
|
||||||
|
// A minimal but complete example cBot: a simple moving-average crossover.
|
||||||
|
//
|
||||||
|
// It goes long when the fast SMA crosses above the slow SMA and short on the
|
||||||
|
// opposite cross, closing any opposing position first. It is intentionally
|
||||||
|
// simple — its job is to exercise the full Linux build/run toolchain end to
|
||||||
|
// end (compile to .algo with `dotnet build`, run headless in the cTrader
|
||||||
|
// console Docker image), NOT to be a profitable strategy.
|
||||||
|
[Robot(AccessRights = AccessRights.None)]
|
||||||
|
public class SmaCrossOverBot : Robot
|
||||||
|
{
|
||||||
|
[Parameter("Fast MA Period", DefaultValue = 12, MinValue = 1, Group = "Moving Averages")]
|
||||||
|
public int FastPeriod { get; set; }
|
||||||
|
|
||||||
|
[Parameter("Slow MA Period", DefaultValue = 26, MinValue = 1, Group = "Moving Averages")]
|
||||||
|
public int SlowPeriod { get; set; }
|
||||||
|
|
||||||
|
[Parameter("Volume (lots)", DefaultValue = 0.01, MinValue = 0.01, Step = 0.01, Group = "Trade")]
|
||||||
|
public double VolumeInLots { get; set; }
|
||||||
|
|
||||||
|
[Parameter("Stop Loss (pips)", DefaultValue = 20, MinValue = 0, Group = "Trade")]
|
||||||
|
public double StopLossPips { get; set; }
|
||||||
|
|
||||||
|
[Parameter("Take Profit (pips)", DefaultValue = 40, MinValue = 0, Group = "Trade")]
|
||||||
|
public double TakeProfitPips { get; set; }
|
||||||
|
|
||||||
|
private const string Label = "SmaCrossOverBot";
|
||||||
|
|
||||||
|
private SimpleMovingAverage _fastMa;
|
||||||
|
private SimpleMovingAverage _slowMa;
|
||||||
|
|
||||||
|
protected override void OnStart()
|
||||||
|
{
|
||||||
|
_fastMa = Indicators.SimpleMovingAverage(Bars.ClosePrices, FastPeriod);
|
||||||
|
_slowMa = Indicators.SimpleMovingAverage(Bars.ClosePrices, SlowPeriod);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnBar()
|
||||||
|
{
|
||||||
|
// Compare the two most recently *closed* bars. Index 1 is the last
|
||||||
|
// closed bar; index 2 the one before it. (Index 0 is still forming.)
|
||||||
|
var fastPrev = _fastMa.Result.Last(2);
|
||||||
|
var slowPrev = _slowMa.Result.Last(2);
|
||||||
|
var fastNow = _fastMa.Result.Last(1);
|
||||||
|
var slowNow = _slowMa.Result.Last(1);
|
||||||
|
|
||||||
|
var crossedUp = fastPrev <= slowPrev && fastNow > slowNow;
|
||||||
|
var crossedDown = fastPrev >= slowPrev && fastNow < slowNow;
|
||||||
|
|
||||||
|
if (crossedUp)
|
||||||
|
EnterMarket(TradeType.Buy);
|
||||||
|
else if (crossedDown)
|
||||||
|
EnterMarket(TradeType.Sell);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EnterMarket(TradeType direction)
|
||||||
|
{
|
||||||
|
var ours = Positions.FindAll(Label, SymbolName);
|
||||||
|
|
||||||
|
// Close any of our positions pointing the other way; bail out if we
|
||||||
|
// already hold one in the desired direction.
|
||||||
|
foreach (var position in ours)
|
||||||
|
{
|
||||||
|
if (position.TradeType != direction)
|
||||||
|
ClosePosition(position);
|
||||||
|
else
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var volume = Symbol.QuantityToVolumeInUnits(VolumeInLots);
|
||||||
|
double? stopLoss = StopLossPips > 0 ? StopLossPips : (double?)null;
|
||||||
|
double? takeProfit = TakeProfitPips > 0 ? TakeProfitPips : (double?)null;
|
||||||
|
|
||||||
|
ExecuteMarketOrder(direction, SymbolName, volume, Label, stopLoss, takeProfit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user