diff --git a/.github/scripts/conan-profile.sh b/.github/scripts/conan-profile.sh index 083f3cfe..1df327dd 100644 --- a/.github/scripts/conan-profile.sh +++ b/.github/scripts/conan-profile.sh @@ -5,13 +5,12 @@ set -e conan profile detect -f std=23 -version=18 +version=14.2 profile="$(conan profile path default)" mv "$profile" "${profile}.bak" sed -e 's/^\(compiler\.cppstd=\).\{1,\}$/\1'"$std/" \ - -e 's/^\(compiler\.version=\).\{1,\}$/\1'"$version/" \ "${profile}.bak" > "$profile" rm "${profile}.bak" diff --git a/.github/workflows/exchange-ci.yml b/.github/workflows/exchange-ci.yml index 912d547b..6f4384fa 100644 --- a/.github/workflows/exchange-ci.yml +++ b/.github/workflows/exchange-ci.yml @@ -288,6 +288,7 @@ jobs: LLVM_DIR: '/usr/lib/llvm-18/lib/cmake/llvm' NUTC_WRAPPER_BINARY_PATH: ${{ github.workspace }}/exchange/build/WRAPPER NUTC_CPP_TEMPLATE_PATH: ${{ github.workspace }}/exchange/template.cpp + NUTC_LINTER_SPAWNER_BINARY_PATH: ${{ github.workspace }}/exchange/build/LINTER-spawner steps: - uses: actions/checkout@v3 diff --git a/.github/workflows/linter-cicd.yml b/.github/workflows/linter-cicd.yml deleted file mode 100644 index a69b3785..00000000 --- a/.github/workflows/linter-cicd.yml +++ /dev/null @@ -1,326 +0,0 @@ -name: Linter - Continuous Integration - -on: - push: - branches: - - main - paths: - - 'linter/**' - - '.github/workflows/linter-cicd.yml' - - pull_request: - branches: - - main - paths: - - 'linter/**' - - '.github/workflows/linter-cicd.yml' - - workflow_dispatch: - -# We only care about the latest revision of a PR, so cancel all previous instances. -concurrency: - group: linter-ci-${{ github.event.pull_request.number || github.ref_name }} - cancel-in-progress: true - -jobs: - lint: - runs-on: ubuntu-22.04 - defaults: - run: - working-directory: linter - - steps: - - uses: actions/checkout@v3 - with: - submodules: 'recursive' - - - uses: actions/setup-python@v4 - with: { python-version: "3.12" } - - - name: Install LLVM 17 - run: | - wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | sudo tee /etc/apt/trusted.gpg.d/apt.llvm.org.asc - sudo apt-add-repository "deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-17 main" - sudo apt update - sudo apt install llvm-17 llvm-17-dev llvm-17-tools clang-17 clang-tidy-17 clang-format-17 clang-tools-17 libclang-17-dev -y - - - name: Install codespell - run: pip3 install codespell - - - name: Lint - run: cmake -D FORMAT_COMMAND=clang-format-17 -P cmake/lint.cmake - - - name: Spell check - run: cmake -P cmake/spell.cmake - - sanitize: - needs: [lint] - - runs-on: ubuntu-22.04 - defaults: - run: - working-directory: linter - - - env: - CC: clang-17 - CXX: clang++-17 - CLANG_DIR: '/usr/lib/llvm-17/lib/cmake/clang' - LLVM_DIR: '/usr/lib/llvm-17/lib/cmake/llvm' - NUTC_SPAWNER_BINARY_PATH: ${{ github.workspace }}/linter/build/sanitize/NUTC-linter-spawner - - steps: - - uses: actions/checkout@v3 - with: - submodules: 'recursive' - - - name: Install Python - uses: actions/setup-python@v4 - with: { python-version: "3.12" } - - - name: Install Python - uses: actions/setup-python@v4 - with: { python-version: "3.12-dev" } - - - name: Install LLVM 17 - run: | - wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | sudo tee /etc/apt/trusted.gpg.d/apt.llvm.org.asc - sudo apt-add-repository "deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-17 main" - sudo apt update - sudo apt install llvm-17 llvm-17-dev llvm-17-tools clang-17 clang-tidy-17 clang-tools-17 libclang-17-dev -y - - - name: Install Cache Conan dependencies - id: cache-conan - uses: actions/cache@v3 - env: - cache-name: cache-conan-deps - with: - path: ~/.conan2 - key: ${{ runner.os }}-builder-${{ env.cache-name }}-${{ hashFiles('conanfile.py') }} - restore-keys: ${{ runner.os }}-builder-${{ env.cache-name }}- - - - name: Install dependencies - run: | - pip3 install conan - - sudo apt install libssl-dev -y - - bash < ../.github/scripts/conan-profile.sh - conan install . -s build_type=Release -b missing - - - name: Configure - run: cmake --preset=ci-sanitize - - - name: Build - run: cmake --build build/sanitize -j 2 - - - name: Test - working-directory: linter/build/sanitize - env: - ASAN_OPTIONS: "strict_string_checks=1:\ - detect_stack_use_after_return=1:\ - check_initialization_order=1:\ - strict_init_order=1:\ - detect_leaks=1" - UBSAN_OPTIONS: print_stacktrace=1 - run: ctest --output-on-failure --no-tests=error -j 2 - - test-linux: - needs: [lint] - - strategy: - matrix: - os: [ubuntu-22.04] - - runs-on: ${{ matrix.os }} - defaults: - run: - working-directory: linter - - - env: - CC: clang-17 - CXX: clang++-17 - CLANG_DIR: '/usr/lib/llvm-17/lib/cmake/clang' - LLVM_DIR: '/usr/lib/llvm-17/lib/cmake/llvm' - NUTC_SPAWNER_BINARY_PATH: ${{ github.workspace }}/linter/build/NUTC-linter-spawner - - steps: - - uses: actions/checkout@v3 - with: - submodules: 'recursive' - - - name: Install LLVM 17 - run: | - wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | sudo tee /etc/apt/trusted.gpg.d/apt.llvm.org.asc - sudo apt-add-repository "deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-17 main" - sudo apt update - sudo apt install llvm-17 llvm-17-dev llvm-17-tools clang-17 clang-tidy-17 clang-tools-17 libclang-17-dev -y - - - name: Install static analyzers - if: matrix.os == 'ubuntu-22.04' - run: >- - sudo apt install cppcheck -y -q - - sudo update-alternatives --install - /usr/bin/clang-tidy clang-tidy - /usr/bin/clang-tidy-17 160 - - - name: Install Python - uses: actions/setup-python@v4 - with: { python-version: "3.12" } - - - name: Install Python - uses: actions/setup-python@v4 - with: { python-version: "3.12-dev" } - - - name: Install dependencies - shell: bash - run: | - pip3 install conan - - sudo apt install libssl-dev -y - - bash < ../.github/scripts/conan-profile.sh - conan install . -s build_type=Release -b missing - - - name: Setup MultiToolTask - if: matrix.os == 'windows-2022' - run: | - Add-Content "$env:GITHUB_ENV" 'UseMultiToolTask=true' - Add-Content "$env:GITHUB_ENV" 'EnforceProcessCountAcrossBuilds=true' - - - name: Configure - shell: pwsh - run: cmake "--preset=ci-$("${{ matrix.os }}".split("-")[0])" - - - name: Build - run: cmake --build build --config Release -j 2 - - - name: Install - run: cmake --install build --config Release --prefix prefix - - - name: Test - working-directory: linter/build - run: ctest --output-on-failure --no-tests=error -C Release -j 2 - - test-darwin: - needs: [lint] - - strategy: - matrix: - os: [macos-14] - - runs-on: ${{ matrix.os }} - defaults: - run: - working-directory: linter - - env: - CC: /opt/homebrew/opt/llvm@17/bin/clang - CXX: /opt/homebrew/opt/llvm@17/bin/clang++ - CLANG_DIR: '/opt/homebrew/opt/llvm@17/bin/clang' - LLVM_DIR: '/opt/homebrew/opt/llvm@17' - NUTC_SPAWNER_BINARY_PATH: ${{ github.workspace }}/linter/build/NUTC-linter-spawner - - steps: - - uses: actions/checkout@v3 - with: - submodules: 'recursive' - - - name: Install LLVM 17 - run: | - brew install llvm@17 - brew install clang-format - - - name: Install static analyzers - if: matrix.os == 'macos-14' - run: >- - brew install cppcheck - - - name: Install Python - uses: actions/setup-python@v4 - with: { python-version: "3.12" } - - - name: Install Python - uses: actions/setup-python@v4 - with: { python-version: "3.12-dev" } - - - name: Install dependencies - shell: bash - run: | - pip3 install conan - conan profile detect - python3 ../.github/scripts/write_config.py - conan install . -s build_type=Release -b missing - - - name: Setup MultiToolTask - if: matrix.os == 'windows-2022' - run: | - Add-Content "$env:GITHUB_ENV" 'UseMultiToolTask=true' - Add-Content "$env:GITHUB_ENV" 'EnforceProcessCountAcrossBuilds=true' - - - name: Configure - shell: pwsh - run: cmake "--preset=ci-$("${{ matrix.os }}".split("-")[0])" - - - name: Build - run: cmake --build build --config Release -j 2 - - - name: Install - run: cmake --install build --config Release --prefix prefix - - - name: Test - working-directory: linter/build - run: ctest --output-on-failure --no-tests=error -C Release -j 2 - - - docs: - # Deploy docs only when builds succeed - needs: [sanitize, test-darwin, test-linux] - - runs-on: ubuntu-22.04 - defaults: - run: - working-directory: linter - - - # To enable, first you have to create an orphaned gh-pages branch: - # - # git switch --orphan gh-pages - # git commit --allow-empty -m "Initial commit" - # git push -u origin gh-pages - # - # Edit the placeholder below to your GitHub name, so this action - # runs only in your repository and no one else's fork. After these, delete - # this comment and the last line in the conditional below. - # If you do not wish to use GitHub Pages for deploying documentation, then - # simply delete this job similarly to the coverage one. - if: github.ref == 'refs/heads/main' - && github.event_name == 'push' - && github.repository_owner == 'northwesternfintech' - - steps: - - uses: actions/checkout@v3 - with: - submodules: 'recursive' - - - uses: actions/setup-python@v4 - with: { python-version: "3.12" } - - - name: Install m.css dependencies - run: pip3 install jinja2 Pygments - - - name: Install Doxygen - run: sudo apt update -q - && sudo apt install doxygen -q -y - - - name: Build docs - run: cmake "-DPROJECT_SOURCE_DIR=$PWD" "-DPROJECT_BINARY_DIR=$PWD/build" - -P cmake/docs-ci.cmake - - - name: Deploy docs - uses: peaceiris/actions-gh-pages@v3 - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - publish_dir: build/docs/html diff --git a/docker/dev/docker-compose.yml b/docker/dev/docker-compose.yml new file mode 100644 index 00000000..a2013f35 --- /dev/null +++ b/docker/dev/docker-compose.yml @@ -0,0 +1,130 @@ +# Full stack docker compose +# Remove web/firebase components for prod + +version: '3' +services: + sandbox: + image: nutc-exchange + build: + context: ../.. + dockerfile: exchange/docker/sandbox/Dockerfile + args: + firebase_emulator: "false" + restart: unless-stopped + environment: + - NUTC_EXPOSE_METRICS=1 + command: ["--sandbox"] + + #port: 16124 + webserver: + image: nutc-webserver + build: + context: ../.. + dockerfile: webserver/WebserverDockerfile + restart: unless-stopped + + linter: + image: nutc-linter + restart: unless-stopped + build: + context: ../.. + dockerfile: exchange/docker/linter/Dockerfile + args: + firebase_emulator: "false" + + # Exposed on port 9000 + prometheus: + image: prom/prometheus + volumes: + - ../../exchange/docker/sandbox/prometheus.yml:/etc/prometheus/prometheus.yml + command: + - '--config.file=/etc/prometheus/prometheus.yml' + - '--storage.tsdb.retention.time=12h' + restart: unless-stopped + + reverse-proxy: + image: nginx:latest + ports: + - "26389:80" + volumes: + - ./nginx.conf:/etc/nginx/nginx.conf + restart: unless-stopped + depends_on: + - webserver + - grafana + + grafana: + image: grafana/grafana + restart: unless-stopped + user: "${UID}:${GID}" + ports: + - "3000:3000" + environment: + - GF_SECURITY_ALLOW_EMBEDDING=true + - GF_AUTH_ANONYMOUS_ENABLED=true + - GF_AUTH_ANONYMOUS_ORG_NAME=MAIN + - GF_AUTH_ANONYMOUS_ORG_ROLE=Viewer + volumes: + - ../../exchange/docker/dev/grafana_data:/var/lib/grafana + # - /var/lib/grafana/grafana.db + # - /var/lib/grafana/alerting + + web: + image: node:latest + restart: unless-stopped + working_dir: /app + environment: + - PORT=3001 + volumes: + - ../../web:/app + command: ["npm", "run", "dev",] + ports: + - "3001:3001" + depends_on: + - postgres + + localstack: + image: localstack/localstack + restart: unless-stopped + ports: + - "4566:4566" + - "4571:4571" + - "8080:8080" + environment: + - SERVICES=s3 + - DEFAULT_REGION=us-east-1 + - DATA_DIR=/var/lib/localstack/data + - AWS_ACCESS_KEY_ID=test + - AWS_SECRET_ACCESS_KEY=test + - S3_FORCE_PATH_STYLE=true + volumes: + - localstack:/var/lib/localstack + + awscli: + image: amazon/aws-cli + environment: + AWS_ACCESS_KEY_ID: test + AWS_SECRET_ACCESS_KEY: test + AWS_DEFAULT_REGION: us-east-1 + depends_on: + - localstack + volumes: + - ../../web/dev/local-dev-setup.sh:/home/init.sh + - ../../web/dev/cors.json:/home/cors.json + entrypoint: /home/init.sh + + postgres: + image: postgres:13 + restart: always + environment: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + POSTGRES_DB: nutc + ports: + - "5432:5432" + volumes: + - postgres_data:/var/lib/postgresql/data + +volumes: + postgres_data: + localstack: diff --git a/docker/dev/nginx.conf b/docker/dev/nginx.conf new file mode 100644 index 00000000..a9d8ee73 --- /dev/null +++ b/docker/dev/nginx.conf @@ -0,0 +1,51 @@ +user nginx; +worker_processes 1; + +events { + worker_connections 1024; +} + + +http { + sendfile on; + keepalive_timeout 65; + + map $http_upgrade $connection_upgrade { + default upgrade; + '' close; + } + + upstream webserver { + server webserver:16124; + } + + upstream grafana { + server grafana:3000; + } + + server { + listen 80; + + location /webserver/ { + rewrite ^/webserver(/.*)$ $1 break; + proxy_pass http://webserver; + proxy_set_header Host $host; + # proxy_http_version 1.1; + # proxy_set_header Upgrade $http_upgrade; + # proxy_set_header Connection "upgrade"; + } + + location / { + proxy_pass http://grafana; + proxy_set_header Host $host; + } + + location /api/live/ { + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection $connection_upgrade; + proxy_set_header Host $host; + proxy_pass http://grafana; + } + } +} diff --git a/docker/docker-compose.yml b/docker/prod/docker-compose.yml similarity index 53% rename from docker/docker-compose.yml rename to docker/prod/docker-compose.yml index 8ef02431..9b092074 100644 --- a/docker/docker-compose.yml +++ b/docker/prod/docker-compose.yml @@ -7,24 +7,21 @@ services: image: nutc-exchange build: context: .. - dockerfile: exchange/docker/sandbox/SandboxDockerfile + dockerfile: exchange/docker/sandbox/Dockerfile args: firebase_emulator: "false" restart: unless-stopped environment: - NUTC_EXPOSE_METRICS=1 command: ["--bots-only"] - networks: - - net + #port: 16124 webserver: image: nutc-webserver build: context: .. dockerfile: webserver/WebserverDockerfile restart: unless-stopped - networks: - - net linter: image: nutc-linter @@ -34,46 +31,6 @@ services: dockerfile: linter/LinterDockerfile args: firebase_emulator: "false" - networks: - - net - - firebase: - image: spine3/firebase-emulator - depends_on: - - website - restart: unless-stopped - ports: - - "4000:4000" - - "4400:4400" - - "5001:5001" - - "9000:9000" - - "9099:9099" - - "9199:9199" - environment: - GCP_PROJECT: "nutc-web" - ENABLE_UI: "true" - volumes: - - ../web/firebase.json:/firebase/firebase.json - - ../web/baseline-data:/firebase/baseline-data - - ../web/database.rules.json:/firebase/database.rules.json - - ../web/storage.rules:/firebase/storage.rules - - ../web/functions:/firebase/functions - networks: - - net - - website: - image: node:20 - restart: unless-stopped - working_dir: /app - volumes: - - ../web:/app - - /app/node_modules - ports: - - "3001:3001" - command: > - sh -c "npm i && cd functions && npm i && npm run build && cd .. && npm run dev" - environment: - - NODE_ENV=development # Exposed on port 9000 prometheus: @@ -84,8 +41,6 @@ services: - '--config.file=/etc/prometheus/prometheus.yml' - '--storage.tsdb.retention.time=12h' restart: unless-stopped - networks: - - net reverse-proxy: image: nginx:latest @@ -97,15 +52,13 @@ services: depends_on: - webserver - grafana - networks: - - net grafana: image: grafana/grafana restart: unless-stopped - user: "472:472" + user: "${UID}:${GID}" ports: - - "3000:3000" + - "3001:3001" environment: - GF_SECURITY_ALLOW_EMBEDDING=true - GF_AUTH_ANONYMOUS_ENABLED=true @@ -113,13 +66,6 @@ services: - GF_AUTH_ANONYMOUS_ORG_ROLE=Viewer volumes: - ../exchange/docker/sandbox/grafana_data:/var/lib/grafana - - /var/lib/grafana/grafana.db - - /var/lib/grafana/alerting - networks: - - net + # - /var/lib/grafana/grafana.db + # - /var/lib/grafana/alerting -networks: - net: - ipam: - config: - - subnet: 172.20.0.0/16 diff --git a/docker/nginx.conf b/docker/prod/nginx.conf similarity index 100% rename from docker/nginx.conf rename to docker/prod/nginx.conf diff --git a/exchange/CMakeLists.txt b/exchange/CMakeLists.txt index 6713461a..2de366f9 100644 --- a/exchange/CMakeLists.txt +++ b/exchange/CMakeLists.txt @@ -30,8 +30,6 @@ add_library( src/exchange/algos/normal_mode/normal_mode.cpp src/exchange/algos/algo_manager.cpp - src/exchange/logging.cpp - src/exchange/curl/curl.cpp src/exchange/wrappers/handle/wrapper_handle.cpp @@ -98,10 +96,6 @@ target_link_libraries(EXCHANGE_lib PUBLIC Crow::Crow) find_package(fmt REQUIRED) target_link_libraries(EXCHANGE_lib PUBLIC fmt::fmt) -# quill -find_package(quill REQUIRED) -target_link_libraries(EXCHANGE_lib PUBLIC quill::quill) - # libcurl find_package(CURL REQUIRED) target_link_libraries(EXCHANGE_lib PUBLIC CURL::libcurl) @@ -180,7 +174,6 @@ add_library( src/wrapper/messaging/rate_limiter.cpp # Utils - src/wrapper/util/logging.cpp src/wrapper/config/argparse.cpp ) @@ -223,14 +216,103 @@ target_link_libraries(WRAPPER_exe PRIVATE Python3::Python) target_link_libraries(WRAPPER_exe PRIVATE boost::boost) target_link_libraries(WRAPPER_exe PRIVATE ${Python3_LIBRARIES}) +# ---- LINTER ---------- +add_library( + LINTER_lib OBJECT + + src/linter/fetching/fetching.cpp + src/linter/runtime/cpp/cpp_runtime.cpp + src/linter/runtime/python/python_runtime.cpp + src/linter/spawning/spawning.cpp + src/linter/crow/crow.cpp + # Utils +) + +add_library( + LINTER_spawner_lib OBJECT + + src/linter/lint/lint.cpp + src/linter/runtime/cpp/cpp_runtime.cpp + src/linter/runtime/python/python_runtime.cpp +) + +target_include_directories( + LINTER_lib ${warning_guard} + PUBLIC + "$" +) + +target_compile_features(LINTER_lib PUBLIC cxx_std_23) + +target_link_libraries(LINTER_lib PUBLIC fmt::fmt) +target_link_libraries(LINTER_lib PUBLIC quill::quill) +target_link_libraries(LINTER_lib PUBLIC CURL::libcurl) +target_link_libraries(LINTER_lib PUBLIC glaze::glaze) +target_link_libraries(LINTER_lib PUBLIC pybind11::pybind11) +target_link_libraries(LINTER_lib PUBLIC Crow::Crow) +target_link_libraries(LINTER_lib PUBLIC Python3::Python) +target_link_libraries(LINTER_lib PUBLIC argparse::argparse) +target_link_libraries(LINTER_lib PUBLIC boost::boost) + +target_include_directories( + LINTER_spawner_lib ${warning_guard} + PUBLIC + "$" +) + +target_link_libraries(LINTER_spawner_lib PRIVATE quill::quill) +target_link_libraries(LINTER_spawner_lib PRIVATE glaze::glaze) +target_link_libraries(LINTER_spawner_lib PRIVATE pybind11::pybind11) +target_link_libraries(LINTER_spawner_lib PRIVATE Python3::Python) +target_link_libraries(LINTER_spawner_lib PRIVATE CURL::libcurl) +target_link_libraries(LINTER_spawner_lib PRIVATE boost::boost) + +# ---- Declare main executable ---- + +add_executable(LINTER_exe src/linter/main.cpp) +add_executable(LINTER::exe ALIAS LINTER_exe) + +set_property(TARGET LINTER_exe PROPERTY OUTPUT_NAME LINTER) + +target_compile_features(LINTER_exe PRIVATE cxx_std_23) + +target_link_libraries(LINTER_exe PRIVATE LINTER_lib) +target_link_libraries(LINTER_exe PRIVATE fmt::fmt) +target_link_libraries(LINTER_exe PRIVATE quill::quill) + +target_link_libraries(LINTER_exe PRIVATE argparse::argparse) +target_link_libraries(LINTER_exe PRIVATE CURL::libcurl) +target_link_libraries(LINTER_exe PRIVATE glaze::glaze) +target_link_libraries(LINTER_exe PRIVATE pybind11::pybind11) +target_link_libraries(LINTER_exe PRIVATE Crow::Crow) +target_link_libraries(LINTER_exe PRIVATE Python3::Python) + +# ---- Declare secondary (process spawning) executable ---- + +add_executable(LINTER_spawner_exe src/linter/spawner/main.cpp) +add_executable(LINTER_spawner::exe ALIAS LINTER_spawner_exe) + +set_property(TARGET LINTER_spawner_exe PROPERTY OUTPUT_NAME LINTER_spawner) + +target_compile_features(LINTER_spawner_exe PRIVATE cxx_std_23) + +target_link_libraries(LINTER_spawner_exe PRIVATE LINTER_spawner_lib) +target_link_libraries(LINTER_spawner_exe PRIVATE CURL::libcurl) +target_link_libraries(LINTER_spawner_exe PRIVATE pybind11::pybind11) +target_link_libraries(LINTER_spawner_exe PRIVATE quill::quill) +target_link_libraries(LINTER_spawner_exe PRIVATE glaze::glaze) +target_link_libraries(LINTER_spawner_exe PRIVATE Python3::Python) + # ---- COMMON ---------- add_library(COMMON_lib OBJECT - src/common/file_operations/file_operations.cpp src/common/firebase/firebase.cpp + src/common/file_operations/file_operations.cpp src/common/util.cpp src/common/types/decimal.cpp src/common/types/algorithm/local_algorithm.cpp + src/common/logging/logging.cpp + src/common/compilation/compile_cpp.cpp ) target_include_directories( @@ -239,6 +321,10 @@ target_include_directories( "$" ) +# quill +find_package(quill REQUIRED) +target_link_libraries(COMMON_lib PUBLIC quill::quill) + target_link_libraries(COMMON_lib PUBLIC fmt::fmt) target_link_libraries(COMMON_lib PUBLIC glaze::glaze) target_link_libraries(COMMON_lib PUBLIC yaml-cpp::yaml-cpp) @@ -249,6 +335,12 @@ target_link_libraries(COMMON_lib PRIVATE boost::boost) target_link_libraries(EXCHANGE_lib PUBLIC COMMON_lib) target_link_libraries(EXCHANGE_exe PRIVATE COMMON_lib) +target_link_libraries(LINTER_lib PUBLIC COMMON_lib) +target_link_libraries(LINTER_exe PRIVATE COMMON_lib) + +target_link_libraries(LINTER_spawner_lib PUBLIC COMMON_lib) +target_link_libraries(LINTER_spawner_exe PRIVATE COMMON_lib) + target_link_libraries(WRAPPER_lib PUBLIC COMMON_lib) target_link_libraries(WRAPPER_exe PRIVATE COMMON_lib) @@ -263,6 +355,10 @@ if(lto_supported) set_target_properties(EXCHANGE_lib PROPERTIES INTERPROCEDURAL_OPTIMIZATION_RELEASE TRUE) set_target_properties(EXCHANGE_exe PROPERTIES INTERPROCEDURAL_OPTIMIZATION_RELEASE TRUE) set_target_properties(COMMON_lib PROPERTIES INTERPROCEDURAL_OPTIMIZATION_RELEASE TRUE) + set_target_properties(LINTER_exe PROPERTIES INTERPROCEDURAL_OPTIMIZATION_RELEASE TRUE) + set_target_properties(LINTER_lib PROPERTIES INTERPROCEDURAL_OPTIMIZATION_RELEASE TRUE) + set_target_properties(LINTER_spawner_lib PROPERTIES INTERPROCEDURAL_OPTIMIZATION_RELEASE TRUE) + set_target_properties(LINTER_spawner_exe PROPERTIES INTERPROCEDURAL_OPTIMIZATION_RELEASE TRUE) else() message(WARNING "LTO is not supported: ${error}") endif() @@ -276,7 +372,6 @@ endif() # ---- Developer mode ---- if(NOT NUTC24_DEVELOPER_MODE) -message("lol") return() elseif(NOT PROJECT_IS_TOP_LEVEL) message( diff --git a/exchange/Taskfile.yml b/exchange/Taskfile.yml index 9fe99796..18cff1b0 100644 --- a/exchange/Taskfile.yml +++ b/exchange/Taskfile.yml @@ -127,6 +127,7 @@ tasks: run-itest: dir: '{{if eq .RELEASE_BUILD "false"}}.{{else}}build{{end}}' vars: + LINTER_SPAWNER_RELATIVE_PATH: './build{{if eq .RELEASE_BUILD "false"}}/dev{{end}}/LINTER_spawner' WRAPPER_RELATIVE_PATH: './build{{if eq .RELEASE_BUILD "false"}}/dev{{end}}/WRAPPER' DEV_TEST_FLAGS: '--timeout 2 --preset=dev' RELEASE_TEST_FLAGS: '--output-on-failure --no-tests=error --timeout 10 -C Release' @@ -134,5 +135,6 @@ tasks: env: NUTC_CPP_TEMPLATE_PATH: 'test_algos/cpp/template.cpp' NUTC_WRAPPER_BINARY_PATH: '{{.PWD}}/{{.WRAPPER_RELATIVE_PATH}}' + NUTC_LINTER_SPAWNER_BINARY_PATH: '{{.PWD}}/{{.LINTER_SPAWNER_RELATIVE_PATH}}' cmds: - ctest -j 4 {{.TEST_FLAGS}} -R "Integration*" diff --git a/exchange/docker/dev/grafana_data/grafana.db b/exchange/docker/dev/grafana_data/grafana.db index 72f858cf..0d3083a0 100644 Binary files a/exchange/docker/dev/grafana_data/grafana.db and b/exchange/docker/dev/grafana_data/grafana.db differ diff --git a/exchange/docker/linter/Dockerfile b/exchange/docker/linter/Dockerfile new file mode 100644 index 00000000..06d76ef8 --- /dev/null +++ b/exchange/docker/linter/Dockerfile @@ -0,0 +1,39 @@ +#build stage +FROM python:3.12 as build + +RUN pip install conan numpy pandas polars scipy scikit-learn sortedcontainers lightgbm\ + # c++ stuff + && apt update \ + && apt install -y --no-install-recommends build-essential libssl-dev cmake git + +WORKDIR /app/exchange +COPY ./exchange/conanfile.py /app/exchange/conanfile.py +COPY ./.github/scripts/conan-profile.sh /app/exchange + +RUN cat conan-profile.sh | bash \ + && conan install . -b missing + +COPY ./exchange/src /app/exchange/src +COPY ./exchange/CMakeLists.txt /app/exchange +COPY ./exchange/CMakePresets.json /app/exchange +COPY ./exchange/cmake /app/exchange/cmake +COPY ./exchange/test /app/exchange/test + +RUN cmake --preset=ci-docker + +RUN cmake --build build --config Release -j + +RUN mv /app/exchange/build/LINTER_spawner /app/LINTER_spawner +RUN mv /app/exchange/build/LINTER /app/LINTER + +ENV NUTC_LINTER_SPAWNER_BINARY_PATH="/app/LINTER_spawner" + +RUN chmod +x /app/LINTER +RUN chmod +x /app/LINTER_spawner + +COPY ./exchange/template.cpp /app/template.cpp +ENV NUTC_CPP_TEMPLATE_PATH="/app/template.cpp" + +EXPOSE 18081 + +CMD /app/LINTER diff --git a/exchange/docker/sandbox/SandboxDockerfile b/exchange/docker/sandbox/Dockerfile similarity index 63% rename from exchange/docker/sandbox/SandboxDockerfile rename to exchange/docker/sandbox/Dockerfile index 547ca6e8..05c9bc0e 100644 --- a/exchange/docker/sandbox/SandboxDockerfile +++ b/exchange/docker/sandbox/Dockerfile @@ -18,27 +18,24 @@ COPY ./exchange/CMakePresets.json /app/exchange COPY ./exchange/cmake /app/exchange/cmake COPY ./exchange/test /app/exchange/test -ARG firebase_emulator=false +RUN cmake --preset=ci-docker -RUN if [ "$firebase_emulator" = "false" ]; then \ - cmake --preset=ci-docker; \ - else \ - cmake --preset=ci-docker -DLOCAL_DEV=ON; \ - fi +RUN cmake --build build --config Release -j -RUN cmake --build build --config Release -j6 - -RUN mv /app/exchange/build/NUTC /usr/bin/NUTC-exchange -RUN mv /app/exchange/build/WRAPPER /usr/bin/WRAPPER +RUN mv /app/exchange/build/NUTC /app/NUTC +RUN mv /app/exchange/build/WRAPPER /app/WRAPPER # Todo: make default? COPY ./exchange/config.yml /app/exchange/config.yml -RUN chmod +x /usr/bin/NUTC-exchange /usr/bin/WRAPPER +RUN chmod +x /app/NUTC /app/WRAPPER + +COPY ./exchange/template.cpp /app/template.cpp -ENV NUTC_WRAPPER_BINARY_PATH="/usr/bin/WRAPPER" +ENV NUTC_WRAPPER_BINARY_PATH="/app/WRAPPER" ENV NUTC_CONFIG_FILE="/app/exchange/config.yml" +ENV NUTC_CPP_TEMPLATE_PATH="/app/template.cpp" EXPOSE 4152 18080 -ENTRYPOINT ["/usr/bin/NUTC-exchange"] +ENTRYPOINT ["/app/NUTC"] diff --git a/exchange/docker/sandbox/grafana_data/grafana.db b/exchange/docker/sandbox/grafana_data/grafana.db index b1776ac3..79696930 100644 Binary files a/exchange/docker/sandbox/grafana_data/grafana.db and b/exchange/docker/sandbox/grafana_data/grafana.db differ diff --git a/exchange/src/common/compilation/compile_cpp.cpp b/exchange/src/common/compilation/compile_cpp.cpp new file mode 100644 index 00000000..2cbb9a54 --- /dev/null +++ b/exchange/src/common/compilation/compile_cpp.cpp @@ -0,0 +1,67 @@ +#include "compile_cpp.hpp" + +#include "common/file_operations/file_operations.hpp" + +#include + +namespace nutc::common { +namespace { +std::string +get_cpp_template_path() +{ + static const char* template_path_env = std::getenv("NUTC_CPP_TEMPLATE_PATH"); + if (template_path_env == nullptr) { + throw std::runtime_error("Template.cpp path not set, unable to compile cpp"); + } + if (!file_exists(template_path_env)) { + throw std::runtime_error( + fmt::format("File {} does not exist", template_path_env) + ); + } + + return template_path_env; +} + +std::optional +exec_command(const std::string& command) +{ + std::array buffer{}; + std::string result; + + FILE* pipe = popen((command + " 2>&1").c_str(), "r"); + if (pipe == nullptr) { + throw std::runtime_error("popen() failed!"); + } + while (fgets(buffer.data(), buffer.size(), pipe) != nullptr) { + result += buffer.data(); + } + if (pclose(pipe) != 0) { + return result; + } + return std::nullopt; +} +} // namespace + +std::string +compile_cpp(const std::filesystem::path& filepath) +{ + std::string binary_output = (boost::filesystem::temp_directory_path() + / boost::filesystem::unique_path("%%%%-%%%%-%%%%.tmp")) + .string(); + + std::string command = fmt::format( + "g++ -std=c++20 -fPIC -shared -o {} -include {} {}", binary_output, + filepath.string(), get_cpp_template_path() + ); + + std::optional result = exec_command(command); + + if (result) { + throw std::runtime_error(fmt::format( + "Compilation of {} failed. Compiler output below:\n {}", filepath.string(), + result.value() + )); + } + return binary_output; +} +} // namespace nutc::common diff --git a/exchange/src/common/compilation/compile_cpp.hpp b/exchange/src/common/compilation/compile_cpp.hpp new file mode 100644 index 00000000..bcfdbdfc --- /dev/null +++ b/exchange/src/common/compilation/compile_cpp.hpp @@ -0,0 +1,13 @@ +#pragma once + +#include +#include + +#include +#include + +namespace nutc::common { + +// TODO: shouldnt return filepath as string +std::string compile_cpp(const std::filesystem::path& filepath); +} // namespace nutc::common diff --git a/exchange/src/exchange/logging.cpp b/exchange/src/common/logging/logging.cpp similarity index 98% rename from exchange/src/exchange/logging.cpp rename to exchange/src/common/logging/logging.cpp index 998dc302..f7c193f8 100644 --- a/exchange/src/exchange/logging.cpp +++ b/exchange/src/common/logging/logging.cpp @@ -1,4 +1,4 @@ -#include "logging.hpp" +#include "common/logging/logging.hpp" #include diff --git a/exchange/src/exchange/logging.hpp b/exchange/src/common/logging/logging.hpp similarity index 97% rename from exchange/src/exchange/logging.hpp rename to exchange/src/common/logging/logging.hpp index f4ff4fc6..6e3690bf 100644 --- a/exchange/src/exchange/logging.hpp +++ b/exchange/src/common/logging/logging.hpp @@ -1,11 +1,13 @@ #pragma once -#include "config/static/config.hpp" - #include #include +#define LOG_DIR "logs" +#define LOG_FILE (LOG_DIR "/app.log") +#define LOG_BACKTRACE_SIZE 10 + namespace nutc { namespace logging { diff --git a/exchange/src/common/types/algorithm/local_algorithm.cpp b/exchange/src/common/types/algorithm/local_algorithm.cpp index cffd6296..22eb5d52 100644 --- a/exchange/src/common/types/algorithm/local_algorithm.cpp +++ b/exchange/src/common/types/algorithm/local_algorithm.cpp @@ -1,6 +1,7 @@ #include "local_algorithm.hpp" #include "base_algorithm.hpp" +#include "common/compilation/compile_cpp.hpp" #include "common/file_operations/file_operations.hpp" #include @@ -10,38 +11,6 @@ #include namespace nutc::common { -namespace { -std::string -get_cpp_template_path() -{ - static const char* template_path_env = std::getenv("NUTC_CPP_TEMPLATE_PATH"); - if (template_path_env == nullptr) - throw std::runtime_error("Template.cpp path not set, unable to compile cpp"); - return template_path_env; -} -} // namespace - -std::string -LocalAlgorithm::compile_cpp(const std::filesystem::path& filepath) -{ - std::string binary_output = (boost::filesystem::temp_directory_path() - / boost::filesystem::unique_path("%%%%-%%%%-%%%%.tmp")) - .string(); - - std::string command = fmt::format( - "g++ -std=c++20 -fPIC -shared -o {} -include {} {}", binary_output, - filepath.string(), get_cpp_template_path() - ); - - int result = system(command.c_str()); - - if (result != 0) { - throw std::runtime_error( - fmt::format("Compilation of {} failed", filepath.string()) - ); - } - return binary_output; -} LocalAlgorithm::LocalAlgorithm(AlgoLanguage language, std::filesystem::path filepath) : BaseAlgorithm{language}, filepath_{std::move(filepath)} @@ -57,7 +26,7 @@ std::string LocalAlgorithm::get_algo_string() const { if (get_language() == AlgoLanguage::cpp) { - return common::read_file_content(compile_cpp(filepath_)); + return common::read_file_content(common::compile_cpp(filepath_)); } if (get_language() == AlgoLanguage::python) { return common::read_file_content(filepath_); diff --git a/exchange/src/common/types/algorithm/local_algorithm.hpp b/exchange/src/common/types/algorithm/local_algorithm.hpp index d1770916..d828d30e 100644 --- a/exchange/src/common/types/algorithm/local_algorithm.hpp +++ b/exchange/src/common/types/algorithm/local_algorithm.hpp @@ -17,6 +17,5 @@ class LocalAlgorithm : public BaseAlgorithm { std::string get_id() const; private: - static std::string compile_cpp(const std::filesystem::path& filepath); }; } // namespace nutc::common diff --git a/exchange/src/common/types/algorithm/remote_algorithm.hpp b/exchange/src/common/types/algorithm/remote_algorithm.hpp index dd552047..bc37d0bf 100644 --- a/exchange/src/common/types/algorithm/remote_algorithm.hpp +++ b/exchange/src/common/types/algorithm/remote_algorithm.hpp @@ -1,27 +1,52 @@ #pragma once #include "base_algorithm.hpp" +#include "common/compilation/compile_cpp.hpp" +#include "common/file_operations/file_operations.hpp" + +#include + +#include namespace nutc::common { // TODO class RemoteAlgorithm : public BaseAlgorithm { + std::string id_; + std::string algo_data_; + public: - RemoteAlgorithm() : BaseAlgorithm(AlgoLanguage::cpp) - { - throw std::runtime_error("Not implemented"); - } + RemoteAlgorithm(AlgoLanguage language, std::string algo_id, std::string algo_data) : + BaseAlgorithm{language}, id_{std::move(algo_id)}, + algo_data_{std::move(algo_data)} + {} - static std::string - get_algo_string() + std::string + get_algo_string() const { - throw std::runtime_error("Not implemented"); + if (get_language() == AlgoLanguage::cpp) { + // TODO: clean up + std::string binary_output = + (boost::filesystem::temp_directory_path() + / boost::filesystem::unique_path("%%%%-%%%%-%%%%.tmp")) + .string(); + + std::ofstream algo_file(binary_output); + algo_file << algo_data_ << std::flush; + algo_file.close(); + + return common::read_file_content(common::compile_cpp(binary_output)); + } + if (get_language() == AlgoLanguage::python) { + return algo_data_; + } + + throw std::runtime_error("Unknown algo language"); } - // todo: deprecate - static std::string - get_id() + std::string + get_id() const { - throw std::runtime_error("Not implemented"); + return id_; } }; } // namespace nutc::common diff --git a/exchange/src/common/types/ticker.hpp b/exchange/src/common/types/ticker.hpp index e2239ed6..c93086a9 100644 --- a/exchange/src/common/types/ticker.hpp +++ b/exchange/src/common/types/ticker.hpp @@ -1,6 +1,7 @@ #pragma once #include + #include #include #include @@ -10,7 +11,7 @@ namespace nutc::common { // NOTE: this must be the same as Side in template.hpp enum class Ticker : std::uint8_t { ETH = 0, BTC = 1, LTC = 2 }; // NOLINT -static constexpr auto TICKERS = {Ticker::ETH, Ticker::BTC, Ticker::LTC}; +static inline constexpr auto TICKERS = {Ticker::ETH, Ticker::BTC, Ticker::LTC}; inline std::string to_string(Ticker ticker) diff --git a/exchange/src/exchange/algos/normal_mode/normal_mode.cpp b/exchange/src/exchange/algos/normal_mode/normal_mode.cpp index 9cd5c1fc..affc59ad 100644 --- a/exchange/src/exchange/algos/normal_mode/normal_mode.cpp +++ b/exchange/src/exchange/algos/normal_mode/normal_mode.cpp @@ -2,7 +2,7 @@ #include "common/util.hpp" #include "exchange/curl/curl.hpp" -#include "exchange/logging.hpp" +#include "common/logging/logging.hpp" #include "exchange/traders/trader_types/algo_trader.hpp" #include "exchange/wrappers/creation/rmq_wrapper_init.hpp" @@ -40,7 +40,8 @@ NormalModeAlgoInitializer::initialize_trader_container( std::string algo_id = user["latestAlgoId"].get(); try { - traders.add_trader(common::RemoteAlgorithm{}, start_capital); + // TODO: add back + // traders.add_trader(common::RemoteAlgorithm{}, start_capital); log_i(main, "Created user"); } catch (const std::runtime_error& err) { log_w(main, "Failed to create user {}", user_id); diff --git a/exchange/src/exchange/bots/bot_container.cpp b/exchange/src/exchange/bots/bot_container.cpp index af35935a..316457cb 100644 --- a/exchange/src/exchange/bots/bot_container.cpp +++ b/exchange/src/exchange/bots/bot_container.cpp @@ -12,9 +12,10 @@ namespace nutc::exchange { void -BotContainer::generate_orders(common::decimal_price midprice) +BotContainer::generate_orders( + common::decimal_price midprice, common::decimal_price theo +) { - auto theo = fabs(theo_generator_.generate_next_magnitude()); variance_calculator_.record_price(midprice); decimal_price cumulative_interest_limit{}; diff --git a/exchange/src/exchange/bots/bot_container.hpp b/exchange/src/exchange/bots/bot_container.hpp index 4678c139..6a240e5e 100644 --- a/exchange/src/exchange/bots/bot_container.hpp +++ b/exchange/src/exchange/bots/bot_container.hpp @@ -1,7 +1,6 @@ #pragma once #include "common/types/decimal.hpp" #include "exchange/config/dynamic/ticker_config.hpp" -#include "exchange/theo/brownian.hpp" #include "exchange/traders/trader_container.hpp" #include "exchange/traders/trader_types/bot_trader.hpp" #include "shared_bot_state.hpp" @@ -14,28 +13,18 @@ namespace nutc::exchange { */ class BotContainer { using BotVector = std::vector>; - BrownianMotion theo_generator_; VarianceCalculator variance_calculator_; BotVector bots_{}; public: - void generate_orders(common::decimal_price midprice); + void generate_orders(common::decimal_price midprice, common::decimal_price theo); BotContainer( - common::Ticker ticker, common::decimal_price starting_price, - TraderContainer& trader_container, bot_config bots - ) : - theo_generator_(starting_price), - bots_(create_bots(trader_container, ticker, bots)) + common::Ticker ticker, TraderContainer& trader_container, bot_config bots + ) : bots_(create_bots(trader_container, ticker, bots)) {} - common::decimal_price - get_theo() const - { - return theo_generator_.get_magnitude(); - } - double get_variance() const { diff --git a/exchange/src/exchange/bots/bot_types/market_maker.cpp b/exchange/src/exchange/bots/bot_types/market_maker.cpp index 21d00358..a4d0f731 100644 --- a/exchange/src/exchange/bots/bot_types/market_maker.cpp +++ b/exchange/src/exchange/bots/bot_types/market_maker.cpp @@ -22,11 +22,12 @@ struct price_level { // TODO: parameterize constexpr double BASE_SPREAD = 0.16; -constexpr uint8_t LEVELS = 3; +constexpr uint8_t LEVELS = 4; constexpr std::array PRICE_LEVELS{ - price_level{BASE_SPREAD + .00, 1.0 / 2}, - price_level{BASE_SPREAD + .05, 1.0 / 3}, - price_level{BASE_SPREAD + .10, 1.0 / 6} + price_level{BASE_SPREAD + .00, 1.0 / 2 }, + price_level{BASE_SPREAD + .05, 1.0 / 3 }, + price_level{BASE_SPREAD + .10, 1.0 / 8 }, + price_level{BASE_SPREAD + .15, 1.0 / 24} }; } // namespace @@ -34,7 +35,7 @@ constexpr std::array PRICE_LEVELS{ namespace nutc::exchange { void -MarketMakerBot::place_orders(Side side, decimal_price theo, decimal_price spread_offset) +MarketMakerBot::place_orders_(Side side, decimal_price theo, decimal_price spread_offset) { // Approximation common::decimal_quantity total_quantity = { @@ -82,9 +83,10 @@ MarketMakerBot::take_action(const shared_bot_state& state) decimal_price spread_offset = 0.0; decimal_price lean = calculate_lean_percent(state); - decimal_price theo = state.THEO - (lean * 10.0) + generate_gaussian_noise(0, .05); - place_orders(Side::buy, theo, spread_offset); - place_orders(Side::sell, theo, spread_offset); + decimal_price theo = state.THEO - (lean * 1.0) + generate_gaussian_noise(0, .05); + + place_orders_(Side::buy, theo, spread_offset); + place_orders_(Side::sell, theo, spread_offset); } } // namespace nutc::exchange diff --git a/exchange/src/exchange/bots/bot_types/market_maker.hpp b/exchange/src/exchange/bots/bot_types/market_maker.hpp index efee05c1..6857ab42 100644 --- a/exchange/src/exchange/bots/bot_types/market_maker.hpp +++ b/exchange/src/exchange/bots/bot_types/market_maker.hpp @@ -41,11 +41,11 @@ class MarketMakerBot : public BotTrader { return TYPE; } - decimal_price calculate_lean_percent(const shared_bot_state& state); + static decimal_price calculate_lean_percent(const shared_bot_state& state); private: void - place_orders(common::Side side, decimal_price theo, decimal_price spread_offset); + place_orders_(common::Side side, decimal_price theo, decimal_price spread_offset); }; } // namespace nutc::exchange diff --git a/exchange/src/exchange/bots/bot_types/retail.cpp b/exchange/src/exchange/bots/bot_types/retail.cpp index 5b1cb5aa..43f6d6b0 100644 --- a/exchange/src/exchange/bots/bot_types/retail.cpp +++ b/exchange/src/exchange/bots/bot_types/retail.cpp @@ -9,7 +9,7 @@ namespace nutc::exchange { void RetailBot::take_action(const shared_bot_state& state) { - static std::uniform_real_distribution<> dis{0.0, 1.0}; + static std::uniform_real_distribution<> dis{0.0, 1}; auto p_trade = common::decimal_price{1.0} - get_capital_utilization(); diff --git a/exchange/src/exchange/main.cpp b/exchange/src/exchange/main.cpp index 0ae24249..822e2fa4 100644 --- a/exchange/src/exchange/main.cpp +++ b/exchange/src/exchange/main.cpp @@ -3,7 +3,7 @@ #include "exchange/algos/algo_manager.hpp" #include "exchange/config/dynamic/argparse.hpp" #include "exchange/config/dynamic/config.hpp" -#include "exchange/logging.hpp" +#include "common/logging/logging.hpp" #include "exchange/matching_cycle/base/base_cycle.hpp" #include "exchange/matching_cycle/cycle_interface.hpp" #include "exchange/matching_cycle/dev/dev_cycle.hpp" diff --git a/exchange/src/exchange/matching_cycle/sandbox/sandbox_cycle.hpp b/exchange/src/exchange/matching_cycle/sandbox/sandbox_cycle.hpp index ce164f33..5da465bd 100644 --- a/exchange/src/exchange/matching_cycle/sandbox/sandbox_cycle.hpp +++ b/exchange/src/exchange/matching_cycle/sandbox/sandbox_cycle.hpp @@ -14,13 +14,15 @@ class SandboxMatchingCycle : public DevMatchingCycle { private: void - before_cycle_(uint64_t) override + before_cycle_(uint64_t tick) override { auto traders = CrowServer::get_instance().get_and_clear_pending_traders(); std::for_each(traders.begin(), traders.end(), [this](auto&& trader) { get_traders().add_trader(trader); }); + + DevMatchingCycle::before_cycle_(tick); } }; } // namespace nutc::exchange diff --git a/exchange/src/exchange/metrics/on_tick_metrics.cpp b/exchange/src/exchange/metrics/on_tick_metrics.cpp index 17ac64d4..3ab7d20f 100644 --- a/exchange/src/exchange/metrics/on_tick_metrics.cpp +++ b/exchange/src/exchange/metrics/on_tick_metrics.cpp @@ -81,6 +81,14 @@ TickerMetricsPusher::report_ticker_stats(TickerContainer& tickers) } }; + auto log_theo = [&](common::Ticker ticker, TickerData& info) { + ticker_theo + .Add({ + {"ticker", common::to_string(ticker)} + }) + .Set(double{(info.get_theo())}); + }; + // auto log_variance = [&](common::Ticker ticker, const TickerData& info) { // ticker_midprice_variance_gauge // .Add({ @@ -92,6 +100,7 @@ TickerMetricsPusher::report_ticker_stats(TickerContainer& tickers) for (auto [ticker, info] : tickers) { log_midprice(ticker, info); log_best_ba(ticker, info); + log_theo(ticker, info); // log_variance(ticker, info); } } @@ -153,14 +162,14 @@ TickerMetricsPusher::report_trader_stats(const TickerContainer& tickers) per_trader_pnl_gauge .Add({ - {"trader_type", trader.get_type()}, {"id", trader.get_id() }, + {"trader_type", trader.get_type()}, }) .Set(pnl); per_trader_capital_gauge .Add({ - {"trader_type", trader.get_type()}, {"id", trader.get_id() }, + {"trader_type", trader.get_type()}, }) .Set(capital); }; diff --git a/exchange/src/exchange/metrics/on_tick_metrics.hpp b/exchange/src/exchange/metrics/on_tick_metrics.hpp index 6877aefe..09175bdb 100644 --- a/exchange/src/exchange/metrics/on_tick_metrics.hpp +++ b/exchange/src/exchange/metrics/on_tick_metrics.hpp @@ -24,6 +24,7 @@ class TickerMetricsPusher { Gauge ticker_midprice_gauge = create_gauge_("ticker_midprice"); Gauge best_ba_gauge = create_gauge_("best_ba"); Gauge ticker_midprice_variance_gauge = create_gauge_("ticker_midprice_variance"); + Gauge ticker_theo = create_gauge_("ticker_theo"); Counter matches_quantity_counter = create_counter_("matches_quantity_total"); Counter orders_quantity_counter = create_counter_("orders_quantity_total"); Counter cancellation_counter = create_counter_("order_cancellations_total"); diff --git a/exchange/src/exchange/orders/ticker_container.cpp b/exchange/src/exchange/orders/ticker_container.cpp index 60cb9b48..951629a4 100644 --- a/exchange/src/exchange/orders/ticker_container.cpp +++ b/exchange/src/exchange/orders/ticker_container.cpp @@ -1,5 +1,7 @@ #include "ticker_container.hpp" +#include "common/types/ticker.hpp" + namespace nutc::exchange { TickerContainer::TickerContainer( @@ -110,9 +112,21 @@ TickerContainer::create_tickers( const std::vector& configs, TraderContainer& traders ) { - std::vector result = create_tickers(); + std::vector result; + // this is really bad. fix soon + std::unordered_map ticker_map; for (const auto& config : configs) { - result[std::to_underlying(config.TICKER)].set_bot_config(traders, config); + ticker_map.emplace( + std::piecewise_construct, + std::forward_as_tuple(std::to_underlying(config.TICKER)), + std::forward_as_tuple(traders, config) + ); + } + for (std::size_t ticker = 0; ticker < common::TICKERS.size(); ticker++) { + if (ticker_map.contains(ticker)) + result.emplace_back(ticker_map.at(ticker)); + else + result.emplace_back(static_cast(ticker)); } return result; } diff --git a/exchange/src/exchange/orders/ticker_container.hpp b/exchange/src/exchange/orders/ticker_container.hpp index 9f2c43b0..7f4fe475 100644 --- a/exchange/src/exchange/orders/ticker_container.hpp +++ b/exchange/src/exchange/orders/ticker_container.hpp @@ -10,7 +10,9 @@ class TickerContainer { std::vector tickers; public: - TickerContainer(const std::vector& configs, TraderContainer& traders); + TickerContainer( + const std::vector& configs, TraderContainer& traders + ); TickerContainer(); diff --git a/exchange/src/exchange/orders/ticker_data.hpp b/exchange/src/exchange/orders/ticker_data.hpp index 3ecb463b..194d1737 100644 --- a/exchange/src/exchange/orders/ticker_data.hpp +++ b/exchange/src/exchange/orders/ticker_data.hpp @@ -1,8 +1,10 @@ #pragma once #include "common/types/decimal.hpp" +#include "common/types/ticker.hpp" #include "exchange/bots/bot_container.hpp" #include "exchange/config/dynamic/ticker_config.hpp" #include "exchange/orders/orderbook/composite_orderbook.hpp" +#include "exchange/theo/brownian.hpp" #include "exchange/traders/trader_container.hpp" #include @@ -15,9 +17,15 @@ namespace nutc::exchange { */ class TickerData { CompositeOrderBook limit_orderbook_; + BrownianMotion theo_generator_; // NOLINT std::vector bot_containers_; public: + explicit TickerData(TraderContainer& traders, const ticker_config& config) : + limit_orderbook_{config.TICKER}, theo_generator_{config.STARTING_PRICE}, + bot_containers_{create_bot_containers(traders, config.TICKER, config.BOTS)} + {} + explicit TickerData(common::Ticker ticker) : limit_orderbook_{ticker} {} CompositeOrderBook& @@ -36,32 +44,29 @@ class TickerData { generate_bot_orders() { auto midprice = get_orderbook().get_midprice(); + auto theo = fabs(theo_generator_.generate_next_magnitude()); std::ranges::for_each(bot_containers_, [&](auto& bot_container) { - bot_container.generate_orders(midprice); + bot_container.generate_orders(midprice, theo); }); } - void - set_bot_config(TraderContainer& traders, const ticker_config& config) + common::decimal_price + get_theo() const { - bot_containers_ = create_bot_containers( - traders, config.TICKER, config.STARTING_PRICE, config.BOTS - ); + return theo_generator_.get_magnitude(); } private: static std::vector create_bot_containers( TraderContainer& trader_container, common::Ticker ticker, - common::decimal_price starting_price, const std::vector& configs + const std::vector& configs ) { std::vector bot_containers; bot_containers.reserve(configs.size()); for (const bot_config& bot_config : configs) { - bot_containers.emplace_back( - ticker, starting_price, trader_container, bot_config - ); + bot_containers.emplace_back(ticker, trader_container, bot_config); } return bot_containers; } diff --git a/exchange/src/exchange/sandbox_server/crow.cpp b/exchange/src/exchange/sandbox_server/crow.cpp index 47971d8d..798994bd 100644 --- a/exchange/src/exchange/sandbox_server/crow.cpp +++ b/exchange/src/exchange/sandbox_server/crow.cpp @@ -1,10 +1,13 @@ #include "crow.hpp" +#include "common/logging/logging.hpp" #include "common/messages_exchange_to_wrapper.hpp" +#include "common/types/algorithm/base_algorithm.hpp" #include "exchange/config/dynamic/config.hpp" -#include "exchange/logging.hpp" #include "exchange/traders/trader_types/algo_trader.hpp" +#include + namespace nutc::exchange { CrowServer::CrowServer() : @@ -12,47 +15,57 @@ CrowServer::CrowServer() : timer_thread([this]() { io_context_.run(); }) { CROW_ROUTE(app, "/sandbox//") - ([this](const crow::request& req, std::string user_id, std::string algo_id) { - crow::response res; - res.code = 200; - // Set CORS headers - res.add_header("Access-Control-Allow-Origin", "*"); - res.add_header( - "Access-Control-Allow-Methods", "GET, POST, PATCH, PUT, DELETE, OPTIONS" + .methods(crow::HTTPMethod::POST, crow::HTTPMethod::OPTIONS)( + [this]( + const crow::request& req, std::string algo_id, std::string language + ) { + crow::response res; + res.code = 200; + // Set CORS headers + res.add_header("Access-Control-Allow-Origin", "*"); + res.add_header("Access-Control-Allow-Methods", "POST, OPTIONS"); + res.add_header( + "Access-Control-Allow-Headers", "Origin, Content-Type, Accept" + ); + + // Handle preflight request for OPTIONS method + if (req.method == crow::HTTPMethod::OPTIONS) { + res.code = 204; + return res; + } + + try { + log_i( + sandbox_server, + "Received sandbox request with algo_id {} and language {}", + algo_id, language + ); + common::AlgoLanguage language_enum = + language == "Python" ? common::AlgoLanguage::python + : common::AlgoLanguage::cpp; + std::string algorithm_data = req.body; + add_pending_trader_(algo_id, language_enum, algorithm_data); + return res; + } catch (const std::exception& e) { + log_e(sandbox_server, "Failed to spawn algorithm: {}", e.what()); + return crow::response(500); + } + } ); - res.add_header("Access-Control-Allow-Headers", "Origin, Content-Type, Accept"); - - // Handle preflight request for OPTIONS method - if (req.method == crow::HTTPMethod::OPTIONS) { - res.code = 204; - return res; - } - - try { - log_i( - sandbox_server, - "Received sandbox request with user id {} and algoid {}", user_id, - algo_id - ); - add_pending_trader(user_id, algo_id); - return res; - } catch (...) { - return crow::response(500); - } - }); server_thread = std::thread([this] { app.signal_clear().port(18080).run(); }); } void -CrowServer::add_pending_trader( - [[maybe_unused]] const std::string& user_id, - [[maybe_unused]] const std::string& algo_id +CrowServer::add_pending_trader_( + const std::string& algo_id, common::AlgoLanguage language, + const std::string& algorithm_data ) { static const auto STARTING_CAPITAL = Config::get().constants().STARTING_CAPITAL; - auto trader = - std::make_shared(common::RemoteAlgorithm{}, STARTING_CAPITAL); + auto trader = std::make_shared( + common::RemoteAlgorithm{language, algo_id, algorithm_data}, STARTING_CAPITAL + ); trader_lock.lock(); traders_to_add.push_back(trader); diff --git a/exchange/src/exchange/sandbox_server/crow.hpp b/exchange/src/exchange/sandbox_server/crow.hpp index 58c556b5..64e92429 100644 --- a/exchange/src/exchange/sandbox_server/crow.hpp +++ b/exchange/src/exchange/sandbox_server/crow.hpp @@ -48,7 +48,10 @@ class CrowServer { ~CrowServer(); private: - void add_pending_trader(const std::string& user_id, const std::string& algo_id); + void add_pending_trader_( + const std::string& algo_id, common::AlgoLanguage language, + const std::string& algorithm_data + ); void start_remove_timer_(unsigned int time_ms, std::weak_ptr trader_ptr); }; diff --git a/exchange/src/exchange/theo/brownian.cpp b/exchange/src/exchange/theo/brownian.cpp index 8e29b664..108082ac 100644 --- a/exchange/src/exchange/theo/brownian.cpp +++ b/exchange/src/exchange/theo/brownian.cpp @@ -68,6 +68,12 @@ BrownianMotion::generate_market_tick_() return delta; } +bool +BrownianMotion::market_event_ongoing_() const +{ + return event_ticks_remaining_ > 0; +} + double BrownianMotion::generate_nonmarket_tick_() { @@ -85,14 +91,11 @@ BrownianMotion::should_start_new_market_event_() double BrownianMotion::generate_next_magnitude() { - bool market_event_ongoing = event_ticks_remaining_ > 0; - - if (!market_event_ongoing && should_start_new_market_event_()) { + if (!market_event_ongoing_() && should_start_new_market_event_()) { config_new_market_event_(); - market_event_ongoing = true; } - if (market_event_ongoing) { + if (market_event_ongoing_()) { event_ticks_remaining_--; cur_magnitude_ += generate_market_tick_(); return fabs(cur_magnitude_); @@ -100,6 +103,7 @@ BrownianMotion::generate_next_magnitude() // Handle as a normal tick cur_magnitude_ += generate_nonmarket_tick_(); + assert(fabs(cur_magnitude_) < 1000); return fabs(cur_magnitude_); } diff --git a/exchange/src/exchange/theo/brownian.hpp b/exchange/src/exchange/theo/brownian.hpp index e83ec925..cdb4d783 100644 --- a/exchange/src/exchange/theo/brownian.hpp +++ b/exchange/src/exchange/theo/brownian.hpp @@ -62,6 +62,7 @@ class BrownianMotion { generate_norm_(double mean, double stdev, Signedness sign = Signedness::Either); double generate_uniform_(double low, double high); bool generate_bool_(double probability_of_true); + bool market_event_ongoing_() const; double generate_brownian_motion_(double mean, Signedness direction = Signedness::Either); diff --git a/exchange/src/exchange/wrappers/messaging/pipe_reader.cpp b/exchange/src/exchange/wrappers/messaging/pipe_reader.cpp index 2942c28c..1fea5d41 100644 --- a/exchange/src/exchange/wrappers/messaging/pipe_reader.cpp +++ b/exchange/src/exchange/wrappers/messaging/pipe_reader.cpp @@ -2,7 +2,7 @@ #include "async_pipe_runner.hpp" #include "common/messages_wrapper_to_exchange.hpp" -#include "exchange/logging.hpp" +#include "common/logging/logging.hpp" #include #include diff --git a/linter/src/common.hpp b/exchange/src/linter/common.hpp similarity index 95% rename from linter/src/common.hpp rename to exchange/src/linter/common.hpp index ca32da82..95989bd0 100644 --- a/linter/src/common.hpp +++ b/exchange/src/linter/common.hpp @@ -2,8 +2,8 @@ // Common headers -#include "config.h" -#include "logging.hpp" +#include "linter/config.h" +#include "common/logging/logging.hpp" #include #include diff --git a/linter/src/config.h.in b/exchange/src/linter/config.h similarity index 77% rename from linter/src/config.h.in rename to exchange/src/linter/config.h index 6c5c149e..4b4f7636 100644 --- a/linter/src/config.h.in +++ b/exchange/src/linter/config.h @@ -14,20 +14,20 @@ /* NOLINTEND */ // Logging -#define LOG_BACKTRACE_SIZE 10 - -#define LOG_DIR "logs" -#define LOG_FILE (LOG_DIR "/app.log") #define LOG_FILE_SIZE (1024 * 1024 / 2) // 512 KB #define LOG_BACKUP_COUNT 5 #ifdef NUTC_LOCAL_DEV -# define FIREBASE_URL "http://firebase:9000/" +# define S3_URL "http://localhost:4566" +# define WEBSERVER_URL "http://localhost:16124" #else -# define FIREBASE_URL "https://nutc-web-default-rtdb.firebaseio.com/" +# define S3_URL "https://nutc.s3.us-east-2.amazonaws.com" +# define WEBSERVER_URL "http://localhost:16124" #endif +#define S3_BUCKET "nutc" + // Linting #define LINT_AUTO_TIMEOUT_SECONDS 10 diff --git a/linter/src/crow/crow.cpp b/exchange/src/linter/crow/crow.cpp similarity index 53% rename from linter/src/crow/crow.cpp rename to exchange/src/linter/crow/crow.cpp index 13ab12d5..60d5e2b0 100644 --- a/linter/src/crow/crow.cpp +++ b/exchange/src/linter/crow/crow.cpp @@ -1,8 +1,8 @@ #include "crow.hpp" -#include "firebase/fetching.hpp" -#include "logging.hpp" -#include "spawning/spawning.hpp" +#include "linter/fetching/fetching.hpp" +#include "common/logging/logging.hpp" +#include "linter/spawning/spawning.hpp" namespace nutc { namespace crow { @@ -33,31 +33,34 @@ get_server_thread() return res; } - if (!req.url_params.get("uid")) { - log_e(main, "No uid provided"); - return crow::response(400); - }; - if (!req.url_params.get("algo_id")) { + if (!req.url_params.get("algo_url")) { log_e(main, "No algo_id provided"); return crow::response(400); } - std::string uid = req.url_params.get("uid"); - std::string algo_id = req.url_params.get("algo_id"); + if (!req.url_params.get("language")) { + log_e(main, "No language provided"); + return crow::response(400); + } + std::string algo_url = req.url_params.get("algo_url"); + std::string language = req.url_params.get("language"); - auto algo_code = nutc::client::get_algo(uid, algo_id); + spawning::AlgoLanguage algo_language; + if (language == "Python") { + algo_language = spawning::AlgoLanguage::Python; + } + else if (language == "Cpp") { + algo_language = spawning::AlgoLanguage::Cpp; + } + else { + log_e(main, "Invalid language provided: {}", language); + return crow::response(400); + } + + auto algo_code = client::storage_request(algo_url); if (!algo_code.has_value()) { - nutc::client::set_lint_failure( - uid, - algo_id, - fmt::format( - "[linter] FAILURE - could not find algo {} for id {}\n", - algo_id, - uid - ) - ); crow::json::wvalue response = crow::json::wvalue({ - {"linting_status", - static_cast(client::LintingResultOption::UNKNOWN)} + {"lint_success", false }, + {"message", "Algo file not found"} }); res.body = response.dump(); @@ -66,19 +69,11 @@ get_server_thread() return res; } - client::LintingResultOption algo_status_code; - auto lint_res = spawner_manager.spawn_client(algo_code.value()); - if (lint_res.success) { - nutc::client::set_lint_success(uid, algo_id, lint_res.message); - algo_status_code = client::LintingResultOption::SUCCESS; - } - else { - nutc::client::set_lint_failure(uid, algo_id, lint_res.message); - algo_status_code = client::LintingResultOption::FAILURE; - } - + auto lint_res = + spawner_manager.spawn_client(algo_code.value(), algo_language); crow::json::wvalue response({ - {"linting_status", static_cast(algo_status_code)} + {"lint_success", lint_res.success }, + {"message", client::replaceDisallowedValues(lint_res.message)} }); res.body = response.dump(); diff --git a/linter/src/crow/crow.hpp b/exchange/src/linter/crow/crow.hpp similarity index 100% rename from linter/src/crow/crow.hpp rename to exchange/src/linter/crow/crow.hpp diff --git a/exchange/src/linter/fetching/fetching.cpp b/exchange/src/linter/fetching/fetching.cpp new file mode 100644 index 00000000..b38cbb74 --- /dev/null +++ b/exchange/src/linter/fetching/fetching.cpp @@ -0,0 +1,62 @@ +#include "fetching.hpp" + +#include +#include + +#include +#include + +namespace nutc { +namespace client { +std::string +replaceDisallowedValues(const std::string& input) +{ + std::regex newlinePattern("\\n"); + std::string input2 = std::regex_replace(input, newlinePattern, "\\n"); + std::regex disallowedPattern("[.$#\\[\\]]"); + + return std::regex_replace(input2, disallowedPattern, ""); +} + +static size_t +write_callback(void* contents, size_t size, size_t nmemb, void* userp) +{ + auto* str = reinterpret_cast(userp); + auto* data = static_cast(contents); + + str->append(data, size * nmemb); + return size * nmemb; +} + +std::optional +storage_request(const std::string& url) +{ + std::string readBuffer; + + CURL* curl = curl_easy_init(); + if (curl) { + CURLcode res = curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); + if (res != CURLE_OK) { + return std::nullopt; + } + res = curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); + if (res != CURLE_OK) { + return std::nullopt; + } + res = curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer); + if (res != CURLE_OK) { + return std::nullopt; + } + + res = curl_easy_perform(curl); + if (res != CURLE_OK) { + return std::nullopt; + } + curl_easy_cleanup(curl); + } + + return readBuffer; +} + +} // namespace client +} // namespace nutc diff --git a/exchange/src/linter/fetching/fetching.hpp b/exchange/src/linter/fetching/fetching.hpp new file mode 100644 index 00000000..dab4d249 --- /dev/null +++ b/exchange/src/linter/fetching/fetching.hpp @@ -0,0 +1,28 @@ +#pragma once + +#include +#include + +#include +#include + +namespace nutc { +namespace client { + +struct SetLintBody { + bool success; + std::string message; +}; + +std::optional storage_request(const std::string& url); +std::string replaceDisallowedValues(const std::string& input); + +} // namespace client +} // namespace nutc + +template <> +struct glz::meta { + using t = nutc::client::SetLintBody; + static constexpr auto value = + object("success", &t::success, "message", &t::message); +}; diff --git a/exchange/src/linter/lint/lint.cpp b/exchange/src/linter/lint/lint.cpp new file mode 100644 index 00000000..2a5f0645 --- /dev/null +++ b/exchange/src/linter/lint/lint.cpp @@ -0,0 +1,104 @@ +#include "lint.hpp" + +#include "common/types/ticker.hpp" +#include "common/util.hpp" + +#include +#include + +#include + +namespace nutc { +namespace lint { + +lint_result +lint(Runtime& runtime) +{ + std::string out_message = "[linter] starting to lint algorithm\n"; + auto init_err = runtime.init(); + if (init_err.has_value()) { + out_message += fmt::format("{}\n", init_err.value()); + return {false, out_message}; + } + + try { + runtime.fire_on_orderbook_update( + common::Ticker::ETH, common::Side::buy, 1.0, 1.0 + ); + } catch (const std::exception& e) { + out_message += fmt::format("Failed to run on_orderbook_update: {}", e.what()); + return {false, out_message}; + } + + try { + runtime.fire_on_trade_update(common::Ticker::ETH, common::Side::buy, 1.0, 1.0); + } catch (const std::exception& e) { + out_message += fmt::format("Failed to run on_trade_update: {}", e.what()); + return {false, out_message}; + } + + try { + runtime.fire_on_orderbook_update( + common::Ticker::BTC, common::Side::buy, 1.0, 1.0 + ); + } catch (const std::exception& e) { + out_message += fmt::format("Failed to run on_orderbook_update: {}", e.what()); + return {false, out_message}; + } + + try { + runtime.fire_on_trade_update(common::Ticker::BTC, common::Side::buy, 1.0, 1.0); + } catch (const std::exception& e) { + out_message += fmt::format("Failed to run on_trade_update: {}", e.what()); + return {false, out_message}; + } + + try { + runtime.fire_on_account_update( + common::Ticker::BTC, common::Side::buy, 1.0, 1.0, 1.0 + ); + } catch (const std::exception& e) { + out_message += fmt::format("Failed to run on_trade_update: {}", e.what()); + return {false, out_message}; + } + + try { + runtime.fire_on_account_update( + common::Ticker::BTC, common::Side::buy, 1.0, 1.0, 1.0 + ); + } catch (const std::exception& e) { + out_message += fmt::format("Failed to run on_account_update: {}", e.what()); + return {false, out_message}; + } + + try { + runtime.fire_on_orderbook_update( + common::Ticker::LTC, common::Side::buy, 1.0, 1.0 + ); + } catch (const std::exception& e) { + out_message += fmt::format("Failed to run on_orderbook_update: {}", e.what()); + return {false, out_message}; + } + + try { + runtime.fire_on_trade_update(common::Ticker::LTC, common::Side::buy, 1.0, 1.0); + } catch (const std::exception& e) { + out_message += fmt::format("Failed to run on_trade_update: {}", e.what()); + return {false, out_message}; + } + + try { + runtime.fire_on_account_update( + common::Ticker::LTC, common::Side::buy, 1.0, 1.0, 1.0 + ); + } catch (const std::exception& e) { + out_message += fmt::format("Failed to run on_account_update: {}", e.what()); + return {false, out_message}; + } + + out_message += "\n[linter] linting process succeeded!\n"; + return {true, out_message}; +} + +} // namespace lint +} // namespace nutc diff --git a/exchange/src/linter/lint/lint.hpp b/exchange/src/linter/lint/lint.hpp new file mode 100644 index 00000000..d123b291 --- /dev/null +++ b/exchange/src/linter/lint/lint.hpp @@ -0,0 +1,12 @@ +#pragma once + +#include "linter/lint/lint_result.hpp" +#include "linter/runtime/runtime.hpp" + +namespace nutc { +namespace lint { + +[[nodiscard]] lint_result lint(Runtime& runtime); + +} // namespace lint +} // namespace nutc diff --git a/linter/src/lint/lint_result.hpp b/exchange/src/linter/lint/lint_result.hpp similarity index 100% rename from linter/src/lint/lint_result.hpp rename to exchange/src/linter/lint/lint_result.hpp diff --git a/linter/src/main.cpp b/exchange/src/linter/main.cpp similarity index 68% rename from linter/src/main.cpp rename to exchange/src/linter/main.cpp index 1d72293d..91656f58 100644 --- a/linter/src/main.cpp +++ b/exchange/src/linter/main.cpp @@ -1,7 +1,8 @@ +#include #define CROW_MAIN -#include "config.h" -#include "crow/crow.hpp" -#include "logging.hpp" +#include "common/logging/logging.hpp" +#include "linter/config.h" +#include "linter/crow/crow.hpp" #include #include @@ -11,7 +12,7 @@ #include #include -static std::tuple +static void process_arguments(int argc, const char** argv) { argparse::ArgumentParser program( @@ -28,15 +29,6 @@ process_arguments(int argc, const char** argv) .implicit_value(true) .nargs(0); - uint8_t verbosity = 0; - program.add_argument("-v", "--verbose") - .help("increase output verbosity") - .action([&](const auto& /* unused */) { ++verbosity; }) - .append() - .default_value(false) - .implicit_value(true) - .nargs(0); - try { program.parse_args(argc, argv); } catch (const std::runtime_error& err) { @@ -44,18 +36,15 @@ process_arguments(int argc, const char** argv) std::cerr << program; exit(1); // NOLINT(concurrency-*) } - - return std::make_tuple(verbosity); } int main(int argc, const char** argv) { - // Parse args - auto [verbosity] = process_arguments(argc, argv); + process_arguments(argc, argv); // Start logging and print the build info - nutc::logging::init(verbosity); + nutc::logging::init(quill::LogLevel::Info); log_i(main, "Starting NUTC Linter"); auto server_thread = nutc::crow::get_server_thread(); diff --git a/exchange/src/linter/runtime/cpp/cpp_runtime.cpp b/exchange/src/linter/runtime/cpp/cpp_runtime.cpp new file mode 100644 index 00000000..58f064cd --- /dev/null +++ b/exchange/src/linter/runtime/cpp/cpp_runtime.cpp @@ -0,0 +1,105 @@ +#include "cpp_runtime.hpp" + +#include "common/compilation/compile_cpp.hpp" + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +namespace nutc::lint { + +CppRuntime::CppRuntime( + std::string algo, LimitOrderFunction limit_order, MarketOrderFunction market_order, + CancelOrderFunction cancel_order +) : + Runtime( + std::move(algo), std::move(limit_order), std::move(market_order), + std::move(cancel_order) + ) +{} + +CppRuntime::~CppRuntime() +{ + if (dl_handle_ != nullptr) { + dlclose(dl_handle_); + } +} + +std::optional +CppRuntime::init() +{ + boost::filesystem::path temp_dir = boost::filesystem::temp_directory_path(); + boost::filesystem::path temp_file = + temp_dir / boost::filesystem::unique_path("tempfile-%%%%-%%%%"); + + std::ofstream algo_file(temp_file.string()); + algo_file << algo_ << std::flush; + algo_file.close(); + + // TODO: improve + std::string compiled_binary_path; + try { + compiled_binary_path = common::compile_cpp(temp_file.string()); + } catch (const std::exception& e) { + return fmt::format("[linter] failed to compile C++ code: {}", e.what()); + } + + dl_handle_ = dlopen(compiled_binary_path.c_str(), RTLD_NOW); + if (dl_handle_ == nullptr) { + std::string err = dlerror(); + return fmt::format("[linter] failed to dlopen: {}", err); + } + + auto init_func = reinterpret_cast(dlsym(dl_handle_, "init")); + on_trade_update_func_ = + reinterpret_cast(dlsym(dl_handle_, "on_trade_update")); + on_orderbook_update_func_ = + reinterpret_cast(dlsym(dl_handle_, "on_orderbook_update") + ); + on_account_update_func_ = + reinterpret_cast(dlsym(dl_handle_, "on_account_update")); + + if (init_func == nullptr || on_trade_update_func_ == nullptr + || on_orderbook_update_func_ == nullptr || on_account_update_func_ == nullptr) { + return fmt::format("[linter] failed to dynamically load functions"); + } + strategy_object_ = + init_func(m_market_order_func, m_limit_order_func, m_cancel_order_func); + + return std::nullopt; +} + +void +CppRuntime::fire_on_trade_update( + common::Ticker ticker, common::Side side, float price, float quantity +) const +{ + on_trade_update_func_(strategy_object_, ticker, side, quantity, price); +} + +void +CppRuntime::fire_on_orderbook_update( + common::Ticker ticker, common::Side side, float price, float quantity +) const +{ + on_orderbook_update_func_(strategy_object_, ticker, side, quantity, price); +} + +void +CppRuntime::fire_on_account_update( + common::Ticker ticker, common::Side side, float price, float quantity, float capital +) const +{ + on_account_update_func_(strategy_object_, ticker, side, quantity, price, capital); +} + +} // namespace nutc::lint diff --git a/exchange/src/linter/runtime/cpp/cpp_runtime.hpp b/exchange/src/linter/runtime/cpp/cpp_runtime.hpp new file mode 100644 index 00000000..d7e70f4b --- /dev/null +++ b/exchange/src/linter/runtime/cpp/cpp_runtime.hpp @@ -0,0 +1,55 @@ +#pragma once + +#include "linter/runtime/runtime.hpp" + +namespace nutc::lint { + +class CppRuntime : public Runtime { +public: + CppRuntime( + std::string algo, + LimitOrderFunction limit_order, + MarketOrderFunction market_order, + CancelOrderFunction cancel_order + ); + + ~CppRuntime() override; + + std::optional init() override; + + void fire_on_trade_update( + common::Ticker ticker, common::Side side, float price, float quantity + ) const override; + + void fire_on_orderbook_update( + common::Ticker ticker, common::Side side, float price, float quantity + ) const override; + + void fire_on_account_update( + common::Ticker ticker, + common::Side side, + float price, + float quantity, + float capital + ) const override; +private: + + using Strategy = void; + using InitFunc = Strategy* (*)(MarketOrderFunction, + LimitOrderFunction, + CancelOrderFunction); + using OnTradeUpdateFunc = + void (*)(Strategy*, common::Ticker, common::Side, float, float); + using OnOrderBookUpdateFunc = OnTradeUpdateFunc; + using OnAccountUpdateFunc = void (*)( + Strategy*, common::Ticker, common::Side, float, float, float + ); + + OnTradeUpdateFunc on_trade_update_func_; + OnOrderBookUpdateFunc on_orderbook_update_func_; + OnAccountUpdateFunc on_account_update_func_; + + Strategy* strategy_object_; + void* dl_handle_{}; +}; +} // namespace nutc::lint diff --git a/exchange/src/linter/runtime/python/python_runtime.cpp b/exchange/src/linter/runtime/python/python_runtime.cpp new file mode 100644 index 00000000..df86f36e --- /dev/null +++ b/exchange/src/linter/runtime/python/python_runtime.cpp @@ -0,0 +1,161 @@ +#include "python_runtime.hpp" + +#include +#include +#include + +namespace nutc::lint { + +namespace py = pybind11; + +PyRuntime::~PyRuntime() +{ + pybind11::finalize_interpreter(); +} + +std::optional +PyRuntime::init() +{ + auto api_status = + create_api_module(m_limit_order_func, m_market_order_func, m_cancel_order_func); + if (!api_status) { + return "[linter] failed to create API module\n"; + } + auto init_status = run_initialization_code(algo_); + if (init_status.has_value()) { + return init_status.value(); + } + + return std::nullopt; +} + +void +PyRuntime::fire_on_trade_update( + common::Ticker ticker, common::Side side, float price, float quantity +) const +{ + py::globals()["strategy"].attr("on_trade_update")( + ticker, side, static_cast(quantity), static_cast(price) + ); +} + +void +PyRuntime::fire_on_orderbook_update( + common::Ticker ticker, common::Side side, float price, float quantity +) const +{ + py::globals()["strategy"].attr("on_orderbook_update")( + ticker, side, static_cast(quantity), static_cast(price) + ); +} + +void +PyRuntime::fire_on_account_update( + common::Ticker ticker, common::Side side, float price, float quantity, + float capital +) const +{ + py::globals()["strategy"].attr("on_account_update")( + ticker, side, static_cast(quantity), static_cast(price), + static_cast(capital) + ); +} + +bool +PyRuntime::create_api_module( + LimitOrderFunction publish_limit_order, MarketOrderFunction publish_market_order, + CancelOrderFunction cancel_order +) +{ + try { + py::module_ sys = py::module_::import("sys"); + // TODO: disable this for testing + py::exec(R"( + import sys + import os + class SuppressOutput(object): + def write(self, txt): + pass + def flush(self): + pass + + sys.stdout = SuppressOutput() + )"); + py::module module = py::module::create_extension_module( + "nutc_api", "NUTC Exchange API", new py::module::module_def + ); + + py::enum_(module, "Side") + .value("BUY", common::Side::buy) + .value("SELL", common::Side::sell) + .export_values(); + py::enum_(module, "Ticker") + .value("ETH", common::Ticker::ETH) + .value("BTC", common::Ticker::BTC) + .value("LTC", common::Ticker::LTC) + .export_values(); + module.def("publish_market_order", publish_market_order); + module.def("publish_limit_order", publish_limit_order); + module.def("cancel_order", cancel_order); + + auto sys_modules = sys.attr("modules").cast(); + sys_modules["nutc_api"] = module; + + py::exec(R"(import nutc_api)"); + } catch (...) { + return false; + } + return true; +} + +std::optional +PyRuntime::run_initialization_code(const std::string& py_code) +{ + py::exec("Side = nutc_api.Side"); + py::exec("Ticker = nutc_api.Ticker"); + + try { + py::exec(py_code); + } catch (const std::exception& e) { + return fmt::format("Failed to import code: {}", e.what()); + } + + py::exec("Side = nutc_api.Side"); + py::exec("Ticker = nutc_api.Ticker"); + py::exec(R"( + def place_market_order(side: Side, ticker: Ticker, quantity: float): + return nutc_api.publish_market_order(side, ticker, quantity) + )"); + py::exec(R"( + def place_limit_order(side: Side, ticker: Ticker, quantity: float, price: float, ioc: bool = False): + return nutc_api.publish_limit_order(side, ticker, quantity, price, ioc) + )"); + py::exec(R"( + def cancel_order(ticker: Ticker, order_id: int): + return nutc_api.cancel_order(ticker, order_id) + )"); + + py::exec("Side = nutc_api.Side"); + py::exec("Ticker = nutc_api.Ticker"); + + try { + py::exec("strategy = Strategy()"); + } catch (const std::exception& e) { + return fmt::format("Failed to run initialization: {}", e.what()); + } + + try { + py::object main_module = py::module_::import("__main__"); + py::dict main_dict = main_module.attr("__dict__"); + py::object on_trade_update = main_dict["strategy"].attr("on_trade_update"); + py::object on_orderbook_update = + main_dict["strategy"].attr("on_orderbook_update"); + py::object on_account_update = main_dict["strategy"].attr("on_account_update"); + } catch (py::error_already_set& e) { + return fmt::format("Failed to import callback functions: {}", e.what()); + } + + return std::nullopt; +} + +} // namespace nutc::lint diff --git a/exchange/src/linter/runtime/python/python_runtime.hpp b/exchange/src/linter/runtime/python/python_runtime.hpp new file mode 100644 index 00000000..4abad44a --- /dev/null +++ b/exchange/src/linter/runtime/python/python_runtime.hpp @@ -0,0 +1,49 @@ +#pragma once + +#include "linter/runtime/runtime.hpp" + +#include + +namespace nutc::lint { + +class PyRuntime : public Runtime { +public: + PyRuntime( + std::string algo, LimitOrderFunction place_limit_order, + MarketOrderFunction place_market_order, CancelOrderFunction cancel_order + ) : + Runtime( + std::move(algo), std::move(place_limit_order), + std::move(place_market_order), std::move(cancel_order) + ) + { + pybind11::initialize_interpreter(); + } + + ~PyRuntime() override; + + std::optional init() override; + + void fire_on_trade_update( + common::Ticker ticker, common::Side side, float price, float quantity + ) const override; + + void fire_on_orderbook_update( + common::Ticker ticker, common::Side side, float price, float quantity + ) const override; + + void fire_on_account_update( + common::Ticker ticker, common::Side side, float price, float quantity, + float capital + ) const override; + +private: + static bool create_api_module( + LimitOrderFunction publish_limit_order, + MarketOrderFunction publish_market_order, CancelOrderFunction cancel_order + ); + static std::optional run_initialization_code(const std::string& py_code + ); +}; + +} // namespace nutc::lint diff --git a/exchange/src/linter/runtime/runtime.hpp b/exchange/src/linter/runtime/runtime.hpp new file mode 100644 index 00000000..1c2df439 --- /dev/null +++ b/exchange/src/linter/runtime/runtime.hpp @@ -0,0 +1,59 @@ +#pragma once + +#include "common/types/ticker.hpp" +#include "common/util.hpp" + +#include + +#include +#include +#include + +namespace nutc::lint { + +using LimitOrderFunction = std::function; +using MarketOrderFunction = + std::function; +using CancelOrderFunction = + std::function; + +class Runtime { +public: + virtual ~Runtime() = default; + + Runtime(const Runtime&) = default; + Runtime(Runtime&&) noexcept = default; + Runtime& operator=(const Runtime&) = default; + Runtime& operator=(Runtime&&) noexcept = default; + + Runtime( + std::string algo, LimitOrderFunction limit_order, + MarketOrderFunction market_order, CancelOrderFunction cancel_order + ) : + algo_(std::move(algo)), m_limit_order_func(std::move(limit_order)), + m_market_order_func(std::move(market_order)), + m_cancel_order_func(std::move(cancel_order)) + {} + + virtual std::optional init() = 0; + virtual void fire_on_trade_update( + common::Ticker ticker, common::Side side, float price, float quantity + ) const = 0; + virtual void fire_on_orderbook_update( + common::Ticker ticker, common::Side side, float price, float quantity + ) const = 0; + virtual void fire_on_account_update( + common::Ticker ticker, common::Side side, float price, float quantity, + float buyer_capital + ) const = 0; + +protected: + std::string algo_; + LimitOrderFunction m_limit_order_func; + MarketOrderFunction m_market_order_func; + CancelOrderFunction m_cancel_order_func; +}; + +} // namespace nutc::lint diff --git a/exchange/src/linter/spawner/main.cpp b/exchange/src/linter/spawner/main.cpp new file mode 100644 index 00000000..5fe04229 --- /dev/null +++ b/exchange/src/linter/spawner/main.cpp @@ -0,0 +1,89 @@ +#include "common/types/decimal.hpp" +#include "common/types/ticker.hpp" +#include "common/util.hpp" +#include "linter/lint/lint.hpp" +#include "linter/lint/lint_result.hpp" +#include "linter/runtime/cpp/cpp_runtime.hpp" +#include "linter/runtime/python/python_runtime.hpp" + +#include +#include +#include +#include +#include + +#include + +#include +#include + +namespace { +bool +mock_limit_func(nutc::common::Side, nutc::common::Ticker, float, float, bool = false) +{ + return true; +} + +bool +mock_market_func(nutc::common::Side, nutc::common::Ticker, float) +{ + return true; +} + +bool +mock_cancel_func(nutc::common::Ticker, std::int64_t) +{ + return true; +} +} // namespace + +void +send_response(const std::string& response) +{ + std::cout << nutc::common::base64_encode(response) << std::endl; +} + +int +main(int argc, char* argv[]) +{ + if (argc < 2) { + send_response("[linter] no language provided"); + return 1; + } + + std::string algo_code_base64; + std::getline(std::cin, algo_code_base64); + + std::string algo_code = nutc::common::base64_decode(algo_code_base64); + + nutc::lint::lint_result lint_result; + std::string flag = argv[1]; + if (flag == "-python") { + nutc::lint::PyRuntime runtime( + algo_code, mock_limit_func, mock_market_func, mock_cancel_func + ); + lint_result = nutc::lint::lint(runtime); + } + else if (flag == "-cpp") { + nutc::lint::CppRuntime runtime( + algo_code, mock_limit_func, mock_market_func, mock_cancel_func + ); + lint_result = nutc::lint::lint(runtime); + } + else { + send_response("[linter] no language provided"); + return 1; + } + + auto output = glz::write_json(lint_result); + if (output) { + send_response(output.value()); + } + else { + send_response(fmt::format( + "[linter] ERROR WRITING LINT RESULT: {}", glz::format_error(output.error()) + )); + } + + return 0; +} diff --git a/linter/src/spawning/spawning.cpp b/exchange/src/linter/spawning/spawning.cpp similarity index 63% rename from linter/src/spawning/spawning.cpp rename to exchange/src/linter/spawning/spawning.cpp index d60e78da..00fd1bd0 100644 --- a/linter/src/spawning/spawning.cpp +++ b/exchange/src/linter/spawning/spawning.cpp @@ -1,6 +1,7 @@ #include "spawning.hpp" -#include "config.h" +#include "common/util.hpp" +#include "linter/config.h" #include #include @@ -13,11 +14,14 @@ namespace spawning { const std::filesystem::path& LintProcessManager::spawner_binary_path() { + static constexpr auto LINTER_SPAWNER_BINARY_ENV_VAR = + "NUTC_LINTER_SPAWNER_BINARY_PATH"; static const char* spawner_binary_location = - std::getenv("NUTC_SPAWNER_BINARY_PATH"); // NOLINT + std::getenv(LINTER_SPAWNER_BINARY_ENV_VAR); // NOLINT if (spawner_binary_location == nullptr) [[unlikely]] { - throw std::runtime_error("NUTC_SPAWNER_BINARY_PATH environment variable not set" - ); + throw std::runtime_error(fmt::format( + "{} environment variable not set", LINTER_SPAWNER_BINARY_ENV_VAR + )); } static const std::filesystem::path spawner_binary_path{spawner_binary_location}; @@ -28,17 +32,29 @@ LintProcessManager::spawner_binary_path() } nutc::lint::lint_result -LintProcessManager::spawn_client(const std::string& algo_code) +LintProcessManager::spawn_client(const std::string& algo_code, AlgoLanguage language) { static const std::string path{spawner_binary_path()}; auto in_pipe = std::make_shared(io_context); bp::opstream out_pipe; + auto get_language_flag = [](AlgoLanguage language) { + switch (language) { + case nutc::spawning::AlgoLanguage::Python: + return "-python"; + case nutc::spawning::AlgoLanguage::Cpp: + return "-cpp"; + default: + throw std::runtime_error("Unknown language"); + } + }; + auto child = std::make_shared( - bp::exe(path), bp::std_in * in_pipe, io_context + bp::exe(path), bp::args(get_language_flag(language)), + bp::std_in stderr, bp::std_out > *in_pipe, io_context ); - out_pipe << algo_code << std::flush; + out_pipe << common::base64_encode(algo_code) << std::endl; out_pipe.pipe().close(); auto kill_timer = std::make_shared(io_context); @@ -51,7 +67,8 @@ LintProcessManager::spawn_client(const std::string& algo_code) in_pipe->close(); res.success = false; res.message += fmt::format( - "[linter] FAILED to lint algo\n\nYour code did not execute within {} " + "[linter] FAILED to lint algo\n\nYour code did not execute within " + "{} " "seconds. Check all " "functions to see if you have an infinite loop or infinite " "recursion.\n\nIf you continue to experience this error, " @@ -67,9 +84,7 @@ LintProcessManager::spawn_client(const std::string& algo_code) auto buffer = std::make_shared(); async_read_until( - *in_pipe, - *buffer, - '\n', + *in_pipe, *buffer, '\n', [buffer, kill_timer, child, in_pipe, &res](const auto& ec, auto) { if (!ec) { kill_timer->cancel(); @@ -84,13 +99,15 @@ LintProcessManager::spawn_client(const std::string& algo_code) if (child->running()) { child->terminate(); } + std::string decoded_message = common::base64_decode(message); - auto error = glz::read_json(res, message); + auto error = + glz::read_json(res, decoded_message); if (error) { res = { - false, - "Internal server error. Reach out to nuft@u.northwesten.edu " - "for support" + false, "Internal server error. Reach out to " + "nuft@u.northwesten.edu " + "for support" }; }; in_pipe->cancel(); diff --git a/linter/src/spawning/spawning.hpp b/exchange/src/linter/spawning/spawning.hpp similarity index 68% rename from linter/src/spawning/spawning.hpp rename to exchange/src/linter/spawning/spawning.hpp index ec4a8d21..90f9104e 100644 --- a/linter/src/spawning/spawning.hpp +++ b/exchange/src/linter/spawning/spawning.hpp @@ -1,6 +1,6 @@ #pragma once -#include "lint/lint_result.hpp" +#include "linter/lint/lint_result.hpp" #include #include @@ -11,12 +11,17 @@ namespace nutc { namespace spawning { +enum class AlgoLanguage { + Python, + Cpp +}; + namespace ba = boost::asio; class LintProcessManager { public: const std::filesystem::path& spawner_binary_path(); - nutc::lint::lint_result spawn_client(const std::string&); + nutc::lint::lint_result spawn_client(const std::string&, AlgoLanguage language); private: ba::io_context io_context{}; diff --git a/exchange/src/wrapper/main.cpp b/exchange/src/wrapper/main.cpp index bf9a861b..28ad881f 100644 --- a/exchange/src/wrapper/main.cpp +++ b/exchange/src/wrapper/main.cpp @@ -3,7 +3,7 @@ #include "wrapper/config/argparse.hpp" #include "wrapper/messaging/exchange_communicator.hpp" #include "wrapper/runtime/cpp/cpp_runtime.hpp" -#include "wrapper/util/logging.hpp" +#include "common/logging/logging.hpp" #include "wrapper/util/resource_limits.hpp" #include diff --git a/exchange/src/wrapper/messaging/exchange_communicator.cpp b/exchange/src/wrapper/messaging/exchange_communicator.cpp index bf2e7bf7..f6adc888 100644 --- a/exchange/src/wrapper/messaging/exchange_communicator.cpp +++ b/exchange/src/wrapper/messaging/exchange_communicator.cpp @@ -35,6 +35,12 @@ ExchangeCommunicator::consume_algorithm() return algorithm; } +common::tick_update +ExchangeCommunicator::consume_tick_update() +{ + return consume_message(); +} + template T ExchangeCommunicator::consume_message() diff --git a/exchange/src/wrapper/messaging/exchange_communicator.hpp b/exchange/src/wrapper/messaging/exchange_communicator.hpp index 9d4e8ba9..a6a1150e 100644 --- a/exchange/src/wrapper/messaging/exchange_communicator.hpp +++ b/exchange/src/wrapper/messaging/exchange_communicator.hpp @@ -32,8 +32,7 @@ class ExchangeCommunicator { algorithm_content consume_algorithm(); - template - T consume_message(); + common::tick_update consume_tick_update(); static void publish_message(const std::string& message); @@ -54,6 +53,10 @@ class ExchangeCommunicator { LimitOrderFunction place_limit_order(); MarketOrderFunction place_market_order(); CancelOrderFunction cancel_order(); + +private: + template + T consume_message(); }; } // namespace nutc::wrapper diff --git a/exchange/src/wrapper/runtime/runtime.cpp b/exchange/src/wrapper/runtime/runtime.cpp index 960d46b4..dec59b09 100644 --- a/exchange/src/wrapper/runtime/runtime.cpp +++ b/exchange/src/wrapper/runtime/runtime.cpp @@ -11,7 +11,7 @@ Runtime::process_message(start_time&) template <> void -Runtime::process_message(tick_update& tick_update) +Runtime::process_message(tick_update&& tick_update) { std::ranges::for_each(tick_update.ob_updates, [&](const position& u) { fire_on_orderbook_update(u.ticker, u.side, u.price, u.quantity); @@ -39,8 +39,7 @@ void Runtime::main_event_loop() { while (true) { - auto data = communicator_.consume_message(); - std::visit([this](auto message) { process_message(message); }, std::move(data)); + process_message(communicator_.consume_tick_update()); } } } // namespace nutc::wrapper diff --git a/exchange/src/wrapper/util/logging.cpp b/exchange/src/wrapper/util/logging.cpp deleted file mode 100644 index c4148bd5..00000000 --- a/exchange/src/wrapper/util/logging.cpp +++ /dev/null @@ -1,95 +0,0 @@ -#include "logging.hpp" - -#include - -#if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__MINGW64__) \ - || defined(QUILL_NO_THREAD_NAME_SUPPORT) -# define LOGLINE_FORMAT \ - "%(ascii_time) [%(thread:<6)] [%(logger_name:<8)] %(level_name:<8) - " \ - "%(message) (%(fileline))" -#else -# define LOGLINE_FORMAT \ - "%(ascii_time) [%(thread_name:<12)] [%(logger_name:<8)] %(level_name:<8) - " \ - "%(message) (%(fileline))" -#endif - -#ifdef _WIN32 -# define TZ_FORMAT "" -#else -# define TZ_FORMAT " %z" -#endif - -namespace nutc { -namespace logging { - -using namespace quill; // NOLINT(*-using-namespace) -using cc = quill::ConsoleColours; - -void -init(quill::LogLevel log_level) -{ - detail::application_log_level = log_level; - -#ifdef _WIN32 - // NOTE: on win32 a signal handler is needed for each new thread - quill::init_signal_handler(); -#endif - - // Create our config object - quill::Config cfg; - - // Set main logger name - cfg.default_logger_name = "main"; - - // - // Initialize print handler - // - quill::ConsoleColours colors; - colors.set_colour(LogLevel::TraceL3, cc::white); - colors.set_colour(LogLevel::TraceL2, cc::white); - colors.set_colour(LogLevel::TraceL1, cc::white); - colors.set_colour(LogLevel::Debug, cc::cyan); - colors.set_colour(LogLevel::Info, cc::green); - -#ifdef _WIN32 - // NOLINTBEGIN(*-signed-bitwise) - colors.set_colour(LogLevel::Warning, cc::yellow | cc::bold); - colors.set_colour(LogLevel::Error, cc::red | cc::bold); - colors.set_colour(LogLevel::Critical, cc::bold | cc::white | cc::on_red); - // NOLINTEND(*-signed-bitwise) -#else - colors.set_colour(LogLevel::Warning, cc::yellow + cc::bold); - colors.set_colour(LogLevel::Error, cc::red + cc::bold); - colors.set_colour(LogLevel::Critical, cc::bold + cc::white + cc::on_red); -#endif - - colors.set_colour(LogLevel::Backtrace, cc::magenta); - - auto stdout_handler = quill::stdout_handler("console", colors); - stdout_handler->set_pattern( - LOGLINE_FORMAT, - "%Y-%m-%dT%T.%Qms" TZ_FORMAT // ISO 8601 but with space instead of T - ); - stdout_handler->set_log_level(log_level); - - cfg.default_handlers.emplace_back(stdout_handler); - - // Send the config - quill::configure(cfg); - - // Set backtrace and log level on the main logger - quill::Logger* main_logger = quill::get_logger(); - main_logger->init_backtrace(LOG_BACKTRACE_SIZE, quill::LogLevel::Error); - main_logger->set_log_level(log_level); - - // Set the thread name - set_thread_name("MainThread"); - - // Start the logging backend thread - quill::start(true); - - LOG_INFO(main_logger, "Logging initialized!"); -} - -} // namespace logging -} // namespace nutc diff --git a/exchange/src/wrapper/util/logging.hpp b/exchange/src/wrapper/util/logging.hpp deleted file mode 100644 index 89f40b8a..00000000 --- a/exchange/src/wrapper/util/logging.hpp +++ /dev/null @@ -1,134 +0,0 @@ -#pragma once - -#include "wrapper/config/config.h" - -#include - -#include - -namespace nutc { -namespace logging { - -#if DEBUG() // Debug mode -static constexpr quill::LogLevel DEFAULT_LOG_LEVEL = quill::LogLevel::Debug; -#else // Release mode -static constexpr quill::LogLevel DEFAULT_LOG_LEVEL = quill::LogLevel::Info; -#endif - -namespace detail { - -// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) -inline quill::LogLevel application_log_level; - -inline quill::Logger* -get_logger(const std::string& name) -{ - quill::Logger* logger = nullptr; - - try { - logger = quill::get_logger(name.c_str()); - } catch (quill::QuillError&) { - logger = quill::create_logger(name); - logger->set_log_level(application_log_level); - logger->init_backtrace(LOG_BACKTRACE_SIZE, quill::LogLevel::Error); - } - - return logger; -} - -} // namespace detail - -/** - * Set our thread name. - */ -inline void -set_thread_name(const std::string& name) -{ - quill::detail::set_thread_name(name.c_str()); -} - -/** - * Set up logging. - */ -void init(quill::LogLevel log_level = DEFAULT_LOG_LEVEL); - -/** - * Set up logging. - */ -inline void -init(uint8_t verbosity = 0) -{ - auto log_level = static_cast(DEFAULT_LOG_LEVEL); - - if (verbosity <= log_level) - log_level -= verbosity; - else // protect from underflow - log_level = 0; - - init(static_cast(log_level)); -} - -/****************************************************************************** - * LOGGERS - *****************************************************************************/ -// NOLINTBEGIN(cppcoreguidelines-avoid-non-const-global-variables) - -inline quill::Logger* -get_main_logger() -{ - // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) - static auto* logger = quill::get_root_logger(); - return logger; -} - -// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define CREATE_LOG_CATEGORY(category) \ - inline quill::Logger* get_##category##_logger() \ - { \ - static auto* logger = detail::get_logger(#category); \ - return logger; \ - } \ - class ____dummy_##category // makes you add a semicolon - -// Create loggers here for every category -CREATE_LOG_CATEGORY(wrapper_init); -CREATE_LOG_CATEGORY(wrapper_py_runtime); -CREATE_LOG_CATEGORY(wrapper_redis); -CREATE_LOG_CATEGORY(wrapper_web); -CREATE_LOG_CATEGORY(wrapper_libcurl); -CREATE_LOG_CATEGORY(wrapper_rabbitmq); - -#undef CREATE_LOG_CATEGORY -// NOLINTEND(cppcoreguidelines-avoid-non-const-global-variables) - -} // namespace logging -} // namespace nutc - -// NOLINTBEGIN -#define log_bt(category, ...) \ - LOG_BACKTRACE(nutc::logging::get_##category##_logger(), __VA_ARGS__) - -#define log_t3(category, ...) \ - LOG_TRACE_L3(nutc::logging::get_##category##_logger(), __VA_ARGS__) - -#define log_t2(category, ...) \ - LOG_TRACE_L2(nutc::logging::get_##category##_logger(), __VA_ARGS__) - -#define log_t1(category, ...) \ - LOG_TRACE_L1(nutc::logging::get_##category##_logger(), __VA_ARGS__) - -#define log_d(category, ...) \ - LOG_DEBUG(nutc::logging::get_##category##_logger(), __VA_ARGS__) - -#define log_i(category, ...) \ - LOG_INFO(nutc::logging::get_##category##_logger(), __VA_ARGS__) - -#define log_w(category, ...) \ - LOG_WARNING(nutc::logging::get_##category##_logger(), __VA_ARGS__) - -#define log_e(category, ...) \ - LOG_ERROR(nutc::logging::get_##category##_logger(), __VA_ARGS__) - -#define log_c(category, ...) \ - LOG_CRITICAL(nutc::logging::get_##category##_logger(), __VA_ARGS__) -// NOLINTEND diff --git a/exchange/template.cpp b/exchange/template.cpp index a9d02fab..ea9f3b22 100644 --- a/exchange/template.cpp +++ b/exchange/template.cpp @@ -5,6 +5,8 @@ // #include "template.hpp" #include +#include +#include using PlaceMarketOrder = std::function; using PlaceLimitOrder = std::function; diff --git a/exchange/test/CMakeLists.txt b/exchange/test/CMakeLists.txt index bc83801e..04ef1f3d 100644 --- a/exchange/test/CMakeLists.txt +++ b/exchange/test/CMakeLists.txt @@ -31,6 +31,8 @@ add_executable(NUTC_tests src/unit/types/decimal.cpp src/integration/tests/basic.cpp + src/integration/tests/linter_py_test.cpp + src/integration/tests/linter_cpp_test.cpp src/integration/tests/cancellation.cpp ) @@ -43,6 +45,7 @@ target_include_directories( target_link_libraries( NUTC_tests PRIVATE EXCHANGE_lib + LINTER_lib COMMON_lib GTest::gtest_main ) diff --git a/exchange/test/src/integration/tests/linter_cpp_test.cpp b/exchange/test/src/integration/tests/linter_cpp_test.cpp new file mode 100644 index 00000000..b046b29a --- /dev/null +++ b/exchange/test/src/integration/tests/linter_cpp_test.cpp @@ -0,0 +1,106 @@ +#include "linter/spawning/spawning.hpp" + +#include + +#include + +class IntegrationLinterCppTest : public ::testing::Test { +protected: + nutc::spawning::LintProcessManager manager; +}; + +const std::string basic_algo = R"(#include +#include +enum class Side { buy = 0, sell = 1 }; +enum class Ticker : std::uint8_t { ETH = 0, BTC = 1, LTC = 2 }; // NOLINT +bool place_market_order(Side side, Ticker ticker, float quantity); +std::int64_t place_limit_order(Side side, Ticker ticker, float quantity, + float price, bool ioc = false); +bool cancel_order(Ticker ticker, std::int64_t order_id); + +class Strategy { +public: + Strategy() { + place_market_order(Side::buy, Ticker::ETH, 1.0); + } + + void on_trade_update(Ticker ticker, Side side, float quantity, float price) {place_limit_order(Side::buy, Ticker::LTC, 1.0, 1.0);} + void on_orderbook_update(Ticker ticker, Side side, float quantity, + float price) {place_market_order(Side::sell, Ticker::BTC, 1.0);} + + void on_account_update(Ticker ticker, Side side, float price, float quantity, + float capital_remaining) {cancel_order(Ticker::BTC, 5);} +}; +)"; + +const std::string syntax_error = R"(#include +#include +enum class Side { buy = 0, sell = 1 }; +enum class Ticker : std::uint8_t { ETH = 0, BTC = 1, LTC = 2 }; // NOLINT +bool place_market_order(Side side, Ticker ticker, float quantity); +std::int64_t place_limit_order(Side side, Ticker ticker, float quantity, + float price, bool ioc = false); +bool cancel_order(Ticker ticker, std::int64_t order_id); + +class Strategy { +public: + Strategy() { + } + + void on_trade_update(Ticker ticker, Side side, float quantity, float price) {} + void on_orderbook_update(Ticker ticker, Side side, float quantity, + float price) { SYNTAX ERROR } + + void on_account_update(Ticker ticker, Side side, float price, float quantity, + float capital_remaining) {} +}; +)"; + +const std::string exception_thrown = R"(#include +#include +#include +enum class Side { buy = 0, sell = 1 }; +enum class Ticker : std::uint8_t { ETH = 0, BTC = 1, LTC = 2 }; // NOLINT +bool place_market_order(Side side, Ticker ticker, float quantity); +std::int64_t place_limit_order(Side side, Ticker ticker, float quantity, + float price, bool ioc = false); +bool cancel_order(Ticker ticker, std::int64_t order_id); + +class Strategy { +public: + Strategy() { + } + + void on_trade_update(Ticker ticker, Side side, float quantity, float price) {} + void on_orderbook_update(Ticker ticker, Side side, float quantity, + float price) { throw std::runtime_error("This is an error"); } + + void on_account_update(Ticker ticker, Side side, float price, float quantity, + float capital_remaining) {} +}; +)"; + +using nutc::spawning::AlgoLanguage; + +TEST_F(IntegrationLinterCppTest, basic) +{ + auto lint_result = manager.spawn_client(basic_algo, AlgoLanguage::Cpp); + std::cout << "first " << lint_result.message << "\n"; + ASSERT_TRUE(lint_result.success); +} + +TEST_F(IntegrationLinterCppTest, SyntaxErrorDetection) +{ + auto lint_result = manager.spawn_client(syntax_error, AlgoLanguage::Cpp); + ASSERT_FALSE(lint_result.success); + EXPECT_TRUE(lint_result.message.contains("‘SYNTAX’ was not declared in this scope") + ); +} + +TEST_F(IntegrationLinterCppTest, RuntimeError) +{ + auto lint_result = manager.spawn_client(exception_thrown, AlgoLanguage::Cpp); + ASSERT_FALSE(lint_result.success); + EXPECT_TRUE(lint_result.message.contains("Failed to run on_orderbook_update")); + EXPECT_TRUE(lint_result.message.contains("This is an error")); +} diff --git a/linter/test/src/NUTC-linter_test.cpp b/exchange/test/src/integration/tests/linter_py_test.cpp similarity index 52% rename from linter/test/src/NUTC-linter_test.cpp rename to exchange/test/src/integration/tests/linter_py_test.cpp index 9defcc93..fea18206 100644 --- a/linter/test/src/NUTC-linter_test.cpp +++ b/exchange/test/src/integration/tests/linter_py_test.cpp @@ -1,8 +1,8 @@ -#include "spawning/spawning.hpp" +#include "linter/spawning/spawning.hpp" #include -class IntegrationLinterTest : public ::testing::Test { +class IntegrationLinterPyTest : public ::testing::Test { protected: nutc::spawning::LintProcessManager manager; }; @@ -11,41 +11,18 @@ const std::string basic_algo = R"(class Strategy: def __init__(self) -> None: pass - def on_trade_update(self, ticker: str, side: str, price: float, quantity: float) -> None: + def on_trade_update(self, ticker: Ticker, side: Side, price: float, quantity: float) -> None: pass def on_orderbook_update( - self, ticker: str, side: str, price: float, quantity: float + self, ticker: Ticker, side: Side, price: float, quantity: float ) -> None: pass def on_account_update( self, - ticker: str, - side: str, - price: float, - quantity: float, - capital_remaining: float, - ) -> None: - pass -)"; - -const std::string incorrect_arguments_algo = R"(class Strategy: - def __init__(self) -> None: - pass - - def on_trade_update(self, ticker: str, side: str, price: float, quantity: float) -> None: - place_limit_order("ETHUSD", "BUY", 5, 5) - - def on_orderbook_update( - self, ticker: str, side: str, price: float, quantity: float - ) -> None: - pass - - def on_account_update( - self, - ticker: str, - side: str, + ticker: Ticker, + side: Side, price: float, quantity: float, capital_remaining: float, @@ -53,23 +30,24 @@ const std::string incorrect_arguments_algo = R"(class Strategy: pass )"; +// TODO: fix/restore const std::string timeout_algo = R"(import time class Strategy: def __init__(self) -> None: time.sleep(20) - def on_trade_update(self, ticker: str, side: str, price: float, quantity: float) -> None: + def on_trade_update(self, ticker: Ticker, side: Side, price: float, quantity: float) -> None: pass def on_orderbook_update( - self, ticker: str, side: str, price: float, quantity: float + self, ticker: Ticker, side: Side, price: float, quantity: float ) -> None: pass def on_account_update( self, - ticker: str, - side: str, + ticker: Ticker, + side: Side, price: float, quantity: float, capital_remaining: float, @@ -81,14 +59,14 @@ const std::string missing_on_trade_update_algo = R"(class Strategy: def __init__(self) -> None: pass def on_orderbook_update( - self, ticker: str, side: str, price: float, quantity: float + self, ticker: Ticker, side: Side, price: float, quantity: float ) -> None: pass def on_account_update( self, - ticker: str, - side: str, + ticker: Ticker, + side: Side, price: float, quantity: float, capital_remaining: float, @@ -100,12 +78,12 @@ const std::string missing_on_orderbook_update_algo = R"(class Strategy: def __init__(self) -> None: pass - def on_trade_update(self, ticker: str, side: str, price: float, quantity: float) -> None: + def on_trade_update(self, ticker: Ticker, side: Side, price: float, quantity: float) -> None: pass def on_account_update( self, - ticker: str, - side: str, + ticker: Ticker, + side: Side, price: float, quantity: float, capital_remaining: float, @@ -117,33 +95,27 @@ const std::string missing_on_account_update_algo = R"(class Strategy: def __init__(self) -> None: pass - def on_trade_update(self, ticker: str, side: str, price: float, quantity: float) -> None: + def on_trade_update(self, ticker: Ticker, side: Side, price: float, quantity: float) -> None: pass def on_orderbook_update( - self, ticker: str, side: str, price: float, quantity: float + self, ticker: Ticker, side: Side, price: float, quantity: float ) -> None: pass )"; -TEST_F(IntegrationLinterTest, basic) +TEST_F(IntegrationLinterPyTest, basic) { - auto lint_result = manager.spawn_client(basic_algo); + auto lint_result = + manager.spawn_client(basic_algo, nutc::spawning::AlgoLanguage::Python); ASSERT_TRUE(lint_result.success); } -TEST_F(IntegrationLinterTest, invalidSideArg) +TEST_F(IntegrationLinterPyTest, timeout) { - auto lint_result = manager.spawn_client(incorrect_arguments_algo); - ASSERT_FALSE(lint_result.success); - ASSERT_TRUE( - lint_result.message.find("Side should be BUY or SELL") - != std::string::npos - ); -} - -TEST_F(IntegrationLinterTest, timeout) -{ - auto lint_result = manager.spawn_client(timeout_algo); + // TODO: complete + return; + auto lint_result = + manager.spawn_client(timeout_algo, nutc::spawning::AlgoLanguage::Python); ASSERT_FALSE(lint_result.success); ASSERT_TRUE( lint_result.message.find("Your code did not execute within") @@ -151,20 +123,20 @@ TEST_F(IntegrationLinterTest, timeout) ); } -TEST_F(IntegrationLinterTest, invalidAlgo) +TEST_F(IntegrationLinterPyTest, invalidAlgo) { std::string algo = R"(not_valid_python)"; - auto lint_result = manager.spawn_client(algo); + auto lint_result = manager.spawn_client(algo, nutc::spawning::AlgoLanguage::Python); ASSERT_FALSE(lint_result.success); ASSERT_TRUE( lint_result.message.find("Failed to import code:") != std::string::npos ); } -TEST_F(IntegrationLinterTest, noStrategyClass) +TEST_F(IntegrationLinterPyTest, noStrategyClass) { std::string algo = R"(import math)"; - auto lint_result = manager.spawn_client(algo); + auto lint_result = manager.spawn_client(algo, nutc::spawning::AlgoLanguage::Python); ASSERT_FALSE(lint_result.success); ASSERT_TRUE( lint_result.message.find("NameError: name 'Strategy' is not defined") @@ -172,23 +144,29 @@ TEST_F(IntegrationLinterTest, noStrategyClass) ); } -TEST_F(IntegrationLinterTest, missingRequiredFunction) +TEST_F(IntegrationLinterPyTest, missingRequiredFunction) { - auto lint_result = manager.spawn_client(missing_on_trade_update_algo); + auto lint_result = manager.spawn_client( + missing_on_trade_update_algo, nutc::spawning::AlgoLanguage::Python + ); ASSERT_FALSE(lint_result.success); ASSERT_TRUE( lint_result.message.find("has no attribute 'on_trade_update'") != std::string::npos ); - lint_result = manager.spawn_client(missing_on_orderbook_update_algo); + lint_result = manager.spawn_client( + missing_on_orderbook_update_algo, nutc::spawning::AlgoLanguage::Python + ); ASSERT_FALSE(lint_result.success); ASSERT_TRUE( lint_result.message.find("has no attribute 'on_orderbook_update'") != std::string::npos ); - lint_result = manager.spawn_client(missing_on_account_update_algo); + lint_result = manager.spawn_client( + missing_on_account_update_algo, nutc::spawning::AlgoLanguage::Python + ); ASSERT_FALSE(lint_result.success); ASSERT_TRUE( lint_result.message.find("has no attribute 'on_account_update'") diff --git a/exchange/test/src/util/helpers/test_cycle.cpp b/exchange/test/src/util/helpers/test_cycle.cpp index bec1c437..ad63b364 100644 --- a/exchange/test/src/util/helpers/test_cycle.cpp +++ b/exchange/test/src/util/helpers/test_cycle.cpp @@ -2,7 +2,7 @@ #include "common/messages_wrapper_to_exchange.hpp" #include "common/util.hpp" -#include "exchange/logging.hpp" +#include "common/logging/logging.hpp" #include #include diff --git a/exchange/test/src/util/process.cpp b/exchange/test/src/util/process.cpp index b1e45d57..50621270 100644 --- a/exchange/test/src/util/process.cpp +++ b/exchange/test/src/util/process.cpp @@ -2,7 +2,7 @@ #include "common/types/decimal.hpp" #include "exchange/algos/dev_mode/dev_mode.hpp" -#include "exchange/logging.hpp" +#include "common/logging/logging.hpp" #include diff --git a/linter/.clang-format b/linter/.clang-format deleted file mode 100644 index 9d31b83f..00000000 --- a/linter/.clang-format +++ /dev/null @@ -1,189 +0,0 @@ ---- -Language: Cpp -AccessModifierOffset: -4 -AlignAfterOpenBracket: BlockIndent -AlignArrayOfStructures: Left -AlignConsecutiveAssignments: None -AlignConsecutiveBitFields: None -AlignConsecutiveDeclarations: None -AlignConsecutiveMacros: AcrossEmptyLines -AlignEscapedNewlines: Right -AlignOperands: Align -AlignTrailingComments: true -AllowAllArgumentsOnNextLine: true -AllowAllParametersOfDeclarationOnNextLine: true -AllowShortBlocksOnASingleLine: Empty -AllowShortCaseLabelsOnASingleLine: false -AllowShortEnumsOnASingleLine: true -AllowShortFunctionsOnASingleLine: Inline -AllowShortIfStatementsOnASingleLine: Never -AllowShortLambdasOnASingleLine: All -AllowShortLoopsOnASingleLine: false -AlwaysBreakAfterReturnType: AllDefinitions -AlwaysBreakBeforeMultilineStrings: false -AlwaysBreakTemplateDeclarations: Yes -AttributeMacros: - - __capability -BasedOnStyle: "LLVM" -BinPackArguments: false -BinPackParameters: false -BitFieldColonSpacing: Both -BraceWrapping: - AfterCaseLabel: false - AfterClass: false - AfterControlStatement: Never - AfterEnum: false - AfterFunction: true - AfterNamespace: false - AfterObjCDeclaration: false - AfterStruct: false - AfterUnion: false - AfterExternBlock: false - BeforeCatch: false - BeforeElse: true - BeforeLambdaBody: false - BeforeWhile: false - IndentBraces: false - SplitEmptyFunction: false - SplitEmptyRecord: true - SplitEmptyNamespace: true -BreakAfterJavaFieldAnnotations: true -BreakBeforeBinaryOperators: NonAssignment -BreakBeforeBraces: Custom -BreakBeforeConceptDeclarations: true -BreakBeforeTernaryOperators: true -BreakConstructorInitializers: AfterColon -BreakInheritanceList: AfterColon -BreakStringLiterals: true -ColumnLimit: 88 -CommentPragmas: "^( IWYU pragma:| NOLINT)" -CompactNamespaces: false -ConstructorInitializerIndentWidth: 4 -ContinuationIndentWidth: 4 -Cpp11BracedListStyle: true -DeriveLineEnding: false -DerivePointerAlignment: false -DisableFormat: false -EmptyLineAfterAccessModifier: Never -EmptyLineBeforeAccessModifier: LogicalBlock -ExperimentalAutoDetectBinPacking: false -FixNamespaceComments: true -ForEachMacros: - - foreach - - Q_FOREACH - - BOOST_FOREACH -IfMacros: - - KJ_IF_MAYBE -IncludeBlocks: Regroup -IncludeCategories: - # Headers in "" with extension. - - Regex: '"([A-Za-z0-9.\Q/-_\E])+"' - Priority: 1 - CaseSensitive: false - # Headers in <> from libraries. - - Regex: "^(<(gsl|catch2))" - Priority: 2 - CaseSensitive: false - # C headers - - Regex: '' - Priority: 4 - CaseSensitive: false - # Headers in <> without extension. - - Regex: '<([A-Za-z0-9\Q/-_\E])+>' - Priority: 5 - CaseSensitive: false - # Headers in <> with extension. - - Regex: '<([A-Za-z0-9.\Q/-_\E])+>' - Priority: 3 - CaseSensitive: false -IncludeIsMainRegex: "(Test)?$" -IncludeIsMainSourceRegex: "" -IndentAccessModifiers: false -IndentCaseLabels: true -IndentCaseBlocks: true -IndentExternBlock: AfterExternBlock -IndentGotoLabels: false -IndentPPDirectives: AfterHash -IndentRequires: false -IndentWidth: 4 -IndentWrappedFunctionNames: false -KeepEmptyLinesAtTheStartOfBlocks: false -LambdaBodyIndentation: Signature -MacroBlockBegin: "" -MacroBlockEnd: "" -MaxEmptyLinesToKeep: 1 -NamespaceIndentation: None -PackConstructorInitializers: NextLine -PenaltyBreakAssignment: 2 -PenaltyBreakBeforeFirstCallParameter: 19 -PenaltyBreakComment: 300 -PenaltyBreakFirstLessLess: 120 -PenaltyBreakOpenParenthesis: 0 -PenaltyBreakString: 1000 -PenaltyBreakTemplateDeclaration: 10 -PenaltyExcessCharacter: 1000000 -PenaltyIndentedWhitespace: 0 -PenaltyReturnTypeOnItsOwnLine: 60 -PointerAlignment: Left -PPIndentWidth: 2 -QualifierAlignment: Leave -ReferenceAlignment: Pointer -ReflowComments: true -RemoveBracesLLVM: false -SeparateDefinitionBlocks: Always -ShortNamespaceLines: 1 -SortIncludes: CaseInsensitive -SortUsingDeclarations: true -SpaceAfterCStyleCast: false -SpaceAfterLogicalNot: false -SpaceAfterTemplateKeyword: true -SpaceAroundPointerQualifiers: Default -SpaceBeforeAssignmentOperators: true -SpaceBeforeCaseColon: false -SpaceBeforeCpp11BracedList: false -SpaceBeforeCtorInitializerColon: true -SpaceBeforeInheritanceColon: true -SpaceBeforeParens: ControlStatementsExceptControlMacros -# Ignored as SpaceBeforeParens != Custom -SpaceBeforeParensOptions: - AfterControlStatements: true - AfterForeachMacros: true - AfterFunctionDefinitionName: false - AfterFunctionDeclarationName: false - AfterIfMacros: true - AfterOverloadedOperator: false - BeforeNonEmptyParentheses: false -SpaceBeforeRangeBasedForLoopColon: true -SpaceBeforeSquareBrackets: false -SpaceInEmptyBlock: false -SpaceInEmptyParentheses: false -SpacesInAngles: Never -SpacesBeforeTrailingComments: 1 -SpacesInConditionalStatement: false -SpacesInContainerLiterals: false -SpacesInCStyleCastParentheses: false -SpacesInLineCommentPrefix: - Minimum: 1 - Maximum: -1 -SpacesInParentheses: false -SpacesInSquareBrackets: false -Standard: Latest -StatementAttributeLikeMacros: - - Q_EMIT -StatementMacros: - - Q_UNUSED - - QT_REQUIRE_VERSION - - wxBEGIN_EVENT_TABLE - - wxEND_EVENT_TABLE - - EVT_MENU -TabWidth: 4 -UseCRLF: false -UseTab: Never -WhitespaceSensitiveMacros: - - STRINGIZE - - PP_STRINGIZE - - BOOST_PP_STRINGIZE - - NS_SWIFT_NAME - - CF_SWIFT_NAME ---- - diff --git a/linter/.clang-tidy b/linter/.clang-tidy deleted file mode 100644 index d9de2cc8..00000000 --- a/linter/.clang-tidy +++ /dev/null @@ -1,134 +0,0 @@ ---- -Checks: "\ - boost-*,\ - bugprone-*,\ - cert-*,\ - clang-analyzer-*,\ - clang-diagnostic-*,\ - concurrency-*,\ - cppcoreguidelines-*,\ - google-*,\ - hicpp-*,\ - llvm-*,\ - misc-*,\ - modernize-*,\ - performance-*,\ - portability-*,\ - readability-*,\ - fuchsia-multiple-inheritance,\ - fuchsia-trailing-return,\ - fuchsia-virtual-inheritance,\ - google-runtime-int,\ - -hicpp-braces-around-statements,\ - -google-readability-braces-around-statements,\ - -llvm-header-guard,\ - -hicpp-no-array-decay,\ - -modernize-concat-nested-namespaces,\ - -cppcoreguidelines-pro-bounds-array-to-pointer-decay,\ - -modernize-use-trailing-return-type,\ - -cppcoreguidelines-owning-memory,\ - -hicpp-named-parameter,\ - -readability-named-parameter,\ - -readability-uppercase-literal-suffix,\ - -readability-implicit-bool-conversion,\ - -hicpp-uppercase-literal-suffix,\ - -misc-use-anonymous-namespace,\ - -bugprone-easily-swappable-parameters,\ - -*-reinterpret-cast,\ - -cppcoreguidelines-avoid-const-or-ref-data-members" -WarningsAsErrors: false -AnalyzeTemporaryDtors: false -FormatStyle: file -HeaderFilterRegex: "(^config.h|.*\\.hpp)$" -CheckOptions: - llvm-else-after-return.WarnOnConditionVariables: "false" - modernize-loop-convert.MinConfidence: reasonable - modernize-replace-auto-ptr.IncludeStyle: llvm - modernize-pass-by-value.IncludeStyle: llvm - google-readability-namespace-comments.ShortNamespaceLines: "10" - google-readability-namespace-comments.SpacesBeforeComments: "2" - cppcoreguidelines-non-private-member-variables-in-classes.IgnoreClassesWithAllMemberVariablesBeingPublic: "true" - readability-braces-around-statements.ShortStatementLines: 3 - cert-err33-c.CheckedFunctions: "::aligned_alloc;::asctime_s;::at_quick_exit;::atexit;::bsearch;::bsearch_s;::btowc;::c16rtomb;::c32rtomb;::calloc;::clock;::cnd_broadcast;::cnd_init;::cnd_signal;::cnd_timedwait;::cnd_wait;::ctime_s;::fclose;::fflush;::fgetc;::fgetpos;::fgets;::fgetwc;::fopen;::fopen_s;::fprintf;::fprintf_s;::fputc;::fputs;::fputwc;::fputws;::fread;::freopen;::freopen_s;::fscanf;::fscanf_s;::fseek;::fsetpos;::ftell;::fwprintf;::fwprintf_s;::fwrite;::fwscanf;::fwscanf_s;::getc;::getchar;::getenv;::getenv_s;::gets_s;::getwc;::getwchar;::gmtime;::gmtime_s;::localtime;::localtime_s;::malloc;::mbrtoc16;::mbrtoc32;::mbsrtowcs;::mbsrtowcs_s;::mbstowcs;::mbstowcs_s;::memchr;::mktime;::mtx_init;::mtx_lock;::mtx_timedlock;::mtx_trylock;::mtx_unlock;::printf_s;::putc;::putwc;::raise;::realloc;::remove;::rename;::scanf;::scanf_s;::setlocale;::setvbuf;::signal;::snprintf;::snprintf_s;::sprintf;::sprintf_s;::sscanf;::sscanf_s;::strchr;::strerror_s;::strftime;::strpbrk;::strrchr;::strstr;::strtod;::strtof;::strtoimax;::strtok;::strtok_s;::strtol;::strtold;::strtoll;::strtoul;::strtoull;::strtoumax;::strxfrm;::swprintf;::swprintf_s;::swscanf;::swscanf_s;::thrd_create;::thrd_detach;::thrd_join;::thrd_sleep;::time;::timespec_get;::tmpfile;::tmpfile_s;::tmpnam;::tmpnam_s;::tss_create;::tss_get;::tss_set;::ungetc;::ungetwc;::vfprintf;::vfprintf_s;::vfscanf;::vfscanf_s;::vfwprintf;::vfwprintf_s;::vfwscanf;::vfwscanf_s;::vprintf_s;::vscanf;::vscanf_s;::vsnprintf;::vsnprintf_s;::vsprintf;::vsprintf_s;::vsscanf;::vsscanf_s;::vswprintf;::vswprintf_s;::vswscanf;::vswscanf_s;::vwprintf_s;::vwscanf;::vwscanf_s;::wcrtomb;::wcschr;::wcsftime;::wcspbrk;::wcsrchr;::wcsrtombs;::wcsrtombs_s;::wcsstr;::wcstod;::wcstof;::wcstoimax;::wcstok;::wcstok_s;::wcstol;::wcstold;::wcstoll;::wcstombs;::wcstombs_s;::wcstoul;::wcstoull;::wcstoumax;::wcsxfrm;::wctob;::wctrans;::wctype;::wmemchr;::wprintf_s;::wscanf;::wscanf_s;" - modernize-loop-convert.MaxCopySize: "16" - cert-dcl16-c.NewSuffixes: "L;LL;LU;LLU" - cert-oop54-cpp.WarnOnlyIfThisHasSuspiciousField: "false" - cert-str34-c.DiagnoseSignedUnsignedCharComparisons: "false" - modernize-use-nullptr.NullMacros: "NULL" - llvm-qualified-auto.AddConstToQualified: "false" - modernize-loop-convert.NamingStyle: CamelCase - llvm-else-after-return.WarnOnUnfixable: "false" - google-readability-function-size.StatementThreshold: "800" - bugprone-argument-comment.StrictMode: "true" - # Prefer using enum classes with 2 values for parameters instead of bools - bugprone-argument-comment.CommentBoolLiterals: "true" - bugprone-misplaced-widening-cast.CheckImplicitCasts: "true" - bugprone-sizeof-expression.WarnOnSizeOfIntegerExpression: "true" - bugprone-suspicious-string-compare.WarnOnLogicalNotComparison: "true" - readability-simplify-boolean-expr.ChainedConditionalReturn: "true" - readability-simplify-boolean-expr.ChainedConditionalAssignment: "true" - readability-uniqueptr-delete-release.PreferResetCall: "true" - readability-function-cognitive-complexity.IgnoreMacros: "true" - cppcoreguidelines-init-variables.MathHeader: "" - cppcoreguidelines-narrowing-conversions.PedanticMode: "true" - readability-else-after-return.WarnOnUnfixable: "true" - readability-else-after-return.WarnOnConditionVariables: "true" - readability-inconsistent-declaration-parameter-name.Strict: "true" - readability-qualified-auto.AddConstToQualified: "true" - readability-redundant-access-specifiers.CheckFirstDeclaration: "true" - readability-identifier-naming.AbstractClassCase: "CamelCase" - readability-identifier-naming.ClassCase: "CamelCase" - readability-identifier-naming.ClassConstantCase: "lower_case" - readability-identifier-naming.ClassMemberCase: "lower_case" - readability-identifier-naming.ClassMethodCase: "lower_case" - readability-identifier-naming.ConstantCase: "UPPER_CASE" - readability-identifier-naming.ConstantMemberCase: "UPPER_CASE" - readability-identifier-naming.ConstantParameterCase: "lower_case" - readability-identifier-naming.ConstantPointerParameterCase: "lower_case" - readability-identifier-naming.ConstexprFunctionCase: "lower_case" - readability-identifier-naming.ConstexprMethodCase: "lower_case" - readability-identifier-naming.ConstexprVariableCase: "UPPER_CASE" - readability-identifier-naming.EnumCase: "CamelCase" - readability-identifier-naming.EnumConstantCase: "UPPER_CASE" - readability-identifier-naming.FunctionCase: "lower_case" - readability-identifier-naming.GlobalConstantCase: "UPPER_CASE" - readability-identifier-naming.GlobalConstantPointerCase: "UPPER_CASE" - readability-identifier-naming.GlobalFunctionCase: "lower_case" - readability-identifier-naming.GlobalPointerCase: "lower_case" - readability-identifier-naming.GlobalVariableCase: "lower_case" - readability-identifier-naming.InlineNamespaceCase: "lower_case" - readability-identifier-naming.LocalConstantCase: "lower_case" - readability-identifier-naming.LocalConstantPointerCase: "lower_case" - readability-identifier-naming.LocalPointerCase: "lower_case" - readability-identifier-naming.LocalVariableCase: "lower_case" - readability-identifier-naming.MacroDefinitionCase: "UPPER_CASE" - readability-identifier-naming.MemberCase: "lower_case" - readability-identifier-naming.MethodCase: "lower_case" - readability-identifier-naming.NamespaceCase: "lower_case" - readability-identifier-naming.ParameterCase: "lower_case" - readability-identifier-naming.ParameterPackCase: "lower_case" - readability-identifier-naming.PointerParameterCase: "lower_case" - readability-identifier-naming.PrivateMemberCase: "lower_case" - readability-identifier-naming.PrivateMemberSuffix: "_" - readability-identifier-naming.PrivateMethodCase: "lower_case" - readability-identifier-naming.PrivateMethodSuffix: "_" - readability-identifier-naming.ProtectedMemberCase: "lower_case" - readability-identifier-naming.ProtectedMemberSuffix: "_" - readability-identifier-naming.ProtectedMethodCase: "lower_case" - readability-identifier-naming.ProtectedMethodSuffix: "_" - readability-identifier-naming.PublicMemberCase: "lower_case" - readability-identifier-naming.PublicMethodCase: "lower_case" - readability-identifier-naming.ScopedEnumConstantCase: "lower_case" - readability-identifier-naming.StaticConstantCase: "lower_case" - readability-identifier-naming.StaticVariableCase: "lower_case" - readability-identifier-naming.StructCase: "lower_case" - readability-identifier-naming.TemplateParameterCase: "CamelCase" - readability-identifier-naming.TemplateTemplateParameterCase: "CamelCase" - readability-identifier-naming.TypeAliasCase: "lower_case" - readability-identifier-naming.TypedefCase: "lower_case" - readability-identifier-naming.TypeTemplateParameterCase: "CamelCase" - readability-identifier-naming.UnionCase: "lower_case" - readability-identifier-naming.ValueTemplateParameterCase: "CamelCase" - readability-identifier-naming.VariableCase: "lower_case" - readability-identifier-naming.VirtualMethodCase: "lower_case" ---- diff --git a/linter/.clangd b/linter/.clangd deleted file mode 100644 index fd829e02..00000000 --- a/linter/.clangd +++ /dev/null @@ -1,2 +0,0 @@ -CompileFlags: - CompilationDatabase: "build/dev" diff --git a/linter/.codespellignore b/linter/.codespellignore deleted file mode 100644 index 0e50ea7c..00000000 --- a/linter/.codespellignore +++ /dev/null @@ -1 +0,0 @@ -ws diff --git a/linter/.codespellrc b/linter/.codespellrc deleted file mode 100644 index b8dc9cee..00000000 --- a/linter/.codespellrc +++ /dev/null @@ -1,8 +0,0 @@ -[codespell] -builtin = clear,rare,en-GB_to_en-US,names,informal,code -check-filenames = -check-hidden = -skip = */.git,*/build,*/prefix,*/conan,*/logs,*/3rd-party -quiet-level = 2 -ignore-words = .codespellignore -ignore-words-list = ba diff --git a/linter/.dockerignore b/linter/.dockerignore deleted file mode 100644 index dcdfa5c1..00000000 --- a/linter/.dockerignore +++ /dev/null @@ -1,12 +0,0 @@ -.idea/ -.vs/ -.vscode/ -build/ -cmake-build-*/ -conan/ -prefix/ -**/.DS_Store -CMakeLists.txt.user -CMakeUserPresets.json -logs/ -compile_commands.json diff --git a/linter/.gitignore b/linter/.gitignore deleted file mode 100644 index 03f75c6a..00000000 --- a/linter/.gitignore +++ /dev/null @@ -1,13 +0,0 @@ -.idea/ -conan-profile.sh -.vs/ -.vscode/ -build/ -cmake-build-*/ -conan/ -prefix/ -**/.DS_Store -CMakeLists.txt.user -CMakeUserPresets.json -logs/ -compile_commands.json diff --git a/linter/BUILDING-DEPRECATED.md b/linter/BUILDING-DEPRECATED.md deleted file mode 100644 index f9f9de61..00000000 --- a/linter/BUILDING-DEPRECATED.md +++ /dev/null @@ -1,64 +0,0 @@ -# Building with CMake - -## Dependencies - -For a list of dependencies, please refer to [conanfile.py](conanfile.py). - -## Build - -This project doesn't require any special command-line flags to build to keep -things simple. - -Here are the steps for building in release mode with a single-configuration -generator, like the Unix Makefiles one: - -```sh -cmake -S . -B build -D CMAKE_BUILD_TYPE=Release -cmake --build build -``` - -Here are the steps for building in release mode with a multi-configuration -generator, like the Visual Studio ones: - -```sh -cmake -S . -B build -cmake --build build --config Release -``` - -### Building with MSVC - -Note that MSVC by default is not standards compliant and you need to pass some -flags to make it behave properly. See the `flags-windows` preset in the -[CMakePresets.json](CMakePresets.json) file for the flags and with what -variable to provide them to CMake during configuration. - -### Building on Apple Silicon - -CMake supports building on Apple Silicon properly since 3.20.1. Make sure you -have the [latest version][1] installed. - -## Install - -This project doesn't require any special command-line flags to install to keep -things simple. As a prerequisite, the project has to be built with the above -commands already. - -The below commands require at least CMake 3.15 to run, because that is the -version in which [Install a Project][2] was added. - -Here is the command for installing the release mode artifacts with a -single-configuration generator, like the Unix Makefiles one: - -```sh -cmake --install build -``` - -Here is the command for installing the release mode artifacts with a -multi-configuration generator, like the Visual Studio ones: - -```sh -cmake --install build --config Release -``` - -[1]: https://cmake.org/download/ -[2]: https://cmake.org/cmake/help/latest/manual/cmake.1.html#install-a-project diff --git a/linter/CMakeLists.txt b/linter/CMakeLists.txt deleted file mode 100644 index ed2f06b1..00000000 --- a/linter/CMakeLists.txt +++ /dev/null @@ -1,148 +0,0 @@ -cmake_minimum_required(VERSION 3.14) - -include(FetchContent) -include(cmake/prelude.cmake) - -project( - NUTC-linter - VERSION 0.1.0 - DESCRIPTION "Linter for the Northwestern University Trading Competition." - HOMEPAGE_URL "https://example.com/" - LANGUAGES CXX -) - -include(cmake/project-is-top-level.cmake) -include(cmake/variables.cmake) - -configure_file(src/config.h.in config.h) - -# ---- Load Dependencies ---- - -# Conan -find_package(fmt REQUIRED) # String formatting -find_package(quill REQUIRED) # Logging - -find_package(argparse REQUIRED) # Argument parsing -find_package(CURL REQUIRED) -find_package(glaze REQUIRED) -find_package(Python3 3.12 COMPONENTS Interpreter Development EXACT REQUIRED) -find_package(pybind11 REQUIRED) -find_package(Crow REQUIRED) -find_package(Boost REQUIRED) - -option(LOCAL_DEV "Enable local dev endpoints" OFF) - -if(LOCAL_DEV) - add_definitions(-DNUTC_LOCAL_DEV) -endif() - - -# ---- Declare library ---- - -add_library( - NUTC-linter_lib OBJECT - src/firebase/fetching.cpp - src/pywrapper/runtime.cpp - src/spawning/spawning.cpp - src/crow/crow.cpp - # Utils - src/logging.cpp -) - -add_library( - NUTC-linter-spawner_lib OBJECT - src/lint/lint.cpp - src/pywrapper/runtime.cpp -) - -# --- Main executable libs ---- - -target_include_directories( - NUTC-linter_lib ${warning_guard} - PUBLIC - "$" - "$" -) - -target_compile_features(NUTC-linter_lib PUBLIC cxx_std_20) - -target_link_libraries(NUTC-linter_lib PUBLIC fmt::fmt) -target_link_libraries(NUTC-linter_lib PUBLIC quill::quill) -target_link_libraries(NUTC-linter_lib PUBLIC CURL::libcurl) -target_link_libraries(NUTC-linter_lib PUBLIC glaze::glaze) -target_link_libraries(NUTC-linter_lib PUBLIC pybind11::pybind11) -target_link_libraries(NUTC-linter_lib PUBLIC Crow::Crow) -target_link_libraries(NUTC-linter_lib PUBLIC Python3::Python) -target_link_libraries(NUTC-linter_lib PUBLIC argparse::argparse) -target_link_libraries(NUTC-linter_lib PUBLIC boost::boost) - -# ---- The other executable's libs ---- - -target_include_directories( - NUTC-linter-spawner_lib ${warning_guard} - PUBLIC - "$" - "$" -) - -target_link_libraries(NUTC-linter-spawner_lib PRIVATE quill::quill) -target_link_libraries(NUTC-linter-spawner_lib PRIVATE glaze::glaze) -target_link_libraries(NUTC-linter-spawner_lib PRIVATE pybind11::pybind11) -target_link_libraries(NUTC-linter-spawner_lib PRIVATE Python3::Python) -target_link_libraries(NUTC-linter-spawner_lib PRIVATE CURL::libcurl) -target_link_libraries(NUTC-linter-spawner_lib PRIVATE boost::boost) - -# ---- Declare main executable ---- - -add_executable(NUTC-linter_exe src/main.cpp) -add_executable(NUTC-linter::exe ALIAS NUTC-linter_exe) - -set_property(TARGET NUTC-linter_exe PROPERTY OUTPUT_NAME NUTC-linter) - -target_compile_features(NUTC-linter_exe PRIVATE cxx_std_20) - -target_link_libraries(NUTC-linter_exe PRIVATE NUTC-linter_lib) -target_link_libraries(NUTC-linter_exe PRIVATE fmt::fmt) -target_link_libraries(NUTC-linter_exe PRIVATE quill::quill) - -target_link_libraries(NUTC-linter_exe PRIVATE argparse::argparse) -target_link_libraries(NUTC-linter_exe PRIVATE CURL::libcurl) -target_link_libraries(NUTC-linter_exe PRIVATE glaze::glaze) -target_link_libraries(NUTC-linter_exe PRIVATE pybind11::pybind11) -target_link_libraries(NUTC-linter_exe PRIVATE Crow::Crow) -target_link_libraries(NUTC-linter_exe PRIVATE Python3::Python) - -# ---- Declare secondary (process spawning) executable ---- - -add_executable(NUTC-linter-spawner_exe src/spawner/main.cpp) -add_executable(NUTC-linter-spawner::exe ALIAS NUTC-linter-spawner_exe) - -set_property(TARGET NUTC-linter-spawner_exe PROPERTY OUTPUT_NAME NUTC-linter-spawner) - -target_compile_features(NUTC-linter-spawner_exe PRIVATE cxx_std_20) - -target_link_libraries(NUTC-linter-spawner_exe PRIVATE NUTC-linter-spawner_lib) -target_link_libraries(NUTC-linter-spawner_exe PRIVATE CURL::libcurl) -target_link_libraries(NUTC-linter-spawner_exe PRIVATE pybind11::pybind11) -target_link_libraries(NUTC-linter-spawner_exe PRIVATE quill::quill) -target_link_libraries(NUTC-linter-spawner_exe PRIVATE glaze::glaze) -target_link_libraries(NUTC-linter-spawner_exe PRIVATE Python3::Python) - -# ---- Install rules ---- - -if(NOT CMAKE_SKIP_INSTALL_RULES) - include(cmake/install-rules.cmake) -endif() - -# ---- Developer mode ---- - -if(NOT NUTC-linter_DEVELOPER_MODE) - return() -elseif(NOT PROJECT_IS_TOP_LEVEL) - message( - AUTHOR_WARNING - "Developer mode is intended for developers of NUTC-linter" - ) -endif() - -include(cmake/dev-mode.cmake) diff --git a/linter/CMakePresets.json b/linter/CMakePresets.json deleted file mode 100644 index e233b804..00000000 --- a/linter/CMakePresets.json +++ /dev/null @@ -1,199 +0,0 @@ -{ - "version": 2, - "cmakeMinimumRequired": { - "major": 3, - "minor": 14, - "patch": 0 - }, - "configurePresets": [ - { - "name": "cmake-pedantic", - "hidden": true, - "warnings": { - "dev": true, - "deprecated": true, - "uninitialized": true, - "unusedCli": true, - "systemVars": false - }, - "errors": { - "dev": false, - "deprecated": true - } - }, - { - "name": "dev-mode", - "hidden": true, - "inherits": "cmake-pedantic", - "cacheVariables": { - "NUTC-linter_DEVELOPER_MODE": "ON" - } - }, - { - "name": "conan", - "hidden": true, - "cacheVariables": { - "CMAKE_TOOLCHAIN_FILE": "${sourceDir}/conan/conan_toolchain.cmake", - "CMAKE_POLICY_DEFAULT_CMP0091": "NEW" - } - }, - { - "name": "cppcheck", - "hidden": true, - "cacheVariables": { - "CMAKE_CXX_CPPCHECK": "cppcheck;--inline-suppr;--platform=native" - } - }, - { - "name": "clang-tidy", - "hidden": true, - "cacheVariables": { - "CMAKE_CXX_CLANG_TIDY": "clang-tidy;--header-filter=^${sourceDir}/" - } - }, - { - "name": "ci-std", - "description": "This preset makes sure the project actually builds with at least the specified standard", - "hidden": true, - "cacheVariables": { - "CMAKE_CXX_EXTENSIONS": "OFF", - "CMAKE_CXX_STANDARD": "20", - "CMAKE_CXX_STANDARD_REQUIRED": "ON" - } - }, - { - "name": "flags-linux", - "hidden": true, - "cacheVariables": { - "CMAKE_CXX_FLAGS": "-D_FORTIFY_SOURCE=3 -fstack-protector-strong -fstack-clash-protection -Wall -Wextra -Wpedantic -Wconversion -Wsign-conversion -Wcast-qual -Wformat=2 -Wundef -Werror=float-equal -Wshadow -Wcast-align -Wunused -Wnull-dereference -Wdouble-promotion -Wimplicit-fallthrough -Wextra-semi -Woverloaded-virtual -Wnon-virtual-dtor -Wold-style-cast", - "CMAKE_EXE_LINKER_FLAGS": "-Wl,--allow-shlib-undefined,--as-needed,-z,noexecstack,-z,relro,-z,now", - "CMAKE_SHARED_LINKER_FLAGS": "-Wl,--allow-shlib-undefined,--as-needed,-z,noexecstack,-z,relro,-z,now" - } - }, - { - "name": "flags-darwin", - "hidden": true, - "cacheVariables": { - "CMAKE_CXX_FLAGS": "-fstack-protector-strong -Wall -Wextra -Wpedantic -Wconversion -Wsign-conversion -Wcast-qual -Wformat=2 -Wundef -Werror=float-equal -Wshadow -Wcast-align -Wunused -Wnull-dereference -Wdouble-promotion -Wimplicit-fallthrough -Wextra-semi -Woverloaded-virtual -Wnon-virtual-dtor -Wold-style-cast" - } - }, - { - "name": "flags-windows", - "description": "Note that all the flags after /W4 are required for MSVC to conform to the language standard", - "hidden": true, - "cacheVariables": { - "CMAKE_CXX_FLAGS": "/sdl /analyze /analyze:external- /guard:cf /utf-8 /diagnostics:caret /w14165 /w44242 /w44254 /w44263 /w34265 /w34287 /w44296 /w44365 /w44388 /w44464 /w14545 /w14546 /w14547 /w14549 /w14555 /w34619 /w34640 /w24826 /w14905 /w14906 /w14928 /w45038 /W4 /permissive- /volatile:iso /Zc:inline /Zc:preprocessor /Zc:lambda /Zc:__cplusplus /Zc:externConstexpr /Zc:throwingNew /EHsc", - "CMAKE_EXE_LINKER_FLAGS": "/machine:x64 /guard:cf" - } - }, - { - "name": "flags-windows-mingw", - "hidden": true, - "cacheVariables": { - "CMAKE_CXX_FLAGS": "-D_FORTIFY_SOURCE=3 -fstack-protector-strong -Wall -Wextra -Wpedantic -Wconversion -Wsign-conversion -Wcast-qual -Wformat=2 -Wundef -Werror=float-equal -Wshadow -Wcast-align -Wunused -Wnull-dereference -Wdouble-promotion -Wimplicit-fallthrough -Wextra-semi -Woverloaded-virtual -Wnon-virtual-dtor -Wold-style-cast", - "CMAKE_EXE_LINKER_FLAGS": "-Wl,--allow-shlib-undefined,--as-needed", - "CMAKE_SHARED_LINKER_FLAGS": "-Wl,--allow-shlib-undefined,--as-needed" - } - }, - { - "name": "ci-linux", - "generator": "Unix Makefiles", - "hidden": true, - "inherits": ["flags-linux", "ci-std"], - "cacheVariables": { - "CMAKE_BUILD_TYPE": "Release" - } - }, - { - "name": "ci-darwin", - "generator": "Unix Makefiles", - "hidden": true, - "inherits": ["flags-darwin", "ci-std"], - "cacheVariables": { - "CMAKE_BUILD_TYPE": "Release" - } - }, - { - "name": "ci-win64", - "inherits": ["flags-windows", "ci-std"], - "generator": "Visual Studio 17 2022", - "architecture": "x64", - "hidden": true - }, - { - "name": "ci-win64-mingw", - "inherits": ["flags-windows-mingw", "ci-std"], - "generator": "Ninja", - "hidden": true - }, - { - "name": "coverage-linux", - "binaryDir": "${sourceDir}/build/coverage", - "inherits": "ci-linux", - "hidden": true, - "cacheVariables": { - "ENABLE_COVERAGE": "ON", - "CMAKE_BUILD_TYPE": "Coverage", - "CMAKE_CXX_FLAGS_COVERAGE": "-Og -g --coverage -fkeep-inline-functions -fkeep-static-functions", - "CMAKE_EXE_LINKER_FLAGS_COVERAGE": "--coverage", - "CMAKE_SHARED_LINKER_FLAGS_COVERAGE": "--coverage", - "CMAKE_MAP_IMPORTED_CONFIG_COVERAGE": "Coverage;RelWithDebInfo;Release;Debug;" - } - }, - { - "name": "ci-coverage", - "inherits": ["coverage-linux", "dev-mode", "conan"], - "cacheVariables": { - "COVERAGE_HTML_COMMAND": "" - } - }, - { - "name": "ci-sanitize", - "binaryDir": "${sourceDir}/build/sanitize", - "inherits": ["ci-linux", "dev-mode", "conan"], - "cacheVariables": { - "CMAKE_BUILD_TYPE": "Sanitize", - "CMAKE_CXX_FLAGS_SANITIZE": "-O2 -g -fsanitize=address,undefined -fno-omit-frame-pointer -fno-common", - "CMAKE_MAP_IMPORTED_CONFIG_SANITIZE": "Sanitize;RelWithDebInfo;Release;Debug;" - } - }, - { - "name": "ci-build", - "binaryDir": "${sourceDir}/build", - "hidden": true - }, - { - "name": "ci-macos", - "inherits": ["ci-build", "ci-darwin", "dev-mode", "conan"] - }, - { - "name": "ci-ubuntu", - "inherits": [ - "ci-build", - "ci-linux", - "clang-tidy", - "conan", - "cppcheck", - "dev-mode" - ] - }, - { - "name": "ci-windows", - "inherits": ["ci-build", "ci-win64", "dev-mode", "conan"] - }, - { - "name": "ci-docker", - "inherits": ["ci-build", "ci-linux", "conan"] - }, - { - "name": "ci-sanitize-darwin", - "binaryDir": "${sourceDir}/build/sanitize", - "inherits": ["ci-darwin", "dev-mode", "conan"], - "cacheVariables": { - "CMAKE_BUILD_TYPE": "Sanitize", - "CMAKE_CXX_FLAGS_SANITIZE": "-O2 -g -fsanitize=address,undefined -fno-omit-frame-pointer -fno-common", - "CMAKE_MAP_IMPORTED_CONFIG_SANITIZE": "Sanitize;RelWithDebInfo;Release;Debug;" - } - } - ] -} diff --git a/linter/CODE_OF_CONDUCT.md b/linter/CODE_OF_CONDUCT.md deleted file mode 100644 index d1202311..00000000 --- a/linter/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,5 +0,0 @@ -# Code of Conduct - -* You will be judged by your contributions first, and your sense of humor - second. -* Nobody owes you anything. diff --git a/linter/CONTRIBUTING.md b/linter/CONTRIBUTING.md deleted file mode 100644 index 10cccf38..00000000 --- a/linter/CONTRIBUTING.md +++ /dev/null @@ -1,19 +0,0 @@ -# Contributing - - - -## Code of Conduct - -Please see the [`CODE_OF_CONDUCT.md`](CODE_OF_CONDUCT.md) document. - -## Getting started - -Helpful notes for developers can be found in the [`HACKING.md`](HACKING.md) -document. - -In addition to he above, if you use the presets file as instructed, then you -should NOT check it into source control, just as the CMake documentation -suggests. diff --git a/linter/HACKING.md b/linter/HACKING.md deleted file mode 100644 index af9b1a1e..00000000 --- a/linter/HACKING.md +++ /dev/null @@ -1,156 +0,0 @@ -# Hacking - -Here is some wisdom to help you build and test this project as a developer and -potential contributor. - -If you plan to contribute, please read the [CONTRIBUTING](CONTRIBUTING.md) -guide. - -## Developer mode - -Build system targets that are only useful for developers of this project are -hidden if the `NUTC-client_DEVELOPER_MODE` option is disabled. Enabling this -option makes tests and other developer targets and options available. Not -enabling this option means that you are a consumer of this project and thus you -have no need for these targets and options. - -Developer mode is always set to on in CI workflows. - -### Presets - -This project makes use of [presets][1] to simplify the process of configuring -the project. As a developer, you are recommended to always have the [latest -CMake version][2] installed to make use of the latest Quality-of-Life -additions. - -You have a few options to pass `NUTC-client_DEVELOPER_MODE` to the configure -command, but this project prefers to use presets. - -As a developer, you should create a `CMakeUserPresets.json` file at the root of -the project: - -```json -{ - "version": 2, - "cmakeMinimumRequired": { - "major": 3, - "minor": 14, - "patch": 0 - }, - "configurePresets": [ - { - "name": "dev", - "binaryDir": "${sourceDir}/build/dev", - "inherits": ["dev-mode", "conan", "ci-"], - "cacheVariables": { - "CMAKE_BUILD_TYPE": "Debug" - } - } - ], - "buildPresets": [ - { - "name": "dev", - "configurePreset": "dev", - "configuration": "Debug" - } - ], - "testPresets": [ - { - "name": "dev", - "configurePreset": "dev", - "configuration": "Debug", - "output": { - "outputOnFailure": true - } - } - ] -} -``` - -You should replace `` in your newly created presets file with the name of -the operating system you have, which may be `win64`, `linux` or `darwin`. You -can see what these correspond to in the -[`CMakePresets.json`](CMakePresets.json) file. - -`CMakeUserPresets.json` is also the perfect place in which you can put all -sorts of things that you would otherwise want to pass to the configure command -in the terminal. - -### Dependency manager - -The above preset will make use of the [conan][conan] dependency manager. After -installing it, make sure you have a [Conan profile][profile] setup, then -download the dependencies and generate the necessary CMake files by running -this command in the project root: - -```sh -conan install . -s build_type=Debug -b missing -``` - -Note that if your conan profile does not specify the same compiler, standard -level, build type and runtime library as CMake, then that could potentially -cause issues. See the link above for profiles documentation. - -[conan]: https://conan.io/ -[profile]: https://docs.conan.io/2/reference/config_files/profiles.html - -### Configure, build and test - -If you followed the above instructions, then you can configure, build and test -the project respectively with the following commands from the project root on -any operating system with any build system: - -```sh -cmake --preset=dev -cmake --build --preset=dev -ctest --preset=dev -``` - -If you are using a compatible editor (e.g. VSCode) or IDE (e.g. CLion, VS), you -will also be able to select the above created user presets for automatic -integration. - -Please note that both the build and test commands accept a `-j` flag to specify -the number of jobs to use, which should ideally be specified to the number of -threads your CPU has. You may also want to add that to your preset using the -`jobs` property, see the [presets documentation][1] for more details. - -### Developer mode targets - -These are targets you may invoke using the build command from above, with an -additional `-t ` flag: - -#### `coverage` - -Available if `ENABLE_COVERAGE` is enabled. This target processes the output of -the previously run tests when built with coverage configuration. The commands -this target runs can be found in the `COVERAGE_TRACE_COMMAND` and -`COVERAGE_HTML_COMMAND` cache variables. The trace command produces an info -file by default, which can be submitted to services with CI integration. The -HTML command uses the trace command's output to generate an HTML document to -`/coverage_html` by default. - -#### `docs` - -Available if `BUILD_MCSS_DOCS` is enabled. Builds to documentation using -Doxygen and m.css. The output will go to `/docs` by default -(customizable using `DOXYGEN_OUTPUT_DIRECTORY`). - -#### `format-check` and `format-fix` - -These targets run the clang-format tool on the codebase to check errors and to -fix them respectively. Customization available using the `FORMAT_PATTERNS` and -`FORMAT_COMMAND` cache variables. - -#### `run-exe` - -Runs the executable target `NUTC-client_exe`. - -#### `spell-check` and `spell-fix` - -These targets run the codespell tool on the codebase to check errors and to fix -them respectively. Customization available using the `SPELL_COMMAND` cache -variable. - -[1]: https://cmake.org/cmake/help/latest/manual/cmake-presets.7.html -[2]: https://cmake.org/download/ diff --git a/linter/LinterDockerfile b/linter/LinterDockerfile deleted file mode 100644 index 9f0f9119..00000000 --- a/linter/LinterDockerfile +++ /dev/null @@ -1,43 +0,0 @@ -#build stage -FROM python:3.12 as build - -RUN pip install conan numpy pandas polars scipy scikit-learn sortedcontainers lightgbm\ - # c++ stuff - && apt update \ - && apt install -y --no-install-recommends build-essential libssl-dev cmake git - -WORKDIR /app/linter -COPY ./linter/conanfile.py /app/linter/conanfile.py -COPY ./.github/scripts/conan-profile.sh /app/linter - -RUN cat conan-profile.sh | bash \ - && conan install . -b missing - -COPY ./linter/src /app/linter/src -COPY ./linter/CMakeLists.txt /app/linter -COPY ./linter/CMakePresets.json /app/linter -COPY ./linter/cmake /app/linter/cmake -COPY ./linter/test /app/linter/test - -ARG firebase_emulator=false - -RUN if [ "$firebase_emulator" = "false" ]; then \ - cmake --preset=ci-docker; \ - else \ - cmake --preset=ci-docker -DLOCAL_DEV=ON; \ - fi - -RUN cmake --build build --config Release -j6 - -ENV NUTC_SPAWNER_BINARY_PATH="/bin/NUTC-linter-spawner" - -RUN mv /app/linter/build/NUTC-linter-spawner /bin/NUTC-linter-spawner -RUN mv /app/linter/build/NUTC-linter /bin/NUTC-linter - -RUN chmod +x /bin/NUTC-linter -RUN chmod +x /bin/NUTC-linter-spawner - -EXPOSE 18081 - - -CMD NUTC-linter diff --git a/linter/README.md b/linter/README.md deleted file mode 100644 index 31e4f1bb..00000000 --- a/linter/README.md +++ /dev/null @@ -1,19 +0,0 @@ -# NUTC-linter - -This is the NUTC-linter project. - -# Building and installing - -See the [BUILDING](BUILDING.md) document. - -# Contributing - -See the [CONTRIBUTING](CONTRIBUTING.md) document. - -# Licensing - - diff --git a/linter/Taskfile.yml b/linter/Taskfile.yml deleted file mode 100644 index 8694a5b7..00000000 --- a/linter/Taskfile.yml +++ /dev/null @@ -1,91 +0,0 @@ -version: '3' - -vars: - NAME: NUTC-linter - - RELEASE_BUILD: "false" - RELEASE_PRESET: "ci-ubuntu" - -tasks: - start-nix: - cmds: - - | - if [ -z "${IN_NIX_SHELL}" ]; then - nix-shell {{.TASKFILE_DIR}}/../config/shell.nix - else - echo "Already in a nix-shell." - fi - - deps: - dir: '{{.USER_WORKING_DIR}}' - vars: - BUILD_TYPE: '{{if eq .RELEASE_BUILD "true"}}Release{{else}}Debug{{end}}' - cmds: - - conan install . -s build_type={{.BUILD_TYPE}} -b missing -pr cpp20 -pr:b cpp20 - - fmt: - dir: '{{.USER_WORKING_DIR}}' - cmds: - - cmake -D FIX=YES -P cmake/lint.cmake - - cmake -D FIX=YES -P cmake/spell.cmake - - init: - dir: '{{.USER_WORKING_DIR}}' - vars: - PRESET: '{{if eq .RELEASE_BUILD "true"}}{{.RELEASE_PRESET}}{{else}}dev{{end}}' - preconditions: - - test -f CMakeUserPresets.json - cmds: - - cmake --preset={{.PRESET}} - - build: - dir: '{{.USER_WORKING_DIR}}' - vars: - CMAKE_SUFFIX: '{{if eq .RELEASE_BUILD "true"}}build --config Release{{else}}--preset=dev{{end}}' - preconditions: - - test -f CMakeUserPresets.json - cmds: - - cmake --build {{.CMAKE_SUFFIX}} -j - - run: - env: - NUTC_SPAWNER_BINARY_PATH: '{{if eq .RELEASE_BUILD "true"}}./build/NUTC-linter-spawner{{else}}./build/dev/NUTC-linter-spawner{{end}}' - vars: - LINTER_PATH: '{{if eq .RELEASE_BUILD "true"}}build/{{.NAME}}{{else}}build/dev/{{.NAME}}{{end}}' - cmds: - - task: built - - ./{{ .LINTER_PATH }} - - run-v: - env: - SPDLOG_LEVEL: trace - cmds: - - task: run - - test: - env: - NUTC_SPAWNER_BINARY_PATH: '../NUTC-linter-spawner' - - dir: '{{if eq .RELEASE_BUILD "true"}}./build{{else}}.{{end}}' - vars: - DEV_TEST_FLAGS: '--preset=dev' - RELEASE_TEST_FLAGS: '--output-on-failure --no-tests=error -C Release' - TEST_FLAGS: '{{if eq .RELEASE_BUILD "true"}}{{.RELEASE_TEST_FLAGS}}{{else}}{{.DEV_TEST_FLAGS}}{{end}}' - cmds: - - task: build - - ctest {{.TEST_FLAGS}} - - docs: - dir: '{{.USER_WORKING_DIR}}' - cmds: - - cmake --build --preset=dev -t docs - - cmake --build --preset=dev -t docs-serve - - clean: - dir: '{{.USER_WORKING_DIR}}' - cmds: - - cmake --build --preset=dev -t clean - - default: - cmds: - - task: run diff --git a/linter/cmake/coverage.cmake b/linter/cmake/coverage.cmake deleted file mode 100644 index c89cc161..00000000 --- a/linter/cmake/coverage.cmake +++ /dev/null @@ -1,33 +0,0 @@ -# ---- Variables ---- - -# We use variables separate from what CTest uses, because those have -# customization issues -set( - COVERAGE_TRACE_COMMAND - lcov -c -q - -o "${PROJECT_BINARY_DIR}/coverage.info" - -d "${PROJECT_BINARY_DIR}" - --include "${PROJECT_SOURCE_DIR}/*" - CACHE STRING - "; separated command to generate a trace for the 'coverage' target" -) - -set( - COVERAGE_HTML_COMMAND - genhtml --legend -f -q - "${PROJECT_BINARY_DIR}/coverage.info" - -p "${PROJECT_SOURCE_DIR}" - -o "${PROJECT_BINARY_DIR}/coverage_html" - CACHE STRING - "; separated command to generate an HTML report for the 'coverage' target" -) - -# ---- Coverage target ---- - -add_custom_target( - coverage - COMMAND ${COVERAGE_TRACE_COMMAND} - COMMAND ${COVERAGE_HTML_COMMAND} - COMMENT "Generating coverage report" - VERBATIM -) diff --git a/linter/cmake/dev-mode.cmake b/linter/cmake/dev-mode.cmake deleted file mode 100644 index ca6dd1c6..00000000 --- a/linter/cmake/dev-mode.cmake +++ /dev/null @@ -1,28 +0,0 @@ -include(cmake/folders.cmake) - -include(CTest) -if(BUILD_TESTING) - add_subdirectory(test) -endif() - -add_custom_target( - run-exe - COMMAND NUTC-linter_exe - VERBATIM -) -add_dependencies(run-exe NUTC-linter_exe) - -option(BUILD_MCSS_DOCS "Build documentation using Doxygen and m.css" OFF) -if(BUILD_MCSS_DOCS) - include(cmake/docs.cmake) -endif() - -option(ENABLE_COVERAGE "Enable coverage support separate from CTest's" OFF) -if(ENABLE_COVERAGE) - include(cmake/coverage.cmake) -endif() - -include(cmake/lint-targets.cmake) -include(cmake/spell-targets.cmake) - -add_folders(Project) diff --git a/linter/cmake/docs-ci.cmake b/linter/cmake/docs-ci.cmake deleted file mode 100644 index ae7f0c73..00000000 --- a/linter/cmake/docs-ci.cmake +++ /dev/null @@ -1,112 +0,0 @@ -cmake_minimum_required(VERSION 3.14) - -foreach(var IN ITEMS PROJECT_BINARY_DIR PROJECT_SOURCE_DIR) - if(NOT DEFINED "${var}") - message(FATAL_ERROR "${var} must be defined") - endif() -endforeach() -set(bin "${PROJECT_BINARY_DIR}") -set(src "${PROJECT_SOURCE_DIR}") - -# ---- Dependencies ---- - -set(mcss_SOURCE_DIR "${bin}/docs/.ci") -if(NOT IS_DIRECTORY "${mcss_SOURCE_DIR}") - file(MAKE_DIRECTORY "${mcss_SOURCE_DIR}") - file( - DOWNLOAD - https://github.com/friendlyanon/m.css/releases/download/release-1/mcss.zip - "${mcss_SOURCE_DIR}/mcss.zip" - STATUS status - EXPECTED_MD5 00cd2757ebafb9bcba7f5d399b3bec7f - ) - if(NOT status MATCHES "^0;") - message(FATAL_ERROR "Download failed with ${status}") - endif() - execute_process( - COMMAND "${CMAKE_COMMAND}" -E tar xf mcss.zip - WORKING_DIRECTORY "${mcss_SOURCE_DIR}" - RESULT_VARIABLE result - ) - if(NOT result EQUAL "0") - message(FATAL_ERROR "Extraction failed with ${result}") - endif() - file(REMOVE "${mcss_SOURCE_DIR}/mcss.zip") -endif() - -find_program(Python3_EXECUTABLE NAMES python3 python) -if(NOT Python3_EXECUTABLE) - message(FATAL_ERROR "Python executable was not found") -endif() - -# ---- Process project() call in CMakeLists.txt ---- - -file(READ "${src}/CMakeLists.txt" content) - -string(FIND "${content}" "project(" index) -if(index EQUAL "-1") - message(FATAL_ERROR "Could not find \"project(\"") -endif() -string(SUBSTRING "${content}" "${index}" -1 content) - -string(FIND "${content}" "\n)\n" index) -if(index EQUAL "-1") - message(FATAL_ERROR "Could not find \"\\n)\\n\"") -endif() -string(SUBSTRING "${content}" 0 "${index}" content) - -file(WRITE "${bin}/docs-ci.project.cmake" "docs_${content}\n)\n") - -macro(list_pop_front list out) - list(GET "${list}" 0 "${out}") - list(REMOVE_AT "${list}" 0) -endmacro() - -function(docs_project name) - cmake_parse_arguments(PARSE_ARGV 1 "" "" "VERSION;DESCRIPTION;HOMEPAGE_URL" LANGUAGES) - set(PROJECT_NAME "${name}" PARENT_SCOPE) - if(DEFINED _VERSION) - set(PROJECT_VERSION "${_VERSION}" PARENT_SCOPE) - string(REGEX MATCH "^[0-9]+(\\.[0-9]+)*" versions "${_VERSION}") - string(REPLACE . ";" versions "${versions}") - set(suffixes MAJOR MINOR PATCH TWEAK) - while(NOT versions STREQUAL "" AND NOT suffixes STREQUAL "") - list_pop_front(versions version) - list_pop_front(suffixes suffix) - set("PROJECT_VERSION_${suffix}" "${version}" PARENT_SCOPE) - endwhile() - endif() - if(DEFINED _DESCRIPTION) - set(PROJECT_DESCRIPTION "${_DESCRIPTION}" PARENT_SCOPE) - endif() - if(DEFINED _HOMEPAGE_URL) - set(PROJECT_HOMEPAGE_URL "${_HOMEPAGE_URL}" PARENT_SCOPE) - endif() -endfunction() - -include("${bin}/docs-ci.project.cmake") - -# ---- Generate docs ---- - -if(NOT DEFINED DOXYGEN_OUTPUT_DIRECTORY) - set(DOXYGEN_OUTPUT_DIRECTORY "${bin}/docs") -endif() -set(out "${DOXYGEN_OUTPUT_DIRECTORY}") - -foreach(file IN ITEMS Doxyfile conf.py) - configure_file("${src}/docs/${file}.in" "${bin}/docs/${file}" @ONLY) -endforeach() - -set(mcss_script "${mcss_SOURCE_DIR}/documentation/doxygen.py") -set(config "${bin}/docs/conf.py") - -file(REMOVE_RECURSE "${out}/html" "${out}/xml") - -execute_process( - COMMAND "${Python3_EXECUTABLE}" "${mcss_script}" "${config}" - WORKING_DIRECTORY "${bin}/docs" - RESULT_VARIABLE result -) -if(NOT result EQUAL "0") - message(FATAL_ERROR "m.css returned with ${result}") -endif() diff --git a/linter/cmake/docs.cmake b/linter/cmake/docs.cmake deleted file mode 100644 index c6cdda6a..00000000 --- a/linter/cmake/docs.cmake +++ /dev/null @@ -1,46 +0,0 @@ -# ---- Dependencies ---- - -set(extract_timestamps "") -if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.24") - set(extract_timestamps DOWNLOAD_EXTRACT_TIMESTAMP YES) -endif() - -include(FetchContent) -FetchContent_Declare( - mcss URL - https://github.com/friendlyanon/m.css/releases/download/release-1/mcss.zip - URL_MD5 00cd2757ebafb9bcba7f5d399b3bec7f - SOURCE_DIR "${PROJECT_BINARY_DIR}/mcss" - UPDATE_DISCONNECTED YES - ${extract_timestamps} -) -FetchContent_MakeAvailable(mcss) - -find_package(Python3 3.6 REQUIRED) - -# ---- Declare documentation target ---- - -set( - DOXYGEN_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/docs" - CACHE PATH "Path for the generated Doxygen documentation" -) - -set(working_dir "${PROJECT_BINARY_DIR}/docs") - -foreach(file IN ITEMS Doxyfile conf.py) - configure_file("docs/${file}.in" "${working_dir}/${file}" @ONLY) -endforeach() - -set(mcss_script "${mcss_SOURCE_DIR}/documentation/doxygen.py") -set(config "${working_dir}/conf.py") - -add_custom_target( - docs - COMMAND "${CMAKE_COMMAND}" -E remove_directory - "${DOXYGEN_OUTPUT_DIRECTORY}/html" - "${DOXYGEN_OUTPUT_DIRECTORY}/xml" - COMMAND "${Python3_EXECUTABLE}" "${mcss_script}" "${config}" - COMMENT "Building documentation using Doxygen and m.css" - WORKING_DIRECTORY "${working_dir}" - VERBATIM -) diff --git a/linter/cmake/folders.cmake b/linter/cmake/folders.cmake deleted file mode 100644 index da7bd33a..00000000 --- a/linter/cmake/folders.cmake +++ /dev/null @@ -1,21 +0,0 @@ -set_property(GLOBAL PROPERTY USE_FOLDERS YES) - -# Call this function at the end of a directory scope to assign a folder to -# targets created in that directory. Utility targets will be assigned to the -# UtilityTargets folder, otherwise to the ${name}Targets folder. If a target -# already has a folder assigned, then that target will be skipped. -function(add_folders name) - get_property(targets DIRECTORY PROPERTY BUILDSYSTEM_TARGETS) - foreach(target IN LISTS targets) - get_property(folder TARGET "${target}" PROPERTY FOLDER) - if(DEFINED folder) - continue() - endif() - set(folder Utility) - get_property(type TARGET "${target}" PROPERTY TYPE) - if(NOT type STREQUAL "UTILITY") - set(folder "${name}") - endif() - set_property(TARGET "${target}" PROPERTY FOLDER "${folder}Targets") - endforeach() -endfunction() diff --git a/linter/cmake/install-rules.cmake b/linter/cmake/install-rules.cmake deleted file mode 100644 index 025c4539..00000000 --- a/linter/cmake/install-rules.cmake +++ /dev/null @@ -1,8 +0,0 @@ -install( - TARGETS NUTC-linter_exe - RUNTIME COMPONENT NUTC-linter_Runtime -) - -if(PROJECT_IS_TOP_LEVEL) - include(CPack) -endif() diff --git a/linter/cmake/lint-targets.cmake b/linter/cmake/lint-targets.cmake deleted file mode 100644 index 1a8d405b..00000000 --- a/linter/cmake/lint-targets.cmake +++ /dev/null @@ -1,33 +0,0 @@ -set( - FORMAT_PATTERNS - src/*.cpp src/*.hpp - include/*.hpp - test/*.cpp test/*.hpp - CACHE STRING - "; separated patterns relative to the project source dir to format" -) - -set(FORMAT_COMMAND clang-format CACHE STRING "Formatter to use") - -add_custom_target( - format-check - COMMAND "${CMAKE_COMMAND}" - -D "FORMAT_COMMAND=${FORMAT_COMMAND}" - -D "PATTERNS=${FORMAT_PATTERNS}" - -P "${PROJECT_SOURCE_DIR}/cmake/lint.cmake" - WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}" - COMMENT "Linting the code" - VERBATIM -) - -add_custom_target( - format-fix - COMMAND "${CMAKE_COMMAND}" - -D "FORMAT_COMMAND=${FORMAT_COMMAND}" - -D "PATTERNS=${FORMAT_PATTERNS}" - -D FIX=YES - -P "${PROJECT_SOURCE_DIR}/cmake/lint.cmake" - WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}" - COMMENT "Fixing the code" - VERBATIM -) diff --git a/linter/cmake/lint.cmake b/linter/cmake/lint.cmake deleted file mode 100644 index 7660278e..00000000 --- a/linter/cmake/lint.cmake +++ /dev/null @@ -1,51 +0,0 @@ -cmake_minimum_required(VERSION 3.14) - -macro(default name) - if(NOT DEFINED "${name}") - set("${name}" "${ARGN}") - endif() -endmacro() - -default(FORMAT_COMMAND clang-format) -default( - PATTERNS - src/*.cpp src/*.hpp - include/*.hpp - test/*.cpp test/*.hpp -) -default(FIX NO) - -set(flag --output-replacements-xml) -set(args OUTPUT_VARIABLE output) -if(FIX) - set(flag -i) - set(args "") -endif() - -file(GLOB_RECURSE files ${PATTERNS}) -set(badly_formatted "") -set(output "") -string(LENGTH "${CMAKE_SOURCE_DIR}/" path_prefix_length) - -foreach(file IN LISTS files) -execute_process( - COMMAND "${FORMAT_COMMAND}" --style=file "${flag}" "${file}" - WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" - RESULT_VARIABLE result - ${args} - ) - if(NOT result EQUAL "0") - message(FATAL_ERROR "'${file}': formatter returned with ${result}") - endif() - if(NOT FIX AND output MATCHES "incomplete_format='true'") - string(SUBSTRING "${file}" "${path_prefix_length}" -1 relative_file) - list(APPEND badly_formatted "${relative_file}") - endif() - set(output "") -endforeach() - -if(NOT badly_formatted STREQUAL "") - list(JOIN badly_formatted "\n" bad_list) - message("The following files are badly formatted:\n\n${bad_list}\n") - message(FATAL_ERROR "Run again with FIX=YES to fix these files.") -endif() diff --git a/linter/cmake/prelude.cmake b/linter/cmake/prelude.cmake deleted file mode 100644 index c37d590e..00000000 --- a/linter/cmake/prelude.cmake +++ /dev/null @@ -1,10 +0,0 @@ -# ---- In-source guard ---- - -if(CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR) - message( - FATAL_ERROR - "In-source builds are not supported. " - "Please read the BUILDING document before trying to build this project. " - "You may need to delete 'CMakeCache.txt' and 'CMakeFiles/' first." - ) -endif() diff --git a/linter/cmake/project-is-top-level.cmake b/linter/cmake/project-is-top-level.cmake deleted file mode 100644 index 3435fc0e..00000000 --- a/linter/cmake/project-is-top-level.cmake +++ /dev/null @@ -1,6 +0,0 @@ -# This variable is set by project() in CMake 3.21+ -string( - COMPARE EQUAL - "${CMAKE_SOURCE_DIR}" "${PROJECT_SOURCE_DIR}" - PROJECT_IS_TOP_LEVEL -) diff --git a/linter/cmake/spell-targets.cmake b/linter/cmake/spell-targets.cmake deleted file mode 100644 index 0c21cab7..00000000 --- a/linter/cmake/spell-targets.cmake +++ /dev/null @@ -1,22 +0,0 @@ -set(SPELL_COMMAND codespell CACHE STRING "Spell checker to use") - -add_custom_target( - spell-check - COMMAND "${CMAKE_COMMAND}" - -D "SPELL_COMMAND=${SPELL_COMMAND}" - -P "${PROJECT_SOURCE_DIR}/cmake/spell.cmake" - WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}" - COMMENT "Checking spelling" - VERBATIM -) - -add_custom_target( - spell-fix - COMMAND "${CMAKE_COMMAND}" - -D "SPELL_COMMAND=${SPELL_COMMAND}" - -D FIX=YES - -P "${PROJECT_SOURCE_DIR}/cmake/spell.cmake" - WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}" - COMMENT "Fixing spelling errors" - VERBATIM -) diff --git a/linter/cmake/spell.cmake b/linter/cmake/spell.cmake deleted file mode 100644 index e05ecd73..00000000 --- a/linter/cmake/spell.cmake +++ /dev/null @@ -1,29 +0,0 @@ -cmake_minimum_required(VERSION 3.14) - -macro(default name) - if(NOT DEFINED "${name}") - set("${name}" "${ARGN}") - endif() -endmacro() - -default(SPELL_COMMAND codespell) -default(FIX NO) - -set(flag "") -if(FIX) - set(flag -w) -endif() - -execute_process( - COMMAND "${SPELL_COMMAND}" ${flag} - WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" - RESULT_VARIABLE result -) - -if(result EQUAL "65") - message(FATAL_ERROR "Run again with FIX=YES to fix these errors.") -elseif(result EQUAL "64") - message(FATAL_ERROR "Spell checker printed the usage info. Bad arguments?") -elseif(NOT result EQUAL "0") - message(FATAL_ERROR "Spell checker returned with ${result}") -endif() diff --git a/linter/cmake/variables.cmake b/linter/cmake/variables.cmake deleted file mode 100644 index 4db59098..00000000 --- a/linter/cmake/variables.cmake +++ /dev/null @@ -1,29 +0,0 @@ -# ---- Developer mode ---- - -# Developer mode enables targets and code paths in the CMake scripts that are -# only relevant for the developer(s) of NUTC-linter -# Targets necessary to build the project must be provided unconditionally, so -# consumers can trivially build and package the project -if(PROJECT_IS_TOP_LEVEL) - option(NUTC-linter_DEVELOPER_MODE "Enable developer mode" OFF) -endif() - - -# ---- Warning guard ---- - -# target_include_directories with the SYSTEM modifier will request the compiler -# to omit warnings from the provided paths, if the compiler supports that -# This is to provide a user experience similar to find_package when -# add_subdirectory or FetchContent is used to consume this project -set(warning_guard "") -if(NOT PROJECT_IS_TOP_LEVEL) - option( - NUTC-linter_INCLUDES_WITH_SYSTEM - "Use SYSTEM modifier for NUTC-linter's includes, disabling warnings" - ON - ) - mark_as_advanced(NUTC-linter_INCLUDES_WITH_SYSTEM) - if(NUTC-linter_INCLUDES_WITH_SYSTEM) - set(warning_guard SYSTEM) - endif() -endif() diff --git a/linter/conanfile.py b/linter/conanfile.py deleted file mode 100644 index 87dc6f3a..00000000 --- a/linter/conanfile.py +++ /dev/null @@ -1,27 +0,0 @@ -from conan import ConanFile - - -class Recipe(ConanFile): - settings = "os", "compiler", "build_type", "arch" - generators = "CMakeToolchain", "CMakeDeps", "VirtualRunEnv" - - def layout(self): - self.folders.generators = "conan" - - def requirements(self): - self.requires("zlib/1.3", override=True) - self.requires("fmt/10.2.1") - self.requires("quill/3.7.0") # logging - self.requires("libcurl/8.6.0") - self.requires("glaze/2.4.0") - self.requires("pybind11/2.12.0") - self.requires("boost/1.83.0") - - self.requires("argparse/3.0") - self.requires("crowcpp-crow/1.1.0") - - def configure(self): - self.options["boost"].without_test = True - - def build_requirements(self): - self.test_requires("gtest/1.13.0") diff --git a/linter/docs/Doxyfile.in b/linter/docs/Doxyfile.in deleted file mode 100644 index bcdedad4..00000000 --- a/linter/docs/Doxyfile.in +++ /dev/null @@ -1,32 +0,0 @@ -# Configuration for Doxygen for use with CMake -# Only options that deviate from the default are included -# To create a new Doxyfile containing all available options, call `doxygen -g` - -# Get Project name and version from CMake -PROJECT_NAME = "@PROJECT_NAME@" -PROJECT_NUMBER = "@PROJECT_VERSION@" - -# Add sources -INPUT = "@PROJECT_SOURCE_DIR@/README.md" "@PROJECT_SOURCE_DIR@/include" "@PROJECT_SOURCE_DIR@/src" "@PROJECT_SOURCE_DIR@/docs/pages" -EXTRACT_ALL = YES -RECURSIVE = YES -OUTPUT_DIRECTORY = "@DOXYGEN_OUTPUT_DIRECTORY@" - -# Use the README as a main page -USE_MDFILE_AS_MAINPAGE = "@PROJECT_SOURCE_DIR@/README.md" - -# set relative include paths -FULL_PATH_NAMES = YES -STRIP_FROM_PATH = "@PROJECT_SOURCE_DIR@/include" "@PROJECT_SOURCE_DIR@" -STRIP_FROM_INC_PATH = - -# We use m.css to generate the html documentation, so we only need XML output -GENERATE_XML = YES -GENERATE_HTML = NO -GENERATE_LATEX = NO -XML_PROGRAMLISTING = NO -CREATE_SUBDIRS = NO - -# Include all directories, files and namespaces in the documentation -# Disable to include only explicitly documented objects -M_SHOW_UNDOCUMENTED = YES diff --git a/linter/docs/conf.py.in b/linter/docs/conf.py.in deleted file mode 100644 index b81e3d92..00000000 --- a/linter/docs/conf.py.in +++ /dev/null @@ -1,6 +0,0 @@ -DOXYFILE = 'Doxyfile' - -LINKS_NAVBAR1 = [ - (None, 'pages', [(None, 'about')]), - (None, 'namespaces', []), -] diff --git a/linter/docs/pages/about.dox b/linter/docs/pages/about.dox deleted file mode 100644 index 2efbda93..00000000 --- a/linter/docs/pages/about.dox +++ /dev/null @@ -1,7 +0,0 @@ -/** - * @page about About - * @section about-doxygen Doxygen documentation - * This page is auto generated using - * Doxygen, making use of some useful - * special commands. - */ diff --git a/linter/resources/cpp20 b/linter/resources/cpp20 deleted file mode 100644 index 8c7d8566..00000000 --- a/linter/resources/cpp20 +++ /dev/null @@ -1,7 +0,0 @@ -[settings] -os=Linux -arch=x86_64 -compiler=gcc -compiler.version=12.2 -compiler.libcxx=libstdc++11 -build_type=Release diff --git a/linter/src/firebase/fetching.cpp b/linter/src/firebase/fetching.cpp deleted file mode 100644 index 013b9ab7..00000000 --- a/linter/src/firebase/fetching.cpp +++ /dev/null @@ -1,236 +0,0 @@ -#include "fetching.hpp" - -#include "config.h" - -#include -#include - -#include -#include - -namespace nutc { -namespace client { - -static std::string -get_firebase_endpoint(const std::string& params) -{ -#ifdef NUTC_LOCAL_DEV - return FIREBASE_URL + params + "?ns=nutc-web-default-rtdb"; -#else - return FIREBASE_URL + params; -#endif -} - -void -set_lint_result(const std::string& uid, const std::string& algo_id, bool succeeded) -{ - std::string success = "\"success\""; - std::string failure = "\"failure\""; - std::string params = - fmt::format("users/{}/algos/{}/lintResults.json", uid, algo_id); - - firebase_request( - "PUT", get_firebase_endpoint(params), succeeded ? success : failure - ); -} - -std::string -replaceDisallowedValues(const std::string& input) -{ - std::regex newlinePattern("\\n"); - std::string input2 = std::regex_replace(input, newlinePattern, "\\n"); - std::regex disallowedPattern("[.$#\\[\\]]"); - - return std::regex_replace(input2, disallowedPattern, ""); -} - -void -set_lint_success( - const std::string& uid, const std::string& algo_id, const std::string& success -) -{ - std::string json_success = "\"" + replaceDisallowedValues(success) + "\""; - std::string params1 = - fmt::format("users/{}/algos/{}/lintSuccessMessage.json", uid, algo_id); - std::string params2 = fmt::format("users/{}/latestAlgoId.json", uid); - - firebase_request("PUT", get_firebase_endpoint(params1), json_success); - - firebase_request("PUT", get_firebase_endpoint(params2), "\"" + algo_id + "\""); - set_lint_result(uid, algo_id, true); -} - -void -set_lint_failure( - const std::string& uid, const std::string& algo_id, const std::string& failure -) -{ - std::string json_failure = "\"" + replaceDisallowedValues(failure) + "\""; - std::string params = - fmt::format("users/{}/algos/{}/lintFailureMessage.json", uid, algo_id); - firebase_request("PUT", get_firebase_endpoint(params), json_failure); - set_lint_result(uid, algo_id, false); -} - -std::optional -get_user_info(const std::string& uid) -{ - std::string url = fmt::format("users/{}.json", uid); - return firebase_request("GET", get_firebase_endpoint(url)); -} - -static size_t -write_callback(void* contents, size_t size, size_t nmemb, void* userp) -{ - auto* str = reinterpret_cast(userp); - auto* data = static_cast(contents); - - str->append(data, size * nmemb); - return size * nmemb; -} - -std::optional -storage_request(const std::string& firebase_url) -{ - std::string readBuffer; - - CURL* curl = curl_easy_init(); - if (curl) { - CURLcode res = curl_easy_setopt(curl, CURLOPT_URL, firebase_url.c_str()); - if (res != CURLE_OK) { - return std::nullopt; - } - res = curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); - if (res != CURLE_OK) { - return std::nullopt; - } - res = curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer); - if (res != CURLE_OK) { - return std::nullopt; - } - - res = curl_easy_perform(curl); - if (res != CURLE_OK) { - return std::nullopt; - } - curl_easy_cleanup(curl); - } - - return readBuffer; -} - -std::optional -get_algo(const std::string& uid, const std::string& algo_id) -{ - auto maybe_user_info = get_user_info(uid); - if (!maybe_user_info.has_value()) { - return std::nullopt; - } - auto user_info = maybe_user_info.value(); - // if not has "algos" - if (!user_info.contains("algos") || !user_info["algos"].contains(algo_id)) { - return std::nullopt; - } - glz::json_t algo_info = user_info["algos"][algo_id]; - std::string downloadURL = algo_info["downloadURL"].get(); - auto algo_file = storage_request(downloadURL); - return algo_file; -} - -nutc::client::LintingResultOption -get_algo_status(const std::string& uid, const std::string& algo_id) -{ - auto maybe_user_info = get_user_info(uid); - if (!maybe_user_info.has_value()) { - return nutc::client::LintingResultOption::UNKNOWN; - } - auto user_info = maybe_user_info.value(); - // if not has "algos" - if (!user_info.contains("algos")) { - return nutc::client::LintingResultOption::UNKNOWN; - } - - // check if algo id exists - if (!user_info["algos"].contains(algo_id)) { - return nutc::client::LintingResultOption::UNKNOWN; - } - glz::json_t algo_info = user_info["algos"][algo_id]; - - // check if this algo id has lint results - if (!algo_info.contains("lintResults")) { - return nutc::client::LintingResultOption::UNKNOWN; - } - - std::string linting_result = algo_info["lintResults"].get(); - - switch (linting_result[0]) { - case 'f': - return nutc::client::LintingResultOption::FAILURE; - case 's': - return nutc::client::LintingResultOption::SUCCESS; - default: - return nutc::client::LintingResultOption::PENDING; - } -} - -std::optional -firebase_request( - const std::string& method, const std::string& url, const std::string& data -) -{ - std::string readBuffer; - - CURL* curl = curl_easy_init(); - if (curl) { - CURLcode res = curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); - if (res != CURLE_OK) { - return std::nullopt; - } - res = curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); - if (res != CURLE_OK) { - return std::nullopt; - } - res = curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer); - if (res != CURLE_OK) { - return std::nullopt; - } - - if (method == "POST") { - res = curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data.c_str()); - if (res != CURLE_OK) { - return std::nullopt; - } - } - else if (method == "PUT") { - res = curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT"); - if (res != CURLE_OK) { - return std::nullopt; - } - res = curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data.c_str()); - if (res != CURLE_OK) { - return std::nullopt; - } - } - else if (method == "DELETE") { - res = curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE"); - if (res != CURLE_OK) { - return std::nullopt; - } - } - - res = curl_easy_perform(curl); - if (res != CURLE_OK) { - return std::nullopt; - } - - curl_easy_cleanup(curl); - } - glz::json_t json{}; - auto error = glz::read_json(json, readBuffer); - if (error) { - return std::nullopt; - } - return json; -} -} // namespace client -} // namespace nutc diff --git a/linter/src/firebase/fetching.hpp b/linter/src/firebase/fetching.hpp deleted file mode 100644 index 5297a862..00000000 --- a/linter/src/firebase/fetching.hpp +++ /dev/null @@ -1,40 +0,0 @@ -#pragma once - -#include -#include - -#include -#include - -namespace nutc { -namespace client { - -enum class LintingResultOption { UNKNOWN = -1, FAILURE, SUCCESS, PENDING }; - -// database request - change name -std::optional firebase_request( - const std::string& method, const std::string& url, const std::string& data = "" -); - -std::optional storage_request(const std::string& url); - -std::optional get_user_info(const std::string& uid); - -void -set_lint_result(const std::string& uid, const std::string& algo_id, bool succeeded); - -void set_lint_failure( - const std::string& uid, const std::string& algo_id, const std::string& failure -); -void set_lint_success( - const std::string& uid, const std::string& algo_id, const std::string& success -); - -[[nodiscard]] std::optional -get_algo(const std::string& uid, const std::string& algo_id); -[[nodiscard]] LintingResultOption get_algo_status( - const std::string& uid, const std::string& algo_id -); // returns a LintingResultOption enum - -} // namespace client -} // namespace nutc diff --git a/linter/src/lint/lint.cpp b/linter/src/lint/lint.cpp deleted file mode 100644 index d378da53..00000000 --- a/linter/src/lint/lint.cpp +++ /dev/null @@ -1,74 +0,0 @@ -#include "lint.hpp" - -#include "pywrapper/runtime.hpp" - -#include -#include - -#include -#include -#include - -namespace nutc { -namespace lint { - -namespace { -bool -mock_limit_func(const std::string& side, const std::string&, float, float) -{ - if (side == "BUY" || side == "SELL") - return true; - throw std::runtime_error( - fmt::format("Side should be BUY or SELL, but called with side: {}", side) - ); -} - -bool -mock_market_func(const std::string& side, const std::string&, float) -{ - if (side == "BUY" || side == "SELL") - return true; - throw std::runtime_error( - fmt::format("Side should be BUY or SELL, but called with side: {}", side) - ); -} -} // namespace - -lint_result -lint(const std::string& algo_code) -{ - std::string out_message = "[linter] starting to lint algorithm\n"; - bool ok = nutc::pywrapper::create_api_module(mock_limit_func, mock_market_func); - if (!ok) { - out_message += "[linter] failed to create API module\n"; - return {false, out_message}; - } - ok = nutc::pywrapper::supress_stdout(); - if (!ok) { - out_message += "[linter] failed to initialize python environment\n"; - return {false, out_message}; - } - - std::optional err = nutc::pywrapper::import_py_code(algo_code); - if (err.has_value()) { - out_message += fmt::format("{}\n", err.value()); - return {false, out_message}; - } - - err = nutc::pywrapper::run_initialization(); - if (err.has_value()) { - out_message += fmt::format("{}\n", err.value()); - return {false, out_message}; - } - - err = nutc::pywrapper::trigger_callbacks(); - if (err.has_value()) { - out_message += fmt::format("{}\n", err.value()); - return {false, out_message}; - } - out_message += "\n[linter] linting process succeeded!\n"; - return {true, out_message}; -} - -} // namespace lint -} // namespace nutc diff --git a/linter/src/lint/lint.hpp b/linter/src/lint/lint.hpp deleted file mode 100644 index 3dcb502d..00000000 --- a/linter/src/lint/lint.hpp +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include "lint/lint_result.hpp" - -#include - -namespace nutc { -namespace lint { - -[[nodiscard]] lint_result lint(const std::string& algo_code); - -} // namespace lint -} // namespace nutc diff --git a/linter/src/logging.cpp b/linter/src/logging.cpp deleted file mode 100644 index b6973997..00000000 --- a/linter/src/logging.cpp +++ /dev/null @@ -1,122 +0,0 @@ -#include "logging.hpp" - -#include "common.hpp" -#include "config.h" - -#include -#include - -#if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__MINGW64__) \ - || defined(QUILL_NO_THREAD_NAME_SUPPORT) -# define LOGLINE_FORMAT \ - "%(ascii_time) [%(thread:<6)] [%(logger_name:<8)] %(level_name:<8) - " \ - "%(message) (%(fileline))" -#else -# define LOGLINE_FORMAT \ - "%(ascii_time) [%(thread_name:<12)] [%(logger_name:<8)] %(level_name:<8) - " \ - "%(message) (%(fileline))" -#endif - -#ifdef _WIN32 -# define TZ_FORMAT "" -#else -# define TZ_FORMAT " %z" -#endif - -namespace nutc { -namespace logging { - -using namespace quill; // NOLINT(*-using-namespace) -using cc = quill::ConsoleColours; - -void -init(quill::LogLevel log_level) -{ - detail::application_log_level = log_level; - -#ifdef _WIN32 - // NOTE: on win32 a signal handler is needed for each new thread - quill::init_signal_handler(); -#endif - - // Create the logs directory - if (!std::filesystem::is_directory(LOG_DIR)) - std::filesystem::create_directory(LOG_DIR); - - // Create our config object - quill::Config cfg; - - // Set main logger name - cfg.default_logger_name = "main"; - - // - // Initialize print handler - // - quill::ConsoleColours colors; - colors.set_colour(LogLevel::TraceL3, cc::white); - colors.set_colour(LogLevel::TraceL2, cc::white); - colors.set_colour(LogLevel::TraceL1, cc::white); - colors.set_colour(LogLevel::Debug, cc::cyan); - colors.set_colour(LogLevel::Info, cc::green); - -#ifdef _WIN32 - // NOLINTBEGIN(*-signed-bitwise) - colors.set_colour(LogLevel::Warning, cc::yellow | cc::bold); - colors.set_colour(LogLevel::Error, cc::red | cc::bold); - colors.set_colour(LogLevel::Critical, cc::bold | cc::white | cc::on_red); - // NOLINTEND(*-signed-bitwise) -#else - colors.set_colour(LogLevel::Warning, cc::yellow + cc::bold); - colors.set_colour(LogLevel::Error, cc::red + cc::bold); - colors.set_colour(LogLevel::Critical, cc::bold + cc::white + cc::on_red); -#endif - - colors.set_colour(LogLevel::Backtrace, cc::magenta); - - auto stdout_handler = quill::stdout_handler("console", colors); - stdout_handler->set_pattern( - LOGLINE_FORMAT, - "%Y-%m-%dT%T.%Qms" TZ_FORMAT // ISO 8601 but with space instead of T - ); - stdout_handler->set_log_level(log_level); - - cfg.default_handlers.emplace_back(stdout_handler); - - // - // Initialize rotating file handler - // - quill::RotatingFileHandlerConfig handler_cfg; - - handler_cfg.set_rotation_max_file_size(LOG_FILE_SIZE); - handler_cfg.set_max_backup_files(LOG_BACKUP_COUNT); - handler_cfg.set_open_mode('a'); - - auto file_handler = quill::rotating_file_handler(LOG_FILE, handler_cfg); - - file_handler->set_pattern( - LOGLINE_FORMAT, - "%Y-%m-%dT%T.%Qms" TZ_FORMAT // ISO 8601 - ); - file_handler->set_log_level(log_level); - - cfg.default_handlers.emplace_back(file_handler); - - // Send the config - quill::configure(cfg); - - // Set backtrace and log level on the main logger - quill::Logger* main_logger = quill::get_logger(); - main_logger->init_backtrace(LOG_BACKTRACE_SIZE, quill::LogLevel::Error); - main_logger->set_log_level(log_level); - - // Set the thread name - set_thread_name("MainThread"); - - // Start the logging backend thread - quill::start(true); - - LOG_INFO(main_logger, "Logging initialized!"); -} - -} // namespace logging -} // namespace nutc diff --git a/linter/src/logging.hpp b/linter/src/logging.hpp deleted file mode 100644 index 469c5032..00000000 --- a/linter/src/logging.hpp +++ /dev/null @@ -1,139 +0,0 @@ -#pragma once - -#include "config.h" - -#include - -#include - -namespace nutc { -namespace logging { - -#if DEBUG() // Debug mode -static constexpr quill::LogLevel DEFAULT_LOG_LEVEL = quill::LogLevel::Debug; -#else // Release mode -static constexpr quill::LogLevel DEFAULT_LOG_LEVEL = quill::LogLevel::Info; -#endif - -namespace detail { - -// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) -inline quill::LogLevel application_log_level; - -inline quill::Logger* -get_logger(const std::string& name) -{ - quill::Logger* logger = nullptr; - - try { - logger = quill::get_logger(name.c_str()); - } catch (quill::QuillError&) { - logger = quill::create_logger(name); - logger->set_log_level(application_log_level); - logger->init_backtrace(LOG_BACKTRACE_SIZE, quill::LogLevel::Error); - } - - return logger; -} - -} // namespace detail - -/** - * Set our thread name. - */ -inline void -set_thread_name(const std::string& name) -{ - quill::detail::set_thread_name(name.c_str()); -} - -/** - * Set up logging. - */ -void init(quill::LogLevel log_level = DEFAULT_LOG_LEVEL); - -/** - * Set up logging. - */ -inline void -init(uint8_t verbosity = 0) -{ - auto log_level = static_cast(DEFAULT_LOG_LEVEL); - - if (verbosity <= log_level) - log_level -= verbosity; - else // protect from underflow - log_level = 0; - - init(static_cast(log_level)); -} - -/****************************************************************************** - * LOGGERS - *****************************************************************************/ -// NOLINTBEGIN(cppcoreguidelines-avoid-non-const-global-variables) - -inline quill::Logger* -get_main_logger() -{ - // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) - static auto* logger = quill::get_root_logger(); - return logger; -} - -// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define CREATE_LOG_CATEGORY(category) \ - inline quill::Logger* get_##category##_logger() \ - { \ - static auto* logger = detail::get_logger(#category); \ - return logger; \ - } \ - class ____dummy_##category // makes you add a semicolon - -// Create loggers here for every category -CREATE_LOG_CATEGORY(mock_runtime); -CREATE_LOG_CATEGORY(mock_api); -CREATE_LOG_CATEGORY(redis); -CREATE_LOG_CATEGORY(web); -CREATE_LOG_CATEGORY(libcurl); -CREATE_LOG_CATEGORY(rabbitmq); -CREATE_LOG_CATEGORY(firebase); -CREATE_LOG_CATEGORY(crow); -CREATE_LOG_CATEGORY(crow_watchdog); -CREATE_LOG_CATEGORY(timeout_watchdog); -CREATE_LOG_CATEGORY(linting); - -#undef CREATE_LOG_CATEGORY -// NOLINTEND(cppcoreguidelines-avoid-non-const-global-variables) - -} // namespace logging -} // namespace nutc - -// NOLINTBEGIN -#define log_bt(category, ...) \ - LOG_BACKTRACE(nutc::logging::get_##category##_logger(), __VA_ARGS__) - -#define log_t3(category, ...) \ - LOG_TRACE_L3(nutc::logging::get_##category##_logger(), __VA_ARGS__) - -#define log_t2(category, ...) \ - LOG_TRACE_L2(nutc::logging::get_##category##_logger(), __VA_ARGS__) - -#define log_t1(category, ...) \ - LOG_TRACE_L1(nutc::logging::get_##category##_logger(), __VA_ARGS__) - -#define log_d(category, ...) \ - LOG_DEBUG(nutc::logging::get_##category##_logger(), __VA_ARGS__) - -#define log_i(category, ...) \ - LOG_INFO(nutc::logging::get_##category##_logger(), __VA_ARGS__) - -#define log_w(category, ...) \ - LOG_WARNING(nutc::logging::get_##category##_logger(), __VA_ARGS__) - -#define log_e(category, ...) \ - LOG_ERROR(nutc::logging::get_##category##_logger(), __VA_ARGS__) - -#define log_c(category, ...) \ - LOG_CRITICAL(nutc::logging::get_##category##_logger(), __VA_ARGS__) -// NOLINTEND diff --git a/linter/src/pywrapper/runtime.cpp b/linter/src/pywrapper/runtime.cpp deleted file mode 100644 index 2c2df2f1..00000000 --- a/linter/src/pywrapper/runtime.cpp +++ /dev/null @@ -1,166 +0,0 @@ -#include "runtime.hpp" - -#include -#include - -namespace py = pybind11; - -namespace nutc { -namespace pywrapper { - -bool -create_api_module( - std::function - publish_limit_order, - std::function - publish_market_order -) -{ - try { - py::module m = py::module::create_extension_module( - "nutc_api", "Official NUTC Exchange API", new py::module::module_def - ); - - m.def("publish_limit_order", publish_limit_order); - m.def("publish_market_order", publish_market_order); - - py::module_ sys = py::module_::import("sys"); - py::dict sys_modules = sys.attr("modules").cast(); - sys_modules["nutc_api"] = m; - - py::exec(R"(import nutc_api)"); - } catch (...) { - return false; - } - return true; -} - -bool -supress_stdout() -{ - try { - py::exec(R"( - import sys - import os - class SuppressOutput(object): - def write(self, txt): - pass # Do nothing on write - def flush(self): - pass # Do nothing on flush - - sys.stdout = SuppressOutput() - )"); - } catch (...) { - return false; - } - return true; -} - -std::optional -import_py_code(const std::string& code) -{ - try { - py::exec(code); - } catch (const std::exception& e) { - return fmt::format("Failed to import code: {}", e.what()); - } - py::exec(R"( - def place_market_order(side, ticker, quantity): - return nutc_api.publish_market_order(side, ticker, quantity))"); - py::exec(R"( - def place_limit_order(side, ticker, quantity, price): - return nutc_api.publish_limit_order(side, ticker, price, quantity))"); - - return std::nullopt; -} - -std::optional -run_initialization() -{ - try { - py::exec("strategy = Strategy()"); - } - - catch (const std::exception& e) { - return fmt::format("Failed to run initialization: {}", e.what()); - } - - try { - py::object main_module = py::module_::import("__main__"); - py::dict main_dict = main_module.attr("__dict__"); - py::object on_trade_update = main_dict["strategy"].attr("on_trade_update"); - py::object on_orderbook_update = - main_dict["strategy"].attr("on_orderbook_update"); - py::object on_account_update = main_dict["strategy"].attr("on_account_update"); - } catch (py::error_already_set& e) { - return fmt::format("Failed to import callback functions: {}", e.what()); - } - - return std::nullopt; -} - -std::optional -trigger_callbacks() -{ - try { - py::exec(R"(place_limit_order("BUY", "ETH", 1.0, 1.0))"); - } catch (const std::exception& e) { - return fmt::format("Failed to run place_limit_order: {}", e.what()); - } - - try { - py::exec(R"(strategy.on_orderbook_update("ETH","BUY",1.0,1.0))"); - } catch (const std::exception& e) { - return fmt::format("Failed to run on_orderbook_update: {}", e.what()); - } - try { - py::exec(R"(strategy.on_trade_update("ETH","BUY",1.0,1.0))"); - } catch (const std::exception& e) { - return fmt::format("Failed to run on_trade_update: {}", e.what()); - } - - try { - py::exec(R"(strategy.on_account_update("ETH","BUY",1.0,1.0,1.0))"); - } catch (const std::exception& e) { - return fmt::format("Failed to run on_account_update: {}", e.what()); - } - - try { - py::exec(R"(strategy.on_orderbook_update("BTC","BUY",1.0,1.0))"); - } catch (const std::exception& e) { - return fmt::format("Failed to run on_orderbook_update: {}", e.what()); - } - try { - py::exec(R"(strategy.on_trade_update("BTC","BUY",1.0,1.0))"); - } catch (const std::exception& e) { - return fmt::format("Failed to run on_trade_update: {}", e.what()); - } - - try { - py::exec(R"(strategy.on_account_update("BTC","BUY",1.0,1.0,1.0))"); - } catch (const std::exception& e) { - return fmt::format("Failed to run on_account_update: {}", e.what()); - } - - try { - py::exec(R"(strategy.on_orderbook_update("LTC","BUY",1.0,1.0))"); - } catch (const std::exception& e) { - return fmt::format("Failed to run on_orderbook_update: {}", e.what()); - } - try { - py::exec(R"(strategy.on_trade_update("LTC","BUY",1.0,1.0))"); - } catch (const std::exception& e) { - return fmt::format("Failed to run on_trade_update: {}", e.what()); - } - - try { - py::exec(R"(strategy.on_account_update("LTC","BUY",1.0,1.0,1.0))"); - } catch (const std::exception& e) { - return fmt::format("Failed to run on_account_update: {}", e.what()); - } - - return std::nullopt; -} - -} // namespace pywrapper -} // namespace nutc diff --git a/linter/src/pywrapper/runtime.hpp b/linter/src/pywrapper/runtime.hpp deleted file mode 100644 index fd3c3d51..00000000 --- a/linter/src/pywrapper/runtime.hpp +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -#include -#include -#include - -namespace nutc { -namespace pywrapper { -[[nodiscard]] bool create_api_module( - std::function - publish_limit_order, - std::function - publish_market_order -); -[[nodiscard]] bool supress_stdout(); -[[nodiscard]] std::optional import_py_code(const std::string& code); - -[[nodiscard]] std::optional run_initialization(); - -[[nodiscard]] std::optional trigger_callbacks(); -} // namespace pywrapper -} // namespace nutc diff --git a/linter/src/spawner/main.cpp b/linter/src/spawner/main.cpp deleted file mode 100644 index f31a75a7..00000000 --- a/linter/src/spawner/main.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#include "lint/lint.hpp" - -#include -#include -#include - -#include - -#include -#include - -int -main() -{ - std::string algo_code; - std::string line; - while (std::getline(std::cin, line)) { - algo_code += line + '\n'; - } - - // Initialize py - pybind11::initialize_interpreter(); - - auto lint_result = nutc::lint::lint(algo_code); - - pybind11::finalize_interpreter(); - std::cout << glz::write_json(lint_result) << "\n"; - - return 0; -} diff --git a/linter/test/CMakeLists.txt b/linter/test/CMakeLists.txt deleted file mode 100644 index e4b12e5e..00000000 --- a/linter/test/CMakeLists.txt +++ /dev/null @@ -1,36 +0,0 @@ -# Parent project does not export its library target, so this CML implicitly -# depends on being added from it, i.e. the testing is done only from the build -# tree and is not feasible from an install location - -project(NUTC-linterTests LANGUAGES CXX) -if(NOT CMAKE_BUILD_TYPE) - set(CMAKE_BUILD_TYPE Debug) -endif() - - -# ---- Dependencies ---- - -find_package(GTest REQUIRED) -include(GoogleTest) - -# ---- Tests ---- - -add_executable(NUTC-linter_test src/NUTC-linter_test.cpp) -target_include_directories( - NUTC-linter_test ${warning_guard} - PUBLIC - "$" - "$" - ) -target_link_libraries( - NUTC-linter_test PRIVATE - NUTC-linter_lib - GTest::gtest_main -) -target_compile_features(NUTC-linter_test PRIVATE cxx_std_20) - -gtest_discover_tests(NUTC-linter_test) - -# ---- End-of-file commands ---- - -add_folders(Test) diff --git a/web-old/.eslintrc.json b/web-old/.eslintrc.json deleted file mode 100644 index bffb357a..00000000 --- a/web-old/.eslintrc.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "next/core-web-vitals" -} diff --git a/web-old/.firebaserc b/web-old/.firebaserc deleted file mode 100644 index d02b88b9..00000000 --- a/web-old/.firebaserc +++ /dev/null @@ -1,5 +0,0 @@ -{ - "projects": { - "default": "nutc-web" - } -} diff --git a/web-old/.gitignore b/web-old/.gitignore deleted file mode 100644 index 55cefc14..00000000 --- a/web-old/.gitignore +++ /dev/null @@ -1,43 +0,0 @@ -# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. -*.log -bun.* -baseline-data -functions/__pycache__ -em-storage/** - -firebase-seed - -# dependencies -/node_modules -/.pnp -.pnp.js -functions/venv - -# testing -/coverage - -# next.js -/.next/ -/out/ - -# production -/build - -# misc -.DS_Store -*.pem - -# debug -npm-debug.log* -yarn-debug.log* -yarn-error.log* - -# local env files -.env*.local - -# vercel -.vercel - -# typescript -*.tsbuildinfo -next-env.d.ts diff --git a/web-old/app/app-rejected/layout.tsx b/web-old/app/app-rejected/layout.tsx deleted file mode 100644 index 6df11ae8..00000000 --- a/web-old/app/app-rejected/layout.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import RedirectOnAuth from "@/app/login/auth/redirectOnAuth"; -export default function AppRejectedLayout({ - children, -}: { - children: React.ReactNode; -}) { - return ( -
- - {children} -
- ); -} diff --git a/web-old/app/app-rejected/page.tsx b/web-old/app/app-rejected/page.tsx deleted file mode 100644 index 3117b78e..00000000 --- a/web-old/app/app-rejected/page.tsx +++ /dev/null @@ -1,93 +0,0 @@ -"use client"; -import { Fragment, useRef, useState } from "react"; -import { Dialog, Transition } from "@headlessui/react"; -import { ExclamationTriangleIcon } from "@heroicons/react/24/outline"; -import { useRouter } from "next/navigation"; - -export default function Example() { - const [open, setOpen] = useState(true); - const router = useRouter(); - - const cancelButtonRef = useRef(null); - const goBack = () => { - router.push("/"); - }; - - return ( - - - -
- - -
-
- - -
-
-
-
- - You were not selected to join Northwestern Trading - Competition 2024. - -
-

- We recieved a large number of applications this year, - and we are sorry to inform you that you were not - selected to join Northwestern Trading Competition 2024. - We wish you the best of luck in your future endeavors. -

-
-
-
-
- -
-
-
-
-
-
-
- ); -} diff --git a/web-old/app/app-submitted/layout.tsx b/web-old/app/app-submitted/layout.tsx deleted file mode 100644 index 3b6225cd..00000000 --- a/web-old/app/app-submitted/layout.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import RedirectOnAuth from "@/app/login/auth/redirectOnAuth"; -export default function AppSubmittedLayout({ - children, -}: { - children: React.ReactNode; -}) { - return ( -
- - {children} -
- ); -} diff --git a/web-old/app/app-submitted/page.tsx b/web-old/app/app-submitted/page.tsx deleted file mode 100644 index 2b69b11f..00000000 --- a/web-old/app/app-submitted/page.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import Link from "next/link"; -export default function AppSubmitted() { - return ( -
-
- -
-

- Application Submitted -

-

- Application Submitted -

-

- We'll get back to you within three business days -

-
- - Back to home - -
-
-
-
- ); -} diff --git a/web-old/app/assets/background.png b/web-old/app/assets/background.png deleted file mode 100644 index af24fe08..00000000 Binary files a/web-old/app/assets/background.png and /dev/null differ diff --git a/web-old/app/dash/algoType.tsx b/web-old/app/dash/algoType.tsx deleted file mode 100644 index 98a633fb..00000000 --- a/web-old/app/dash/algoType.tsx +++ /dev/null @@ -1,13 +0,0 @@ -export default interface AlgorithmType { - lintResults: string; - uploadDate: string; - downloadURL: string; - fileIdKey: string; - uploadTime: number; - name: string; - description: string; - sandboxLogFileURL?: string; - lintFailureMessage?: string; - lintSuccessMessage?: string; - caseType: string; -} diff --git a/web-old/app/dash/dash.tsx b/web-old/app/dash/dash.tsx deleted file mode 100644 index 2814657c..00000000 --- a/web-old/app/dash/dash.tsx +++ /dev/null @@ -1,330 +0,0 @@ -"use client"; -import { Fragment, useEffect, useState } from "react"; -import Link from "next/link"; -import { Dialog, Transition } from "@headlessui/react"; -import Logo from "@/app/assets/logo.png"; -import Image from "next/image"; -import { useUserInfo } from "@/app/login/auth/context"; -import { - ArrowDownOnSquareIcon, - ArrowTrendingUpIcon, - ArrowUpTrayIcon, - Bars3Icon, - QuestionMarkCircleIcon, - XMarkIcon, - UserPlusIcon, -} from "@heroicons/react/24/outline"; -import { usePathname } from "next/navigation"; - -const navigation = [ - { - name: "Submissions", - href: "/dash", - icon: ArrowTrendingUpIcon, - activeName: "/dash", - }, - { - name: "FAQ", - href: "/dash/faq", - icon: QuestionMarkCircleIcon, - activeName: "/dash/faq", - }, - { - name: "Download Template", - href: "/dash/template", - icon: ArrowDownOnSquareIcon, - activeName: "/dash/template", - }, - { - name: "Upload Algorithm", - href: "/dash/submit", - icon: ArrowUpTrayIcon, - activeName: "/dash/submit", - }, - { - name: "Partner Settings", - href: "/dash/group", - icon: UserPlusIcon, - activeName: "/dash/group", - }, -]; - -function classNames(...classes: any) { - return classes.filter(Boolean).join(" "); -} - -export default function Dash(content: React.ReactNode) { - const [sidebarOpen, setSidebarOpen] = useState(false); - const [currentPage, setCurrentPage] = useState(""); - const { user } = useUserInfo(); - const pathName = usePathname(); - - //array of AlgorithmType - const [submissions, setSubmissions]: any = useState([]); - - useEffect(() => { - setCurrentPage(pathName); - }, [pathName]); - - useEffect(() => { - const algos = user?.algos; - const tmpSubmissions: any = []; - //iterate over values - if (!algos) { - return; - } - var i = 1; //not proud of this - //@ts-ignore - for (const [key, value] of algos) { - tmpSubmissions.push({ - id: key, - name: value.name, - href: `/dash/submissions/${key}`, - initial: String(i), - // So janky lmfao - current: window.location.href.includes(key), - }); - i++; - } - if (tmpSubmissions.length > 0) { - setSubmissions(tmpSubmissions); - } - }, [user]); - - return ( - <> -
- - - -
- - -
- - - -
- -
-
-
-
- Your Company -
- -
-
-
-
-
-
- - {/* static sidebar for desktop */} -
-
-
- Your Company -
- -
-
- -
- -
- Dashboard -
- - Your profile - - -
- -
-
{content}
-
-
- - ); -} diff --git a/web-old/app/dash/faq/page.tsx b/web-old/app/dash/faq/page.tsx deleted file mode 100644 index a59b6c6f..00000000 --- a/web-old/app/dash/faq/page.tsx +++ /dev/null @@ -1,124 +0,0 @@ -"use client"; -import { Disclosure } from "@headlessui/react"; -import { MinusSmallIcon, PlusSmallIcon } from "@heroicons/react/24/outline"; - -const faqs = [ - { - question: "What is the Northwestern Trading Competition?", - answer: - "NUTC is a competition to design a trading algorithm that maximizes a metric, usually PnL (net profit and loss) against other algorithms in the competition. In other words, you want your algorithm to buy and sell securities in a way that maximizes the amount of money you end up with.", - }, - { - question: "How can I get started?", - answer: - "Download the template, read the instructions carefully, and modify the Strategy class. Feel free to add new functions to the class, but DO NOT change the signatures of the provided functions.", - }, - { - question: "What are the functions in the algorithm template?", - answer: - "There are four main functions that allow you to interact with the exchange. place_market_order allows you to place orders for the exchange at a given price/quantity, and you can call this in any function (including __init__). on_orderbook_update is called when a new order is placed by another algorithm (BUY or SELL). on_trade_update is called when two orders match (one BUY, one SELL). This could be your order or two other orders. on_account_update is called when one of *your* orders matches with another order. Together, all of these functions are sufficient for you to maintain a complete copy of the local orderbook - this is highly recommended.", - }, - { - question: "What does a zero-quantity order mean?", - answer: - "All liqudity at this price level was fulfilled. This helps you to update your order book - you can now safely remove that price level.", - }, - { - question: "How does place_market_order work?", - answer: - "You can place an order (BUY or SELL) at a given price/quantity for a given stock ticker. Importantly, it returns True if the order was placed, or False if it was not placed (due to you placing more than 30 orders in a minute). You may want to handle the case where you aren't able to place an order due to the rate limit.", - }, - { question: "How much starting capital do I have?", answer: "100,000" }, - { - question: "What libraries can I use?", - answer: - "numpy, pandas, scipy, polars, and scikit-learn are currently available, all at latest. More libraries may be made available upon request.", - }, - { - question: "How can I do well in the competition?", - answer: - "Read up on how trading algorithms work. Oftentimes, the winner is not the most advanced algorithm - it's the most clever. Use the sandbox to confirm your algorithm's behavior.", - }, - { - question: "How do I know my code will work?", - answer: - "When you submit an algorithm on this website, it will be tested automatically. If any function fails to run, you can click on the submission to view the error.", - }, - { - question: "How many algorithms can I submit?", - answer: - "As many as you want, but the last algorithm that passes linting will be the one to run in the contest.", - }, - { - question: "How does order matching work?", - answer: - "Matches are done via Price-Time priority. In other words, when a BUY order is submitted, if the SELL order with lowest asking price <= the BUY price, they will match (and vice versa for incoming SELL orders).", - }, - { - question: "When is the deadline to submit algorithms?", - answer: "11:59pm on 5/3.", - }, - { - question: "How are algorithms evaluated?", - answer: - "By the amount of capital they hold at the end of the competition (incl. value of held stocks, which are automatically liquidated at a fair market price, with market impact.)", - }, - { - question: "How does the market start?", - answer: - "There are many liquidity providing bots on the exchange who will automatically trade with one another. Your algorithm should react to these trades - placing trades during initialization is heavily advised against.", - }, - { - question: "What if I have other questions or have issues with the website?", - answer: "Please reach out in the piazza", - }, -]; - -export default function FAQs() { - return ( -
-
-
-

- Frequently asked questions -

-
- {faqs.map((faq) => ( - - {({ open }) => ( - <> -
- - - {faq.question} - - - {open ? ( - - -
- -

- {faq.answer} -

-
- - )} -
- ))} -
-
-
-
- ); -} diff --git a/web-old/app/dash/group/page.tsx b/web-old/app/dash/group/page.tsx deleted file mode 100644 index ff08d9b5..00000000 --- a/web-old/app/dash/group/page.tsx +++ /dev/null @@ -1,100 +0,0 @@ -"use client"; -import { useUserInfo } from "@/app/login/auth/context"; -import { useFirebase } from "@/app/firebase/context"; -import Swal from "sweetalert2"; -import { useState } from "react"; - -export default function Group() { - const [iv, setIv] = useState(""); - const handleChange = (event: any) => { - setIv(event.target.value); - }; - const userInfo = useUserInfo(); - const { functions } = useFirebase(); - if (!userInfo?.user?.isInAGroup) { - return ( -
-
-
-

- Add a partner -

-

- Share your group ID with your partner -

-

- IMPORTANT: Do not share - your Group ID with anyone except your group member. -

-
-

- Your Group ID:{" "} - - {userInfo.user?.uid ?? "You must be logged in"} - -

-
-
- -
-
-

- Join a group -

-

- Enter your partner's group ID -

-
-
- - -
-

- Above section on your partner's dashboard -

-
-
-
- ); - } else { - return ( -
-
-

- You are already in a group. -

-
-
- ); - } -} diff --git a/web-old/app/dash/layout.tsx b/web-old/app/dash/layout.tsx deleted file mode 100644 index 5e2181f2..00000000 --- a/web-old/app/dash/layout.tsx +++ /dev/null @@ -1,16 +0,0 @@ -"use client"; -import RedirectOnAuth from "@/app/login/auth/redirectOnAuth"; -import Dash from "@/app/dash/dash"; - -export default function DashLayout({ - children, -}: { - children: React.ReactNode; -}) { - return ( -
- - {Dash(children)} -
- ); -} diff --git a/web-old/app/dash/no-submissions.tsx b/web-old/app/dash/no-submissions.tsx deleted file mode 100644 index 823290fe..00000000 --- a/web-old/app/dash/no-submissions.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import { PlusIcon } from "@heroicons/react/20/solid"; -import { ArrowUpOnSquareIcon } from "@heroicons/react/24/outline"; -import Link from "next/link"; - -export default function NoSubmissions() { - return ( -
- -

- No submissions -

-

- Get started by uploading your first algorithm. -

-
- -
-
- ); -} diff --git a/web-old/app/dash/page.tsx b/web-old/app/dash/page.tsx deleted file mode 100644 index f0c1f471..00000000 --- a/web-old/app/dash/page.tsx +++ /dev/null @@ -1,329 +0,0 @@ -"use client"; -import { Fragment, useEffect, useState } from "react"; -import NoSubmissions from "./no-submissions"; -import { Menu, Transition } from "@headlessui/react"; -const statuses: any = { - pending: "text-yellow-500 bg-yellow-100/10", - success: "text-green-400 bg-green-400/10", - failure: "text-rose-400 bg-rose-400/10", -}; -const environments: any = { - Results: "text-indigo-400 bg-indigo-400/10 ring-indigo-400/20", - Pending: "text-gray-400 bg-gray-400/10 ring-gray-400/20", - "Lint Output": "text-rose-400 bg-rose-400/10 ring-rose-400/30", -}; -const deployments: any = [ - { - id: 1, - href: "#", - projectName: "new-experimental-algo", - teamName: "Shxiv", - status: "pending", - statusText: "Linting Succeeded 13m 16s ago", - description: "Waiting for Simulation", - environment: "Pending", - }, - { - id: 2, - href: "#", - projectName: "RL-buggy-test", - teamName: "Shxiv", - status: "error", - statusText: "Linting failed 25m 52s ago", - description: "Linting Failed", - environment: "Lint Output", - }, - { - id: 3, - href: "#", - projectName: "DL-test-4", - teamName: "Shxiv", - status: "finished", - statusText: "Simulation ran 4h 32m ago", - description: "Finished Running", - environment: "Results", - }, -]; - -const activityItems = [ - { - title: "Linting Succeeded", - projectName: "new-experimental-algo", - date: "13m", - dateTime: "2023-01-23T11:00", - }, - { - title: "Linting Started", - projectName: "new-experimental-algo", - date: "15m", - dateTime: "2023-01-23T11:00", - }, - { - title: "Linting Failed", - projectName: "RL-buggy-test", - date: "25m", - dateTime: "2023-01-23T11:00", - }, - { - title: "Simulation Run", - projectName: "DL-test-4", - date: "4h", - dateTime: "2023-01-23T11:00", - }, - { - title: "Linting Succeeded", - projectName: "DL-test-4", - date: "5h", - dateTime: "2023-01-23T11:00", - }, - { - title: "Linting Started", - projectName: "DL-test-4", - date: "5h", - dateTime: "2023-01-23T11:00", - }, -]; - -import { - ChevronRightIcon, - ChevronUpDownIcon, - MagnifyingGlassIcon, -} from "@heroicons/react/20/solid"; -import { useUserInfo } from "../login/auth/context"; -import AlgorithmType from "./algoType"; - -function classNames(...classes: any) { - return classes.filter(Boolean).join(" "); -} -export default function Dashboard() { - const [algos, setAlgos] = useState([]); - const { user } = useUserInfo(); - - useEffect(() => { - const algos = user?.algos; - if (!algos) { - return; - } - var tmpAlgos: any = []; - //@ts-ignore - for (const [key, value] of algos) { - const test: AlgorithmType = value; - tmpAlgos.push({ - id: key, - href: `/dash/submissions/${key}`, - projectName: value.name, - teamName: value.name, - status: test.lintResults, - statusText: test.lintResults, - description: test.description, - environment: test.lintResults, - }); - } - setAlgos(tmpAlgos); - }, [user]); - - const [searchTerm, setSearchTerm] = useState(""); - - const handleSearchChange = (event: React.ChangeEvent) => { - setSearchTerm(event.target.value); - }; - - return ( -
-
-
-
- -
-
-
-
-
-
-
-

- Submissions -

- - {/* Sort dropdown */} - - - Sort by - - - - - {({ active }) => ( - - Name - - )} - - - {({ active }) => ( - - Date updated - - )} - - - {({ active }) => ( - - Status - - )} - - - - -
- - {/* Deployment list */} -
    - {algos.length === 0 && } - {algos - .filter( - (algo: any) => - searchTerm === "" || - (algo.projectName && - algo.projectName - .toLowerCase() - .includes(searchTerm.toLowerCase())), - ) - .map((deployment: any) => ( -
  • -
    -
    - -
    -

    {deployment.description}

    - - - -

    {deployment.statusText}

    -
    -
    -
    - {deployment.environment} -
    -
  • - ))} -
-
- -
- ); -} diff --git a/web-old/app/dash/submissions/[id]/page.tsx b/web-old/app/dash/submissions/[id]/page.tsx deleted file mode 100644 index 3697c64d..00000000 --- a/web-old/app/dash/submissions/[id]/page.tsx +++ /dev/null @@ -1,109 +0,0 @@ -"use client"; -import { useUserInfo } from "@/app/login/auth/context"; -import { useEffect, useState } from "react"; -import { useRouter } from "next/navigation"; -import { apiEndpoint } from "@/config"; -import {ArrowDownTrayIcon} from "@heroicons/react/24/solid" -import React from "react"; -export default function Page({ params }: { params: { id: string } }) { - const userInfo = useUserInfo(); - const router = useRouter(); - useEffect(() => { - if (!userInfo?.user) { - return; - } - if (!userInfo?.user?.algos) { - router.push("/dash"); - } - if (!userInfo?.user?.algos?.has(params.id)) { - router.push("/dash"); - } - }); - - const formatNewLines = (str: string) => { - const LINES = str.split("\n"); - return LINES.map((line: string, index: number) => ( - -

{line}

- {index < LINES.length - 1 &&
} -
- )); - }; - - const algoDetails = userInfo?.user?.algos?.get(params.id); - const lintFailureMessage = algoDetails?.lintFailureMessage; - const lintSuccessMessage = algoDetails?.lintSuccessMessage; - const stringToRender = lintFailureMessage || lintSuccessMessage || ""; - const upTime = (algoDetails?.uploadTime || 0) + 1000; - const sandboxTimeMs = 300000; - const baseEndpoint = - apiEndpoint() + - `/d-solo/cdk4teh4zl534a/ppl?orgId=1&var-traderid=${userInfo?.user?.uid}-${params.id}&from=${upTime}&theme=dark`; - - const [url, setUrl] = useState(baseEndpoint + `&refresh=5s`); - - useEffect(() => { - if (upTime + sandboxTimeMs > Date.now()) { - setUrl(baseEndpoint + "&refresh=5s"); - setTimeout( - () => { - setUrl(baseEndpoint + `&to=${upTime + sandboxTimeMs}`); - }, - upTime + sandboxTimeMs - Date.now(), - ); - } else { - setUrl(baseEndpoint + `&to=${upTime + sandboxTimeMs}`); - } - }, [userInfo.user]); - - if (stringToRender === "") { - return ( -
-

Waiting on output...

-
- ); - } else if (stringToRender.includes("succeeded")) { - return ( -
-

Sandbox View of {algoDetails?.name}

-

Ensure to review the case packet. Results may be deleted after 24 hours.

- - - Download Submission - - -
-

Profit and Loss

- -
- -
-

Capital

- -
-
- ); - } else { - return formatNewLines(stringToRender); - } -} diff --git a/web-old/app/dash/submit/page.tsx b/web-old/app/dash/submit/page.tsx deleted file mode 100644 index 020d38ff..00000000 --- a/web-old/app/dash/submit/page.tsx +++ /dev/null @@ -1,462 +0,0 @@ -"use client"; -import { CheckIcon, PaperClipIcon, ChevronUpDownIcon } from "@heroicons/react/24/solid"; -import { apiEndpoint } from "@/config"; -import axios from "axios"; -import { Fragment, useRef, useState } from "react"; -import AlgorithmType from "@/app/dash/algoType"; -import Swal from "sweetalert2"; -import { push, ref, set } from "firebase/database"; -import { getDownloadURL, ref as sRef, uploadBytes } from "firebase/storage"; -import { useFirebase } from "@/app/firebase/context"; -import { useUserInfo } from "@/app/login/auth/context"; -import { Listbox, Transition } from '@headlessui/react' -import Link from "next/link"; - -const CASES = [ - { id: 1, name: 'HFT' }, - { id: 2, name: 'Crypto Trading' }, -] - -function classNames(...classes: any) { - return classes.filter(Boolean).join(' ') -} - -async function uploadAlgo( - database: any, - storage: any, - uid: string, - file: File, -) { - const fileRef = push(ref(database, `users/${uid}/algos`)); - if (!fileRef) { - return { downloadURL: "", fileIdKey: "", fileRef: "" }; - } - const fileIdKey: string = `${uid}/${fileRef.key}` || ""; //bad practice - const storageRef = sRef(storage); - const fileType = file.type.split("/")[1]; - const algoRef = sRef(storageRef, `algos/${fileIdKey}.${fileType}`); - try { - const snapshot = await uploadBytes(algoRef, file); - const tmpDownloadURL = await getDownloadURL(snapshot.ref); //in theory, we should be saving the ID, rather than URL. this is easier. - const downloadURL = tmpDownloadURL.replace("localhost", "firebase"); - return { downloadURL, fileIdKey, fileRef }; - } catch (e) { - console.log(e); - return { downloadURL: "", fileIdKey: "", fileRef: "" }; - } -} - -const CASE_DOCUMENT_URL= "https://docs.google.com/document/d/1FfWrKIXGO7oPKTTTwyprH3kM8WrnIuZmp9kcH4lo6CA/" - -async function writeNewAlgo( - algo: AlgorithmType, - algoRef: any, - database: any, - uid: string, -) { - if (algo.downloadURL === "" || algo.description === "" || algo.name === "") { - Swal.fire({ - title: "Please fill out all fields", - icon: "warning", - toast: true, - position: "top-end", - showConfirmButton: false, - timer: 4000, - timerProgressBar: true, - didOpen: (toast) => { - toast.addEventListener("mouseenter", Swal.stopTimer); - toast.addEventListener("mouseleave", Swal.resumeTimer); - }, - }); - return false; - } - algo.lintResults = "pending"; - algo.uploadDate = new Date().toISOString(); - - await set(algoRef, algo); - // await functions.httpsCallable("emailApplication")(); - // above should be lint function - return true; -} - -export default function Submission() { - const defaultAlgo: AlgorithmType = { - lintResults: "pending", - uploadDate: "", - downloadURL: "", - fileIdKey: "", - name: "", - description: "", - uploadTime: 0, - caseType: CASES[0].name, - }; - - const handleCaseChange = (e: any) => { - setAlgo((prevState) => ({ - ...prevState, - caseType: e.name, - })); - } - - - const handleInputChange = (e: any) => { - const { name, value } = e.target; - //@ts-ignore - setAlgo((prevState) => ({ - ...prevState, - [name]: value, - })); - }; - - const [isDragOver, setDragOver] = useState(false); - const dropRef: any = useRef(); - - const handleDragOver = (e: any) => { - e.preventDefault(); - setDragOver(true); - }; - - const handleDragLeave = () => { - setDragOver(false); - }; - - const handleDrop = (e: any) => { - e.preventDefault(); - setDragOver(false); - - const files = e.dataTransfer.files; - handleAlgoChange(files[0]); - }; - - const userInfo = useUserInfo(); - const { database, storage, functions } = useFirebase(); - - const handleAlgoChange = async (selectedFile: any) => { - if (!selectedFile) { - return; - } - const fileName = selectedFile.name; - const fileExtension = fileName.split(".").pop().toLowerCase(); - if (fileExtension !== "py") { - Swal.fire({ - title: "Please upload a Python file", - icon: "error", - toast: true, - position: "top-end", - showConfirmButton: false, - timer: 2000, - timerProgressBar: true, - didOpen: (toast) => { - toast.addEventListener("mouseenter", Swal.stopTimer); - toast.addEventListener("mouseleave", Swal.resumeTimer); - }, - }); - return; - } - const downloadLink = await uploadAlgo( - database, - storage, - userInfo?.user?.uid || "unknown", - selectedFile, - ); - if (downloadLink.downloadURL !== "") { - setAlgo((prevState) => ({ - ...prevState, - downloadURL: downloadLink.downloadURL, - fileIdKey: downloadLink.fileIdKey, - uploadTime: Date.now(), - })); - setAlgoRef(downloadLink.fileRef); - Swal.fire({ - title: "Algorithm uploaded!", - icon: "success", - toast: true, - position: "top-end", - showConfirmButton: false, - timer: 4000, - timerProgressBar: true, - didOpen: (toast) => { - toast.addEventListener("mouseenter", Swal.stopTimer); - toast.addEventListener("mouseleave", Swal.resumeTimer); - }, - }); - } else { - Swal.fire({ - title: "Algorithm upload failed", - icon: "error", - toast: true, - position: "top-end", - showConfirmButton: false, - timer: 4000, - timerProgressBar: true, - didOpen: (toast) => { - toast.addEventListener("mouseenter", Swal.stopTimer); - toast.addEventListener("mouseleave", Swal.resumeTimer); - }, - }); - } - }; - - const [algo, setAlgo] = useState(defaultAlgo); - const [algoRef, setAlgoRef]: any = useState(null); - return ( -
-
-
-
-

- Submission Information -

-

- This information will help to identify your submission, as well as - give our judges a better understanding of your project. -

- -
-
- -
-
- -
-
-
- - -
- - {({ open }) => ( - <> -
- Case: - - - -
-
- - {algo.caseType} - - - - - - - {CASES.map((c) => ( - - classNames( - active ? 'bg-indigo-600 text-white' : 'text-white', - 'relative cursor-default select-none py-2 pl-3 pr-9' - ) - } - value={c} - > - {({ selected, active }) => ( - <> - - {c.name} - - - {selected ? ( - - - ) : null} - - )} - - ))} - - -
- - )} -
-
-
- -
-