# crypto-trading-bot: basic auth on an order dashboard, and npm test runs half the suite

> Haehnchen/crypto-trading-bot is a TypeScript trading bot with a web dashboard that can place manual orders behind nothing but HTTP basic auth, a Telegram setup whose documented first step is inviting a third-party bot into your group, a start script that rebuilds the production bundle every time it runs, and a test command that covers only the TypeScript half of the suite.

**Haehnchen/crypto-trading-bot** — Cryptocurrency trading bot in javascript for Bitfinex, Bitmex, Binance, Bybit ... (public edition)

- Repository: https://github.com/Haehnchen/crypto-trading-bot
- Stars: 3,532 · Forks: 1,020
- Language: TypeScript
- License: MIT
- Published: 2026-09-23 · Updated: 2026-09-23 · Language: en
- Canonical page: https://hysenlabs.com/projects/haehnchen-crypto-trading-bot

## The README says the bundled strategies are usually not profitable

Two lines into this README, under the title, there is a bold sentence: not production ready, only basic functionality. That is the first thing a reader is told.

Then the strategies section says something more specific and more useful. It introduces the built-in strategies by telling you the common strategies with indicators are inside, and then adds that most of the time they are not profitable. It sends you to a list of more advanced strategies instead, and to a directory of examples.

That is an unusual and genuinely useful admission. A trading framework whose own strategies are described as usually losing money is telling you that the framework is the artefact and the strategies are examples, which is exactly the right way round for a reference implementation.

Two strategies are named. One catches dips. The other is described in bold as long term invest, and expanded as a dollar-cost-averaging dip investor strategy. So the pair covers a short-term entry and a slow accumulation approach, and the bold lead-in on the second is a hint about which one the author considers the more serious.

The repository description adds one more piece of framing: it calls this the public edition, next to naming four exchanges. So there is a fuller edition somewhere, and what is published here is a subset.

None of that is a criticism. A bot that tells you its own strategies lose money, and that a commercial edition exists, is more useful to evaluate than one that shows you a backtest.

## Basic auth in front of a dashboard that can place manual orders

The web interface has four sections listed: a dashboard, a view covering trades, positions and orders, and a section called manual orders. So the browser can place orders.

The security section says the webserver provides just basic auth for access, and suggests combining that with HTTPS for a public server, followed by an nginx server block that proxies to the loopback port on 443 with certificates managed elsewhere.

Basic auth is the whole of the access control. The dependency list confirms it in the most literal way: the authentication library is a dependency called basic-auth, sitting in a list of twenty-one alongside the web framework, the templating engines, the exchange library and the database driver. There is no session library, no CSRF middleware and no security-header middleware in the visible dependencies. There is compression and there is a cookie parser.

So the interface that can move money sits behind a scheme where the credential is sent, base64 encoded, on every single request. That is tolerable over TLS and indefensible without it, which is exactly what the README says, and its fix is a proxy.

The sample configuration is the part worth reading twice. It proxies to the loopback port and listens on 443 with certificates. It has no plain-HTTP server block and no redirect from one, so the TLS host is the only thing this configuration serves. There is nothing about rate limiting, account lockout, or source restriction on the loopback binding either.

None of that means the setup is wrong. It means the security posture of this project is one line of documentation long, and the thing being protected holds exchange credentials and can place orders.

## The documented way to get your group id is to invite a third-party bot into it

The Telegram section is the longest setup walkthrough in the README, and it contains one step that deserves a warning it does not get.

The flow is: create a bot through Telegram's bot father service and get a token. Create a group. Add the bot as an administrator, with a parenthetical instruction to uncheck the option that would make all members admins. Then, to find the group's numeric id, invite a third-party bot called RawDataBot into the group and read the id out of the chat field of a message it can see.

The privilege instruction is correct and specific. Granting a bot administrator rights and explicitly not granting the permission that promotes all members is a real distinction in the Telegram bot API, and the README gets it right. That part is good documentation.

The id-retrieval step is the part with no caveat at all. The documented mechanism is to admit an unfamiliar third-party bot into a group you intend to use for trading notifications. That bot then observes the group. Nothing in the README says what it does with what it sees, nothing says the step is temporary, and nothing offers an alternative.

For a group where you will paste trade signals and account activity, that is the step to think about. The alternative, which anyone familiar with the Telegram API would reach for immediately, is to read the id from the bot you already created, or to set it once by hand in the configuration.

