diff --git a/java-examples/src/main/java/bisq/bots/TakeBestPricedOfferToSellBsq.java b/java-examples/src/main/java/bisq/bots/TakeBestPricedOfferToSellBsq.java index 5622119..c8084b0 100644 --- a/java-examples/src/main/java/bisq/bots/TakeBestPricedOfferToSellBsq.java +++ b/java-examples/src/main/java/bisq/bots/TakeBestPricedOfferToSellBsq.java @@ -32,7 +32,52 @@ import static java.math.RoundingMode.HALF_UP; import static protobuf.OfferDirection.BUY; /** - * Bot for buying BSQ with BTC at an attractive (lower) price. The bot receives BSQ for BTC. + * This bot's general use case is to buy BSQ with BTC at a low BTC price. It periodically checks the + * Sell BSQ (Buy BTC) market, and takes a configured maximum number of offers to buy BSQ from you according to criteria + * you define in the bot's configuration file: TakeBestPricedOfferToSellBsq.properties (located in project's + * src/main/resources directory). You will need to replace the default values in the configuration file for your + * use cases. + *
+ * After the maximum number of BSQ swap offers have been taken (good to start with 1), the bot will shut down. The API
+ * daemon will not be shut down because swaps do not require additional payment related steps taken outside Bisq, or
+ * in the GUI.
+ *
+ * Here is one possible use case: + *
+ * Take 5 BSQ swap offers to sell BSQ for BTC, priced no higher than -1.00% below the 30-day average BSQ price if: + * + * the offer's BTC amount is between 0.10 and 0.25 BTC + * the offer maker is one of two preferred trading peers + * the current transaction mining fee rate is less than or equal 25 sats / byte + * + * The bot configurations for these rules are set in TakeBestPricedOfferToSellBsq.properties as follows: + * + * maxTakeOffers=5 + * minMarketPriceMargin=-1.00 + * minAmount=0.10 + * maxAmount=0.25 + * preferredTradingPeers=preferred-address-1.onion:9999,preferred-address-2.onion:9999 + * maxTxFeeRate=25 + *+ * Usage + *
+ * You must encrypt your wallet password before running this bot. If it is not already encrypted, you can use the CLI:
+ *
+ * $ ./bisq-cli --password=xyz --port=9998 setwalletpassword --wallet-password="be careful" + *+ * There are some {@link bisq.bots.Config program options} common to all the Java bot examples, passed on the command + * line. The only one you must provide (no default value) is your API daemon's password option: + * `--password
+ * You can pass the '--dryrun=true' option to the program to see what offers your bot would take with a given
+ * configuration. This will help you avoid taking offers by mistake.
+ *
+ * TakeBestPricedOfferToBuyBsq --password=api-password --port=api-port [--dryrun=true|false] + *+ *
+ * The '--simulate-regtest-payment=true' option is ignored by this bot. Taking a swap triggers execution of the swap.
+ *
+ * @see bisq.bots.Config.java
*/
@Slf4j
@Getter
@@ -99,7 +144,8 @@ public class TakeBestPricedOfferToSellBsq extends AbstractBot {
continue;
}
- // Get all available and takeable offers, sorted by price ascending.
+ // Get all available buy BTC with BSQ offers, sorted by price ascending.
+ // The list contains only fixed-priced offers.
var offers = getOffers(BUY.name(), CURRENCY_CODE).stream()
.filter(o -> !isAlreadyTaken.test(o))
.toList();
@@ -125,7 +171,6 @@ public class TakeBestPricedOfferToSellBsq extends AbstractBot {
takeCriteria.printOfferAgainstCriteria(cheapestOffer);
});
- printDryRunProgress();
runCountdown(log, pollingInterval);
pingDaemon(startTime);
}
@@ -134,17 +179,21 @@ public class TakeBestPricedOfferToSellBsq extends AbstractBot {
private void takeOffer(TakeCriteria takeCriteria, OfferInfo offer) {
log.info("Will attempt to take offer '{}'.", offer.getId());
takeCriteria.printOfferAgainstCriteria(offer);
+
+ // An encrypted wallet must be unlocked before calling takeoffer and gettrade(s).
+ // Unlock the wallet for 5 minutes. If the wallet is already unlocked, this request
+ // will override the timeout of the previous unlock request.
+ try {
+ unlockWallet(walletPassword, 300);
+ } catch (NonFatalException nonFatalException) {
+ handleNonFatalException(nonFatalException, pollingInterval);
+ }
+
if (isDryRun) {
addToOffersTaken(offer);
numOffersTaken++;
- maybeShutdownAfterSuccessfulSwap(numOffersTaken, maxTakeOffers);
} else {
- // An encrypted wallet must be unlocked before calling takeoffer and gettrade.
- // Unlock the wallet for 10 minutes. If the wallet is already unlocked,
- // this command will override the timeout of the previous unlock command.
try {
- unlockWallet(walletPassword, 600);
-
printBTCBalances("BTC Balances Before Swap Execution");
printBSQBalances("BSQ Balances Before Swap Execution");
@@ -155,13 +204,13 @@ public class TakeBestPricedOfferToSellBsq extends AbstractBot {
printBSQBalances("BSQ Balances After Swap Execution");
numOffersTaken++;
- maybeShutdownAfterSuccessfulSwap(numOffersTaken, maxTakeOffers);
} catch (NonFatalException nonFatalException) {
handleNonFatalException(nonFatalException, pollingInterval);
} catch (StatusRuntimeException fatalException) {
handleFatalBsqSwapException(fatalException);
}
}
+ maybeShutdownAfterSuccessfulSwap(numOffersTaken, maxTakeOffers);
}
private void printBotConfiguration() {
@@ -169,6 +218,7 @@ public class TakeBestPricedOfferToSellBsq extends AbstractBot {
configsByLabel.put("Bot OS:", getOSName() + " " + getOSVersion());
var network = getNetwork();
configsByLabel.put("BTC Network:", network);
+ configsByLabel.put("Dry Run?", isDryRun ? "YES" : "NO");
var isMainnet = network.equalsIgnoreCase("mainnet");
var mainnet30DayAvgBsqPrice = isMainnet ? get30DayAvgBsqPriceInBtc() : null;
configsByLabel.put("My Payment Account:", "");
@@ -226,7 +276,6 @@ public class TakeBestPricedOfferToSellBsq extends AbstractBot {
this.targetPrice = calcTargetBsqPrice(maxMarketPriceMargin, avgBsqPrice);
}
-
/**
* Returns the lowest priced offer passing the filters, or Optional.empty() if not found.
* Max tx fee rate filtering should have passed prior to calling this method.
@@ -277,7 +326,7 @@ public class TakeBestPricedOfferToSellBsq extends AbstractBot {
var filterResultsByLabel = new LinkedHashMap