hedgefund

command
v0.4.21 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 25, 2026 License: MIT Imports: 23 Imported by: 0

README

hedgefund

A four-agent "hedge fund" system for the Solana trading bot in git.noncepad.com/pkg/optimizer (specifically its multimodelv1 mode -- see optimizer/cmd/multimodel.go), built on eino: one agent for risk, one for P&L, one for research, and one fund manager (compose.Workflow) that fans all three into a single synthesized decision.

This is a standalone CLI, runnable today (see Usage below) -- not a library waiting on a caller. For the other, independently built hedge-fund implementation (gitlab.noncepad.com/eflam/wiki/client/hedgefund, compose.Workflow-based text-to-SQL risk/pnl agents, gated real trigger access), see Relationship to go-wiki/client/hedgefund below -- that one's README documents its own, different status.

Status

All four agent objects are built and tested (29 passing tests, go build/go vet clean):

File Agent Shape
risk.go risk react.NewAgent ReAct loop over optimizer/harness's live state.Client wallet tools
pnl.go P&L react.NewAgent ReAct loop over one tool wrapping optimizer/prefetch/pnl.PositionsBetween
research.go research react.NewAgent ReAct loop over local-file tools (PDF/txt/md)
manager.go fund manager compose.Workflow fanning risk/pnl/research (from compose.START) into one synthesis node