The README does show the shape of the data you are reading, as a tree of the message fields with the chat id, the group title and the supergroup type. So it is careful about what the answer looks like, and silent about the cost of getting it.

## npm test runs the TypeScript tests and a second script runs the JavaScript ones

The test section of the README is three lines long. It has a heading, and it says:

```
npm test
```

That is the whole instruction.

The manifest has two test scripts. One runs mocha through the TypeScript loader over every TypeScript test file. The other runs mocha with no loader over every JavaScript test file. Two suites, two commands, two file extensions.

The README names only the first. So a contributor who opens this repository, writes a fix, and does what the README says runs the TypeScript suite, sees it pass, and has no signal at all about the JavaScript suite, which contains tests for the other half of the codebase.

That is a documentation gap with a specific shape. It is not that the tests are missing or that they do not run. It is that the project has two of everything where the README describes one.

The same pattern shows up elsewhere in the manifest. There are three build paths: one plain bundler invocation, the same invocation with a production flag, and a separate TypeScript compiler invocation that nothing in the start path uses. The start script runs the production bundle, the development scripts run the TypeScript source directly through a loader, and the manual TypeScript build appears to be kept for a case the README does not describe.

## The only exactly pinned dependency is the native indicator library

The dependency list has twenty-one entries. Twenty of them are ranges: a caret, a major floor, something in between. One is an exact version, with no operator at all.

That one is the technical analysis library, pinned to a specific version. It is also the only dependency in the list that is not pure JavaScript: it wraps a compiled C library, which is why the README's optional preinstall step is a build toolchain install with administrative privileges.

So the project's hardest dependency to install is the one it pins hardest, and the dependency it pins hardest is the one whose installation needs a compiler on the machine. That is a defensible choice, since a native library is exactly the kind of thing where an unexpected minor release can break the binding. It is also the dependency most likely to fail on a new platform, because a new interpreter or a new node version is a new prebuilt binary or a new compile.

The list also contains a pure-JavaScript indicator library alongside it, at a range. So there are two implementations of technical analysis in one manifest, one native and pinned, one JavaScript and floating, and the README lists both under its technical packages without saying which one a strategy uses or whether the choice is yours.

Two more entries worth pairing. There are two email libraries, one at a range and one older, and the feature list promises email notifications without saying which one sends them. And the date library in the list is a long-established one that has been in maintenance mode for years, sitting in a dependency set that otherwise reaches for current majors of the web framework and the database driver.

## Two documentation directories, two front-end directories, and a dockerignore with no Dockerfile

The repository root has twenty-two entries. Four of them exist in pairs that should probably not both exist.

There is a docs directory and a documentation directory. Both, at the top level, with the same purpose implied by both names. A reader landing on the repository has no way to tell which one is current, and a contributor has no guidance about where to put a new page.

There is a views directory and a web directory. The manifest's templating dependencies explain the first: server-side template layouts for the web interface. The second is presumably the compiled front-end assets, which is a normal split.

There is a docker ignore file and no Dockerfile. That one is unambiguous. The file that lists what must never enter the container image exists at the root of a repository with no container recipe in it, so whatever image people do build from this, the exclusion list was written for a Dockerfile that is not here. The README does not describe a Docker deployment at all, so the ignore file is a leftover pointing at a build that has moved or not yet arrived.

Two more root entries are of a kind this project has several of: an agent instructions file and a Claude instructions file, side by side, alongside a code of conduct that the README never links. And the source entry point, a TypeScript file, sits at the root next to a bundler configuration module.

The manifest adds one inconsistency of its own. Its main field points at a JavaScript file at the repository root, while its binary field points at a file inside the built output directory. Two fields, two different answers to where this package starts.

## The start script rebuilds the production bundle every time it starts

The documented start sequence is short:

```
npm install --production
npm start
```

Then a comment showing how to use a different port, then a line telling you to open a browser at the loopback address on 8080.

What that first command actually does is more than start. The start script is not a start script; it is a build followed by a start. It runs the production bundler invocation, and only if that succeeds does it run the built output with a trade subcommand.

The consequence is that every start compiles. A crash and restart, a configuration change and restart, a service manager bringing the process back after a reboot, a container restart policy firing: each of those runs a full production bundle build before the bot does anything. It is slower than it needs to be, and more to the point it makes the process unable to start on a machine where the build cannot complete, even though the previous build output is sitting right there.

