Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Binaries
/trading-cli
/fetch-symbols
*.exe
*.exe~
*.dll
Expand Down Expand Up @@ -33,3 +34,7 @@ Thumbs.db
# Build
dist/
build/

# Folders
logs/
local/
3 changes: 0 additions & 3 deletions .goreleaser.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,6 @@ release:
go install github.com/alorse/trading-cli/cmd/trading-cli@{{.Tag}}
```

### Binary download
Download the appropriate binary for your platform from the assets below.

brews:
- name: trading-cli
repository:
Expand Down
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,15 @@ Download pre-built binaries for your platform from the [releases page](https://g
# Top gainers on KuCoin
trading-cli top-gainers --exchange KUCOIN --timeframe 15m --limit 10

# Top gainers on Binance Futures
trading-cli top-gainers --exchange BINANCE --timeframe 15m --limit 10 --futures

# Full analysis of Bitcoin
trading-cli coin-analysis --symbol BTCUSDT --exchange KUCOIN --timeframe 1h

# Analysis of a perpetual futures symbol
trading-cli coin-analysis --symbol BTCUSDT.P --exchange BINANCE --timeframe 1h

# Backtest RSI strategy on Apple
trading-cli backtest-strategy --symbol AAPL --strategy rsi --period 1y

Expand Down
27 changes: 22 additions & 5 deletions cmd/fetch-symbols/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package main
import (
"bytes"
"encoding/json"
"flag"
"fmt"
"io/fs"
"net/http"
Expand All @@ -16,6 +17,10 @@ const (
pageSize = 500
)

var (
futures bool
)

var exchanges = []string{
"KUCOIN", "BINANCE", "BYBIT", "OKX", "BITGET",
"COINBASE", "GATE", "MEXC", "HTX", "BITFINEX",
Expand Down Expand Up @@ -60,10 +65,15 @@ func fetchSymbols(exchange string) ([]string, error) {
offset := 0

for {
marketType := "spot"
if futures {
marketType = "swap"
}

reqBody := scanRequest{
Filter: []scanFilter{
{Left: "exchange", Operation: "equal", Right: exchange},
{Left: "type", Operation: "equal", Right: "spot"},
{Left: "type", Operation: "equal", Right: marketType},
},
Symbols: scanSymbolsQuery{Query: scanQueryTypes{Types: []string{}}},
Columns: []string{"name"},
Expand Down Expand Up @@ -118,9 +128,12 @@ func fetchSymbols(exchange string) ([]string, error) {
}

func main() {
dataDir := os.Args[1]
if dataDir == "" {
dataDir = "pkg/tools/screener/data"
flag.BoolVar(&futures, "futures", false, "Fetch futures/perpetual symbols")
flag.Parse()

dataDir := "pkg/tools/screener/data"
if args := flag.Args(); len(args) > 0 {
dataDir = args[0]
}

// Verify directory exists
Expand All @@ -138,7 +151,11 @@ func main() {
os.Exit(1)
}

filename := fmt.Sprintf("%s/%s.txt", strings.TrimRight(dataDir, "/"), strings.ToLower(exchange))
suffix := ""
if futures {
suffix = "_futures"
}
filename := fmt.Sprintf("%s/%s%s.txt", strings.TrimRight(dataDir, "/"), strings.ToLower(exchange), suffix)
content := strings.Join(symbols, "\n") + "\n"

if err := os.WriteFile(filename, []byte(content), fs.FileMode(0644)); err != nil {
Expand Down
24 changes: 16 additions & 8 deletions cmd/trading-cli/stubs.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,19 +50,21 @@ func runTopGainers(cfg *config.Config) error {
exchange := fs.String("exchange", "BINANCE", "Exchange name")
timeframe := fs.String("timeframe", "1D", "Timeframe")
limit := fs.Int("limit", 10, "Number of results")
futures := fs.Bool("futures", false, "Use futures/perpetual symbols")
fs.Parse(os.Args[2:])

return screener.RunTopGainers(cfg, *exchange, *timeframe, *limit)
return screener.RunTopGainers(cfg, *exchange, *timeframe, *limit, *futures)
}

func runTopLosers(cfg *config.Config) error {
fs := flag.NewFlagSet("top-losers", flag.ContinueOnError)
exchange := fs.String("exchange", "BINANCE", "Exchange name")
timeframe := fs.String("timeframe", "1D", "Timeframe")
limit := fs.Int("limit", 10, "Number of results")
futures := fs.Bool("futures", false, "Use futures/perpetual symbols")
fs.Parse(os.Args[2:])

return screener.RunTopLosers(cfg, *exchange, *timeframe, *limit)
return screener.RunTopLosers(cfg, *exchange, *timeframe, *limit, *futures)
}

func runBollingerScan(cfg *config.Config) error {
Expand All @@ -71,9 +73,10 @@ func runBollingerScan(cfg *config.Config) error {
timeframe := fs.String("timeframe", "4h", "Timeframe")
bbwThreshold := fs.Float64("bbw-threshold", 0.04, "Bollinger Band Width threshold")
limit := fs.Int("limit", 10, "Number of results")
futures := fs.Bool("futures", false, "Use futures/perpetual symbols")
fs.Parse(os.Args[2:])

return screener.RunBollingerScan(cfg, *exchange, *timeframe, *bbwThreshold, *limit)
return screener.RunBollingerScan(cfg, *exchange, *timeframe, *bbwThreshold, *limit, *futures)
}

func runRatingFilter(cfg *config.Config) error {
Expand All @@ -82,9 +85,10 @@ func runRatingFilter(cfg *config.Config) error {
timeframe := fs.String("timeframe", "4h", "Timeframe")
rating := fs.Int("rating", 2, "Bollinger Band rating (-3 to 3)")
limit := fs.Int("limit", 10, "Number of results")
futures := fs.Bool("futures", false, "Use futures/perpetual symbols")
fs.Parse(os.Args[2:])

return screener.RunRatingFilter(cfg, *exchange, *timeframe, *rating, *limit)
return screener.RunRatingFilter(cfg, *exchange, *timeframe, *rating, *limit, *futures)
}

// Analysis tools
Expand Down Expand Up @@ -112,9 +116,10 @@ func runConsecutiveCandles(cfg *config.Config) error {
patternType := fs.String("pattern-type", "bullish", "Pattern type (bullish/bearish)")
minGrowth := fs.Float64("min-growth", 2.0, "Minimum growth percentage")
limit := fs.Int("limit", 10, "Number of results")
futures := fs.Bool("futures", false, "Use futures/perpetual symbols")
fs.Parse(os.Args[2:])

return patterns.RunConsecutiveCandles(cfg, *exchange, *timeframe, *patternType, *minGrowth, *limit)
return patterns.RunConsecutiveCandles(cfg, *exchange, *timeframe, *patternType, *minGrowth, *limit, *futures)
}

func runAdvancedCandle(cfg *config.Config) error {
Expand All @@ -123,9 +128,10 @@ func runAdvancedCandle(cfg *config.Config) error {
baseTimeframe := fs.String("base-timeframe", "4h", "Base timeframe")
minSizeIncrease := fs.Float64("min-size-increase", 10.0, "Minimum size increase percentage")
limit := fs.Int("limit", 10, "Number of results")
futures := fs.Bool("futures", false, "Use futures/perpetual symbols")
fs.Parse(os.Args[2:])

return patterns.RunAdvancedCandle(cfg, *exchange, *baseTimeframe, *minSizeIncrease, *limit)
return patterns.RunAdvancedCandle(cfg, *exchange, *baseTimeframe, *minSizeIncrease, *limit, *futures)
}

// Volume tools
Expand All @@ -137,9 +143,10 @@ func runVolumeBreakout(cfg *config.Config) error {
volumeMultiplier := fs.Float64("volume-multiplier", 2.0, "Volume multiplier")
priceChangeMin := fs.Float64("price-change-min", 3.0, "Minimum price change percentage")
limit := fs.Int("limit", 10, "Number of results")
futures := fs.Bool("futures", false, "Use futures/perpetual symbols")
fs.Parse(os.Args[2:])

return volume.RunVolumeBreakout(cfg, *exchange, *timeframe, *volumeMultiplier, *priceChangeMin, *limit)
return volume.RunVolumeBreakout(cfg, *exchange, *timeframe, *volumeMultiplier, *priceChangeMin, *limit, *futures)
}

func runVolumeConfirmation(cfg *config.Config) error {
Expand All @@ -163,9 +170,10 @@ func runSmartVolume(cfg *config.Config) error {
minPriceChange := fs.Float64("min-price-change", 2.0, "Minimum price change percentage")
rsiRange := fs.String("rsi-range", "any", "RSI range (any/oversold/neutral/overbought)")
limit := fs.Int("limit", 10, "Number of results")
futures := fs.Bool("futures", false, "Use futures/perpetual symbols")
fs.Parse(os.Args[2:])

return volume.RunSmartVolume(cfg, *exchange, *minVolumeRatio, *minPriceChange, *rsiRange, *limit)
return volume.RunSmartVolume(cfg, *exchange, *minVolumeRatio, *minPriceChange, *rsiRange, *limit, *futures)
}

// Multi-timeframe
Expand Down
Loading
Loading