A Qt 6 desktop app to trade eToro instruments — indices (SPX500, NSDQ100,
GER40, …), forex, commodities and eToro's thematic baskets — through the
official eToro public API
(api-portal.etoro.com, base URL
https://public-api.etoro.com/api). SPX500 is merely the start-up default;
the instrument selector switches everything live.
Purpose: placing a trade with stop-loss and take-profit through the eToro web interface takes quite a few steps. This app puts everything on one screen — amount, leverage and auto-proposed SL/TP are always ready, so a trade is two deliberate clicks away — and it shows upcoming market events plus a battery of indicators and independent sources that suggest when to buy or sell (and, just as importantly, when to stay out).
It provides:
- an instrument selector with a live time chart of the selected instrument (Qt Charts) and a leverage screener across all instruments;
- an amount field, a leverage selector and auto-proposed SL/TP;
- BUY and SELL buttons (double-press guarded) to open a market position;
- a table of open trades with live P/L, editable SL/TP and marked-close;
- a decision window: multi-source composite call per instrument (technical ensemble, TradingView, news, VIX regime, Fear & Greed, Yahoo intraday, optional Claude synthesis) plus a costed trade plan;
- closed-trades history (7–13 weeks) with cost accounting, a macro-economic event calendar with activity proposals, and an activity log.
If no API keys are configured it runs in a clearly-labelled SIMULATION mode with a synthetic price feed, so it is fully usable before you have credentials.
The full quality pipeline runs natively on both Linux and Windows. Each
*.sh entry point has a one-to-one PowerShell counterpart; see
docs/windows.md for the complete tool mapping and the
Windows-specific notes.
On a naked Debian/Ubuntu Linux, ./setup.sh installs every required tool
and dependency (compilers, CMake, Qt 6 incl. Charts via aqtinstall, the
clang-18/LLVM tooling, cppcheck/clazy/valgrind/lcov, lizard, PMD, Doxygen +
Java, StrictDoc/Doorstop) idempotently; ./setup.sh update brings them to their
latest versions and ./setup.sh status reports what is present. On Windows,
.\setup.ps1 does the same through winget + pip + aqtinstall. License-bound
tools (Axivion Suite, Squish Coco) are detected and reported but must be
installed manually.
The repository has three top-level entry points:
./build_all.sh # everything: app, tests, traceability, docs,
# coverage, static analysis, sanitizers, Axivion,
# and the PDF quality report
./build_all.sh app # ONLY the TradingApp executable (build/TradingApp)
./build_all.sh build test # any subset of stages, in order
./build_all.sh --skip axivion # everything except the (slow) Axivion analysis
./clean_all.sh [--deep] # remove everything generated.\setup.ps1 # provision/verify the Windows toolchain
.\build_all.ps1 # same stages, same order
.\build_all.ps1 build test # any subset of stages
.\build_all.ps1 -Skip axivion # everything except the (slow) Axivion analysis
.\clean_all.ps1 [-Deep] # remove everything generatedStages: build test trace docs coverage analysis sanitize axivion report
(default: all, continuing past failing stages with a summary at the end); the
last one writes downloads/TradingApp-quality-report.pdf — one colour PDF
with the run's verdict, every test function and its result, the traceability
highlights per requirement, the analyzer findings, code metrics, coverage and
the sanitizer results (tools/make_report.py, shared by both platforms); app,
release and android (APK via androiddeployqt) are extra stages that are only run when named, and build_all.ps1
additionally offers vs and deploy. For a different single CMake target:
cmake --build build --target <name>.
No licence, no problem. Stage outcomes are ok / skipped / FAILED. A
stage needing a tool that is license-bound (Axivion Suite, Squish Coco) or
otherwise absent reports skipped with a message saying what to install, and
does not fail the run — so the whole pipeline goes green on a machine with only
the free toolchain. Everything open source that the pipeline needs is
installed for you by ./setup.sh / .\setup.ps1; setup.sh status and
setup.ps1 status list what is present, what is license-bound, and what has no
counterpart on the platform.
build_all.ps1 selects the Qt kit itself (newest kit containing Qt6Charts,
MSVC preferred) and imports the Visual Studio developer environment into the
session, so no "x64 Native Tools" prompt is required. Override the kit with
$env:QT_PREFIX or -QtKit mingw_64.
Requires Qt 6 with the Widgets, Network, and Charts modules (developed against Qt 6.11.1), CMake ≥ 4.2 and a C++23-capable compiler (GCC 13+, Clang 17+, MSVC 19.38+). The sources are plain cross-platform Qt/C++ — the same code builds on Linux, Windows, and Android; only the Qt kit and the packaging step differ.
cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Debug \
-DCMAKE_PREFIX_PATH=$HOME/Qt/6.11.1/gcc_64
cmake --build build
./build/TradingAppInstall the Qt 6 msvc2022_64 kit (with the Charts module), Visual Studio 2022
(or its Build Tools), and CMake — or let .\setup.ps1 do it. Then, from an
ordinary PowerShell prompt:
.\build_all.ps1 app # -> build\TradingApp.exe
.\build_all.ps1 build test # app + tests + JUnit resultsOr by hand, from a Developer command prompt:
cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Debug `
-DCMAKE_PREFIX_PATH=C:\Qt\6.11.1\msvc2022_64
cmake --build build
build\TradingApp.exeThe MinGW kit works too: .\build_all.ps1 -QtKit mingw_64 (the matching
C:\Qt\Tools\mingw*\bin is put on PATH automatically).
CMakeLists.txt is the single description of the build, so the .sln is
generated, not committed:
.\tools\make_vs_solution.ps1 -Open # -> build-vs\TradingApp.sln
.\build_all.ps1 vs # same thing, as a named stageThe solution contains TradingApp, trading_domain, trading_services and all
12 tst_* projects in Debug/Release/RelWithDebInfo; TradingApp is the startup
project, the Qt DLL directory is already on the debugger's PATH, and
Test → Run All Tests works. Re-run the script after adding or removing source
files. Two .sln-free alternatives, both driven by
CMakePresets.json:
- File → Open → Folder on the repository root — Visual Studio offers the
windows-msvc-debugandvisual-studiopresets directly. cmake --preset windows-msvc-debug && cmake --build --preset windows-msvc-debugfrom any shell. Linux haslinux-gcc-debug/linux-gcc-releasepresets too. All presets take the Qt kit from$QT_PREFIX.
To make the built executable runnable on its own — Qt DLLs, the platform plugin, the Schannel TLS backend and the compiler runtime copied next to it:
.\build_all.ps1 deploy # -> build\TradingApp.exe runs with nothing on PATH
.\tools\deploy_app.ps1 -IncludeTests # also make the tst_*.exe standaloneQt 6 uses the Schannel TLS backend on Windows, so HTTPS to the eToro API works with no OpenSSL install. For a distributable package rather than a runnable build tree, see Packaging below.
The Windows pipeline substitutes a few tools that do not exist there — MSVC
/analyze for g++ -fanalyzer, OpenCppCoverage for gcov/lcov, ASan (MSVC) plus
UBSan (clang-cl) for the combined GCC sanitizer build — and reports the genuine
gaps (clazy, TSan, valgrind) instead of hiding them. MC/DC coverage is measured
twice, by Squish Coco and by clang-cl/llvm-cov. Details, and the PowerShell
pitfalls worth knowing about, are in docs/windows.md.
Requires the Qt 6 Android kit (e.g. android_arm64_v8a), the Android SDK +
NDK, and a JDK. The simplest setup is to open the project in Qt Creator with
an Android kit selected, which fills in the SDK/NDK paths and toolchain. On the
command line, configure with the Android kit's qt-cmake wrapper:
~/Qt/6.11.1/android_arm64_v8a/bin/qt-cmake -S . -B build-android -G Ninja \
-DQT_ANDROID_ABIS=arm64-v8a
cmake --build build-android --target apk # produces the APKqt_add_executable() builds the app as a shared library and androiddeployqt
packages it into an APK. The build bundles OpenSSL (fetched at configure
time — see CMakeLists.txt) because Android's Qt does not ship
it and HTTPS to eToro would otherwise fail.
Caveats specific to Android:
- The UI is Qt Widgets — a desktop-style layout. It runs on a phone but is not touch-optimised.
- The APK is sandboxed and has no working directory or
ETORO_*environment, soconfig.json/ env-var configuration does not apply and the app starts in SIMULATION mode. To trade for real you would have to ship credentials into the app's data dir (bundle aconfig.jsonviaQT_ANDROID_PACKAGE_SOURCE_DIR, or write toAppConfigLocation) — private builds only; never publish keys.
| Platform | Artifact | How to run it |
|---|---|---|
| Linux (x86-64) | TradingApp-<version>-x86_64.AppImage |
chmod +x it and run — one file, no install, Qt bundled |
| Windows (x64) | TradingApp-<version>-windows-x64.zip |
unzip anywhere and run TradingApp.exe — every DLL is inside, no Qt and no MSVC redistributable needed |
Both are attached to the latest release,
each with a .sha256 next to it. Build them yourself into downloads/:
tools/package_appimage.sh # Linux -> downloads/TradingApp-<version>-x86_64.AppImage.\tools\package_portable.ps1 # Windows -> downloads\TradingApp-<version>-windows-x64.zipdownloads/ is git-ignored — the artifacts belong to a release, not to the
history. Both scripts build their own Release tree, bundle the Qt runtime
(linuxdeploy + its Qt plugin on Linux, windeployqt on Windows) and print a
SHA-256; .github/workflows/release.yml runs these same two scripts on a v*
tag and attaches the results to the release. Without API keys the app starts in
SIMULATION mode, so a downloaded build is safe to try.
Two caveats worth knowing: the AppImage is built on Ubuntu 22.04, so it needs glibc ≥ 2.35 (any distro from 2022 onwards), and it deliberately does not bundle OpenSSL — Qt loads the system libssl for HTTPS, which keeps the download out of the business of shipping a frozen TLS stack.
cmake --install build --prefix dist produces a self-contained folder with the
binary and every Qt library/plugin it needs, ready to zip or hand to cpack. It
runs windeployqt on Windows and macdeployqt on macOS automatically
(-DTRADINGAPP_SKIP_QT_DEPLOY=ON turns that step off, which is what the AppImage
build does — linuxdeploy handles the bundling there).
The settings are split into two files so the repo never carries a secret:
config.json— non-secret settings (mode, symbol, leverage, …); committed.apiKeyEtoro.json— the API keys only, looked up besideconfig.json; git-ignored — never commit it.
- Sign in at api-portal.etoro.com → Settings → Trading → API Key Management → Create New Key.
- Copy
apiKeyEtoro.example.jsontoapiKeyEtoro.json(next to the binary /config.json, or beside the file theETORO_CONFIGenv var points at) and fill inapiKey/userKey.
Config resolution order (later wins): built-in defaults → config.json →
apiKeyEtoro.json → environment variables. Any field can also be set via env
var:
| Setting | JSON key | Env var | Default |
|---|---|---|---|
| API key | apiKey |
ETORO_API_KEY |
(empty → simulation) |
| User key | userKey |
ETORO_USER_KEY |
(empty → simulation) |
| Mode | mode |
ETORO_MODE |
demo |
| Username | username |
ETORO_USERNAME |
(empty) |
| Symbol | symbol |
ETORO_SYMBOL |
SPX500 |
| Base URL | baseUrl |
ETORO_BASE_URL |
https://public-api.etoro.com/api |
| Order currency | orderCurrency |
ETORO_ORDER_CURRENCY |
usd |
| Leverage | defaultLeverage |
ETORO_LEVERAGE |
1 |
| Poll interval | pollIntervalMs |
ETORO_POLL_MS |
5000 |
mode: "demo"(default) trades your eToro virtual account — no real money. The app uses the/demo/endpoint variants.mode: "real"trades real money. This is opt-in only: the mode badge turns red, the window title says LIVE, and every buy/sell/close asks for confirmation first.
The app will never place a real-money order unless you both provide credentials
and explicitly set mode to real.
All requests send the documented x-api-key, x-user-key, and per-request
x-request-id (UUID) headers. See src/services/EtoroClient.cpp.
| Purpose | Method & path | Verified live |
|---|---|---|
| Resolve instrument | GET /v1/market-data/search?internalSymbolFull=SPX500&fields=… |
✅ (SPX500 = id 27) |
| Chart history | GET /v1/market-data/instruments/{id}/history/candles/{dir}/{interval}/{count} |
✅ |
| Live price | GET /v1/market-data/instruments/rates?instrumentIds={id} |
✅ |
| Open position | POST /v2/trading/execution/{demo|}/orders (orderType: mkt) |
|
| Limit order | POST /v2/trading/execution/{demo|}/orders (orderType: mit + triggerRate) |
|
| Order status | GET /v2/trading/info/{demo|}/orders:lookup?orderId={id} |
|
| Cancel limit order | DELETE /v2/trading/execution/{demo|}/orders/{orderId} |
|
| Close position | POST /v1/trading/execution/{demo|}/market-close-orders/positions/{positionId} |
|
| Portfolio | GET /v1/trading/info/{demo|}/portfolio |
Confirmed real quirks (already handled in code):
- Search ignores a free-text
query=; filter withinternalSymbolFull. The first result row{"instrumentId":-100000}is a placeholder and is skipped. - Candles are nested:
{ candles: [ { instrumentId, candles: [ {fromDate,open,high,low,close} ] } ] }. - Rates fields are
lastExecution/bid/ask(nocurrentRate/close).
Note on JSON schemas. Order and portfolio response schemas are only visible in
the authenticated reference. The client parses responses defensively (tries
several field names, unwraps data) and logs anything it cannot parse to the
Activity panel. Adjust the pick(...) key lists in src/services/EtoroClient.cpp, and the
candle interval/direction/count near the top of EtoroClient.h
(m_candleInterval, m_candleDirection, m_candleCount) if needed.
Market-data calls succeed but trading/portfolio calls return
403 {"errorCode":"InsufficientPermissions"}. This means your API token is an
UnregisteredApplication token without trading scope. Register/approve the
application in the API portal and regenerate the keys to get trading + portfolio
access; no code change is needed afterwards.
The code is organised in three layers, each built as its own target so the dependency direction (UI → services → domain) is enforced by the linker: the domain cannot reach the network, and the services cannot reach the widgets. All layers are plain cross-platform Qt/C++, so the same split holds on Linux, Windows and Android.
Deterministic functions with no I/O and no UI, in namespace trading —
independently unit-testable and shared by every view that shows a signal.
| File | Responsibility |
|---|---|
Models.h |
Instrument, Candle, Position, ... value types |
Indicators.* |
SMA, RSI, MACD, Bollinger, stochastic, volatility, ROC |
Forecasting.* |
OLS regression, kNN analogs, Hurst, Monte-Carlo outlook |
SignalEnsemble.* |
The BUY/SELL indicator vote + VIX confidence haircut |
DecisionEngine.* |
Weighted multi-source composite + AI evidence prompt |
TradePlan.* |
Costed trade proposal: verdict, P(win), risk factor, leverage, SL/TP, cost bill |
PositionMath.* |
SL/TP amount↔rate maths, value-per-point, price decimals |
EventInsight.* |
Macro-event impact heuristics and descriptions |
| File | Responsibility |
|---|---|
Config.* |
Load keys/settings from JSON + env; demo/live decision |
EtoroClient.* |
The broker: eToro REST calls (rates, orders, portfolio, history) |
SimulationEngine.* |
Synthetic feed + virtual account (no-credentials fallback) |
MarketFeeds.* |
Public web feeds: VIX, TradingView ratings, news |
AiAdvisor.* |
Claude (Anthropic API) decision synthesis |
JsonHttp.* |
Shared reply/retry/JSON plumbing for all REST calls |
EconomicCalendar.* |
Macro-economic calendar feed |
| File | Responsibility |
|---|---|
MainWindow.* |
Main window: trade panel, signals, positions, events |
ScreenerDialog.* |
Leverage screener window |
PriceChart.* |
Live time-vs-price Qt Charts widget |
ChartView.* |
Interactive pan/zoom chart view |
PositionsModel.* |
Open-trades table model, in-place re-price |
TradeGauge.* |
Per-trade gauge window |
Palette.h |
Shared UI colors |
main.cpp |
Composition root: builds the services, injects them into the UI |
TRADINGAPP_SHOT=/path/out.png ./build/TradingApp grabs every visible window
to one PNG each (further windows get a -1, -2, … suffix) after 3000 ms and
exits — handy for headless screenshots (QT_QPA_PLATFORM=offscreen).
TRADINGAPP_SHOT_OPEN=1 opens the decision and closed-trades windows first;
TRADINGAPP_SHOT_DELAY_MS overrides the capture delay.
build linux / windows / macos = the three platform jobs of
ci.yml, reported separately because a GitHub badge
reports a workflow and not a job — and the defects this codebase has hit were
platform-specific (MSVC rejected code that GCC and clang accepted). Each job
publishes its own status, failures included, so a red badge names the platform.
The same run also covers traceability, the sanitizers and the static analysis.
tests = the Qt Test suite on its own
(tests.yml), which also measures the coverage
number (line coverage of the domain + services layers, published as a badge
endpoint on the badges branch — no third-party coverage service involved).
sonarcloud is the SonarCloud quality gate for project
MartinSch77_TradingApp — note that it comes from SonarCloud's automatic
analysis of this public repository, not from
sonarcloud.yml, which stays a no-op until the
SONAR_TOKEN secret exists. coverity is the Coverity Scan build status;
that analysis runs server-side on a weekly submission, so the badge trails the
other ones by design. latest release links the downloads below.
Searchable subject tags for this repository. These are the GitHub topics —
keep them in sync with the repository settings (Settings → General → Topics, or
the gh command below), since GitHub search and the topic pages only index what
is configured there, not what a README mentions.
qt qt6 cpp cpp23 cmake cross-platform desktop-application
trading etoro technical-analysis monte-carlo
static-analysis axivion misra clang-tidy cppcheck sanitizers
code-coverage mcdc requirements-traceability strictdoc aspice
functional-safety
Apply them in one go (needs the GitHub CLI, gh auth login once):
gh repo edit MartinSch77/TradingApp \
--add-topic qt --add-topic qt6 --add-topic cpp --add-topic cpp23 \
--add-topic cmake --add-topic cross-platform --add-topic desktop-application \
--add-topic trading --add-topic etoro --add-topic technical-analysis \
--add-topic monte-carlo --add-topic static-analysis --add-topic axivion \
--add-topic misra --add-topic clang-tidy --add-topic cppcheck \
--add-topic sanitizers --add-topic code-coverage --add-topic mcdc \
--add-topic requirements-traceability --add-topic strictdoc --add-topic aspice \
--add-topic functional-safetyGitHub allows at most 20 topics per repository, so if it rejects the tail, drop
the least specific ones (cpp, cmake, cross-platform) first — the
quality-toolchain tags are what make this repository findable, since a
"Qt trading app" is common and a "Qt trading app with MISRA C++, MC/DC coverage
and requirements-as-code traceability" is not.
Trading involves risk of financial loss. This is example software provided as-is,
is not affiliated with or endorsed by eToro, and is not financial advice. Verify
every order in eToro's own interface. Use demo mode until you fully trust the
behaviour on your account.
MIT. Contributions welcome — see CONTRIBUTING.md and SECURITY.md for the quality bar and how to report vulnerabilities.