The port comment is worth a note because it depends on that ordering. Passing extra arguments after the start command appends them to the end of the script string, so the port reaches the built program rather than the bundler. That works, but it works by accident of how the arguments are appended to a two-part command, and it is not documented as anything other than a comment.

The manifest does have two development scripts that run the TypeScript source directly through a loader, one of them in watch mode. Those are the fast path, and they are not in the README.

## Custom strategies are JavaScript files in a TypeScript codebase, under a directory named var

The custom strategy instructions are a comment block showing a file layout:

```
# simple file structure
var/strategies/your_strategy.js

# or wrap strategy into any sub folder depth
var/strategies/my_strategy/my_strategy.js
```

Two things about that. The first is the extension: a strategy is a JavaScript file.

Everything else in this repository is TypeScript. The entry point is a TypeScript file, the source tree is TypeScript, the tests are split between TypeScript and JavaScript files, the build has a dedicated TypeScript compiler path, and the development scripts run the source through a loader that handles TypeScript. A strategy you write is a JavaScript file that the TypeScript process loads at run time. That works, because the loader handles both, and it means your strategy sits outside the project's type checking with no interface to check it against.

The second is the directory. The strategies go in a directory called var, which in most toolchains means generated output or scratch state rather than hand-written source. Nothing in the README says that directory is tracked, so whether your strategy survives a fresh clone depends on a rule the documentation never states.

The nesting rule is the generous part. A strategy can sit directly in the folder or be wrapped in a subdirectory of any depth, and the example shows both, so an organisation with many strategies has somewhere obvious to put them.

The features list calls this profile-based bot management with strategy execution, which is a much grander phrase than what the README then explains. What is actually documented is a folder, a file extension, and two possible locations.

## Conclusion

Read it as the reference implementation its README says it is, and note that its own bundled strategies are described as usually unprofitable, so the framework is the deliverable rather than the strategies. Two things to settle before you run it. The dashboard can place manual orders and the only access control described is basic auth, so put TLS in front of it and treat the loopback binding as the real boundary. And the start command rebuilds the production bundle every time, so plan your restarts accordingly. Whatever you trade with, drive it yourself: the Telegram setup has you admitting a third-party bot into your notification group to read out a chat id, and there is a simpler way to get that value.

## FAQ

### How do I run the Haehnchen crypto trading bot?

Install a C toolchain first if you need one, with apt-get install build-essential, then run npm install --production and npm start, and open http://127.0.0.1:8080 in a browser. A different port is passed by adding it after the start command, as npm start -- --port=55555.

### Is the Haehnchen crypto trading bot production ready?

The README says not production ready, only basic functionality. The repository description calls it the public edition, the manifest version is 0.1.0, and the repository publishes no GitHub releases at all.

### Which exchanges does the Haehnchen crypto trading bot support?

Through the CCXT library, which the README describes as covering more than 100 exchanges. The repository description names Bitfinex, Bitmex, Binance and Bybit, and those four also appear as keywords in the manifest.

### How do I protect the crypto trading bot's web dashboard?

The README says the webserver provides just basic auth and suggests putting an nginx proxy with TLS in front of it, with a sample server block proxying to 127.0.0.1:8080 on port 443. The visible dependency list includes basic-auth, compression and cookie-parser, and no session, CSRF or security-header middleware.

### How do I write my own strategy for the crypto trading bot?

Put a JavaScript file into var/strategies, either directly or wrapped in a subdirectory of any depth. The project's own code is TypeScript, so a custom strategy is loaded at run time by a TypeScript process and is outside its type checking.

### What do the bundled crypto trading strategies do?

The README says the common strategies built on indicators are inside and that most of the time they are not profitable, and points to more advanced strategies instead. Two are named: a dip catcher, and a dollar-cost-averaging dip investor strategy described in bold as long term invest.

## Sources

- [Haehnchen/crypto-trading-bot on GitHub](https://github.com/Haehnchen/crypto-trading-bot)
- [Issues](https://github.com/Haehnchen/crypto-trading-bot/issues)
- [License: MIT](https://github.com/Haehnchen/crypto-trading-bot/blob/master/LICENSE)
- [README](https://github.com/Haehnchen/crypto-trading-bot/blob/master/README.md)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/haehnchen-crypto-trading-bot
