Skip to content

Commit

Permalink
* Optimized orderbook visualization
Browse files Browse the repository at this point in the history
* Univeral addressType
* Updated docs
* Configuration for orderbook refreshment
  • Loading branch information
xestrum committed Nov 19, 2020
1 parent 5faaf75 commit 1bfe160
Show file tree
Hide file tree
Showing 10 changed files with 67 additions and 30 deletions.
18 changes: 14 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ A marketmaker bot based on Broxus Nova.
*huckster* helps you to place asynchronous orders in Broxus Nova orderbook using different strategies and price feeds.

## Building

* Clone *huckster* repository with the `git clone` command.
* Go to the repo directory
* Run `./gradlew build` to build the executable
Expand All @@ -14,6 +13,8 @@ A marketmaker bot based on Broxus Nova.
mv ./build/libs/hucksterFat.jar ./huckster.jar
```

**Important:** You need to have `jdk1.8.0_201` installed to build the app. In case it is not the only Java instance on your PC, specify the path to jdk explicitly by adding `-D org.gradle.java.home=<path/to/jdk>` parameter to Gradlew.

## Running

To run *huckster*, use a regular java syntax:
Expand All @@ -22,13 +23,22 @@ java -jar ./huckster.jar [JOB] [PARAMS]
```

### Supported jobs
* `seller` - Sell at the highest possible price
* `seller`<br/>Sell at the highest possible price
* `orderbook`<br/>Visualize existing orderbook

### Runtime parameters
#### `seller` job
* `-k, --keys <FILE>`<br/>Keys to access Broxus Nova platform
* `-s, --strategy <FILE>`<br/>Orders placement strategy configuration
* `-pad, --priceAdapter <FILE>`<br/>Price adapter configuration
* `-pau, --priceAuth <FILE>`<br/>Price adapter authentication file \[optional\]
* `-pau, --priceAuth <FILE>`<br/>Price adapter authentication file \[optional, adapter-dependent\]

#### `orderbook` job
* `-p, --pair <PAIR>`<br/>
Base and counter currency tickers separated by a delimiter.
Supported delimiters: underscore(`_`), dash(`-`) and slash (`/`)
* `-k, --keys <FILE>`<br/>Keys to access Broxus Nova platform
* `-r, --refresh <SECONDS>`<br/>Orderbook refresh rate in seconds \[optional\]. Default: 10

### Supported strategies
* `simple`<br/>
Expand All @@ -47,6 +57,6 @@ See [examples](examples) folder for samples of strategy configuration files.
Goes without saying, fixed prices per different target currencies.

