Skip to content

Commit

Permalink
Merge pull request #42 from bludnic/feat/build
Browse files Browse the repository at this point in the history
Feat/build
  • Loading branch information
bludnic authored Jul 10, 2024
2 parents 5f77f05 + 5846fba commit 0e9e063
Show file tree
Hide file tree
Showing 477 changed files with 9,813 additions and 1,677 deletions.
8 changes: 6 additions & 2 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,16 @@ NEXT_PUBLIC_PROCESSOR_URL="http://localhost:4000"
# If `true`, then tRPC will be provided by `processor` app.
# If `false`, then `frontend` app will instantiate the tRPC client by itself using Next API Routes
# Accepts: "true" | ""
NEXT_PUBLIC_PROCESSOR_ENABLE_TRPC=
NEXT_PUBLIC_PROCESSOR_ENABLE_TRPC=true
# Build NextJS as a static app (`export`) instead of `standalone`
# Accepts: "true" | ""
NEXT_PUBLIC_STATIC=
DATABASE_URL="postgresql://postgres:[email protected]:5432/postgres"
# Relative to packages/prisma/src
DATABASE_URL="file:../../../dev.db"
ADMIN_PASSWORD=opentrader
NEXT_PUBLIC_CANDLES_SERVICE_API_URL="http://localhost:5001"
NEXT_PUBLIC_CANDLES_SERVICE_API_KEY="opentrader"
# Logging level for ccxt
# Accepts: "true" | ""
CCXT_VERBOSE=
########## SHARED END ######
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ config.prod.json5
exchanges.dev.json5
exchanges.prod.json5
.vercel
dev.db
8 changes: 4 additions & 4 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ COPY --from=builder /app/out/pnpm-lock.yaml ./pnpm-lock.yaml
# Copy Prisma Schema as it is not included in `/json` dir
COPY --from=builder /app/out/full/packages/prisma/src/schema.prisma ./packages/prisma/src/schema.prisma
RUN --mount=type=cache,id=pnpm,target=/root/.local/share/pnpm/store pnpm fetch
RUN pnpm install --offline
RUN pnpm install --prefer-offline

# Build the project and its dependencies
COPY --from=builder /app/out/full/ .
Expand Down Expand Up @@ -73,7 +73,7 @@ RUN corepack enable

WORKDIR /app

COPY --from=installer /app/pro/frontend/out ./pro/frontend/out
COPY --from=installer /app/pro/frontend/dist ./pro/frontend/dist
COPY --from=installer /app/pro/processor ./pro/processor
COPY --from=installer /app/package.json ./package.json
COPY --from=installer /app/pnpm-lock.yaml ./pnpm-lock.yaml
Expand All @@ -93,9 +93,9 @@ RUN addgroup --system --gid 1001 expressjs
RUN adduser --system --uid 1001 expressjs
USER expressjs

COPY --from=optimizer /app/pro/frontend/out ./pro/frontend/out
COPY --from=optimizer /app/pro/frontend/dist ./pro/frontend/dist
COPY --from=optimizer /app/pro/processor ./pro/processor
COPY --from=optimizer /app/node_modules ./node_modules