The fund manager never has real trigger access, at all, full stop. FundDecision mirrors optimizer/cmd/multimodel.go's own CLI flags field-for-field so a human can translate it directly into the real command they'd run by hand -- but this package never calls that command or holds a multimodelv1.Hook. There is no gate to bypass here because there is no trigger tool in this package to begin with -- a stronger guarantee than "gated" (compare go-wiki/client/hedgefund's fund manager, which does hold real trigger tools behind a *TriggerGate). Every manager run prints a PROPOSAL ONLY banner ahead of whatever it proposes.

../contrib/hedgefund/Dockerfile is an unfinished stub (FROM registry.noncepad.com/eflam/solpipe-terminal/run:dev, nothing else yet) -- there is no working container image for this today, only the go run usage below. Go source lives here, in hedgefund/; contrib/hedgefund/ holds only the Dockerfile, per this repo's convention that contrib/ subdirectories are for Dockerfiles and other non-code files, never Go source.

Usage

cd optimizer/hedgefund
go run . -node risk     -prompt "What's our real risk exposure right now?"
go run . -node pnl      -prompt "How has our value changed over the last week?"
go run . -node research -papers-dir /path/to/papers -prompt "Any new model ideas?"
go run . -node manager  -papers-dir /path/to/papers -prompt "Should we do anything right now?"

-prompt is optional for every node -- each has a sensible default question (see main.go) if left blank.

Prerequisites
  • A reachable Ollama server with a tool-calling-capable model pulled (default qwen3-coder:30b at http://localhost:21434). Override with -model/-ollama-url. A smaller model (e.g. qwen2.5:7b) will run, but live-verified this session to reason less reliably about the numbers its own tools hand it -- worth knowing before trusting a manager proposal from a weaker model.
  • risk/manager additionally need a reachable catscope state endpoint (-state-url, required, tcp://ip:port or unix:///path) -- the same internal gRPC/geyser-backed state.Client graph the live trading bot itself reads through (git.noncepad.com/pkg/bot/state), not the public Solana RPC endpoint -- plus Jupiter price API access (no flag needed, a plain HTTPS call) and a wallet to inspect (-wallet, defaults to harness.DefaultWallet -- the real trading child wallet this whole session's work centered on; public key only, no private key ever needed since every tool is read-only).
  • pnl/manager additionally need a real prefetch.db (-db, defaults to ~/.optimizer/prefetch.db) -- the same database optimizer watch-pnl/the live trading bot itself writes to. An empty or missing database isn't an error; pnl just reports "no positions recorded."
  • research/manager additionally read a local directory (-papers-dir, defaults to ~/.optimizer/research-papers) of .pdf/.txt/.md files, flat (not recursive). An empty or missing directory isn't an error either; research just reports nothing to propose.

All four flags above (-state-url, -wallet, -db, -papers-dir) plus -model/-ollama-url/-timeout are shared across every -node value; each node only actually uses the ones it needs.

Example
$ go run . -node manager -papers-dir ~/research -prompt "Should we open any new positions?"
wallet: Hg2p3cfmg3dratEVy94JArTVM7KzEywgNdmFnrfhroh9
> Should we open any new positions?

=== PROPOSAL ONLY -- no real transaction has been sent ===

Rationale: <the model's reasoning over the real risk/pnl/research findings>

  PROPOSED: enable_directional_trading (target So1111...)

or, when the model decides nothing is warranted:

  (no action proposed)

Testing

Every node has its own _test.go (29 tests total). Agent construction and round-trip/error-propagation tests use fakeToolCallingModel (fake_model_test.go) -- deterministic, no live Ollama/network needed. Where real local infrastructure is cheap and worth exercising for real rather than mocking, tests use it directly: pnl_test.go seeds a real temp SQLite database (newTestStore, same pattern go-wiki/client/hedgefund's own tests use) with real pnl_position_snapshot rows; research_test.go writes real temp files, including a real path-traversal attempt against a real file placed just outside the configured directory, to prove resolvePaperPath's guard actually blocks it rather than just asserting the string check fires in isolation. manager_test.go builds BuildFundManagerWorkflow (the testable graph-wiring function -- see its own doc comment) with three stub agents and confirms the fan-in wiring is correct by giving each stub a unique marker response and checking all three reach the fund_manager node's prompt in the right order; this was verified to actually catch a broken mapping (a field-mapping swap was tried by hand once and confirmed to fail the test) before being reverted.

Live network/RPC/Ollama calls are never made in go test -- only via go run per Usage above.

Relationship to go-wiki/client/hedgefund

See that package's own README for the full comparison table. Short version: same four-agent shape, different choices throughout (live state.Client graph reads vs. persisted-snapshot data, ReAct-tool-calling vs. text-to-SQL agent shape, no trigger access at all here vs. hard-gated real trigger access there). Neither supersedes the other; nobody has yet decided whether or how to converge them.

Documentation

Overview

Command hedgefund is the multi-agent hedge-fund system built on top of optimizer/harness. All four agent objects are wired up: risk (risk.go), P&L (pnl.go), and research (research.go) each run standalone as a react.NewAgent ReAct loop; fund manager (manager.go) is the compose.Workflow that fans all three into one synthesized FundDecision -- a proposal only, never a real trigger (see manager.go's own top doc comment for why this package deliberately never gets real trigger access at all, unlike gitlab.noncepad.com/eflam/wiki/client/hedgefund's gated-but-present trigger tools).

Usage:

go run . -node risk     -prompt "What's our real risk exposure right now?"
go run . -node pnl      -prompt "How has our value changed over the last week?"
go run . -node research -prompt "Any new model ideas in the papers directory?"
go run . -node manager  -prompt "Should we do anything right now?"

manager.go is the fourth and last of the four hedge-fund agent objects: the fund manager. Unlike risk.go/pnl.go/research.go (each a standalone react.NewAgent ReAct loop), this is the compose.Workflow this whole package's design was originally scoped around: research, risk, and pnl run as independent, concurrent nodes fanning into one fund_manager node that weighs all three and produces a decision -- same fan-in shape go-wiki/client/hedgefund's own workflow.go uses (AddLambdaNode + AddInputWithOptions field mappings, wf.End()).

Real, deliberate design decision, consistent with this whole package's posture (see README/design notes this was scoped from): the fund manager here NEVER gets trigger access. FundDecision is a plain data structure mirroring optimizer/cmd/multimodel.go's own MultiModelCmd flags -- a proposal for a human to read and decide whether to act on, not something wired to a real multimodelv1.Hook at all. There is no gate to bypass here because there is no trigger tool in this package, full stop -- a stronger guarantee than "gated," since there's no code path to a real transaction to gate in the first place. (Compare go-wiki/client/hedgefund's own fund manager, which does hold gated trigger tools behind a *TriggerGate -- see that package's README for why the two hedge-fund builds took different approaches here.)

pnl.go is the second of the four hedge-fund agent objects: the P&L agent. Unlike risk.go (which reads live on-chain state via harness.WalletTools), this agent reads *recorded history* -- prefetch.db's pnl_position_snapshot table, the same data source this session's own "how much did I start with last week" investigation used by hand, now wrapped as a proper tool via the already-real prefetch/pnl package (pnl.PositionsBetween) rather than hand-rolled SQL. See optimizer/cmd/pnlbetween.go for the CLI equivalent this tool's formatting is adapted from.

research.go is the third of the four hedge-fund agent objects: the research agent. It reads local PDF/text/markdown files from a configured directory and proposes candidate trading-model ideas grounded in their content -- same ReAct-agent-over-narrow-tools shape as risk.go/pnl.go, not the batch load-everything-then-one-Generate-call shape optimizer/../go-wiki/client/hedgefund's own research.go uses (that package's own README documents why these two hedge-fund builds deliberately took different approaches to the same problem).

Uses eino's own document-parsing primitives rather than hand-rolling text extraction: eino core's parser.TextParser for .txt/.md, eino-ext's pure-Go PDF parser (github.com/ledongthuc/pdf underneath, no external binary needed) for .pdf.

Package main (hedgefund) is the real trading wallet's risk- analysis agent -- the first of the four agent objects from the hedge-fund design (fund manager, risk, P&L, research), built as a compose.Workflow node per that design's sketch. It is deliberately READ-ONLY: it reuses harness.WalletTools verbatim (see optimizer/harness/tools.go) rather than inventing its own on-chain queries, so this agent sees exactly what a human checking the wallet by hand would see -- the same check_obligations/get_wallet_balances/ get_portfolio_value_usd tools proven live against this exact wallet during the session this design was distilled from.

The persona below encodes the real risk mechanics of catscope-rust- bot's multimodelv1 mode (see optimizer/cmd/multimodel.go's own doc comment): pair, directional, and hawkes trade types all really borrow on Kamino/Solend for their short legs (real liquidation exposure); dispersion instead shorts via a real Phoenix SOL-PERP position (real funding-rate/margin exposure, not a lending-protocol borrow). A risk assessment that doesn't know this distinction can't reason about what's actually at stake in what it's looking at.

Source Files

  • main.go
  • manager.go
  • pnl.go
  • research.go
  • risk.go

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL