知識庫 / Spring / Spring Boot RSS 訂閱

構建基於 Cassandre Spring Boot Starter 的交易機器人

Spring Boot
HongKong
11
12:32 PM · Dec 06 ,2025

1. 概述

交易機器人是一種可以自動在市場或交易所下單的計算機程序,無需人工干預。

在本教程中,我們將使用 Cassandre 創建一個簡單的加密貨幣交易機器人,該機器人將在我們認為的最佳時機生成頭寸。

2. 機器人概述

交易是指“互相交換一件物品來換取另一件物品”。

在金融市場中,它指的是購買股票、期貨、期權、互換、債券,或者像我們案例中那樣,購買一定數量的加密貨幣。 這裏的想法是在特定價格購買加密貨幣,然後在更高的價格出售以獲利(即使在價格下跌的情況下,通過空頭頭寸也能獲利)。

我們將使用沙盒交易所;沙盒是一個虛擬系統,其中我們擁有“假”資產,可以下達訂單並接收報價單。

首先,讓我們看看我們將做什麼:

  • 將 Cassandre Spring Boot Starter 添加到我們的項目
  • 添加必要的配置以連接到交易所
  • 創建一個策略:
    • 接收來自交易所的報價單
    • 選擇何時購買
    • 在合適的時間購買時,檢查是否有足夠的資產並創建頭寸
    • 顯示日誌以查看頭寸何時打開/關閉以及我們賺了多少收益
  • 運行對歷史數據的測試,以查看我們是否可以盈利

3. Maven 依賴

讓我們從添加必要的依賴項到我們的 <em >pom.xml</em> 開始,首先添加 Cassandre spring boot starter

<dependency>
    <groupId>tech.cassandre.trading.bot</groupId>
    <artifactId>cassandre-trading-bot-spring-boot-starter</artifactId>
    <version>4.2.1</version>
</dependency>

Cassandre 依賴 XChange 來連接加密貨幣交易所。對於本教程,我們將使用 Kucoin XChange 庫

<dependency>
    <groupId>org.knowm.xchange</groupId>
    <artifactId>xchange-kucoin</artifactId>
    <version>5.0.8</version>
</dependency>

我們還使用 hsqldb 來存儲數據:

<dependency>
    <groupId>org.hsqldb</groupId>
    <artifactId>hsqldb</artifactId>
    <version>2.5.2</version>
</dependency>

為了測試我們的交易機器人與歷史數據的對比,我們還添加了我們的 Cassandre Spring Boot 測試啓動器

<dependency>
    <groupId>tech.cassandre.trading.bot</groupId>
    <artifactId>cassandre-trading-bot-spring-boot-starter-test</artifactId>
    <version>4.2.1</version>
    <scope>test</scope>
</dependency>

4. 配置

讓我們編輯創建 application.properties 以設置我們的配置:

# Exchange configuration
cassandre.trading.bot.exchange.name=kucoin
cassandre.trading.bot.exchange.username=kucoin.cassandre.test@gmail.com
cassandre.trading.bot.exchange.passphrase=cassandre
cassandre.trading.bot.exchange.key=6054ad25365ac6000689a998
cassandre.trading.bot.exchange.secret=af080d55-afe3-47c9-8ec1-4b479fbcc5e7

# Modes
cassandre.trading.bot.exchange.modes.sandbox=true
cassandre.trading.bot.exchange.modes.dry=false

# Exchange API calls rates (ms or standard ISO 8601 duration like 'PT5S')
cassandre.trading.bot.exchange.rates.account=2000
cassandre.trading.bot.exchange.rates.ticker=2000
cassandre.trading.bot.exchange.rates.trade=2000

# Database configuration
cassandre.trading.bot.database.datasource.driver-class-name=org.hsqldb.jdbc.JDBCDriver
cassandre.trading.bot.database.datasource.url=jdbc:hsqldb:mem:cassandre
cassandre.trading.bot.database.datasource.username=sa
cassandre.trading.bot.database.datasource.password=

配置包含四個類別:

  • 交易所配置:我們為建立與 Kucoin 現有沙盒賬户的連接設置的交易所憑據。
  • 模式:我們希望使用的模式。在本例中,我們要求 Cassandre 使用沙盒數據。
  • 交易所 API 調用速率:指示我們希望從交易所檢索數據的速度(賬户、訂單、交易和報價)。請注意,所有交易所都有我們能夠調用的最大速率。
  • 數據庫配置:Cassandre 使用數據庫來存儲倉位、訂單和交易。對於本教程,我們將使用一個簡單的 hsqld 內存數據庫。當然,在生產環境中,我們應該使用持久化數據庫。

現在,讓我們在 application.properties 文件中創建相同的文件,位於我們的測試目錄中,但我們將 cassandre.trading.bot.exchange.modes.dry 更改為 true,因為在測試期間,我們不想將真實訂單發送到沙盒。我們只想模擬它們。

5. 策略

一個交易策略是指旨在實現盈利回報的固定計劃;我們可以通過為 Java 類添加帶有 <@CassandreStrategy> 註解以及擴展 <BasicCassandreStrategy> 類來創建我們的策略。

讓我們在 <MyFirstStrategy.java> 中創建我們的策略類:

@CassandreStrategy
public class MyFirstStrategy extends BasicCassandreStrategy {

    @Override
    public Set<CurrencyPairDTO> getRequestedCurrencyPairs() {
        return Set.of(new CurrencyPairDTO(BTC, USDT));
    }

    @Override
    public Optional<AccountDTO> getTradeAccount(Set<AccountDTO> accounts) {
        return accounts.stream()
          .filter(a -> "trade".equals(a.getName()))
          .findFirst();
    }
}

實施 BasicCassandreStrategy 強制我們實現兩個方法:getRequestedCurrencyPairs() & getTradeAccount()

getRequestedCurrencyPairs() 中,我們需要返回我們想要從交易所接收的貨幣對列表。貨幣對是兩種不同貨幣的報價,其中一種貨幣相對於另一種貨幣進行報價。在我們的示例中,我們希望使用 BTC/USDT。

為了更清楚地説明,我們可以使用以下 curl 命令手動檢索報價:

curl -s https://api.kucoin.com/api/v1/market/orderbook/level1?symbol=BTC-USDT

我們將會得到類似的東西:

{
  "time": 1620227845003,
  "sequence": "1615922903162",
  "price": "57263.3",
  "size": "0.00306338",
  "bestBid": "57259.4",
  "bestBidSize": "0.00250335",
  "bestAsk": "57260.4",
  "bestAskSize": "0.01"
}

價格值表明 1 個 BTC 的價格為 57263.3 USDT。

我們還需要實現的方法是 getTradeAccount()。 在交易所,我們通常有幾個賬户,Cassandre 需要知道哪個賬户是交易賬户。為此,我們需要實現 getTradeAccount() 方法,該方法將我們擁有的賬户列表作為參數傳遞給它,然後從該列表中返回我們想要用於交易的賬户。

在我們的示例中,我們的交易賬户在交易所名為 “trade”,因此我們只需返回它。

6. 創建位置

為了接收新的數據通知,我們可以覆蓋 BasicCassandreStrategy 的以下方法:

  • onAccountUpdate() 用於接收關於賬户的更新
  • onTickerUpdate() 用於接收新的報價
  • onOrderUpdate() 用於接收關於訂單的更新
  • onTradeUpdate() )用於接收關於交易的更新
  • onPositionUpdate() 用於接收關於位置的更新
  • onPositionStatusUpdate() 用於接收關於位置狀態變更的更新

在本教程中,我們將實現一個簡單的算法:我們檢查所有接收到的新報價。如果 1 BTC 的價格低於 56 000 USDT,我們認為現在是時候買入

為了簡化收益計算,訂單、交易和關閉,Cassandre 提供了用於自動管理位置的類。

要使用它,第一步是使用 PositionRulesDTO 類創建位置規則,例如:

PositionRulesDTO rules = PositionRulesDTO.builder()
  .stopGainPercentage(4f)
  .stopLossPercentage(25f)
  .create();

然後,我們使用該規則創建職位:

createLongPosition(new CurrencyPairDTO(BTC, USDT), new BigDecimal("0.01"), rules);

此時,卡桑德爾將創建一個0.01 BTC的買單。訂單狀態將變為OPENING,當所有相關的交易到達時,狀態將變為OPENED。從現在開始,對於每一個收到的報價,卡桑德爾將自動計算,結合新的價格,判斷以該價格平倉是否會觸發我們的兩個規則(4%止盈或25%止損)。

如果觸發其中一個規則,卡桑德爾將自動創建一個0.01 BTC的賣單。訂單狀態將變為CLOSING,當所有相關的交易到達時,狀態將變為CLOSED

這是我們將使用的代碼:

@Override
public void onTickerUpdate(TickerDTO ticker) {
    if (new BigDecimal("56000").compareTo(ticker.getLast()) == -1) {

        if (canBuy(new CurrencyPairDTO(BTC, USDT), new BigDecimal("0.01"))) {
            PositionRulesDTO rules = PositionRulesDTO.builder()
              .stopGainPercentage(4f)
              .stopLossPercentage(25f)
              .build();
            createLongPosition(new CurrencyPairDTO(BTC, USDT), new BigDecimal("0.01"), rules);
        }
    }
}

總結如下:

  • 對於每一個新的交易對,我們都會檢查價格是否低於 56000。
  • 如果我們的交易賬户上有足夠的USDT,我們就會開立 0.01 BTC 的頭寸。
  • 從現在開始,對於每一個交易對:
    • 如果使用新價格的計算收益超過 4% 的收益或 25% 的虧損,Cassandre 將會關閉我們通過出售購買的 0.01 BTC 創建的頭寸。

7. 跟蹤日誌中的位置演變

我們將最終實現 <em >onPositionStatusUpdate()</em > 函數,以查看位置的開啓/關閉情況:

@Override
public void onPositionStatusUpdate(PositionDTO position) {
    if (position.getStatus() == OPENED) {
        logger.info("> New position opened : {}", position.getPositionId());
    }
    if (position.getStatus() == CLOSED) {
        logger.info("> Position closed : {}", position.getDescription());
    }
}

8. 回溯測試 (Backtesting)

回溯測試,簡單來説,是指在歷史數據上測試交易策略的過程。Cassandre 交易機器人允許我們模擬機器人對歷史數據的反應。

第一步是將我們的歷史數據(CSV 或 TSV 文件)放在 src/test/resources 文件夾中。

如果我們在 Linux 系統上,這裏有一個簡單的腳本來生成它們:

startDate=`date --date="3 months ago" +"%s"`
endDate=`date +"%s"`
curl -s "https://api.kucoin.com/api/v1/market/candles?type=1day&symbol=BTC-USDT&startAt=${startDate}&endAt=${endDate}" \
| jq -r -c ".data[] | @tsv" \
| tac $1 > tickers-btc-usdt.tsv

它將創建一個名為 tickers-btc-usdt.tsv 的文件,其中包含從 startDate (3 個月前) 到 endDate (現在) 的 BTC-USDT 歷史匯率。

第二步是創建我們的虛擬賬户餘額,以模擬我們想要投資的精確資產數量。

在這些文件中,對於每個賬户,我們設置了每種加密貨幣的餘額。例如,這是模擬我們交易賬户資產的 user-trade.csv 的內容:

此文件也必須位於 src/test/resources 文件夾中。

BTC 1
USDT 10000
ETH 10

現在,我們可以添加一個測試:

@SpringBootTest
@Import(TickerFluxMock.class)
@DisplayName("Simple strategy test")
public class MyFirstStrategyLiveTest {
    @Autowired
    private MyFirstStrategy strategy;

    private final Logger logger = LoggerFactory.getLogger(MyFirstStrategyLiveTest.class);

    @Autowired
    private TickerFluxMock tickerFluxMock;

    @Test
    @DisplayName("Check gains")
    public void whenTickersArrives_thenCheckGains() {
        await().forever().until(() -> tickerFluxMock.isFluxDone());

        HashMap<CurrencyDTO, GainDTO> gains = strategy.getGains();

        logger.info("Cumulated gains:");
        gains.forEach((currency, gain) -> logger.info(currency + " : " + gain.getAmount()));

        logger.info("Position still opened :");
        strategy.getPositions()
          .values()
          .stream()
          .filter(p -> p.getStatus().equals(OPENED))
          .forEach(p -> logger.info(" - {} " + p.getDescription()));

        assertTrue(gains.get(USDT).getPercentage() > 0);
    }
    
}

導入來自TickerFluxMock將加載我們src/test/resources文件夾中的歷史數據,並將其發送到我們的策略。然後我們使用await()方法來確保所有從文件中加載的股票已發送到我們的策略。最後,我們顯示已關閉的頭寸、仍未關閉的頭寸以及全局收益。

9. 結論

本教程闡述瞭如何創建與加密貨幣交易所交互的策略,並將其與歷史數據進行測試。

當然,我們的算法相對簡單;但在實際應用中,目標是找到有前景的技術、好的算法以及可靠的數據,以便我們能夠確定何時建立頭寸。例如,我們可以使用技術分析,就像 Cassandre 所做的那樣,集成 ta4j

user avatar
0 位用戶收藏了這個故事!
收藏

發佈 評論

Some HTML is okay.