* `googleSheet`<br/>
Sources price feed from a Google Sheet. Requires OAuth 2.0 file downloaded from Google Developer Account.
Sources price feed from a Google Sheet. Requires [OAuth 2.0 file](https://developers.google.com/identity/protocols/oauth2) downloaded from [Google Developer Account](https://console.developers.google.com/).

See [examples](examples) folder for samples of price feed configuration files.
23 changes: 13 additions & 10 deletions src/main/kotlin/com/broxus/huckster/OrdersQueue.kt
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ object OrdersQueue: OrdersQueue {
event.fromCurrency,
event.toCurrency,
event.fromAmount,
event.toAmount
event.toAmount,
"Huckster MM"
)?.let {

logger2(
Expand Down Expand Up @@ -92,7 +93,7 @@ object OrdersQueue: OrdersQueue {
*/
override fun flush(
userAddress: String,
addressType: AddressType,
addressType: String,
workspaceId: String?,
currency: String?
): Boolean {
Expand All @@ -116,9 +117,9 @@ object OrdersQueue: OrdersQueue {
return true
}

override suspend fun drawOrderBook(base: String, counter: String, refreshInterval: Long) {
override suspend fun drawOrderBook(base: String, counter: String, refreshInterval: Int) {
var orderBook: ExchangeOrderBook?
var averagePrice: Float = 0.0F
var averagePrice: Float
var priceMaxLength: Int = 0
var volumeMaxLength: Int = 0
var minAskPrice: Float
Expand All @@ -136,12 +137,12 @@ object OrdersQueue: OrdersQueue {
).apply {
roundingMode = RoundingMode.HALF_UP
}
var outMessage: String = ""
var outMessage: String
val minScale = 1.0F
val maxScale = 11.0F
var interval: Float
var bars: Int
var t: String = ""
var t: String

while(true) {
orderBook = api!!.getOrderBook(base, counter)
Expand Down Expand Up @@ -190,7 +191,7 @@ object OrdersQueue: OrdersQueue {
//println("\u001Bc")

priceColumnWidth = max(priceMaxLength, 5) + 2
volumeColumnWidth = 11 + volumeMaxLength + 3
volumeColumnWidth = 11 + volumeMaxLength + 4

interval = (maxVolume - minVolume) / (maxScale - minScale)

Expand All @@ -205,7 +206,8 @@ object OrdersQueue: OrdersQueue {
bars = ((ask.volume.toFloat() - minVolume) / interval).toInt() + 1
outMessage +=
"" + ask.rate + " ".repeat(priceColumnWidth - ask.rate.length - 1) + "" +
"".repeat(bars).red() + " " + ask.volume.red() + " ".repeat(volumeColumnWidth - bars - ask.volume.length - 2) + "\n"
" ".repeat(volumeMaxLength - ask.volume.length) + ask.volume.red() +
" ".repeat(volumeColumnWidth - bars - volumeMaxLength - 2) + "".repeat(bars).red() + " " + "\n"
}

if(it.asks.count() == 0) {
Expand All @@ -225,7 +227,8 @@ object OrdersQueue: OrdersQueue {
bars = ((bid.volume.toFloat() - minVolume) / interval).toInt() + 1
outMessage +=
"" + bid.rate + " ".repeat(priceColumnWidth - bid.rate.length - 1) + "" +
"".repeat(bars).green() + " " + bid.volume.green() + " ".repeat(volumeColumnWidth - bars - bid.volume.length - 2) + "\n"
" ".repeat(volumeMaxLength - bid.volume.length) + bid.volume.red() +
" ".repeat(volumeColumnWidth - bars - volumeMaxLength - 2) + "".repeat(bars).red() + " " + "\n"
}

if(it.bids.count() == 0) {
Expand All @@ -238,7 +241,7 @@ object OrdersQueue: OrdersQueue {

print(outMessage)

delay(refreshInterval * 1000)
delay(refreshInterval * 1000L)
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/main/kotlin/com/broxus/huckster/interfaces/OrdersQueue.kt
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@ interface OrdersQueue: CoroutineScope {
*/
fun flush(
userAddress: String,
addressType: AddressType,
addressType: String,
workspaceId: String?,
currency: String?
): Boolean

suspend fun drawOrderBook(base: String, counter: String, refreshInterval: Long)
suspend fun drawOrderBook(base: String, counter: String, refreshInterval: Int)
}
36 changes: 30 additions & 6 deletions src/main/kotlin/com/broxus/huckster/main.kt
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ fun main(args: Array<String>) {
var priceAuthPath = ""
var base = ""
var counter = ""
var refreshInterval = 30
val version = "0.3 rev.1"

val greeting =
" \n" +
Expand All @@ -40,6 +42,7 @@ fun main(args: Array<String>) {
" ".yellow()

val usage =
"huckster v.$version\n\n".bold() +
"USAGE:\n".brightGreen() +
"\thuckster " + "<JOB> ".green() + "[PARAMS]\n".yellow() +
"\t\n" +
Expand All @@ -56,12 +59,16 @@ fun main(args: Array<String>) {
"\t\tStrategy configuration\n" +
"\t\t-pad, --priceAdapter <FILE>".italic() +
"\tPrice adapter configuration\n" +
"\t\t-pau, --priceAuth <FILE>".italic() +
"\tPrice adapter authentication file [optional]\n\n" +
"\t\t[-pau, --priceAuth <FILE>]".italic() +
"\tPrice adapter authentication file [adapter-dependent]\n\n" +
"\tOrderbook:\n".underline() +
"\t\t-p, --pair <PAIR>".italic() +
"\t\t\tBase and counter currency tickers separated by a delimiter.\n" +
"\t\t\t\t\t\t\t\t\tSupported delimiters: underscore(_), dash(-) and slash (/)"
"\t\t\t\t\t\t\t\t\tSupported delimiters: underscore(_), dash(-) and slash (/)\n" +
"\t\t-k, --keys <FILE>".italic() +
"\t\t\tKeys to access Broxus Nova platform\n" +
"\t\t[-r, --refresh <SECONDS>]".italic() +
"\tOrderbook refresh rate in seconds. Default: 10"

val errors: MutableMap<String, MutableList<String>> = mutableMapOf()

Expand Down Expand Up @@ -151,6 +158,23 @@ fun main(args: Array<String>) {
}
}

"--refresh", "-r" -> {
if(i < args.lastIndex) {
args[i + 1].toIntOrNull().let {
when(it) {
null -> {
if(!errors.containsKey("wrong_orderbook")) errors["wrong_orderbook"] = mutableListOf()

errors["wrong_orderbook"]?.add("Refresh rate is not an integer number")
}
else -> refreshInterval = it
}
}

i++
}
}

"--help", "-h" -> {
println(usage)
exitProcess(-1)
Expand Down Expand Up @@ -250,7 +274,7 @@ fun main(args: Array<String>) {
when(command) {
"orderbook" -> {
try {
runBlocking { OrdersQueue.drawOrderBook(base, counter, 10) }
runBlocking { OrdersQueue.drawOrderBook(base, counter, refreshInterval) }
} catch(e: Exception) {
logger2(e.message + "\n" +
e.stackTrace.joinToString("\n").red())
Expand Down Expand Up @@ -301,9 +325,9 @@ fun main(args: Array<String>) {

val launchTime = Date(System.currentTimeMillis() - startTime)
println("huckster".italic() + " launched in " +
SimpleDateFormat("HH:mm:ss.SSS").apply{
SimpleDateFormat("HH:mm:ss").apply{
timeZone = TimeZone.getTimeZone("UTC")
}.format(launchTime)
}.format(launchTime) + "\n"
)

runBlocking { strategyAdapter.run() }
Expand Down
2 changes: 1 addition & 1 deletion src/main/kotlin/com/broxus/huckster/models/Account.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@ import com.google.gson.annotations.Expose
*/
data class Account(
@Expose val userAddress: String,
@Expose val addressType: AddressType,
@Expose val addressType: String,
@Expose val workspaceId: String
)
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import com.broxus.nova.types.AddressType

data class PlaceOrderEvent(
val userAddress: String,
val addressType: AddressType,
val addressType: String,
val workspaceId: String?,
var fromAmount: String,
var toAmount: String,
Expand Down
6 changes: 3 additions & 3 deletions src/main/kotlin/com/broxus/nova/client/NovaApiService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ object NovaApiService {
@Suppress("UNCHECKED_CAST")
fun getSpecificUserBalance(
userAddress: String,
addressType: AddressType,
addressType: String,
workspaceId: String? = null
): List<AccountBalance>? {

Expand Down Expand Up @@ -336,7 +336,7 @@ object NovaApiService {
fun getSpecificUserOrders(
id: String? = null,
userAddress: String,
addressType: AddressType,
addressType: String,
workspaceId: String? = null,
base: String? = null,
counter: String? = null,
Expand Down Expand Up @@ -398,7 +398,7 @@ object NovaApiService {
fun createLimitOrder(
id: String,
userAddress: String,
addressType: AddressType,
addressType: String,
workspaceId: String? = null,
from: String,
to: String,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import com.google.gson.annotations.Expose
data class ExchangeLimitInput (
@Expose val id: String,
@Expose val userAddress: String,
@Expose val addressType: AddressType,
@Expose val addressType: String,
@Expose val workspaceId: String?,
@Expose val from: String,
@Expose val to: String,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import com.google.gson.annotations.Expose
data class ExchangeSearchInput (
@Expose val id: String?,
@Expose val userAddress: String,
@Expose val addressType: AddressType,
@Expose val addressType: String,
@Expose val workspaceId: String?,
@Expose val base: String?,
@Expose val counter: String?,
Expand Down
2 changes: 1 addition & 1 deletion src/main/kotlin/com/broxus/nova/models/UserAccountInput.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@ import com.google.gson.annotations.Expose

data class UserAccountInput (
@Expose val userAddress: String,
@Expose val addressType: AddressType,
@Expose val addressType: String,
@Expose val workspaceId: String?
)

0 comments on commit 1bfe160

Please sign in to comment.