├── .clang-format ├── .conan └── profiles │ ├── arch │ ├── x64 │ └── x86 │ ├── clang │ └── 15 │ │ ├── compiler │ │ ├── x64-libc++-debug │ │ └── x64-libc++-release │ ├── compiler │ ├── clang │ ├── gcc │ └── msvc │ ├── config │ ├── debug │ └── release │ ├── cpp │ └── 20 │ ├── gcc │ └── 12 │ │ ├── compiler │ │ ├── x64-libstdc++11-debug │ │ └── x64-libstdc++11-release │ ├── msvc │ └── 193 │ │ ├── compiler │ │ ├── x64-debug │ │ └── x64-release │ ├── os │ └── current │ └── stl │ ├── libc++ │ └── libstdc++11 ├── .conanrc ├── .github └── workflows │ └── cmake.yml ├── .gitignore ├── .vscode ├── c_cpp_properties.json ├── launch.json ├── settings.json └── tasks.json ├── CMakeLists.txt ├── LICENSE ├── README.md ├── assets └── images │ └── heisenberg_photo.jpg ├── cmake ├── clang_format.cmake └── cpp_crypto_algos_config.hpp.in ├── conanfile.txt ├── requirements.txt ├── resources ├── ComputationalFinanceInCPPWithDomainArchitectures.pdf ├── MLInvestmentMethodology.pptx ├── UniqueOptionPricingMeasureWithNeitherDynamicHedging_nor_CompleteMarkets.pdf ├── optimising_c_code_for_low_latency__1659984565.pdf └── qanda.pdf ├── src ├── .clang-format ├── CMakeLists.txt ├── algo.hpp ├── apps │ ├── CMakeLists.txt │ ├── algo │ │ ├── CMakeLists.txt │ │ └── algo.cpp │ ├── execute_order │ │ ├── CMakeLists.txt │ │ └── execute_order.cpp │ ├── experiment │ │ ├── CMakeLists.txt │ │ └── experiment.cpp │ └── streamer │ │ ├── CMakeLists.txt │ │ └── streamer.cpp ├── cc_damped_mr.hpp ├── cc_kaufman.hpp ├── cc_simple_mr.hpp ├── cc_trade_handler.hpp ├── cc_trade_stream.hpp ├── ccex_order_executor.hpp ├── enum.hpp ├── exchange.hpp ├── order_executor.hpp ├── order_type.hpp ├── program_options.hpp ├── side.hpp ├── trade_data.hpp ├── trade_stream.hpp ├── trade_stream_exception.hpp ├── trade_stream_maker.hpp ├── utils.hpp └── wscc_trade_stream.hpp ├── talks ├── antony │ ├── C++20 Techniques For Algorithmic Trading.pdf │ └── README.md ├── jahan │ └── README.md ├── rainer │ ├── Concepts │ │ ├── Concepts.pdf │ │ ├── account1.cpp │ │ ├── account2.cpp │ │ ├── account3.cpp │ │ ├── account4.cpp │ │ ├── account5.cpp │ │ └── account6.cpp │ ├── ExtendPythonWithCpp │ │ ├── Embed │ │ │ ├── myMath.py │ │ │ └── runPythonFunction.c │ │ ├── Extend │ │ │ ├── Native │ │ │ │ └── setup.py │ │ │ ├── SWIG │ │ │ │ ├── helloWorld.c │ │ │ │ ├── helloWorld.h │ │ │ │ ├── helloWorld.i │ │ │ │ └── setup.py │ │ │ ├── SharedLibrary │ │ │ │ ├── helloWorld.c │ │ │ │ ├── helloWorld.h │ │ │ │ └── main.c │ │ │ └── pybind11 │ │ │ │ ├── function.cpp │ │ │ │ └── human.cpp │ │ └── ExtendEmbedC++Python.pdf │ ├── README.md │ └── Ranges │ │ ├── Ranges.pdf │ │ ├── begin.cpp │ │ ├── rangesAccess.cpp │ │ ├── rangesComposition.cpp │ │ ├── rangesEntireContainer.cpp │ │ ├── rangesFilterTransform.cpp │ │ ├── rangesLazy.cpp │ │ └── sortRanges.cpp └── richard │ └── README.md └── windows.md /.clang-format: -------------------------------------------------------------------------------- 1 | Language: Cpp 2 | Standard: Latest 3 | 4 | ColumnLimit: 120 5 | IndentWidth: 4 6 | UseTab: Never 7 | 8 | BreakBeforeBraces: Custom 9 | BraceWrapping: 10 | AfterCaseLabel: true 11 | AfterClass: true 12 | AfterControlStatement: Always 13 | AfterEnum: true 14 | AfterFunction: true 15 | AfterNamespace: true 16 | AfterStruct: true 17 | AfterUnion: true 18 | AfterExternBlock: true 19 | BeforeCatch: true 20 | BeforeElse: true 21 | BeforeLambdaBody: true 22 | BeforeWhile: true 23 | IndentBraces: false 24 | SplitEmptyFunction: false 25 | SplitEmptyRecord: false 26 | SplitEmptyNamespace: false 27 | BreakBeforeBinaryOperators: None 28 | BreakBeforeTernaryOperators: true 29 | BreakBeforeConceptDeclarations: true 30 | BreakConstructorInitializers: BeforeComma 31 | BreakInheritanceList: BeforeComma 32 | ConstructorInitializerAllOnOneLineOrOnePerLine: false 33 | ConstructorInitializerIndentWidth: 4 34 | ContinuationIndentWidth: 4 35 | Cpp11BracedListStyle: true 36 | 37 | EmptyLineBeforeAccessModifier: LogicalBlock 38 | IncludeBlocks: Preserve 39 | 40 | IndentCaseBlocks: false 41 | IndentCaseLabels: false 42 | IndentWrappedFunctionNames: true 43 | IndentExternBlock: Indent 44 | IndentPPDirectives: AfterHash 45 | IndentRequires: true 46 | LambdaBodyIndentation: Signature 47 | MaxEmptyLinesToKeep: 1 48 | NamespaceIndentation: Inner 49 | 50 | SpaceAfterTemplateKeyword: false 51 | SpaceAroundPointerQualifiers: Default 52 | SpaceBeforeCaseColon: false 53 | SpaceBeforeCpp11BracedList: false 54 | SpaceBeforeCtorInitializerColon: true 55 | SpaceBeforeInheritanceColon: true 56 | SpaceBeforeParens: ControlStatements 57 | SpaceBeforeRangeBasedForLoopColon: true 58 | SpaceBeforeSquareBrackets: false 59 | SpaceInEmptyBlock: false 60 | SpaceInEmptyParentheses: false 61 | SpacesBeforeTrailingComments: 4 62 | SpacesInCStyleCastParentheses: false 63 | SpacesInConditionalStatement: false 64 | SpacesInContainerLiterals: false 65 | SpacesInParentheses: false 66 | SpacesInSquareBrackets: false 67 | 68 | SortIncludes: CaseSensitive 69 | SortUsingDeclarations: true 70 | 71 | AccessModifierOffset: -4 72 | PointerAlignment: Left 73 | AlignAfterOpenBracket: AlwaysBreak 74 | AlignArrayOfStructures: Left 75 | AlignConsecutiveAssignments: None 76 | AlignConsecutiveBitFields: AcrossComments 77 | AlignConsecutiveDeclarations: None 78 | AlignConsecutiveMacros: None 79 | AlignEscapedNewlines: Left 80 | AlignOperands: AlignAfterOperator 81 | AlignTrailingComments: true 82 | AllowShortBlocksOnASingleLine: Always 83 | AllowAllParametersOfDeclarationOnNextLine: true 84 | AllowShortCaseLabelsOnASingleLine: true 85 | AllowShortEnumsOnASingleLine: true 86 | AllowShortFunctionsOnASingleLine: All 87 | AllowShortIfStatementsOnASingleLine: Never 88 | AllowShortLambdasOnASingleLine: All 89 | AllowShortLoopsOnASingleLine: false 90 | AlwaysBreakTemplateDeclarations: Yes 91 | BinPackArguments: false 92 | BinPackParameters: false 93 | BitFieldColonSpacing: After 94 | 95 | CompactNamespaces: true 96 | FixNamespaceComments: true -------------------------------------------------------------------------------- /.conan/profiles/arch/x64: -------------------------------------------------------------------------------- 1 | [settings] 2 | arch=x86_64 3 | -------------------------------------------------------------------------------- /.conan/profiles/arch/x86: -------------------------------------------------------------------------------- 1 | [settings] 2 | arch=x86 3 | -------------------------------------------------------------------------------- /.conan/profiles/clang/15/compiler: -------------------------------------------------------------------------------- 1 | include(../../compiler/clang) 2 | 3 | [settings] 4 | compiler.version=15 5 | -------------------------------------------------------------------------------- /.conan/profiles/clang/15/x64-libc++-debug: -------------------------------------------------------------------------------- 1 | include(../../default) 2 | include(../../arch/x64) 3 | include(../../cpp/20) 4 | include(../../config/debug) 5 | include(../../os/current) 6 | include(compiler) 7 | -------------------------------------------------------------------------------- /.conan/profiles/clang/15/x64-libc++-release: -------------------------------------------------------------------------------- 1 | include(../../default) 2 | include(../../arch/x64) 3 | include(../../cpp/20) 4 | include(../../config/release) 5 | include(../../os/current) 6 | include(compiler) 7 | -------------------------------------------------------------------------------- /.conan/profiles/compiler/clang: -------------------------------------------------------------------------------- 1 | include(../stl/libc++) 2 | 3 | [settings] 4 | compiler=clang 5 | -------------------------------------------------------------------------------- /.conan/profiles/compiler/gcc: -------------------------------------------------------------------------------- 1 | include(../stl/libstdc++11) 2 | 3 | [settings] 4 | compiler=gcc 5 | -------------------------------------------------------------------------------- /.conan/profiles/compiler/msvc: -------------------------------------------------------------------------------- 1 | [settings] 2 | compiler=msvc 3 | -------------------------------------------------------------------------------- /.conan/profiles/config/debug: -------------------------------------------------------------------------------- 1 | [settings] 2 | build_type=Debug 3 | -------------------------------------------------------------------------------- /.conan/profiles/config/release: -------------------------------------------------------------------------------- 1 | [settings] 2 | build_type=Release 3 | -------------------------------------------------------------------------------- /.conan/profiles/cpp/20: -------------------------------------------------------------------------------- 1 | [settings] 2 | compiler.cppstd=20 3 | -------------------------------------------------------------------------------- /.conan/profiles/gcc/12/compiler: -------------------------------------------------------------------------------- 1 | include(../../compiler/gcc) 2 | 3 | [settings] 4 | compiler.version=12 5 | -------------------------------------------------------------------------------- /.conan/profiles/gcc/12/x64-libstdc++11-debug: -------------------------------------------------------------------------------- 1 | include(../../default) 2 | include(../../arch/x64) 3 | include(../../cpp/20) 4 | include(../../config/debug) 5 | include(../../os/current) 6 | include(compiler) 7 | -------------------------------------------------------------------------------- /.conan/profiles/gcc/12/x64-libstdc++11-release: -------------------------------------------------------------------------------- 1 | include(../../default) 2 | include(../../arch/x64) 3 | include(../../cpp/20) 4 | include(../../config/release) 5 | include(../../os/current) 6 | include(compiler) 7 | -------------------------------------------------------------------------------- /.conan/profiles/msvc/193/compiler: -------------------------------------------------------------------------------- 1 | include(../../compiler/msvc) 2 | 3 | [settings] 4 | compiler.version=193 5 | compiler.runtime=dynamic 6 | -------------------------------------------------------------------------------- /.conan/profiles/msvc/193/x64-debug: -------------------------------------------------------------------------------- 1 | include(../../default) 2 | include(../../arch/x64) 3 | include(../../cpp/20) 4 | include(../../config/debug) 5 | include(../../os/current) 6 | include(compiler) 7 | -------------------------------------------------------------------------------- /.conan/profiles/msvc/193/x64-release: -------------------------------------------------------------------------------- 1 | include(../../default) 2 | include(../../arch/x64) 3 | include(../../cpp/20) 4 | include(../../config/release) 5 | include(../../os/current) 6 | include(compiler) 7 | -------------------------------------------------------------------------------- /.conan/profiles/os/current: -------------------------------------------------------------------------------- 1 | [settings] 2 | os = {{ {"Darwin": "Macos"}.get(platform.system(), platform.system()) }} 3 | -------------------------------------------------------------------------------- /.conan/profiles/stl/libc++: -------------------------------------------------------------------------------- 1 | [settings] 2 | compiler.libcxx=libc++ 3 | -------------------------------------------------------------------------------- /.conan/profiles/stl/libstdc++11: -------------------------------------------------------------------------------- 1 | [settings] 2 | compiler.libcxx=libstdc++11 3 | -------------------------------------------------------------------------------- /.conanrc: -------------------------------------------------------------------------------- 1 | conan_home=./.conan2 2 | -------------------------------------------------------------------------------- /.github/workflows/cmake.yml: -------------------------------------------------------------------------------- 1 | name: CMake 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | pull_request: 7 | branches: [main] 8 | 9 | jobs: 10 | build: 11 | name: ${{ matrix.settings.name }} ${{ matrix.configuration }} 12 | runs-on: ${{ matrix.settings.os }} 13 | strategy: 14 | matrix: 15 | configuration: [ "Release", "Debug" ] 16 | settings: 17 | - { 18 | name: "Ubuntu GCC-12", 19 | os: ubuntu-latest, 20 | compiler: { type: GCC, version: 12, conan: "gcc", cc: "gcc-12", cxx: "g++-12", std: 20 }, 21 | lib: "libstdc++11" 22 | } 23 | - { 24 | name: "Ubuntu Clang-15 + libc++", 25 | os: ubuntu-latest, 26 | compiler: { type: CLANG, version: 15, conan: "clang", cc: "clang-15", cxx: "clang++-15", std: 20 }, 27 | lib: "libc++", 28 | } 29 | - { 30 | name: "Visual Studio 2019", 31 | os: windows-latest, 32 | compiler: { type: VISUAL, version: 16, conan: "mscv", cc: "cl", cxx: "cl", std: 20 }, 33 | } 34 | 35 | steps: 36 | - uses: actions/checkout@v2 37 | 38 | - name: Cache Conan data 39 | uses: actions/cache@v3 40 | env: 41 | cache-name: cache-conan-data 42 | with: 43 | path: ${{github.workspace}}/.conan2/p 44 | key: ${{ hashFiles('**/conanfile.py') }}-build-${{ matrix.settings.os }}-${{ matrix.configuration }}-${{ matrix.settings.compiler.conan }}-${{ matrix.settings.compiler.version }}-${{ matrix.settings.lib }} 45 | restore-keys: | 46 | ${{ hashFiles('**/conanfile.py') }}-build-${{ matrix.settings.os }}-${{ matrix.configuration }}-${{ matrix.settings.compiler.conan }}-${{ matrix.settings.compiler.version }}- 47 | ${{ hashFiles('**/conanfile.py') }}-build-${{ matrix.settings.os }}-${{ matrix.configuration }}-${{ matrix.settings.compiler.conan }}- 48 | ${{ hashFiles('**/conanfile.py') }}-build-${{ matrix.settings.os }}-${{ matrix.configuration }}- 49 | ${{ hashFiles('**/conanfile.py') }}-build-${{ matrix.settings.os }}- 50 | 51 | - name: Add msbuild to PATH 52 | if: matrix.settings.os == 'windows-latest' 53 | uses: microsoft/setup-msbuild@v1.3 54 | with: 55 | vs-version: "16.5" 56 | 57 | - name: Install Latest GCC 58 | if: matrix.settings.compiler.type == 'GCC' 59 | uses: egor-tensin/setup-gcc@v1 60 | with: 61 | version: ${{ matrix.settings.compiler.version }} 62 | platform: x64 63 | 64 | - name: Install Latest libstdC++11 65 | if: matrix.settings.compiler.type == 'CLANG' && matrix.settings.lib == 'libstdc++11' 66 | uses: egor-tensin/setup-gcc@v1 67 | with: 68 | version: 12 69 | platform: x64 70 | 71 | - name: Install Clang 72 | if: matrix.settings.compiler.type == 'CLANG' 73 | uses: egor-tensin/setup-clang@v1 74 | with: 75 | version: ${{ matrix.settings.compiler.version }} 76 | platform: x64 77 | 78 | - name: Install Libc++ 79 | if: matrix.settings.compiler.type == 'CLANG' && matrix.settings.lib == 'libc++' 80 | shell: bash 81 | run: | 82 | sudo apt install -y libc++-${{ matrix.settings.compiler.version }}-dev libc++abi-${{ matrix.settings.compiler.version }}-dev libunwind-${{ matrix.settings.compiler.version }}-dev 83 | 84 | - name: Set up Python 85 | uses: actions/setup-python@v2 86 | with: 87 | python-version: '3.11' 88 | 89 | - name: Install Python requirements 90 | run: | 91 | pip install -r ./requirements.txt 92 | 93 | - name: Configure Conan 94 | shell: bash 95 | run: | 96 | conan profile detect --force 97 | sed -i.backup '/^\[settings\]$/,/^\[/ s/^build_type=.*/build_type=${{ matrix.configuration }}/' .conan2/profiles/default 98 | sed -i.backup '/^\[settings\]$/,/^\[/ s/^compiler.cppstd=.*/compiler.cppstd=${{ matrix.settings.compiler.std }}/' .conan2/profiles/default 99 | if [[ "${{ matrix.settings.compiler.type }}" == "GCC" || "${{ matrix.settings.compiler.type }}" == "CLANG" ]]; then 100 | sed -i.backup '/^\[settings\]$/,/^\[/ s/^compiler=.*/compiler=${{ matrix.settings.compiler.conan }}/' .conan2/profiles/default 101 | sed -i.backup '/^\[settings\]$/,/^\[/ s/^compiler.version=.*/compiler.version=${{ matrix.settings.compiler.version }}/' .conan2/profiles/default 102 | sed -i.backup '/^\[settings\]$/,/^\[/ s/^compiler.libcxx=.*/compiler.libcxx=${{ matrix.settings.lib }}/' .conan2/profiles/default 103 | fi 104 | conan profile show -pr default 105 | 106 | - name: Configure Install 107 | if: matrix.settings.os == 'windows-latest' 108 | shell: bash 109 | run: | 110 | conan install "${{github.workspace}}" --build missing -pr:b default -g VCVars -c tools.cmake.cmaketoolchain:generator="Ninja Multi-Config" -of ./build 111 | 112 | - name: Configure Install 113 | if: matrix.settings.os != 'windows-latest' 114 | shell: bash 115 | run: | 116 | conan install "${{github.workspace}}" --build missing -pr:b default -c tools.cmake.cmaketoolchain:generator="Ninja Multi-Config" -of ./build 117 | 118 | - name: Configure CMake 119 | if: matrix.settings.os == 'windows-latest' 120 | shell: cmd 121 | run: | 122 | call build\conanvcvars.bat 123 | call build\conanbuild.bat 124 | cmake --preset conan-default 125 | 126 | - name: Configure CMake 127 | if: matrix.settings.os != 'windows-latest' 128 | shell: bash 129 | run: | 130 | source build/conanbuild.sh 131 | cmake --preset conan-default 132 | 133 | - name: Conan Preset 134 | shell: bash 135 | run: echo "CONAN_PRESET=conan-$(echo ${{matrix.configuration}} | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV 136 | 137 | - name: Build 138 | if: matrix.settings.os == 'windows-latest' 139 | shell: cmd 140 | run: | 141 | call build\conanbuild.bat 142 | cmake --build --preset ${{ env.CONAN_PRESET }} 143 | 144 | - name: Build 145 | if: matrix.settings.os != 'windows-latest' 146 | shell: bash 147 | run: | 148 | source build/conanbuild.sh 149 | cmake --build --preset ${{ env.CONAN_PRESET }} 150 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | 34 | build/* 35 | .venv/* 36 | 37 | # Visual Studio artifacts 38 | .vs 39 | [Oo]ut 40 | 41 | # Conan2 directory 42 | .conan2 43 | 44 | # CMake build artifacts 45 | CMakeUserPresets.json 46 | -------------------------------------------------------------------------------- /.vscode/c_cpp_properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "name": "Linux", 5 | "includePath": [ 6 | "${workspaceFolder}/**", 7 | "${workspaceFolder}/build/_deps/ccapi-src/include/**", 8 | "${workspaceFolder}/build/_deps/websocketpp-src/websocketpp/**", 9 | "~/.conan/data/**", 10 | "${workspaceFolder}/src/**" 11 | ], 12 | "defines": [], 13 | "compilerPath": "/usr/bin/g++-11", 14 | "cStandard": "c17", 15 | "cppStandard": "c++20", 16 | "intelliSenseMode": "linux-gcc-x64", 17 | "configurationProvider": "ms-vscode.cmake-tools" 18 | } 19 | ], 20 | "version": 4 21 | } -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "(gdb) execute_order - FTX", 6 | "type": "cppdbg", 7 | "request": "launch", 8 | "program": "${workspaceFolder}/build/bin/execute_order", 9 | "args": 10 | [ "--exchange=ftx" 11 | , "--symbol=BTC-PERP" 12 | , "--api_key=${env:FTX_API_KEY}" 13 | , "--api_secret=${env:FTX_API_SECRET}" 14 | , "--side=buy" 15 | , "--size=0.0025" 16 | , "--type=market" 17 | ], 18 | "stopAtEntry": false, 19 | "cwd": "${fileDirname}", 20 | "environment": [], 21 | "externalConsole": false, 22 | "MIMode": "gdb", 23 | "setupCommands": [ 24 | { 25 | "description": "Enable pretty-printing for gdb", 26 | "text": "-enable-pretty-printing", 27 | "ignoreFailures": true 28 | }, 29 | { 30 | "description": "Set Disassembly Flavor to Intel", 31 | "text": "-gdb-set disassembly-flavor intel", 32 | "ignoreFailures": true 33 | } 34 | ] 35 | }, 36 | { 37 | "name": "(gdb) streamer - FTX", 38 | "type": "cppdbg", 39 | "request": "launch", 40 | "program": "${workspaceFolder}/build/bin/streamer", 41 | "args": 42 | [ "--exchange", "ftx" 43 | , "--symbols", "BTC-PERP", "SOL-PERP" 44 | ], 45 | "stopAtEntry": false, 46 | "cwd": "${fileDirname}", 47 | "environment": [], 48 | "externalConsole": false, 49 | "MIMode": "gdb", 50 | "setupCommands": [ 51 | { 52 | "description": "Enable pretty-printing for gdb", 53 | "text": "-enable-pretty-printing", 54 | "ignoreFailures": true 55 | }, 56 | { 57 | "description": "Set Disassembly Flavor to Intel", 58 | "text": "-gdb-set disassembly-flavor intel", 59 | "ignoreFailures": true 60 | } 61 | ] 62 | }, 63 | { 64 | "name": "(gdb) algo - FTX - SimpleMR", 65 | "type": "cppdbg", 66 | "request": "launch", 67 | "program": "${workspaceFolder}/build/bin/algo", 68 | "args": 69 | [ "--algo=SimpleMR" 70 | , "--exchange=ftx" 71 | , "--api_key=${env:FTX_API_KEY}" 72 | , "--api_secret=${env:FTX_API_SECRET}" 73 | , "--lookback=50" 74 | , "--reversion_level=2" 75 | , "--base_quantity=0.0025" 76 | , "--symbols=BTC-PERP" 77 | ], 78 | "stopAtEntry": false, 79 | "cwd": "${workspaceFolder}", 80 | "environment": [], 81 | "externalConsole": false, 82 | "MIMode": "gdb", 83 | "setupCommands": [ 84 | { 85 | "description": "Enable pretty-printing for gdb", 86 | "text": "-enable-pretty-printing", 87 | "ignoreFailures": true 88 | }, 89 | { 90 | "description": "Set Disassembly Flavor to Intel", 91 | "text": "-gdb-set disassembly-flavor intel", 92 | "ignoreFailures": true 93 | } 94 | ], 95 | // "preLaunchTask": "CMake build project", 96 | "miDebuggerPath": "/usr/bin/gdb", 97 | }, 98 | { 99 | "name": "(gdb) algo - FTX - Damped", 100 | "type": "cppdbg", 101 | "request": "launch", 102 | "program": "${workspaceFolder}/build/bin/algo", 103 | "args": 104 | [ "--algo=Damped" 105 | , "--exchange=ftx" 106 | , "--api_key=${env:FTX_API_KEY}" 107 | , "--api_secret=${env:FTX_API_SECRET}" 108 | , "--sub_account=Webinar" 109 | , "--lookback=50" 110 | , "--reversion_level=2" 111 | , "--base_quantity=0.0025" 112 | , "--damping=2.5" 113 | , "--symbols=ETH-PERP" 114 | ], 115 | "stopAtEntry": false, 116 | "cwd": "${workspaceFolder}", 117 | "environment": [], 118 | "externalConsole": false, 119 | "MIMode": "gdb", 120 | "setupCommands": [ 121 | { 122 | "description": "Enable pretty-printing for gdb", 123 | "text": "-enable-pretty-printing", 124 | "ignoreFailures": true 125 | }, 126 | { 127 | "description": "Set Disassembly Flavor to Intel", 128 | "text": "-gdb-set disassembly-flavor intel", 129 | "ignoreFailures": true 130 | } 131 | ], 132 | // "preLaunchTask": "CMake build project", 133 | "miDebuggerPath": "/usr/bin/gdb", 134 | }, 135 | { 136 | "name": "(gdb) experiment", 137 | "type": "cppdbg", 138 | "request": "launch", 139 | "program": "${workspaceFolder}/build/bin/experiment", 140 | "args": 141 | [ "--name", "test" 142 | , "--er_period", "8" 143 | ], 144 | "stopAtEntry": false, 145 | "cwd": "${fileDirname}", 146 | "environment": [], 147 | "externalConsole": false, 148 | "MIMode": "gdb", 149 | "setupCommands": [ 150 | { 151 | "description": "Enable pretty-printing for gdb", 152 | "text": "-enable-pretty-printing", 153 | "ignoreFailures": true 154 | }, 155 | { 156 | "description": "Set Disassembly Flavor to Intel", 157 | "text": "-gdb-set disassembly-flavor intel", 158 | "ignoreFailures": true 159 | } 160 | ] 161 | }, 162 | ] 163 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | "*.in": "cpp", 4 | "array": "cpp", 5 | "cctype": "cpp", 6 | "clocale": "cpp", 7 | "cmath": "cpp", 8 | "csignal": "cpp", 9 | "cstdarg": "cpp", 10 | "cstddef": "cpp", 11 | "cstdio": "cpp", 12 | "cstdlib": "cpp", 13 | "cstring": "cpp", 14 | "ctime": "cpp", 15 | "cwchar": "cpp", 16 | "cwctype": "cpp", 17 | "*.ipp": "cpp", 18 | "any": "cpp", 19 | "atomic": "cpp", 20 | "strstream": "cpp", 21 | "bit": "cpp", 22 | "*.tcc": "cpp", 23 | "bitset": "cpp", 24 | "cfenv": "cpp", 25 | "chrono": "cpp", 26 | "codecvt": "cpp", 27 | "compare": "cpp", 28 | "complex": "cpp", 29 | "concepts": "cpp", 30 | "condition_variable": "cpp", 31 | "coroutine": "cpp", 32 | "cstdint": "cpp", 33 | "deque": "cpp", 34 | "list": "cpp", 35 | "map": "cpp", 36 | "set": "cpp", 37 | "unordered_map": "cpp", 38 | "unordered_set": "cpp", 39 | "vector": "cpp", 40 | "exception": "cpp", 41 | "algorithm": "cpp", 42 | "functional": "cpp", 43 | "iterator": "cpp", 44 | "memory": "cpp", 45 | "memory_resource": "cpp", 46 | "numeric": "cpp", 47 | "optional": "cpp", 48 | "random": "cpp", 49 | "ratio": "cpp", 50 | "source_location": "cpp", 51 | "string": "cpp", 52 | "string_view": "cpp", 53 | "system_error": "cpp", 54 | "tuple": "cpp", 55 | "type_traits": "cpp", 56 | "utility": "cpp", 57 | "rope": "cpp", 58 | "slist": "cpp", 59 | "fstream": "cpp", 60 | "future": "cpp", 61 | "initializer_list": "cpp", 62 | "iomanip": "cpp", 63 | "iosfwd": "cpp", 64 | "iostream": "cpp", 65 | "istream": "cpp", 66 | "limits": "cpp", 67 | "mutex": "cpp", 68 | "new": "cpp", 69 | "numbers": "cpp", 70 | "ostream": "cpp", 71 | "ranges": "cpp", 72 | "shared_mutex": "cpp", 73 | "span": "cpp", 74 | "sstream": "cpp", 75 | "stdexcept": "cpp", 76 | "stop_token": "cpp", 77 | "streambuf": "cpp", 78 | "thread": "cpp", 79 | "cinttypes": "cpp", 80 | "typeindex": "cpp", 81 | "typeinfo": "cpp", 82 | "valarray": "cpp", 83 | "variant": "cpp", 84 | "regex": "cpp", 85 | "semaphore": "cpp", 86 | "cassert": "cpp", 87 | "cerrno": "cpp", 88 | "ciso646": "cpp", 89 | "climits": "cpp", 90 | "filesystem": "cpp", 91 | "ios": "cpp", 92 | "locale": "cpp", 93 | "queue": "cpp", 94 | "stack": "cpp", 95 | "version": "cpp" 96 | } 97 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "type": "shell", 6 | "label": "CMake build project", 7 | "options": { 8 | "cwd": "${workspaceFolder}/build" 9 | }, 10 | "command": "cmake -DCMAKE_BUILD_TYPE=Debug .. && cmake --build . 2>&1|tee cmake.out", 11 | "group": { 12 | "kind": "build", 13 | "isDefault": true 14 | }, 15 | "problemMatcher": [] 16 | } 17 | ] 18 | } -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.27) 2 | 3 | # set the project name 4 | project(cpp_crypto_algos LANGUAGES CXX VERSION 2.0) 5 | 6 | include(FetchContent) 7 | 8 | FetchContent_Declare( 9 | ccapi 10 | GIT_REPOSITORY https://github.com/profitviews/ccapi.git 11 | GIT_TAG windows-msvc 12 | ) 13 | FetchContent_Declare( 14 | websocketpp 15 | GIT_REPOSITORY https://github.com/zaphoyd/websocketpp.git 16 | GIT_TAG develop 17 | ) 18 | FetchContent_Declare( 19 | csv2 20 | GIT_REPOSITORY https://github.com/p-ranav/csv2 21 | GIT_TAG master 22 | ) 23 | FetchContent_MakeAvailable(ccapi websocketpp csv2) 24 | 25 | list(APPEND CMAKE_MODULE_PATH ${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/cmake ) 26 | find_package(Boost REQUIRED) 27 | find_package(fmt REQUIRED) 28 | find_package(OpenSSL REQUIRED) 29 | find_package(RapidJSON REQUIRED) 30 | find_package(Threads REQUIRED) 31 | 32 | set(CMAKE_CXX_STANDARD 20) 33 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 34 | set(CMAKE_CXX_EXTENSIONS OFF) 35 | 36 | configure_file(cmake/cpp_crypto_algos_config.hpp.in cpp_crypto_algos_config.hpp) 37 | 38 | include(clang_format) 39 | add_subdirectory(src) -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Richard Hickling 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Heisenberg Algo Trading 2 | 3 | 4 | 5 | ## C++ Crypto Algos 6 | 7 | ### Build steps 8 | 9 | Linux or MacOS. See [here](./windows.md) for Windows. 10 | 11 | * Clone project 12 | ```bash 13 | git clone https://github.com/profitviews/heisenberg.git heisenberg 14 | cd heisenberg 15 | ``` 16 | 17 | * Install and Configure Conan and Ninja 18 | ```bash 19 | python3 -m venv .venv # Create a Python virtual env 20 | source ./.venv/bin/activate # Activate the virtual env 21 | pip install -r ./requirements.txt # Install Conan and Ninja 22 | conan profile detect --force # Generate a default configuration with the local machine settings 23 | conan config install ./.conan # Install supported build profiles from ./.conan to ./conan2 24 | ``` 25 | 26 | * Standard Build 27 | Installing Conan dependencies and configuring CMake presets. 28 | The sample build below is choosing the `Release` configuration: 29 | ```bash 30 | mkdir build 31 | conan install ./ -pr:h .conan2/profiles/gcc/12/x64-libstdc++11-release -pr:b .conan2/profiles/gcc/12/x64-libstdc++11-release -of ./build --build missing 32 | source build/conanbuild.sh 33 | cmake --preset conan-release 34 | cmake --build --preset conan-release 35 | ``` 36 | 37 | * Ninja Multi-Config Build 38 | 39 | Multi-config builds allow you to create a build folder containing sub-folders for different build configurations and build them side-by-side. 40 | To generate all the configurations we run the `conan-default` preset which configures CMake for these configurations `Release` and `Debug`. The sample build below is choosing the `Release` configuration: 41 | ```bash 42 | conan install ./ -pr:h .conan2/profiles/gcc/12/x64-libstdc++11-release -pr:b .conan2/profiles/gcc/12/x64-libstdc++11-release -of ./build --build missing -c tools.cmake.cmaketoolchain:generator="Ninja Multi-Config" 43 | source build/conanbuild.sh 44 | cmake --preset conan-default # The configure stage for multi-config builds is conan-default 45 | cmake --build --preset conan-release # The build stage for multi-config builds is the conan- 46 | ``` 47 | 48 | This will create: 49 | 50 | * `build/bin/algo` which will run a simple Mean Reversion algo on FTX or Coinbase 51 | * For example 52 | ```bash 53 | cd bin 54 | ./algo --exchange=coinbase --algo=SimpleMR --api_key=$COINBASE_API_KEY --api_secret=$COINBASE_API_SECRET --api_phrase=$COINBASE_API_PHRASE --lookback=50 --reversion_level=2 --base_quantity=0.0025 --symbol=ETH-BTC 55 | ``` 56 | -------------------------------------------------------------------------------- /assets/images/heisenberg_photo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/profitviews/heisenberg/912c3f661afa274d70dfe869af92518c8a562cea/assets/images/heisenberg_photo.jpg -------------------------------------------------------------------------------- /cmake/clang_format.cmake: -------------------------------------------------------------------------------- 1 | #[=======================================================================[.rst: 2 | clang_format_target 3 | ------------------ 4 | 5 | Overview 6 | ^^^^^^^^ 7 | 8 | Generates a target for running the clang-format executable on all of the source 9 | files in a target. 10 | 11 | .. code-block:: cmake 12 | 13 | clang_format_target( 14 | [TARGET ] 15 | ) 16 | -- Call the specified command for the version of an exchange for specifed 17 | target type. 18 | 19 | ``TARGET`` specify the target containing the source files to run clang-format 20 | on. 21 | 22 | #]=======================================================================] 23 | function(clang_format_target) 24 | set(options QUIET) 25 | set(oneValueArgs TARGET CONFIG_FILE) 26 | set(multiValueArgs) 27 | cmake_parse_arguments(CLANG_FORMAT "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} ) 28 | 29 | find_program(CLANG_FORMAT_PATH clang-format) 30 | if (NOT CLANG_FORMAT_PATH) 31 | message(WARNING "clang-format not found, disabling support.") 32 | return() 33 | endif() 34 | 35 | execute_process(COMMAND "${CLANG_FORMAT_PATH}" --version OUTPUT_VARIABLE CLANG_FORMAT_OUTPUT) 36 | string(REPLACE "\n" ";" CLANG_FORMAT_OUTPUT "${CLANG_FORMAT_OUTPUT}") 37 | foreach(line ${CLANG_FORMAT_OUTPUT}) 38 | string(REGEX REPLACE "clang-format version ([\\.0-9]+)$" "\\1" CLANG_FORMAT_VERSION "${line}") 39 | if(CLANG_FORMAT_VERSION) 40 | break() 41 | endif() 42 | endforeach() 43 | 44 | if("${CLANG_FORMAT_VERSION}" VERSION_LESS 13.0.0) 45 | message(STATUS "Unsupported version of Clang-Format found. Version 13.0.0 requird, version ${CLANG_FORMAT_VERSION} found") 46 | endif() 47 | 48 | get_property(CLANG_FORMAT_QUIET_REPORTED GLOBAL PROPERTY clang_format_quiet_reported) 49 | if(NOT CLANG_FORMAT_QUIET AND NOT CLANG_FORMAT_QUIET_REPORTED) 50 | set_property(GLOBAL PROPERTY clang_format_quiet_reported TRUE) 51 | message(STATUS "Enabling Clang-Format support. Version: ${CLANG_FORMAT_VERSION}") 52 | endif() 53 | 54 | if(CLANG_FORMAT_TARGET) 55 | get_target_property(targetSources ${CLANG_FORMAT_TARGET} SOURCES) 56 | if (targetSources) 57 | list(APPEND targetAllSources ${targetSources}) 58 | endif() 59 | get_target_property(targetInferfaceSources ${CLANG_FORMAT_TARGET} INTERFACE_SOURCES) 60 | if (targetInferfaceSources) 61 | list(APPEND targetAllSources ${targetInferfaceSources}) 62 | endif() 63 | list(REMOVE_DUPLICATES targetAllSources) 64 | foreach(clangFormatSource ${targetAllSources}) 65 | get_filename_component(clangFormatSource ${clangFormatSource} ABSOLUTE) 66 | list(APPEND clangFormatSources ${clangFormatSource}) 67 | endforeach() 68 | endif() 69 | 70 | add_custom_target(clangformat_${CLANG_FORMAT_TARGET} 71 | COMMAND 72 | ${CLANG_FORMAT_PATH} -style=file -i ${clangFormatSources} 73 | WORKING_DIRECTORY 74 | ${CMAKE_SOURCE_DIR} 75 | COMMENT 76 | "Formatting ${CLANG_FORMAT_TARGET} files with ${CLANG_FORMAT_EXE}" 77 | ) 78 | 79 | if(TARGET clangformat) 80 | add_dependencies(clangformat clangformat_${CLANG_FORMAT_TARGET}) 81 | else() 82 | add_custom_target(clangformat DEPENDS clangformat_${CLANG_FORMAT_TARGET}) 83 | endif() 84 | endfunction() -------------------------------------------------------------------------------- /cmake/cpp_crypto_algos_config.hpp.in: -------------------------------------------------------------------------------- 1 | // the configured options and settings for Tutorial 2 | #define cpp_crypto_algos_VERSION_MAJOR @cpp_crypto_algos_VERSION_MAJOR@ 3 | #define cpp_crypto_algos_VERSION_MINOR @cpp_crypto_algos_VERSION_MINOR@ -------------------------------------------------------------------------------- /conanfile.txt: -------------------------------------------------------------------------------- 1 | [requires] 2 | boost/1.80.0 3 | fmt/8.1.1 4 | openssl/1.1.1q 5 | rapidjson/cci.20211112 6 | 7 | [tool_requires] 8 | cmake/3.27.0 9 | ninja/1.11.1 10 | 11 | [generators] 12 | CMakeDeps 13 | CMakeToolchain 14 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | conan 2 | ninja -------------------------------------------------------------------------------- /resources/ComputationalFinanceInCPPWithDomainArchitectures.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/profitviews/heisenberg/912c3f661afa274d70dfe869af92518c8a562cea/resources/ComputationalFinanceInCPPWithDomainArchitectures.pdf -------------------------------------------------------------------------------- /resources/MLInvestmentMethodology.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/profitviews/heisenberg/912c3f661afa274d70dfe869af92518c8a562cea/resources/MLInvestmentMethodology.pptx -------------------------------------------------------------------------------- /resources/UniqueOptionPricingMeasureWithNeitherDynamicHedging_nor_CompleteMarkets.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/profitviews/heisenberg/912c3f661afa274d70dfe869af92518c8a562cea/resources/UniqueOptionPricingMeasureWithNeitherDynamicHedging_nor_CompleteMarkets.pdf -------------------------------------------------------------------------------- /resources/optimising_c_code_for_low_latency__1659984565.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/profitviews/heisenberg/912c3f661afa274d70dfe869af92518c8a562cea/resources/optimising_c_code_for_low_latency__1659984565.pdf -------------------------------------------------------------------------------- /resources/qanda.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/profitviews/heisenberg/912c3f661afa274d70dfe869af92518c8a562cea/resources/qanda.pdf -------------------------------------------------------------------------------- /src/.clang-format: -------------------------------------------------------------------------------- 1 | Language: Cpp 2 | # BasedOnStyle: Maven 3 | Standard: Latest 4 | 5 | ColumnLimit: 120 6 | IndentWidth: 4 7 | UseTab: Never 8 | 9 | BreakBeforeBraces: Custom 10 | BraceWrapping: 11 | AfterCaseLabel: true 12 | AfterClass: true 13 | AfterControlStatement: Always 14 | AfterEnum: true 15 | AfterFunction: true 16 | AfterNamespace: true 17 | AfterStruct: true 18 | AfterUnion: true 19 | AfterExternBlock: true 20 | BeforeCatch: true 21 | BeforeElse: true 22 | BeforeLambdaBody: true 23 | BeforeWhile: true 24 | IndentBraces: false 25 | SplitEmptyFunction: false 26 | SplitEmptyRecord: false 27 | SplitEmptyNamespace: false 28 | BreakBeforeBinaryOperators: None 29 | BreakBeforeTernaryOperators: true 30 | BreakBeforeConceptDeclarations: true 31 | BreakConstructorInitializers: BeforeComma 32 | BreakInheritanceList: BeforeComma 33 | ConstructorInitializerAllOnOneLineOrOnePerLine: false 34 | ConstructorInitializerIndentWidth: 4 35 | ContinuationIndentWidth: 4 36 | Cpp11BracedListStyle: true 37 | 38 | EmptyLineBeforeAccessModifier: LogicalBlock 39 | IncludeBlocks: Preserve 40 | 41 | IndentCaseBlocks: false 42 | IndentCaseLabels: false 43 | IndentWrappedFunctionNames: true 44 | IndentExternBlock: Indent 45 | IndentPPDirectives: AfterHash 46 | IndentRequires: true 47 | LambdaBodyIndentation: Signature 48 | MaxEmptyLinesToKeep: 1 49 | NamespaceIndentation: Inner 50 | 51 | SpaceAfterTemplateKeyword: false 52 | SpaceAroundPointerQualifiers: Default 53 | SpaceBeforeCaseColon: false 54 | SpaceBeforeCpp11BracedList: false 55 | SpaceBeforeCtorInitializerColon: true 56 | SpaceBeforeInheritanceColon: true 57 | SpaceBeforeParens: ControlStatements 58 | SpaceBeforeRangeBasedForLoopColon: true 59 | SpaceBeforeSquareBrackets: false 60 | SpaceInEmptyBlock: false 61 | SpaceInEmptyParentheses: false 62 | SpacesBeforeTrailingComments: 4 63 | SpacesInCStyleCastParentheses: false 64 | SpacesInConditionalStatement: false 65 | SpacesInContainerLiterals: false 66 | SpacesInParentheses: false 67 | SpacesInSquareBrackets: false 68 | 69 | SortIncludes: CaseSensitive 70 | SortUsingDeclarations: true 71 | 72 | AccessModifierOffset: -4 73 | PointerAlignment: Left 74 | AlignAfterOpenBracket: AlwaysBreak 75 | AlignArrayOfStructures: Left 76 | AlignConsecutiveAssignments: None 77 | AlignConsecutiveBitFields: AcrossComments 78 | AlignConsecutiveDeclarations: None 79 | AlignConsecutiveMacros: None 80 | AlignEscapedNewlines: Left 81 | AlignOperands: AlignAfterOperator 82 | AlignTrailingComments: true 83 | AllowShortBlocksOnASingleLine: Always 84 | AllowAllParametersOfDeclarationOnNextLine: true 85 | AllowShortCaseLabelsOnASingleLine: true 86 | AllowShortEnumsOnASingleLine: true 87 | AllowShortFunctionsOnASingleLine: All 88 | AllowShortIfStatementsOnASingleLine: Never 89 | AllowShortLambdasOnASingleLine: All 90 | AllowShortLoopsOnASingleLine: false 91 | AlwaysBreakTemplateDeclarations: Yes 92 | BinPackArguments: false 93 | BinPackParameters: false 94 | BitFieldColonSpacing: After 95 | 96 | CompactNamespaces: true 97 | FixNamespaceComments: true -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(cpp_crypto_algos_lib 2 | INTERFACE 3 | cc_simple_mr.hpp 4 | cc_kaufman.hpp 5 | cc_damped_mr.hpp 6 | cc_trade_handler.hpp 7 | cc_trade_stream.hpp 8 | ccex_order_executor.hpp 9 | enum.hpp 10 | exchange.hpp 11 | order_executor.hpp 12 | order_type.hpp 13 | program_options.hpp 14 | side.hpp 15 | trade_data.hpp 16 | trade_stream.hpp 17 | trade_stream_exception.hpp 18 | trade_stream_maker.hpp 19 | utils.hpp 20 | wscc_trade_stream.hpp 21 | ) 22 | 23 | target_link_libraries(cpp_crypto_algos_lib 24 | INTERFACE 25 | Boost::headers 26 | Boost::log 27 | Boost::program_options 28 | fmt::fmt 29 | OpenSSL::SSL 30 | OpenSSL::Crypto 31 | rapidjson 32 | Threads::Threads 33 | ) 34 | 35 | target_include_directories(cpp_crypto_algos_lib 36 | INTERFACE 37 | ${PROJECT_BINARY_DIR} 38 | ${PROJECT_SOURCE_DIR}/src 39 | ${PROJECT_SOURCE_DIR}/ccapi_executor 40 | ${ccapi_SOURCE_DIR}/include 41 | ${websocketpp_SOURCE_DIR} 42 | ${csv2_SOURCE_DIR}/include 43 | ) 44 | 45 | target_compile_definitions(cpp_crypto_algos_lib 46 | INTERFACE 47 | CCAPI_ENABLE_SERVICE_EXECUTION_MANAGEMENT 48 | CCAPI_ENABLE_SERVICE_MARKET_DATA 49 | CCAPI_ENABLE_EXCHANGE_BITMEX 50 | CCAPI_ENABLE_EXCHANGE_FTX 51 | CCAPI_ENABLE_EXCHANGE_COINBASE 52 | ) 53 | 54 | target_compile_options(cpp_crypto_algos_lib 55 | INTERFACE 56 | $<$:-fexperimental-library> 57 | $<$:-Wno-terminate> 58 | $<$:/bigobj> 59 | ) 60 | set_property(TARGET cpp_crypto_algos_lib PROPERTY CPP_VISIBILITY_PRESET ON) 61 | set_property(TARGET cpp_crypto_algos_lib PROPERTY VISIBILITY_INLINES_HIDDEN ON) 62 | 63 | clang_format_target(TARGET cpp_crypto_algos_lib) 64 | add_subdirectory(apps) -------------------------------------------------------------------------------- /src/algo.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace profitview 6 | { 7 | 8 | BOOST_DEFINE_ENUM(Algo, Kaufman, SimpleMR, Damped) 9 | 10 | } -------------------------------------------------------------------------------- /src/apps/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(algo) 2 | add_subdirectory(execute_order) 3 | add_subdirectory(streamer) 4 | add_subdirectory(experiment) -------------------------------------------------------------------------------- /src/apps/algo/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(algo) 2 | target_sources(algo 3 | PRIVATE 4 | algo.cpp 5 | ) 6 | 7 | target_link_libraries(algo 8 | PRIVATE 9 | cpp_crypto_algos_lib 10 | ) 11 | 12 | set_target_properties(algo 13 | PROPERTIES 14 | ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib 15 | LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib 16 | RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin 17 | ) 18 | 19 | clang_format_target(TARGET algo) -------------------------------------------------------------------------------- /src/apps/algo/algo.cpp: -------------------------------------------------------------------------------- 1 | #include "algo.hpp" 2 | #include "cc_damped_mr.hpp" 3 | #include "cc_kaufman.hpp" 4 | #include "cc_simple_mr.hpp" 5 | 6 | #include "ccex_order_executor.hpp" 7 | #include "trade_stream_maker.hpp" 8 | #include "utils.hpp" 9 | 10 | #include "program_options.hpp" 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | namespace profitview 17 | { 18 | 19 | struct ProgramArgs 20 | { 21 | std::string algo; 22 | std::string exchange; 23 | std::string api_key; 24 | std::string api_secret; 25 | std::string api_phrase; 26 | std::string sub_account; 27 | int lookback = 0; 28 | double reversion_level = 0.0; 29 | double base_quantity = 0.0; 30 | int er_period = 0, fast_sc = 0, slow_sc = 0, kama_trend = 0; 31 | double damping = 0.0; 32 | std::vector symbols; 33 | 34 | void addOptions(boost::program_options::options_description& options) 35 | { 36 | namespace po = boost::program_options; 37 | // clang-format off 38 | options.add_options() 39 | ("algo", po::value(&algo)->required(), "Algo to use") 40 | ("exchange", po::value(&exchange)->required(), "Crypto Exchange to execute on.") 41 | ("api_key", po::value(&api_key)->required(), "API key for Cypto exchange.") 42 | ("api_secret", po::value(&api_secret)->required(), "API secret for Cypto exchange.") 43 | ("api_phrase", po::value(&api_phrase), "API phrase for Cypto exchange.") 44 | ("sub_account", po::value(&sub_account), "Subaccount on Cypto exchange.") 45 | ("lookback", po::value(&lookback)->required(), "Time period to look back") 46 | ("reversion_level", po::value(&reversion_level), "Mean reversion level.") 47 | ("base_quantity", po::value(&base_quantity)->required(), "Quantity to trade.") 48 | ("er_period", po::value(&er_period), "Efficiency Ratio base period for Kaufman") 49 | ("fast_sc", po::value(&fast_sc), "Fast exponential moving average smoothing period") 50 | ("slow_sc", po::value(&slow_sc), "Slow exponential moving average smoothing period") 51 | ("kama_trend", po::value(&kama_trend), "Kaufman trend prediction period") 52 | ("damping", po::value(&damping), "Standard deviation damping limit") 53 | ("symbols", po::value(&symbols)->multitoken()->required(), "Symbols for cypto assets to trade."); 54 | // clang-format on 55 | } 56 | }; 57 | 58 | } // namespace profitview 59 | 60 | int main(int argc, char* argv[]) 61 | { 62 | using namespace profitview; 63 | ProgramArgs options; 64 | auto const result = parseProgramOptions(argc, argv, options); 65 | if (result) 66 | return result.value(); 67 | 68 | const std::map algos{ 69 | {"SimpleMR", SimpleMR}, 70 | {"Kaufman", Kaufman }, 71 | {"Damped", Damped } 72 | }; 73 | 74 | CcexOrderExecutor executor{options.exchange, options.api_key, options.api_secret, options.api_phrase, options.sub_account}; 75 | 76 | switch (algos.at(options.algo)) 77 | { 78 | case SimpleMR: 79 | TradeStreamMaker::register_stream>( 80 | options.algo, &executor, options.lookback, options.reversion_level, options.base_quantity); 81 | break; 82 | case Kaufman: 83 | TradeStreamMaker::register_stream>( 84 | options.algo, 85 | &executor, 86 | options.lookback, 87 | options.base_quantity, 88 | options.er_period, 89 | options.fast_sc, 90 | options.slow_sc, 91 | options.kama_trend); 92 | break; 93 | case Damped: 94 | TradeStreamMaker::register_stream>( 95 | options.algo, &executor, options.lookback, options.reversion_level, options.base_quantity, options.damping); 96 | break; 97 | default: 98 | BOOST_LOG_TRIVIAL(error) << "Unknown algo" << std::endl; return 2; 99 | } 100 | 101 | TradeStreamMaker::get(options.algo).subscribe(options.exchange, options.symbols); 102 | 103 | std::cout << "Press enter to quit" << std::endl; 104 | std::cin.get(); 105 | 106 | enum 107 | { 108 | OrderId, 109 | Symbol, 110 | OrderSide, 111 | Size, 112 | Price, 113 | Time, 114 | Status 115 | }; 116 | for (const auto& [cid, details] : executor.get_open_orders()) 117 | BOOST_LOG_TRIVIAL(info) << "cid: " << cid << ", Order Id: " << std::get(details) 118 | << ", Symbol: " << std::get(details) << ", Status: " << std::get(details) 119 | << std::endl; 120 | 121 | return 0; 122 | } -------------------------------------------------------------------------------- /src/apps/execute_order/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(execute_order) 2 | target_sources(execute_order 3 | PRIVATE 4 | execute_order.cpp 5 | ) 6 | 7 | target_link_libraries(execute_order 8 | PRIVATE 9 | cpp_crypto_algos_lib 10 | ) 11 | 12 | set_target_properties(execute_order 13 | PROPERTIES 14 | ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib 15 | LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib 16 | RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin 17 | ) 18 | 19 | clang_format_target(TARGET execute_order) -------------------------------------------------------------------------------- /src/apps/execute_order/execute_order.cpp: -------------------------------------------------------------------------------- 1 | #include "ccex_order_executor.hpp" 2 | #include "program_options.hpp" 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | namespace profitview 16 | { 17 | 18 | struct ProgramArgs 19 | { 20 | std::string exchange; 21 | std::string symbol; 22 | std::string api_key; 23 | std::string api_secret; 24 | std::string api_phrase; 25 | std::string sub_account; 26 | Side side = Side::Buy; 27 | double size = 0.0; 28 | OrderType type = OrderType::Limit; 29 | double price = 0.0; 30 | 31 | void addOptions(boost::program_options::options_description& options) 32 | { 33 | namespace po = boost::program_options; 34 | // clang-format off 35 | options.add_options() 36 | ("exchange", po::value(&exchange)->required(), "Crypto Exchange to execute on.") 37 | ("symbol", po::value(&symbol)->required(), "Symbol for cypto assets to trade.") 38 | ("api_key", po::value(&api_key)->required(), "API key for Cypto exchange.") 39 | ("api_secret", po::value(&api_secret)->required(), "API secret for Cypto exchange.") 40 | ("api_phrase", po::value(&api_phrase), "API phrase for Cypto exchange.") 41 | ("sub_account", po::value(&sub_account), "Subaccount on Cypto exchange.") 42 | ("side", po::value(&side)->required(), "The side of the trade .") 43 | ("size", po::value(&size)->required(), "Size to trade.") 44 | ("type", po::value(&type)->required(), "The type of order .") 45 | ("price", po::value(&price), "Price to trade at."); 46 | // clang-format on 47 | } 48 | }; 49 | 50 | } // namespace profitview 51 | auto main(int argc, char* argv[]) -> int 52 | { 53 | using namespace profitview; 54 | ProgramArgs options; 55 | auto const result = parseProgramOptions(argc, argv, options); 56 | if (result) 57 | return result.value(); 58 | 59 | const std::map exchange_names = { 60 | {"ftx", CCAPI_EXCHANGE_NAME_FTX }, 61 | {"coinbase", CCAPI_EXCHANGE_NAME_COINBASE}, 62 | {"bitmex", CCAPI_EXCHANGE_NAME_BITMEX }, 63 | }; 64 | 65 | BOOST_LOG_TRIVIAL(info) << "Running Ccex test."; 66 | 67 | CcexOrderExecutor executor{ 68 | exchange_names.at(options.exchange), options.api_key, options.api_secret, options.api_phrase, options.sub_account}; 69 | 70 | BOOST_LOG_TRIVIAL(info) << options.symbol << "Running: " << std::endl; 71 | executor.new_order(options.symbol, options.side, options.size, options.type, options.price); 72 | 73 | enum 74 | { 75 | OrderId, 76 | Symbol, 77 | OrderSide, 78 | Size, 79 | Price, 80 | Time, 81 | Status 82 | }; 83 | for (const auto& [cid, details] : executor.get_open_orders()) 84 | BOOST_LOG_TRIVIAL(info) << "cid: " << cid << ", symbol: " << std::get(details) 85 | << ", status: " << std::get(details) << std::endl; 86 | return 0; 87 | } -------------------------------------------------------------------------------- /src/apps/experiment/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(experiment) 2 | target_sources(experiment 3 | PRIVATE 4 | experiment.cpp 5 | ) 6 | 7 | target_link_libraries(experiment 8 | PRIVATE 9 | cpp_crypto_algos_lib 10 | ) 11 | 12 | set_target_properties(experiment 13 | PROPERTIES 14 | ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib 15 | LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib 16 | RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin 17 | ) 18 | 19 | clang_format_target(TARGET experiment) -------------------------------------------------------------------------------- /src/apps/experiment/experiment.cpp: -------------------------------------------------------------------------------- 1 | #include "program_options.hpp" 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | #include 12 | 13 | namespace profitview 14 | { 15 | 16 | struct ProgramArgs 17 | { 18 | std::string name; 19 | int er_period; 20 | // std::string symbol; 21 | // std::string api_key; 22 | // std::string api_secret; 23 | // std::string api_phrase; 24 | // double size = 0.0; 25 | // double price = 0.0; 26 | 27 | void addOptions(boost::program_options::options_description& options) 28 | { 29 | namespace po = boost::program_options; 30 | // clang-format off 31 | options.add_options() 32 | ("name", po::value(&name)->required(), "Name of experiment") 33 | ("er_period", po::value(&er_period)->required(), "Efficiency ratio lookback period"); 34 | // clang-format on 35 | } 36 | }; 37 | 38 | } // namespace profitview 39 | 40 | auto main(int argc, char* argv[]) -> int 41 | { 42 | using namespace profitview; 43 | ProgramArgs options; 44 | auto const result = parseProgramOptions(argc, argv, options); 45 | if (result) 46 | return result.value(); 47 | 48 | BOOST_LOG_TRIVIAL(info) << "Running experiments" << std::endl; 49 | 50 | BOOST_LOG_TRIVIAL(info) << " Running: " << options.name << std::endl; 51 | 52 | std::vector a{5, 6, 7, 10, 11, 12, 5, 6, 7, 10, 11, 12, 5, 6, 7, 10, 11, 12, 5, 6, 7, 10, 11, 12}; 53 | std::ofstream exp{"experiment.csv"}; 54 | profitview::util::CsvWriter cw{exp}; 55 | 56 | auto [d, c]{profitview::util::abs_differences(a, options.er_period)}; 57 | 58 | cw.write(a[0], d[0], c, 5.5); 59 | 60 | cw.write("Hello", "there", std::to_string(20.5), a[0], d[0], c, 5.5); 61 | 62 | using namespace std::ranges; 63 | 64 | copy(d, std::ostream_iterator(std::cout, " ")); 65 | BOOST_LOG_TRIVIAL(info) << std::endl << "Change: " << c << std::endl; 66 | 67 | subrange s1{a.begin(), a.begin() + 5}; 68 | subrange s2{a.begin() + 3, a.begin() + 7}; 69 | subrange s3{a.begin(), a.begin() + 10}; 70 | subrange s4{a.begin() + 5, a.begin() + 6}; 71 | 72 | auto [s1m, s1d]{util::is_monotonic(s1)}; 73 | auto [s2m, s2d]{util::is_monotonic(s2)}; 74 | auto [s3m, s3d]{util::is_monotonic(s3)}; 75 | auto [s4m, s4d]{util::is_monotonic(s4)}; 76 | 77 | std::cout << std::boolalpha << s1m << " " << s1d << std::endl 78 | << s2m << " " << s2d << std::endl 79 | << s3m << " " << s3d << std::endl 80 | << s4m << " " << s4d << std::endl 81 | << std::endl; 82 | 83 | return 0; 84 | } -------------------------------------------------------------------------------- /src/apps/streamer/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(streamer) 2 | target_sources(streamer 3 | PRIVATE 4 | streamer.cpp 5 | ) 6 | 7 | target_link_libraries(streamer 8 | PRIVATE 9 | cpp_crypto_algos_lib 10 | ) 11 | 12 | set_target_properties(streamer 13 | PROPERTIES 14 | ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib 15 | LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib 16 | RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin 17 | ) 18 | 19 | clang_format_target(TARGET streamer) -------------------------------------------------------------------------------- /src/apps/streamer/streamer.cpp: -------------------------------------------------------------------------------- 1 | #include "program_options.hpp" 2 | #include "trade_stream_maker.hpp" 3 | #include "wscc_trade_stream.hpp" 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace profitview 11 | { 12 | 13 | struct ProgramArgs 14 | { 15 | std::string exchange; 16 | std::vector symbols; 17 | 18 | void addOptions(boost::program_options::options_description& options) 19 | { 20 | namespace po = boost::program_options; 21 | // clang-format off 22 | options.add_options() 23 | ("exchange", po::value(&exchange)->required(), "Crypto Exchange to execute on.") 24 | ("symbols", po::value(&symbols)->multitoken()->required(), "Symbols for cypto assets to trade."); 25 | // clang-format on 26 | } 27 | }; 28 | 29 | } // namespace profitview 30 | 31 | int main(int argc, char* argv[]) 32 | { 33 | using namespace profitview; 34 | ProgramArgs options; 35 | auto const result = profitview::parseProgramOptions(argc, argv, options); 36 | if (result) 37 | return result.value(); 38 | 39 | auto stream {TradeStreamMaker::register_stream("WSCcStream")}; 40 | stream->subscribe(options.exchange, options.symbols); 41 | 42 | std::cout << "Press enter to quit" << std::endl; 43 | std::cin.get(); 44 | } -------------------------------------------------------------------------------- /src/cc_damped_mr.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "enum.hpp" 4 | #include "cc_trade_stream.hpp" 5 | #include "utils.hpp" 6 | #include "trade_data.hpp" 7 | 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | namespace profitview 14 | { 15 | 16 | template 17 | class CcDamped : public CcTradeStream 18 | { 19 | public: 20 | CcDamped( 21 | const std::string trade_stream_name, 22 | OrderExecutor* executor, 23 | Int lookback, 24 | Float reversion_level, 25 | Float base_quantity, 26 | Float damping, 27 | const std::string& csv_name = "Damped.csv") 28 | : CcTradeStream(trade_stream_name, executor, csv_name) 29 | , lookback_{lookback} 30 | , reversion_level_{reversion_level} 31 | , base_quantity_{base_quantity} 32 | , damping_{damping} 33 | {} 34 | 35 | void onStreamedTrade(TradeData const& trade_data) override 36 | { 37 | trade_data.print(); 38 | 39 | auto& [prices, mean_reached, initial_mean, initial_stdev]{price_structure_[trade_data.symbol]}; 40 | 41 | prices.emplace_back(trade_data.price); 42 | 43 | if (not mean_reached and prices.size() > lookback_) 44 | { 45 | initial_mean = util::ma(prices); 46 | initial_stdev = util::stdev(prices, initial_mean, lookback_); 47 | BOOST_LOG_TRIVIAL(info) << "Initial mean: " << initial_mean << std::endl << std::endl; 48 | mean_reached = true; 49 | } 50 | else if (mean_reached) 51 | { 52 | auto mean{util::ma(prices)}; 53 | BOOST_LOG_TRIVIAL(info) << "MA: " << mean << std::endl << std::endl; 54 | 55 | auto const& damping_factor{damping_ * initial_stdev}; 56 | 57 | // Version 1: chopping the tops/bottoms off outliers 58 | auto const& cut_damped{prices | std::ranges::views::transform([&mean, &damping_factor](auto price) -> auto { 59 | return std::abs(price - mean) > damping_factor 60 | ? boost::math::sign(price - mean) * damping_factor + mean 61 | : price; 62 | })}; 63 | 64 | // Version 2: excluding outliers 65 | auto excluded_damped{prices | std::ranges::views::filter([&mean, &damping_factor](auto price) -> auto { 66 | return std::abs(price - mean) < damping_factor; 67 | })}; 68 | 69 | // Using Version 2 this time: 70 | auto std_reversion{reversion_level_ * util::stdev(excluded_damped, mean, lookback_)}; 71 | BOOST_LOG_TRIVIAL(info) << "Std Reversion: " << std_reversion << std::endl << std::endl; 72 | 73 | prices.pop_front(); 74 | 75 | bool 76 | sell_signal{trade_data.price > mean + std_reversion}, 77 | buy_signal {trade_data.price < mean - std_reversion}; 78 | 79 | if (sell_signal) 80 | { 81 | this->new_order(trade_data.symbol, Side::Sell, base_quantity_, OrderType::Market); 82 | } 83 | else if (buy_signal) 84 | { 85 | this->new_order(trade_data.symbol, Side::Buy, base_quantity_, OrderType::Market); 86 | } 87 | 88 | this->writeCsv( 89 | trade_data.symbol, 90 | trade_data.price, 91 | toString(trade_data.side).data(), 92 | trade_data.size, 93 | trade_data.source, 94 | trade_data.time, 95 | mean, 96 | std_reversion, 97 | buy_signal ? "Buy" : (sell_signal ? "Sell" : "No trade")); 98 | } 99 | } 100 | 101 | struct Data 102 | { 103 | std::deque prices; 104 | bool mean_reached; 105 | Float initial_mean, initial_stdev; 106 | }; 107 | 108 | private: 109 | const Int lookback_; 110 | const Float reversion_level_; 111 | const Float base_quantity_; 112 | const Float damping_; 113 | 114 | std::map price_structure_; 115 | }; 116 | 117 | } // namespace profitview -------------------------------------------------------------------------------- /src/cc_kaufman.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "enum.hpp" 4 | #include "cc_trade_stream.hpp" 5 | #include "utils.hpp" 6 | #include "trade_data.hpp" 7 | 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | namespace profitview 14 | { 15 | 16 | template 17 | class CcKaufman : public CcTradeStream 18 | { 19 | public: 20 | CcKaufman( 21 | const std::string trade_stream_name, 22 | OrderExecutor* executor, 23 | Int lookback, 24 | Float base_quantity, 25 | Int er_period, 26 | Int fast_sc, 27 | Int slow_sc, 28 | Int kama_trend, 29 | const std::string& csv_name = "Kaufman.csv") 30 | : CcTradeStream(trade_stream_name, executor, csv_name) 31 | , lookback_{lookback} 32 | , base_quantity_{base_quantity} 33 | , er_period_{er_period} 34 | , fast_sc_{fast_sc} 35 | , slow_sc_{slow_sc} 36 | , kama_trend_{kama_trend} 37 | {} 38 | 39 | void onStreamedTrade(TradeData const& trade_data) override 40 | { 41 | trade_data.print(); 42 | 43 | auto& [prices, mean_reached, initial_mean, kama, kamas]{price_structure_[trade_data.symbol]}; 44 | 45 | prices.emplace_back(trade_data.price); 46 | 47 | auto sc_factor{2.0 / (fast_sc_ + 1) - 2.0 / (slow_sc_ + 1)}; 48 | auto sc_sum{2.0 / (slow_sc_ + 1)}; 49 | 50 | if (not mean_reached && prices.size() + 1 == lookback_) 51 | { 52 | kama = initial_mean = util::ma(prices); 53 | BOOST_LOG_TRIVIAL(info) << "Initial mean: " << initial_mean << std::endl << std::endl; 54 | mean_reached = true; 55 | } 56 | else if (mean_reached) 57 | { 58 | auto [er_vols, change]{util::abs_differences(prices, er_period_)}; 59 | auto er_vol{util::accumulate(er_vols, 0.0)}; 60 | // Occasionally, the sequence will be constant: 61 | auto er{er_vol > 0 ? change / er_vol : 0.0}; // leading to er_vol of zero 62 | auto root_sc{er * sc_factor + sc_sum}; 63 | auto sc{root_sc * root_sc}; 64 | 65 | BOOST_LOG_TRIVIAL(info) << "ER: " << er << std::endl; 66 | BOOST_LOG_TRIVIAL(info) << "SC: " << sc << std::endl; 67 | 68 | // These could be done on the fly but the complexity would distract 69 | auto mean{util::ma(prices)}; 70 | 71 | prices.pop_front(); // Now we have lookback_ prices already, remove the 72 | // oldest 73 | 74 | kamas.emplace_back(kama = kama + sc * (trade_data.price - kama)); 75 | 76 | if (kamas.size() > kama_trend_) 77 | { 78 | auto [monotonic, up]{util::is_monotonic(std::ranges::subrange{kamas.end() - kama_trend_, kamas.end()})}; 79 | if (not monotonic) // Signal 80 | { 81 | // @todo This will keep buying/selling when the market is not 82 | // directional 83 | // It should have more refined behaviour 84 | this->new_order(trade_data.symbol, up ? Side::Buy : Side::Sell, base_quantity_, OrderType::Market); 85 | } 86 | 87 | this->writeCsv( 88 | trade_data.symbol, 89 | trade_data.price, 90 | toString(trade_data.side).data(), 91 | trade_data.size, 92 | trade_data.source, 93 | trade_data.time, 94 | kama, 95 | monotonic ? (up ? "Up" : "Down") : "Not monotonic"); 96 | 97 | kamas.pop_front(); // Remove oldest KAMA price 98 | } 99 | } 100 | } 101 | 102 | struct Data 103 | { 104 | std::deque prices; 105 | bool mean_reached; 106 | Float initial_mean, kama; 107 | std::deque kamas; 108 | }; 109 | 110 | private: 111 | const Int lookback_; 112 | 113 | double base_quantity_; 114 | Int er_period_, fast_sc_, slow_sc_, kama_trend_; 115 | 116 | std::map price_structure_; 117 | 118 | }; 119 | 120 | } // namespace profitview -------------------------------------------------------------------------------- /src/cc_simple_mr.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "enum.hpp" 4 | #include "cc_trade_stream.hpp" 5 | #include "utils.hpp" 6 | #include "trade_data.hpp" 7 | 8 | #include 9 | #include 10 | 11 | namespace profitview 12 | { 13 | 14 | template 15 | class CcSimpleMR : public CcTradeStream 16 | { 17 | public: 18 | CcSimpleMR( 19 | const std::string trade_stream_name, 20 | OrderExecutor* executor, 21 | Int lookback, 22 | Float reversion_level, 23 | Float base_quantity, 24 | const std::string& csv_name = "SimpleMR.csv") 25 | : CcTradeStream(trade_stream_name, executor, csv_name) 26 | , lookback_{lookback} 27 | , reversion_level_{reversion_level} 28 | , base_quantity_{base_quantity} 29 | {} 30 | 31 | void onStreamedTrade(TradeData const& trade_data) override 32 | { 33 | trade_data.print(); 34 | 35 | auto& [elements, prices]{counted_prices_[trade_data.symbol]}; 36 | 37 | prices.emplace_back(trade_data.price); 38 | 39 | if (prices.size() > lookback_) 40 | { 41 | auto mean{util::ma(prices)}; 42 | 43 | auto std_reversion{reversion_level_ * util::stdev(prices, mean, lookback_)}; 44 | 45 | prices.pop_front(); 46 | 47 | bool 48 | sell_signal{trade_data.price > mean + std_reversion}, 49 | buy_signal {trade_data.price < mean - std_reversion}; 50 | 51 | if (sell_signal) 52 | { 53 | this->new_order(trade_data.symbol, Side::Sell, base_quantity_, OrderType::Market); 54 | } 55 | else if (buy_signal) 56 | { 57 | this->new_order(trade_data.symbol, Side::Buy, base_quantity_, OrderType::Market); 58 | } 59 | 60 | this->writeCsv( 61 | trade_data.symbol, 62 | trade_data.price, 63 | toString(trade_data.side).data(), 64 | trade_data.size, 65 | trade_data.source, 66 | trade_data.time, 67 | mean, 68 | std_reversion, 69 | buy_signal ? "Buy" : (sell_signal ? "Sell" : "No trade")); 70 | } 71 | } 72 | 73 | private: 74 | const Int lookback_; 75 | 76 | const Float reversion_level_; // Multiple of stdev 77 | Float base_quantity_; 78 | 79 | std::map>> counted_prices_; 80 | }; 81 | 82 | } // namespace profitview -------------------------------------------------------------------------------- /src/cc_trade_handler.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "trade_stream_maker.hpp" 4 | #include "trade_stream.hpp" 5 | 6 | #include 7 | 8 | #include 9 | 10 | #include 11 | 12 | #include 13 | 14 | namespace ccapi 15 | { 16 | using namespace profitview; 17 | class CcTradeHandler : public EventHandler 18 | { 19 | public: 20 | CcTradeHandler(const std::string& trade_stream_name) 21 | : trade_stream_name_{trade_stream_name} 22 | , sessionOptions_{} 23 | , sessionConfigs_{} 24 | , session_{nullptr} 25 | , stream_{nullptr} 26 | { 27 | session_ = std::make_unique(sessionOptions_, sessionConfigs_, this); 28 | } 29 | 30 | void set_stream(TradeStream* stream) { stream_ = stream; } 31 | 32 | void subscribe(const std::string& market, const std::vector& symbol_list) 33 | { 34 | market_ = market; // Assuming for the moment that `subscribe` is called only 35 | // once and there's only 1 market 36 | 37 | std::vector subscriptions; 38 | for (auto& symbol : symbol_list) 39 | subscriptions.emplace_back(market, symbol, "TRADE", "", 40 | symbol); // <-- using `symbol` as correlation id 41 | session_->subscribe(subscriptions); 42 | } 43 | 44 | bool processEvent(const Event& event, Session* session) override 45 | { 46 | if (event.getType() == Event::Type::SUBSCRIPTION_DATA) 47 | { 48 | for (const auto& message : event.getMessageList()) 49 | { 50 | const auto& cid{message.getCorrelationIdList()}; // Assumes correlation list matchs 51 | // elements - which it should 52 | for (const auto& [index, element] : message.getElementList() | boost::adaptors::indexed(0)) 53 | { 54 | const auto& e{element.getNameValueMap()}; 55 | assert(stream_ != nullptr); 56 | stream_->onStreamedTrade( 57 | {std::stod(e.at("LAST_PRICE")), 58 | e.at("IS_BUYER_MAKER") == "1" ? Side::Buy : Side::Sell, 59 | std::stod(e.at("LAST_SIZE")), 60 | market_, 61 | cid[index], 62 | message.getTime().time_since_epoch().count() / 1'000'000'000}); 63 | } 64 | } 65 | } 66 | return true; 67 | } 68 | 69 | ~CcTradeHandler() { session_->stop(); } 70 | 71 | private: 72 | const std::string trade_stream_name_; // @note Can't be a reference (why? not understood) 73 | SessionOptions sessionOptions_; 74 | SessionConfigs sessionConfigs_; 75 | std::unique_ptr session_; 76 | TradeStream* stream_; 77 | 78 | std::string market_; 79 | }; 80 | } // namespace ccapi 81 | -------------------------------------------------------------------------------- /src/cc_trade_stream.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "enum.hpp" 4 | #include "order_executor.hpp" 5 | #include "utils.hpp" 6 | #include "wscc_trade_stream.hpp" 7 | 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | namespace profitview 15 | { 16 | 17 | template 18 | class CcTradeStream 19 | : public TradeStream 20 | , private ccapi::CcTradeHandler 21 | { 22 | public: 23 | CcTradeStream( 24 | const std::string trade_stream_name, 25 | OrderExecutor* executor, 26 | const std::string& csv_name) 27 | : ccapi::CcTradeHandler(trade_stream_name) 28 | , executor_{executor} 29 | , csv_{csv_name} 30 | , csv_writer_{csv_} 31 | {} 32 | 33 | void subscribe(const std::string& market, const std::vector& symbol_list) 34 | { 35 | CcTradeHandler::set_stream(this); 36 | CcTradeHandler::subscribe(market, symbol_list); 37 | } 38 | 39 | void writeCsv(auto&&... args) 40 | { 41 | csv_writer_.write(std::forward(args)...); 42 | } 43 | 44 | protected: 45 | 46 | auto new_order(std::string const& symbol, Side side, double orderQty, OrderType type, double price = 0.0) -> auto 47 | { 48 | return executor_->new_order(symbol, side, orderQty, type, price); 49 | } 50 | 51 | private: 52 | OrderExecutor* executor_; 53 | std::ofstream csv_; 54 | util::CsvWriter csv_writer_; 55 | }; 56 | 57 | } // namespace profitview -------------------------------------------------------------------------------- /src/ccex_order_executor.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "order_executor.hpp" 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | namespace ccapi 19 | { 20 | Logger* Logger::logger = nullptr; // This line is needed. 21 | } 22 | 23 | namespace profitview 24 | { 25 | 26 | using ::ccapi::Request; 27 | using ::ccapi::Session; 28 | using ::ccapi::SessionConfigs; 29 | using ::ccapi::SessionOptions; 30 | 31 | class CcexOrderExecutor : public OrderExecutor 32 | { 33 | private: 34 | inline static const std::unordered_map order_type_names_{ 35 | {OrderType::Limit, "Limit" }, 36 | {OrderType::Market, "Market"} 37 | }; 38 | inline static const std::unordered_map side_names_{ 39 | {Side::Buy, "Buy" }, 40 | {Side::Sell, "Sell"} 41 | }; 42 | 43 | std::string order_message_; 44 | std::string api_key_; 45 | std::string api_secret_; 46 | std::string pass_phrase_; 47 | std::string sub_account_; 48 | std::string exchange_; 49 | int expiry_; 50 | 51 | std::unordered_map< 52 | std::string, 53 | std::tuple> 54 | open_orders_; 55 | 56 | inline static const std::map> exchange_key_names_{ 57 | { 58 | {CCAPI_EXCHANGE_NAME_FTX, {CCAPI_FTX_API_KEY, CCAPI_FTX_API_SECRET, "", CCAPI_FTX_API_SUBACCOUNT}}, 59 | {CCAPI_EXCHANGE_NAME_BITMEX, {CCAPI_BITMEX_API_KEY, CCAPI_FTX_API_SECRET, "", ""}}, 60 | {CCAPI_EXCHANGE_NAME_COINBASE, 61 | {CCAPI_COINBASE_API_KEY, CCAPI_COINBASE_API_SECRET, CCAPI_COINBASE_API_PASSPHRASE, ""}}, 62 | } 63 | }; 64 | 65 | class CcexOrderHandler : public ccapi::EventHandler 66 | { 67 | private: 68 | std::atomic_flag ordered_; 69 | 70 | CcexOrderExecutor* executor_; 71 | 72 | public: 73 | CcexOrderHandler(CcexOrderExecutor* executor) 74 | : executor_{executor} 75 | {} 76 | 77 | bool processEvent(const ccapi::Event& event, ccapi::Session* session) override 78 | { 79 | BOOST_LOG_TRIVIAL(info) << "Received an event:\n" + event.toStringPretty(2, 2) << std::endl; 80 | const auto& m{event.getMessageList()}; 81 | const auto& n{m[0].getElementList()[0].getNameValueMap()}; 82 | BOOST_LOG_TRIVIAL(info) << "Status: " 83 | << (n.contains("STATUS") ? n.at("STATUS") 84 | : (n.contains("ERROR_MESSAGE") ? n.at("ERROR_MESSAGE") : "No status")) 85 | << std::endl; 86 | if (n.contains("LIMIT_PRICE")) 87 | { 88 | executor_->add_open_order( 89 | m[0].getCorrelationIdList()[0], 90 | n.at("ORDER_ID"), 91 | n.at("INSTRUMENT"), 92 | n.at("SIDE") == "BUY" ? Side::Buy : Side::Sell, 93 | std::stod(n.at("QUANTITY")), 94 | std::stod(n.at("LIMIT_PRICE")), 95 | m[0].getTimeReceived(), 96 | n.at("STATUS")); 97 | } 98 | ordered_.test_and_set(); 99 | ordered_.notify_one(); 100 | return true; 101 | } 102 | void wait() const 103 | { 104 | BOOST_LOG_TRIVIAL(info) << "Waiting for order event" << std::endl; 105 | ordered_.wait(false); 106 | } 107 | }; 108 | 109 | void add_open_order( 110 | const std::string& cid, 111 | const std::string& order_id, 112 | const std::string& symbol, 113 | Side side, 114 | double size, 115 | double price, 116 | ccapi::TimePoint time, 117 | const std::string& status) 118 | { 119 | open_orders_[cid] = {order_id, symbol, side, size, price, time, status}; 120 | } 121 | 122 | void adjust_exchange_params(const std::string& exchange, auto& params) 123 | { 124 | // Handling of Market orders differs between exchanges 125 | if (params.at("type") == "market") 126 | { 127 | if (exchange == CCAPI_EXCHANGE_NAME_COINBASE) 128 | { 129 | params.erase("price"); 130 | } 131 | } 132 | } 133 | 134 | public: 135 | CcexOrderExecutor( 136 | const std::string& exchange, 137 | const std::string& api_key, 138 | const std::string& api_secret, 139 | const std::string& pass_phrase, 140 | const std::string& sub_account) 141 | : exchange_{exchange} 142 | , api_key_{api_key} 143 | , api_secret_{api_secret} 144 | , pass_phrase_{pass_phrase} 145 | , sub_account_{sub_account} 146 | {} 147 | 148 | friend class CcexOrderHandler; 149 | 150 | const auto& get_open_orders() const { return open_orders_; } 151 | 152 | void new_order( 153 | std::string const& symbol, Side side, double orderQty, OrderType type, double price // = 0.0 154 | ) override 155 | { 156 | SessionOptions session_options; 157 | SessionConfigs session_configs; 158 | CcexOrderHandler event_handler(this); 159 | 160 | enum 161 | { 162 | ApiKey, 163 | ApiSecret, 164 | PassPhrase, 165 | SubAccount 166 | }; 167 | session_configs.setCredential({ 168 | {std::get(exchange_key_names_.at(exchange_)), api_key_ }, 169 | {std::get(exchange_key_names_.at(exchange_)), api_secret_ }, 170 | {std::get(exchange_key_names_.at(exchange_)), pass_phrase_}, 171 | {std::get(exchange_key_names_.at(exchange_)), sub_account_} 172 | }); 173 | 174 | Session session(session_options, session_configs, &event_handler); 175 | Request request(Request::Operation::CREATE_ORDER, exchange_, symbol); 176 | 177 | std::map params{ 178 | {"type", type == OrderType::Market ? "market" : "limit"}, 179 | {"side", side == Side::Buy ? "BUY" : "SELL" }, 180 | {"size", std::to_string(orderQty) }, 181 | {"price", std::to_string(price) } 182 | }; 183 | 184 | adjust_exchange_params(exchange_, params); 185 | 186 | request.appendParam(params); 187 | session.sendRequest(request); 188 | event_handler.wait(); 189 | session.stop(); 190 | } 191 | }; 192 | 193 | } // namespace profitview -------------------------------------------------------------------------------- /src/enum.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace profitview 11 | { 12 | 13 | template 14 | concept BoostDescribeEnum = std::is_enum_v && requires 15 | { 16 | typename boost::describe::describe_enumerators; 17 | }; 18 | 19 | template 20 | std::string_view toString(Enum const value, std::string_view result = {}) 21 | { 22 | boost::mp11::mp_for_each>( 23 | [&result, value](auto describe) 24 | { 25 | if (value == describe.value) 26 | { 27 | result = describe.name; 28 | } 29 | }); 30 | return result; 31 | } 32 | 33 | template 34 | auto fromString(std::string_view const value) 35 | { 36 | std::optional result = std::nullopt; 37 | boost::mp11::mp_for_each>( 38 | [&result, value](auto describe) 39 | { 40 | if (boost::iequals(value, describe.name)) 41 | { 42 | result = describe.value; 43 | } 44 | }); 45 | return result; 46 | } 47 | 48 | } // namespace profitview -------------------------------------------------------------------------------- /src/exchange.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "order_executor.hpp" 4 | #include "order_type.hpp" 5 | #include "side.hpp" 6 | 7 | #include 8 | #include 9 | 10 | namespace profitview 11 | { 12 | 13 | class Exchange 14 | { 15 | public: 16 | virtual ~Exchange() = default; 17 | virtual boost::json::object 18 | new_order(std::string const& symbol, Side side, double orderQty, OrderType type, double price = -1.0) = 0; 19 | }; 20 | 21 | } // namespace profitview 22 | -------------------------------------------------------------------------------- /src/order_executor.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "order_type.hpp" 4 | #include "side.hpp" 5 | 6 | #include 7 | 8 | namespace profitview 9 | { 10 | 11 | class OrderExecutor 12 | { 13 | public: 14 | OrderExecutor() = default; 15 | virtual ~OrderExecutor() = default; 16 | virtual void new_order(std::string const& symbol, Side side, double orderQty, OrderType type, double = 0.0) = 0; 17 | }; 18 | 19 | } // namespace profitview 20 | -------------------------------------------------------------------------------- /src/order_type.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace profitview 6 | { 7 | 8 | BOOST_DEFINE_ENUM_CLASS(OrderType, Limit, Market) 9 | 10 | } -------------------------------------------------------------------------------- /src/program_options.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "cpp_crypto_algos_config.hpp" 4 | #include "enum.hpp" 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | namespace profitview 17 | { 18 | 19 | template 20 | void validate(boost::any& v, const std::vector& values, Enum*, int) 21 | { 22 | namespace po = boost::program_options; 23 | po::validators::check_first_occurrence(v); 24 | std::string const& s = po::validators::get_single_string(values); 25 | 26 | if (auto const value = fromString(s); value.has_value()) 27 | { 28 | v = value.value(); 29 | } 30 | else 31 | { 32 | boost::throw_exception(po::invalid_option_value(s)); 33 | } 34 | } 35 | 36 | // clang-format off 37 | template 38 | concept CustomProgramOptions = requires(T& t, boost::program_options::options_description& options) 39 | { 40 | { t.addOptions(options) } -> std::same_as; 41 | }; 42 | // clang-format on 43 | 44 | std::optional parseProgramOptions(int argc, char* argv[], CustomProgramOptions auto&... options) 45 | { 46 | namespace po = boost::program_options; 47 | try 48 | { 49 | po::options_description desc(fmt::format( 50 | "{} Version {}.{}\n\nUsage: ", 51 | std::filesystem::path(argv[0]).filename().string(), 52 | cpp_crypto_algos_VERSION_MAJOR, 53 | cpp_crypto_algos_VERSION_MINOR)); 54 | 55 | desc.add_options()("help", "produce help message"); 56 | 57 | (options.addOptions(desc), ...); 58 | 59 | po::variables_map vm; 60 | po::store(po::parse_command_line(argc, argv, desc), vm); 61 | 62 | if (vm.count("help")) 63 | { 64 | std::cout << desc << "\n"; 65 | return 1; 66 | } 67 | 68 | po::notify(vm); 69 | } 70 | catch (po::required_option& e) 71 | { 72 | BOOST_LOG_TRIVIAL(error) << e.what() << std::endl; 73 | return 1; 74 | } 75 | return std::nullopt; 76 | } 77 | 78 | } // namespace profitview -------------------------------------------------------------------------------- /src/side.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace profitview 6 | { 7 | 8 | BOOST_DEFINE_ENUM_CLASS(Side, Buy, Sell) 9 | 10 | } -------------------------------------------------------------------------------- /src/trade_data.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | namespace profitview 11 | { 12 | 13 | struct TradeData 14 | { 15 | double price; 16 | Side side; 17 | double size; 18 | std::string source; 19 | std::string symbol; 20 | time_t time; 21 | void print() const 22 | { 23 | fmt::print("Price: {}, ", price); 24 | fmt::print("Side: {}, ", toString(side)); 25 | fmt::print("Size: {}, ", size); 26 | fmt::print("Source: {}, ", source); 27 | fmt::print("Symbol: {}, ", symbol); 28 | fmt::print("Time: {}", std::asctime(std::localtime(&time))); 29 | } 30 | }; 31 | 32 | } // namespace profitview -------------------------------------------------------------------------------- /src/trade_stream.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "trade_data.hpp" 4 | 5 | #include 6 | #include 7 | 8 | namespace profitview 9 | { 10 | 11 | class TradeStream 12 | { 13 | public: 14 | TradeStream() = default; 15 | virtual ~TradeStream() = default; 16 | virtual void onStreamedTrade(TradeData const& trade_data) = 0; 17 | virtual void subscribe(std::string const& market, std::vector const& symbol_list) = 0; 18 | }; 19 | 20 | } // namespace profitview -------------------------------------------------------------------------------- /src/trade_stream_exception.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace profitview 7 | { 8 | 9 | struct TradeStreamException : public std::runtime_error 10 | { 11 | TradeStreamException(std::string const& message) 12 | : std::runtime_error(message) 13 | {} 14 | }; 15 | 16 | } // namespace profitview -------------------------------------------------------------------------------- /src/trade_stream_maker.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "side.hpp" 4 | #include "trade_data.hpp" 5 | #include "trade_stream.hpp" 6 | #include "trade_stream_exception.hpp" 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | namespace profitview 13 | { 14 | 15 | struct TradeStreamMaker 16 | { 17 | public: 18 | template 19 | static auto register_stream(std::string const& name, Args&&... args) -> auto 20 | { 21 | return made[name] = std::make_shared(name, std::forward(args)...); 22 | } 23 | 24 | static TradeStream& get(std::string const& name) { return *made.at(name); } 25 | 26 | private: 27 | inline static std::unordered_map> made; 28 | }; 29 | 30 | } // namespace profitview 31 | -------------------------------------------------------------------------------- /src/utils.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | namespace profitview::util 19 | { 20 | 21 | class CsvWriter : public csv2::Writer> 22 | { // Provides shorthand 23 | // `write()` 24 | public: 25 | CsvWriter(auto& stream) 26 | : csv2::Writer>(stream) 27 | {} 28 | 29 | void write(auto&&... args) 30 | { 31 | write_row>({fmt::format("{}", std::forward(args))...}); 32 | } 33 | }; 34 | 35 | // boost::accumulate should do this, but there's a compile fail 36 | inline auto accumulate(const auto& s, auto i) -> auto { return std::accumulate(std::begin(s), std::end(s), i); } 37 | 38 | inline auto accumulate(auto& s, auto i, auto op) -> auto { return std::accumulate(std::begin(s), std::end(s), i, op); } 39 | 40 | auto stdev(auto& s, auto m, int p) -> auto 41 | { // Calculate standard deviation given mean (m) 42 | auto const variance{[&m, &p](auto a, const auto& v) { return a + (v - m) * (v - m) / (p - 1);}}; 43 | 44 | return std::sqrt(accumulate(s, 0.0, variance)); 45 | } 46 | 47 | auto ma(auto const& s, int p = 0) -> auto { return accumulate(s, 0.0) / (p ? p : s.size()); } 48 | 49 | // Exponential Moving Average (ema) difference formula from 50 | // https://en.wikipedia.org/wiki/Moving_average: 51 | auto ema(auto const& s, auto p, auto m = 0) -> auto 52 | { 53 | auto alpha{2.0f / (p - 1)}; 54 | auto const ema_step{[&alpha](auto a, const auto& price) { return price * alpha + a * (1 - alpha); }}; 55 | 56 | return accumulate(s, m, ema_step); 57 | } 58 | 59 | auto abs_differences(const auto& prices, int e) -> auto 60 | { 61 | auto b{prices.end() - e}; 62 | assert(prices.size() > e); 63 | 64 | using namespace std::ranges; 65 | 66 | std::ranges::subrange lagged{b - 1, prices.end() - 1}, aligned{b, prices.end()}; 67 | std::vector::value_type> differences(e); 68 | transform( 69 | lagged, aligned, differences.begin(), [](auto n, auto m) -> auto { return std::abs(n - m); }); 70 | 71 | return std::make_tuple(differences, prices.back() - *b); 72 | } 73 | 74 | auto is_monotonic(auto const& s) -> std::tuple // { monotonic, up } 75 | { // If monotonic ascending { true, true } 76 | // If monotonic descending { true, false } 77 | // If non-monotonic now ascending { false, true } 78 | // If non-monotonic now descending { false, false } 79 | auto sgn = [](int a, int b) { return a < b ? 1 : (a == b) ? 0 : -1; }; 80 | int prev = 0; 81 | for (int i = 0; i < s.size() - 1; ++i) 82 | { 83 | int c = sgn(s[i], s[i + 1]); 84 | if (c != 0) 85 | { 86 | if (c != prev && prev != 0) 87 | { 88 | return {false, c == 1}; 89 | } 90 | prev = c; 91 | } 92 | } 93 | return {true, prev == 1}; 94 | } 95 | 96 | } // namespace profitview::util -------------------------------------------------------------------------------- /src/wscc_trade_stream.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "cc_trade_handler.hpp" 4 | #include "trade_stream_maker.hpp" 5 | 6 | #include 7 | 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | namespace profitview 14 | { 15 | 16 | class WSCcTradeStream 17 | : public TradeStream 18 | , private ccapi::CcTradeHandler 19 | { 20 | public: 21 | WSCcTradeStream(std::string const& trade_stream_name) 22 | : CcTradeHandler(trade_stream_name) 23 | {} 24 | 25 | void onStreamedTrade(TradeData const& trade_data) override 26 | { 27 | trade_data.print(); 28 | } 29 | 30 | void subscribe(std::string const& market, std::vector const& symbol_list) override 31 | { 32 | CcTradeHandler::set_stream(this); 33 | CcTradeHandler::subscribe(market, symbol_list); 34 | } 35 | }; 36 | 37 | } // namespace profitview -------------------------------------------------------------------------------- /talks/antony/C++20 Techniques For Algorithmic Trading.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/profitviews/heisenberg/912c3f661afa274d70dfe869af92518c8a562cea/talks/antony/C++20 Techniques For Algorithmic Trading.pdf -------------------------------------------------------------------------------- /talks/antony/README.md: -------------------------------------------------------------------------------- 1 | # Heisenberg Talks 2 | 3 | In this directory you will find material particular for [Antony Peacock](https://github.com/Twon)'s part of the Heisenberg series of webinars. 4 | -------------------------------------------------------------------------------- /talks/jahan/README.md: -------------------------------------------------------------------------------- 1 | # Heisenberg Talks 2 | 3 | In this directory you will find material particular for [Jahan Zahid](https://github.com/jzox)'s part of the Heisenberg series of webinars. 4 | -------------------------------------------------------------------------------- /talks/rainer/Concepts/Concepts.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/profitviews/heisenberg/912c3f661afa274d70dfe869af92518c8a562cea/talks/rainer/Concepts/Concepts.pdf -------------------------------------------------------------------------------- /talks/rainer/Concepts/account1.cpp: -------------------------------------------------------------------------------- 1 | // account1.cpp 2 | 3 | #include 4 | 5 | class Account { 6 | public: 7 | Account() = default; 8 | Account(double bal): balance{bal} {} 9 | private: 10 | double balance{0.0}; 11 | }; 12 | 13 | template 14 | bool isSmaller(T t, T t2) { 15 | return t < t2; 16 | } 17 | 18 | int main() { 19 | 20 | std::cout << std::boolalpha; 21 | 22 | double doub1{}; 23 | double doub2{10.5}; 24 | std::cout << "isSmaller(doub1, doub2): " << isSmaller(doub1, doub2) << '\n'; 25 | 26 | Account acc1; 27 | Account acc2(10.5); 28 | std::cout << "isSmaller(acc1, acc2): " << isSmaller(acc1, acc2) << '\n'; 29 | 30 | } -------------------------------------------------------------------------------- /talks/rainer/Concepts/account2.cpp: -------------------------------------------------------------------------------- 1 | // account2.cpp 2 | 3 | #include 4 | #include 5 | 6 | template 7 | concept Smaller = requires(T a, T b) { 8 | { a < b } -> std::convertible_to; 9 | }; 10 | 11 | class Account { 12 | public: 13 | Account() = default; 14 | Account(double bal): balance{bal} {} 15 | private: 16 | double balance{0.0}; 17 | }; 18 | 19 | template 20 | bool isSmaller(T t, T t2) { 21 | return t < t2; 22 | } 23 | 24 | int main() { 25 | 26 | std::cout << std::boolalpha; 27 | 28 | double doub1{}; 29 | double doub2{10.5}; 30 | std::cout << "isSmaller(doub1, doub2): " << isSmaller(doub1, doub2) << '\n'; 31 | 32 | Account acc1; 33 | Account acc2(10.5); 34 | std::cout << "isSmaller(acc1, acc2): " << isSmaller(acc1, acc2) << '\n'; 35 | 36 | } -------------------------------------------------------------------------------- /talks/rainer/Concepts/account3.cpp: -------------------------------------------------------------------------------- 1 | // account3.cpp 2 | 3 | #include 4 | #include 5 | 6 | template 7 | concept Smaller = requires(T a, T b) { 8 | { a < b } -> std::convertible_to; 9 | }; 10 | 11 | class Account { 12 | public: 13 | Account() = default; 14 | Account(double bal): balance{bal} {} 15 | bool operator < (const Account& oth) const { 16 | return balance < oth.balance; 17 | } 18 | private: 19 | double balance{0.0}; 20 | }; 21 | 22 | template 23 | bool isSmaller(T t, T t2) { 24 | return t < t2; 25 | } 26 | 27 | int main() { 28 | 29 | std::cout << std::boolalpha; 30 | 31 | double doub1{}; 32 | double doub2{10.5}; 33 | std::cout << "isSmaller(doub1, doub2): " << isSmaller(doub1, doub2) << '\n'; 34 | 35 | Account acc1; 36 | Account acc2(10.5); 37 | std::cout << "isSmaller(acc1, acc2): " << isSmaller(acc1, acc2) << '\n'; 38 | 39 | } -------------------------------------------------------------------------------- /talks/rainer/Concepts/account4.cpp: -------------------------------------------------------------------------------- 1 | // account4.cpp 2 | 3 | #include 4 | #include 5 | 6 | template 7 | concept Smaller = requires(T a, T b) { 8 | { a < b } -> std::convertible_to; 9 | }; 10 | 11 | class Account { 12 | public: 13 | Account() = default; 14 | Account(double bal): balance{bal} {} 15 | bool operator < (const Account& oth) const { 16 | return balance < oth.balance; 17 | } 18 | private: 19 | double balance{0.0}; 20 | }; 21 | 22 | template 23 | bool isSmaller(T t, T t2) { 24 | return t < t2; 25 | } 26 | 27 | template 28 | bool isGreater(T t, T t2) { 29 | return t > t2; 30 | } 31 | 32 | int main() { 33 | 34 | std::cout << std::boolalpha; 35 | 36 | double doub1{}; 37 | double doub2{10.5}; 38 | std::cout << "isSmaller(doub1, doub2): " << isSmaller(doub1, doub2) << '\n'; 39 | std::cout << "isGreater(doub1, doub2): " << isGreater(doub1, doub2) << '\n'; 40 | 41 | Account acc1; 42 | Account acc2(10.5); 43 | std::cout << "isSmaller(acc1, acc2): " << isSmaller(acc1, acc2) << '\n'; 44 | std::cout << "isGreater(acc1, acc2): " << isGreater(acc1, acc2) << '\n'; 45 | 46 | } -------------------------------------------------------------------------------- /talks/rainer/Concepts/account5.cpp: -------------------------------------------------------------------------------- 1 | // account5.cpp 2 | 3 | #include 4 | #include 5 | 6 | template 7 | concept Smaller = requires(T a, T b) { 8 | { a < b } -> std::convertible_to; 9 | }; 10 | 11 | template 12 | concept Greater = requires(T a, T b) { 13 | { a > b } -> std::convertible_to; 14 | }; 15 | 16 | class Account { 17 | public: 18 | Account() = default; 19 | Account(double bal): balance{bal} {} 20 | bool operator < (const Account& oth) const { 21 | return balance < oth.balance; 22 | } 23 | bool operator > (const Account& oth) const { 24 | return balance > oth.balance; 25 | } 26 | private: 27 | double balance{0.0}; 28 | }; 29 | 30 | template 31 | bool isSmaller(T t, T t2) { 32 | return t < t2; 33 | } 34 | 35 | template 36 | bool isGreater(T t, T t2) { 37 | return t > t2; 38 | } 39 | 40 | int main() { 41 | 42 | std::cout << std::boolalpha; 43 | 44 | double doub1{}; 45 | double doub2{10.5}; 46 | std::cout << "isSmaller(doub1, doub2): " << isSmaller(doub1, doub2) << '\n'; 47 | std::cout << "isGreater(doub1, doub2): " << isGreater(doub1, doub2) << '\n'; 48 | 49 | Account acc1; 50 | Account acc2(10.5); 51 | std::cout << "isSmaller(acc1, acc2): " << isSmaller(acc1, acc2) << '\n'; 52 | std::cout << "isGreater(acc1, acc2): " << isGreater(acc1, acc2) << '\n'; 53 | 54 | } -------------------------------------------------------------------------------- /talks/rainer/Concepts/account6.cpp: -------------------------------------------------------------------------------- 1 | // account6.cpp 2 | 3 | #include 4 | #include 5 | 6 | template 7 | concept Equal = 8 | requires(T a, T b) { 9 | { a == b } -> std::convertible_to; 10 | { a != b } -> std::convertible_to; 11 | }; 12 | 13 | 14 | template 15 | concept Ordering = 16 | Equal && 17 | requires(T a, T b) { 18 | { a <= b } -> std::convertible_to; 19 | { a < b } -> std::convertible_to; 20 | { a > b } -> std::convertible_to; 21 | { a >= b } -> std::convertible_to; 22 | }; 23 | 24 | class Account { 25 | public: 26 | Account() = default; 27 | Account(double bal): balance{bal} {} 28 | auto operator <=> (const Account& oth) const = default; 29 | private: 30 | double balance{0.0}; 31 | }; 32 | 33 | template 34 | bool isSmaller(T t, T t2) { 35 | return t < t2; 36 | } 37 | 38 | template 39 | bool isGreater(T t, T t2) { 40 | return t > t2; 41 | } 42 | 43 | int main() { 44 | 45 | std::cout << std::boolalpha; 46 | 47 | double doub1{}; 48 | double doub2{10.5}; 49 | std::cout << "isSmaller(doub1, doub2): " << isSmaller(doub1, doub2) << '\n'; 50 | std::cout << "isGreater(doub1, doub2): " << isGreater(doub1, doub2) << '\n'; 51 | 52 | Account acc1; 53 | Account acc2(10.5); 54 | std::cout << "isSmaller(acc1, acc2): " << isSmaller(acc1, acc2) << '\n'; 55 | std::cout << "isGreater(acc1, acc2): " << isGreater(acc1, acc2) << '\n'; 56 | 57 | } -------------------------------------------------------------------------------- /talks/rainer/ExtendPythonWithCpp/Embed/myMath.py: -------------------------------------------------------------------------------- 1 | print("Python: ", end = "") 2 | 3 | def fakul(num): 4 | from functools import reduce 5 | print("Returning fakul({})".format(num)) 6 | return reduce(lambda x, y: x * y, range(1, num + 1)) 7 | 8 | def sum(fir, sec): 9 | print("Returning sum({}, {})".format(fir, sec)) 10 | return fir + sec 11 | 12 | def product(fir, sec): 13 | print("Returning product({}, {})".format(fir, sec)) 14 | return fir * sec 15 | -------------------------------------------------------------------------------- /talks/rainer/ExtendPythonWithCpp/Embed/runPythonFunction.c: -------------------------------------------------------------------------------- 1 | #define PY_SSIZE_T_CLEAN 2 | #include 3 | 4 | int main(int argc, char *argv[]) { 5 | PyObject *pName, *pModule, *pFunc; 6 | PyObject *pArgs, *pValue; 7 | int i; 8 | 9 | if (argc < 3) { 10 | fprintf(stderr,"Usage: runPythonFunction [Arguments]\n"); 11 | return 1; 12 | } 13 | 14 | // argv[1]: Module name 15 | // argv[2]: Function name 16 | // argv[3] - argv[n]: Function arguments 17 | 18 | Py_Initialize(); 19 | // Add the local directory to sys.path 20 | PyObject *sysmodule = PyImport_ImportModule("sys"); 21 | PyObject *syspath = PyObject_GetAttrString(sysmodule, "path"); 22 | PyList_Append(syspath, PyUnicode_FromString(".")); 23 | 24 | // Import module 25 | pName = PyUnicode_DecodeFSDefault(argv[1]); 26 | pModule = PyImport_Import(pName); 27 | Py_DECREF(pName); 28 | 29 | if (pModule != NULL) { 30 | // Get function name 31 | pFunc = PyObject_GetAttrString(pModule, argv[2]); 32 | if (pFunc && PyCallable_Check(pFunc)) { 33 | pArgs = PyTuple_New(argc - 3); 34 | // Parse function arguments 35 | for (i = 0; i < argc - 3; ++i) { 36 | pValue = PyLong_FromLong(atoi(argv[i + 3])); 37 | if (!pValue) { 38 | Py_DECREF(pArgs); 39 | Py_DECREF(pModule); 40 | fprintf(stderr, "Cannot convert argument\n"); 41 | return 1; 42 | } 43 | PyTuple_SetItem(pArgs, i, pValue); 44 | } 45 | pValue = PyObject_CallObject(pFunc, pArgs); 46 | Py_DECREF(pArgs); 47 | if (pValue != NULL) { 48 | printf("C: Result of function call: %ld\n", PyLong_AsLong(pValue)); 49 | Py_DECREF(pValue); 50 | } 51 | else { 52 | Py_DECREF(pFunc); 53 | Py_DECREF(pModule); 54 | PyErr_Print(); 55 | fprintf(stderr,"Function call failed\n"); 56 | return 1; 57 | } 58 | } 59 | else { 60 | if (PyErr_Occurred()) PyErr_Print(); 61 | fprintf(stderr, "Cannot find function \"%s\"\n", argv[2]); 62 | } 63 | Py_XDECREF(pFunc); 64 | Py_DECREF(pModule); 65 | } 66 | else { 67 | PyErr_Print(); 68 | fprintf(stderr, "Failed to load \"%s\"\n", argv[1]); 69 | return 1; 70 | } 71 | if (Py_FinalizeEx() < 0) { 72 | return 1; 73 | } 74 | return 0; 75 | } -------------------------------------------------------------------------------- /talks/rainer/ExtendPythonWithCpp/Extend/Native/setup.py: -------------------------------------------------------------------------------- 1 | from distutils.core import setup, Extension 2 | 3 | def main(): 4 | setup(name="helloWorld", 5 | version="1.0.0", 6 | description="Python interface to the hello world C-function.", 7 | author="Rainer Grimm", 8 | author_email="schulung@ModernesCpp.de", 9 | ext_modules=[Extension("helloWorld", ["helloWorldModule.c"])]) 10 | 11 | if __name__ == "__main__": 12 | main() 13 | -------------------------------------------------------------------------------- /talks/rainer/ExtendPythonWithCpp/Extend/SWIG/helloWorld.c: -------------------------------------------------------------------------------- 1 | #include "helloWorld.h" 2 | 3 | void helloWorld() { 4 | printf("Hello World\n"); 5 | } -------------------------------------------------------------------------------- /talks/rainer/ExtendPythonWithCpp/Extend/SWIG/helloWorld.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void helloWorld(); -------------------------------------------------------------------------------- /talks/rainer/ExtendPythonWithCpp/Extend/SWIG/helloWorld.i: -------------------------------------------------------------------------------- 1 | /* hello.i */ 2 | 3 | %module helloWorld 4 | %{ 5 | #define SWIG_FILE_WITH_INIT 6 | #include "helloWorld.h" 7 | %} 8 | 9 | extern void helloWorld(); -------------------------------------------------------------------------------- /talks/rainer/ExtendPythonWithCpp/Extend/SWIG/setup.py: -------------------------------------------------------------------------------- 1 | from distutils.core import setup, Extension 2 | 3 | 4 | helloWorld_module = Extension('_helloWorld', 5 | sources=['helloWorld_wrap.c', 'helloWorld.c'], 6 | ) 7 | 8 | setup (name = 'helloWorld', 9 | version = '1.0.0', 10 | author = "Rainer Grimm", 11 | description = "Python Module helloWorld", 12 | ext_modules = [helloWorld_module], 13 | ) 14 | -------------------------------------------------------------------------------- /talks/rainer/ExtendPythonWithCpp/Extend/SharedLibrary/helloWorld.c: -------------------------------------------------------------------------------- 1 | #include "helloWorld.h" 2 | 3 | void helloWorld() { 4 | printf("Hello World\n"); 5 | } 6 | -------------------------------------------------------------------------------- /talks/rainer/ExtendPythonWithCpp/Extend/SharedLibrary/helloWorld.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void helloWorld(); 4 | -------------------------------------------------------------------------------- /talks/rainer/ExtendPythonWithCpp/Extend/SharedLibrary/main.c: -------------------------------------------------------------------------------- 1 | #include "helloWorld.h" 2 | 3 | int main() { 4 | 5 | helloWorld(); 6 | 7 | } 8 | -------------------------------------------------------------------------------- /talks/rainer/ExtendPythonWithCpp/Extend/pybind11/function.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace py = pybind11; 4 | 5 | int add(int i, int j) { 6 | return i + j; 7 | } 8 | 9 | int sum(int i, int j) { return add(i, j); } 10 | int sum(int i, int j, int k) { return i + j + k;} 11 | 12 | PYBIND11_MODULE(function, m) { 13 | m.def("add", &add, "A function which adds two numbers", 14 | py::arg("i") = 2000, py::arg("j") = 11); 15 | m.def("sum", py::overload_cast(&sum), "Sum up two values"); 16 | m.def("sum", py::overload_cast(&sum), "Sum up three values"); 17 | 18 | m.attr("year") = 2011; 19 | m.attr("language") = "C++11"; 20 | } 21 | 22 | // g++ -O3 -Wall -shared -std=c++14 -fPIC $(python3.6 -m pybind11 --includes) function.cpp -o function$(python3.6-config --extension-suffix) 23 | -------------------------------------------------------------------------------- /talks/rainer/ExtendPythonWithCpp/Extend/pybind11/human.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | struct HumanBeing { 5 | HumanBeing(const std::string& n) : name(n) { } 6 | const std::string& getName() const { return name; } 7 | std::string name; 8 | std::string familyName{"Grimm"}; 9 | virtual ~HumanBeing() = default; 10 | }; 11 | 12 | struct Man: HumanBeing { 13 | Man(const std::string& name): HumanBeing(name) { } 14 | std::string gender() const { return "male"; } 15 | }; 16 | 17 | namespace py = pybind11; 18 | 19 | PYBIND11_MODULE(human, m) { 20 | py::class_(m, "HumanBeing") 21 | .def(py::init()) 22 | .def("getName", &HumanBeing::getName) 23 | .def("__repr__", [](const HumanBeing& h) { return "HumanBeing: " + h.name; }) 24 | .def_readwrite("familyName", &HumanBeing::familyName); 25 | 26 | py::class_(m, "Man") 27 | .def(py::init()) 28 | .def("gender", &Man::gender); 29 | 30 | } 31 | 32 | // g++ -O3 -Wall -shared -std=c++14 -fPIC $(python3.6 -m pybind11 --includes) human.cpp -o human$(python3.6-config --extension-suffix) -------------------------------------------------------------------------------- /talks/rainer/ExtendPythonWithCpp/ExtendEmbedC++Python.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/profitviews/heisenberg/912c3f661afa274d70dfe869af92518c8a562cea/talks/rainer/ExtendPythonWithCpp/ExtendEmbedC++Python.pdf -------------------------------------------------------------------------------- /talks/rainer/README.md: -------------------------------------------------------------------------------- 1 | # Heisenberg Talks 2 | 3 | In this directory you will find material particular for [Rainer Grimm](https://github.com/RainerGrimm)'s part of the Heisenberg series of webinars. 4 | -------------------------------------------------------------------------------- /talks/rainer/Ranges/Ranges.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/profitviews/heisenberg/912c3f661afa274d70dfe869af92518c8a562cea/talks/rainer/Ranges/Ranges.pdf -------------------------------------------------------------------------------- /talks/rainer/Ranges/begin.cpp: -------------------------------------------------------------------------------- 1 | // begin.cpp 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | struct ContainerFree { 8 | ContainerFree(std::size_t len): len_(len), data_(new int[len]){} 9 | size_t len_; 10 | int* data_; 11 | }; 12 | int* begin(const ContainerFree& conFree) { 13 | return conFree.data_; 14 | } 15 | 16 | struct ContainerMember { 17 | ContainerMember(std::size_t len): len_(len), data_(new int[len]){} 18 | int* begin() const { 19 | return data_; 20 | } 21 | size_t len_; 22 | int* data_; 23 | }; 24 | 25 | void callBeginFree(const auto& cont) { 26 | begin(cont); 27 | } 28 | 29 | void callBeginMember(const auto& cont) { 30 | cont.begin(); 31 | } 32 | 33 | int main() { 34 | 35 | const ContainerFree contFree(2020); 36 | const ContainerMember contMemb(2023); 37 | 38 | callBeginFree(contFree); 39 | callBeginMember(contMemb); 40 | 41 | callBeginFree(contMemb); 42 | callBeginMember(contFree); 43 | 44 | } -------------------------------------------------------------------------------- /talks/rainer/Ranges/rangesAccess.cpp: -------------------------------------------------------------------------------- 1 | // rangesAccess.cpp 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | int main() { 8 | 9 | auto beginIt1 = std::begin(std::vector{1, 2, 3}); 10 | auto beginIt2 = std::ranges::begin(std::vector{1, 2, 3}); 11 | 12 | } -------------------------------------------------------------------------------- /talks/rainer/Ranges/rangesComposition.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | 7 | int main() { 8 | 9 | std::map freqWord{ {"witch", 25}, {"wizard", 33}, {"tale", 45}, 10 | {"dog", 4}, {"cat", 34}, {"fish", 23} }; 11 | 12 | std::cout << "All words: "; 13 | for (const auto& name : std::views::keys(freqWord)) { std::cout << name << " "; }; 14 | 15 | std::cout << '\n'; 16 | 17 | std::cout << "All words reverse: "; 18 | for (const auto& name : std::views::keys(freqWord) | std::views::reverse) { std::cout << name << " "; }; 19 | 20 | std::cout << '\n'; 21 | 22 | std::cout << "The first 4 words: "; 23 | for (const auto& name : std::views::keys(freqWord) | std::views::take(4)) { std::cout << name << " "; }; 24 | 25 | std::cout << '\n'; 26 | 27 | std::cout << "All words starting with w: "; 28 | auto firstw = [](const std::string& name){ return name[0] == 'w'; }; 29 | for (const auto& name : std::views::keys(freqWord) | std::views::filter(firstw)) { std::cout << name << " "; }; 30 | 31 | std::cout << '\n'; 32 | 33 | } 34 | -------------------------------------------------------------------------------- /talks/rainer/Ranges/rangesEntireContainer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | 7 | int main() { 8 | 9 | std::map freqWord{ {"witch", 25}, {"wizard", 33}, {"tale", 45}, 10 | {"dog", 4}, {"cat", 34}, {"fish", 23} }; 11 | 12 | std::cout << "Keys" << '\n'; 13 | auto names = std::views::keys(freqWord); 14 | for (const auto& name : names){ std::cout << name << " "; }; 15 | std::cout << '\n'; 16 | for (const auto& name : std::views::keys(freqWord)){ std::cout << name << " "; }; 17 | 18 | std::cout << "\n\n"; 19 | 20 | std::cout << "Values: " << '\n'; 21 | auto values = std::views::values(freqWord); 22 | for (const auto& value : values){ std::cout << value << " "; }; 23 | std::cout << '\n'; 24 | for (const auto& value : std::views::values(freqWord)){ std::cout << value << " "; } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /talks/rainer/Ranges/rangesFilterTransform.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() { 6 | 7 | std::vector numbers = {1, 2, 3, 4, 5, 6}; 8 | 9 | auto results = numbers | std::views::filter([](int n){ return n % 2 == 0;}) 10 | | std::views::transform([](int n){ return n * 2;}); 11 | 12 | for (auto v: results) std::cout << v << " "; 13 | 14 | } -------------------------------------------------------------------------------- /talks/rainer/Ranges/rangesLazy.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | 5 | bool isPrime(int i) { 6 | for (int j=2; j*j <= i; ++j){ 7 | if (i % j == 0) return false; 8 | } 9 | return true; 10 | } 11 | 12 | int main() { 13 | 14 | std::cout << "Numbers from 1000000 to 1001000 (displayed each 100th): " << '\n'; 15 | for (int i: std::views::iota(1000000, 1001000)) { 16 | if (i % 100 == 0) std::cout << i << " "; 17 | } 18 | 19 | std::cout << "\n\n"; 20 | 21 | auto odd = [](int i){ return i % 2 == 1; }; 22 | std::cout << "Odd numbers from 1000000 to 1001000 (displayed each 100th): " << '\n'; 23 | for (int i: std::views::iota(1000000, 1001000) | std::views::filter(odd)) { 24 | if (i % 100 == 1) std::cout << i << " "; 25 | } 26 | 27 | std::cout << "\n\n"; 28 | 29 | std::cout << "Prime numbers from 1000000 to 1001000: " << '\n'; 30 | for (int i: std::views::iota(1000000, 1001000) | std::views::filter(odd) 31 | | std::views::filter(isPrime)) { 32 | std::cout << i << " "; 33 | } 34 | 35 | std::cout << "\n\n"; 36 | 37 | std::cout << "20 prime numbers starting with 1000000: " << '\n'; 38 | for (int i: std::views::iota(1000000) | std::views::filter(odd) 39 | | std::views::filter(isPrime) 40 | | std::views::take(20)) { 41 | std::cout << i << " "; 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /talks/rainer/Ranges/sortRanges.cpp: -------------------------------------------------------------------------------- 1 | // sortRanges.cpp 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | int main() { 8 | 9 | std::vector myVec{-3, 5, 0, 7, -4}; 10 | std::ranges::sort(myVec); 11 | for (auto v: myVec) std::cout << v << " "; // -4, -3, 0, 5, 7 12 | 13 | } -------------------------------------------------------------------------------- /talks/richard/README.md: -------------------------------------------------------------------------------- 1 | # Heisenberg Talks 2 | 3 | In this directory you will find material particular for [Richard Hickling](https://github.com/rthickling)'s part of the Heisenberg series of webinars. 4 | -------------------------------------------------------------------------------- /windows.md: -------------------------------------------------------------------------------- 1 | # Heisenberg - Windows 2 | 3 | ## Build steps 4 | 5 | Download the latest version of [Visual Studio Community 2022](https://visualstudio.microsoft.com/vs/community/). 6 | 7 | Start the Visual Studio 2022 Developer Command Prompt. 8 | 9 | * Install and Configure Conan and Ninja 10 | ```powershell 11 | python -m venv .venv # Create a Python virtual env 12 | .venv\Scripts\activate.bat # Activate the virtual env 13 | pip install -r ./requirements.txt # Install Conan and Ninja 14 | conan profile detect --force # Generate a default configuration with the local machine settings 15 | conan config install ./.conan # Install supported build profiles from ./.conan to ./conan2 16 | ``` 17 | 18 | * Ninja Multi-Config Build 19 | 20 | Multi-config builds allow you to create a build folder containing sub-folders for different build configurations and build them side-by-side. 21 | To generate all the configurations we run the `conan-default` preset which configures CMake for these configurations `Release` and `Debug`. The sample build below is choosing the `Release` configuration: 22 | ```powershell 23 | conan install ./ -pr:h .conan2/profiles/msvc/193/x64-release -pr:b .conan2/profiles/msvc/193/x64-release --build missing -c tools.cmake.cmaketoolchain:generator="Ninja Multi-Config" 24 | build\generators\conanbuild.bat 25 | cmake --preset conan-default # The configure stage for multi-config builds is conan-default 26 | cmake --build --preset conan-release # The build stage for multi-config builds is the conan- 27 | ``` 28 | 29 | This will create: 30 | 31 | * `heisenberg\build\bin\Release\algo.exe` which will run a simple Mean Reversion algo on FTX or Coinbase 32 | * For example 33 | ```powershell 34 | cd bin\Release 35 | .\algo --exchange=coinbase --api_key=$Env:COINBASE_API_KEY --api_secret=$Env:COINBASE_API_SECRET --api_phrase=$Env:COINBASE_API_PHRASE --lookback=50 --reversion_level=2 --base_quantity=0.0025 --symbol=ETH-BTC 36 | ``` 37 | --------------------------------------------------------------------------------