WORKDIR /app/pro/processor
CMD node dist/main.js
CMD node dist/main.mjs
38 changes: 30 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,10 @@ $ cp .env.example .env
$ pnpm install
```

2. Build `/packages/**`
2. Build packages

```bash
$ turbo run build --filter='./packages/*'
$ turbo run build
```

3. Run db migrations
Expand Down Expand Up @@ -108,27 +108,49 @@ Create the strategy configuration file `config.dev.json5`. We will use the `grid
## Run a backtest

Command: `pnpm opentrader backtest <strategy> --from <date> --to <date> -t <timeframe>`
Command: `./bin/cli.sh backtest <strategy> --from <date> --to <date> -t <timeframe>`

Example running a `grid` strategy on `1h` timeframe.

```bash
$ pnpm opentrader backtest grid --from 2024-03-01 --to 2024-06-01 -t 1h
$ bin/cli.sh backtest grid --from 2024-03-01 --to 2024-06-01 -t 1h
```

> To get more accurate results, use a smaller timeframe, e.g. 1m, however, it will take more time to download OHLC data from the exchange.
## Live trading

Command: `pnpm opentrader trade <strategy>`
## Starting the daemon

Before running live trading, you need to start the daemon:

```bash
$ bin/cli.sh up
```

Now the daemon is ready to listen for incoming commands.

> Tip: To run the daemon in the background, use: `bin/cli.sh up -d`
## Running a Live Trading

Command: `bin/cli.sh trade <strategy>`

Example running a live trading with `grid` strategy.

```bash
$ pnpm opentrader trade grid
$ bin/cli.sh trade grid
```

> After `Ctrl+C`, the orders created by the bot will remain on the exchange. To cancel them, use the `pnpm opentrader stop` command.
> To stop the live trading, run `bin/cli.sh stop`
## Stop the daemon

To stop the daemon, run the following command:

```bash
$ bin/cli.sh down
```

# UI

Expand All @@ -148,7 +170,7 @@ Run frontend app:

```shell
$ pnpm i
$ turbo run build --filter='./packages/*'
$ turbo run build
$ turbo run dev
```

Expand Down
10 changes: 0 additions & 10 deletions apps/cli/.eslintrc.js

This file was deleted.

1 change: 1 addition & 0 deletions apps/cli/.gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
node_modules
dist
release
48 changes: 48 additions & 0 deletions apps/cli/bin/opentrader.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#!/usr/bin/env node

import { readFile } from "fs/promises";
import { spawn } from "child_process";
import { fileURLToPath } from "url";
import { dirname } from "path";

// Determine the script's directory
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

// Path to the file containing the admin password
const passwordFile = `${process.env.HOME}/.opentrader/pass`;

// Function to read the password file
async function readPasswordFile(filePath) {
try {
const data = await readFile(filePath, "utf-8");
return data.trim();
} catch (error) {
console.error("Password file not found!");
process.exit(1);
}
}

// Main function to run the script
async function main() {
const adminPassword = await readPasswordFile(passwordFile);

// Set environment variables
const env = {
...process.env,
ADMIN_PASSWORD: adminPassword,
DATABASE_URL: `file:${process.env.HOME}/.opentrader/dev.db`,
};

// Run the Node.js script
const args = [`${__dirname}/../dist/main.mjs`, ...process.argv.slice(2)];
const child = spawn("node", args, { env, stdio: "inherit" });

child.on("close", (code) => {
if (code !== 0) {
console.error(`Process exited with code ${code}`);
}
});
}

main();
1 change: 0 additions & 1 deletion apps/cli/config.prod.json5

This file was deleted.

10 changes: 10 additions & 0 deletions apps/cli/eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import EslintConfig from "@opentrader/eslint/module.js";

export default [
...EslintConfig,
{
rules: {
// overriding rules here
},
},
];
1 change: 0 additions & 1 deletion apps/cli/exchanges.prod.json5

This file was deleted.

43 changes: 30 additions & 13 deletions apps/cli/package.json
Original file line number Diff line number Diff line change
@@ -1,26 +1,32 @@
{
"name": "opentrader",
"version": "0.0.1",
"version": "1.0.0-alpha.5",
"description": "",
"main": "src/index.ts",
"type": "module",
"main": "dist/main.mjs",
"types": "src/index.ts",
"scripts": {
"build": "webpack",
"build": "tsup",
"build:release": "rimraf ./release && tsup -d release/dist && cp -r ./bin ./release/bin && cp -r ./scripts ./release/scripts",
"lint": "eslint . --quiet",
"lint:fix": "eslint . --fix"
},
"author": "bludnic",
"license": "Apache-2.0",
"devDependencies": {
"@opentrader/eslint-config": "workspace:*",
"@opentrader/eslint": "workspace:*",
"@opentrader/tsconfig": "workspace:*",
"@opentrader/types": "workspace:*",
"@types/node": "^20.12.11",
"eslint": "8.54.0",
"@types/express": "^4.17.21",
"@types/node": "^20.14.10",
"esbuild": "^0.23.0",
"eslint": "8.57.0",
"rimraf": "^6.0.1",
"ts-loader": "^9.5.1",
"ts-node": "10.9.2",
"typescript": "5.4.5",
"webpack": "^5.91.0",
"tsup": "^8.1.0",
"typescript": "5.5.3",
"webpack": "^5.92.1",
"webpack-cli": "^5.1.4",
"webpack-node-externals": "^3.0.0"
},
Expand All @@ -29,17 +35,28 @@
"@opentrader/bot": "workspace:*",
"@opentrader/bot-processor": "workspace:*",
"@opentrader/bot-templates": "workspace:*",
"@opentrader/daemon": "workspace:*",
"@opentrader/db": "workspace:*",
"@opentrader/exchanges": "workspace:*",
"@opentrader/logger": "workspace:*",
"@opentrader/processing": "workspace:*",
"@opentrader/tools": "workspace:*",
"@opentrader/trpc": "workspace:*",
"@prisma/client": "5.15.0",
"ccxt": "4.3.27",
"commander": "^12.0.0",
"jayson": "^4.1.0",
"@trpc/client": "^10.45.2",
"@trpc/server": "^10.45.2",
"ccxt": "4.3.59",
"commander": "^12.1.0",
"express": "^4.19.2",
"json5": "^2.2.3",
"pino": "^9.0.0",
"pino-pretty": "^11.0.0"
"pino": "^9.2.0",
"pino-pretty": "^11.2.1",
"random-words": "^2.0.1",
"superjson": "^2.2.1",
"tsx": "^4.16.2",
"zod": "3.23.8"
},
"bin": {
"opentrader": "./bin/opentrader.mjs"
}
}
79 changes: 79 additions & 0 deletions apps/cli/plugins/copy-prisma-schema-plugin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import fs from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { Plugin } from "esbuild";

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

const CLI_DIR = path.resolve(__dirname, "../");
const PRISMA_DIR = path.resolve(CLI_DIR, "../../packages/prisma");
const DIST_DIR = path.resolve(CLI_DIR, "release/dist");

/**
* Copy the Prisma schema file to the release build directory.
*/
export const copyPrismaSchemaPlugin = (): Plugin => ({
name: "copy-prisma-schema",
setup(build) {
if (build.initialOptions.outdir !== "release/dist") {
console.log('Skipping "schema.prisma" copy for non-release build');
return;
}

build.onEnd(() => {
// Copy schema.prisma
const prismaSchemaPath = path.resolve(PRISMA_DIR, "src/schema.prisma");
const prismaSchemaDest = path.resolve(DIST_DIR, "../schema.prisma");

if (!fs.existsSync(DIST_DIR)) {
fs.mkdirSync(DIST_DIR, {
recursive: true,
});
}

fs.copyFileSync(prismaSchemaPath, prismaSchemaDest);

// Copy seed.ts
const prismaSeedPath = path.resolve(CLI_DIR, "seed.ts");
const prismaSeedDest = path.resolve(DIST_DIR, "../seed.ts");
fs.copyFileSync(prismaSeedPath, prismaSeedDest);

// Copy migrations
const prismaMigrationsPath = path.resolve(PRISMA_DIR, "src/migrations");
const prismaMigrationsDest = path.resolve(DIST_DIR, "../migrations");

if (!fs.existsSync(prismaMigrationsDest)) {
fs.mkdirSync(prismaMigrationsDest, {
recursive: true,
});
}

copyDirectory(prismaMigrationsPath, prismaMigrationsDest);
});
},
});

function copyDirectory(src: string, dest: string) {
// Create destination folder if it doesn't exist
if (!fs.existsSync(dest)) {
fs.mkdirSync(dest, { recursive: true });
}

// Read all items in the source directory
const items = fs.readdirSync(src);

// Iterate through each item and copy it to the destination
items.forEach((item) => {
const srcPath = path.join(src, item);
const destPath = path.join(dest, item);

if (fs.lstatSync(srcPath).isDirectory()) {
// If item is a directory, recursively copy it
copyDirectory(srcPath, destPath);
} else {
// If item is a file, copy it
fs.copyFileSync(srcPath, destPath);
}
});
}
Loading

0 comments on commit 0e9e063

Please sign in to comment.