Skip to content

Commit

Permalink
Merge develop (#9)
Browse files Browse the repository at this point in the history
* 4 change endpoint to support multiple coins (#5)

* Fix #2 (#3)

Transactions can be written to json again.

* Refactorings

Move iterating over transactions into service.

* Fix #4

* Fix #1 (#6)

* Fix NPE when swap map is empty

* Fix Mars transactions

* Update gitignore

* Longer sleep between API calls

* Fix #7 (#8)
  • Loading branch information
kerner1000 authored May 10, 2022
1 parent a3b481b commit ec4a8a9
Show file tree
Hide file tree
Showing 26 changed files with 2,654 additions and 88 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,5 @@

# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*

**/transactions
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.github.kerner1000.terra;

import com.github.kerner1000.terra.commons.Coin;
import com.github.kerner1000.terra.transactions.*;

import java.util.Arrays;

public class LunaWeightedMeanCalculatorService extends WeightedMeanCalculatorService {

public LunaWeightedMeanCalculatorService() {
super(Coin.LUNA);
}

protected Iterable<? extends AbstractTransactionVisitor> getVisitors() {
return Arrays.asList(new TerraswapTransactionVisitor(), new AstroportTransactionVisitor(), new MarketTransactionVisitor(), new LoopSwapTransactionVisitor());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.github.kerner1000.terra;

import com.github.kerner1000.terra.commons.Coin;
import com.github.kerner1000.terra.transactions.*;

import java.util.Arrays;

public class MarsWeightedMeanCalculatorService extends WeightedMeanCalculatorService {

public MarsWeightedMeanCalculatorService() {
super(Coin.MARS);
}

protected Iterable<? extends AbstractTransactionVisitor> getVisitors() {
return Arrays.asList(new AstroportTransactionVisitorMars(), new TerraswapTransactionVisitorMars());
}
}
Original file line number Diff line number Diff line change
@@ -1,54 +1,55 @@
package com.github.kerner1000.terra;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.kerner1000.terra.commons.BinnedBuySellMaps;
import com.github.kerner1000.terra.commons.BuySellMaps;
import com.github.kerner1000.terra.commons.SwapPrices;
import com.github.kerner1000.terra.commons.*;
import com.github.kerner1000.terra.feign.LcdClient;
import com.github.kerner1000.terra.feign.LcdTransactionsPagination;
import com.github.kerner1000.terra.json.data.Transaction;
import com.github.kerner1000.terra.transactions.Transactions;
import lombok.extern.slf4j.Slf4j;
import org.openapitools.api.SwapsApi;
import org.openapitools.model.BuySellSwaps;
import org.openapitools.model.BuySellSwapsPerCoin;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RestController;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

@Slf4j
@RestController
public class TerraAppController implements SwapsApi {

private final LcdClient lcdClient;

private final WeightedMeanCalculatorService callbackService;

private final ObjectMapper objectMapper;

private final TerraConfig terraConfig;

public TerraAppController(LcdClient lcdClient, WeightedMeanCalculatorService callbackService, ObjectMapper objectMapper, TerraConfig terraConfig) {
public TerraAppController(LcdClient lcdClient, ObjectMapper objectMapper, TerraConfig terraConfig) {
this.lcdClient = lcdClient;
this.callbackService = callbackService;
this.objectMapper = objectMapper;
this.terraConfig = terraConfig;
}

@Override
public ResponseEntity<BuySellSwaps> getSwaps(String token, String terraAddress) {
log.info("Calculating average buy/sell for {} and address {}", token, terraAddress);
public ResponseEntity<BuySellSwapsPerCoin> getSwaps(String terraAddress, List<String> hide) {
log.info("Calculating average buy/sell for address {}", terraAddress);
long transactionsCount = 0;
long offset = 0;
BuySellMaps collectedSwaps = new BuySellMaps();
BuySellMapsForCoin coinToCollectedSwaps = new BuySellMapsForCoin();
do {
try {
LcdTransactionsPagination lcdTransactionsPagination = lcdClient.searchTransactions(terraAddress, 100, offset);
List<Transaction> transactions = new ArrayList<>(lcdTransactionsPagination.getTxs());
collectedSwaps.add(callbackService.visit(lcdTransactionsPagination.getTxs()));
BuySellMapsForCoin buySellMapsForCoin = new LunaWeightedMeanCalculatorService().visit(lcdTransactionsPagination.getTxs());
BuySellMapsForCoin buySellMapsForCoinMars = new MarsWeightedMeanCalculatorService().visit(lcdTransactionsPagination.getTxs());
coinToCollectedSwaps.add(buySellMapsForCoin);
coinToCollectedSwaps.add(buySellMapsForCoinMars);
transactionsCount += transactions.size();
log.info("Collected {} transactions, current offset: {}", transactionsCount, offset);
if(terraConfig.isWriteTransactions()) {
Expand All @@ -69,11 +70,10 @@ public ResponseEntity<BuySellSwaps> getSwaps(String token, String terraAddress)
}
} while (offset != 0);

SwapPrices result2 = new Transactions().getWeightedMean(collectedSwaps);
log.info("Collected {} transactions, average swap price is {}", transactionsCount, result2);
BinnedBuySellMaps<Double> binnedBuySellMaps = BinnedBuySellMaps.BinnedBuySellMapsFactory.buildWithFixBinSize(collectedSwaps.getBuyMap(), 5);
log.debug("Buy price distribution:\n{}", binnedBuySellMaps.toAsciiHistogram(false));
org.openapitools.model.BuySellSwaps result = Transformer.transform(collectedSwaps);
BuySellSwapsPerCoin result = new BuySellSwapsPerCoin();
for(Map.Entry<Coin, BuySellMaps> entry : coinToCollectedSwaps.entrySet()){
result.addEntriesItem(Transformer.transform(entry.getKey(), entry.getValue()));
}
return ResponseEntity.ok(result);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.github.kerner1000.terra.commons.BuySellMap;
import com.github.kerner1000.terra.commons.BuySellMaps;
import com.github.kerner1000.terra.commons.Coin;
import org.openapitools.model.BuySellSwaps;
import org.openapitools.model.SwapEntry;
import org.openapitools.model.Swaps;
Expand All @@ -11,8 +12,9 @@

public class Transformer {

public static BuySellSwaps transform(BuySellMaps maps){
public static BuySellSwaps transform(Coin coin, BuySellMaps maps){
BuySellSwaps buySellSwaps = new BuySellSwaps();
buySellSwaps.setCoin(coin.toString());
buySellSwaps.setBuy(new Swaps());
buySellSwaps.setSell(new Swaps());
for(Map.Entry<BuySellMap.Key, Number> element : maps.getBuyMap().getMap().entrySet()){
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,35 @@
package com.github.kerner1000.terra;

import com.github.kerner1000.terra.commons.BuySellMaps;
import com.github.kerner1000.terra.commons.BuySellMapsForCoin;
import com.github.kerner1000.terra.commons.Coin;
import com.github.kerner1000.terra.json.data.Transaction;
import com.github.kerner1000.terra.transactions.Transactions;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.web.context.annotation.RequestScope;
import com.github.kerner1000.terra.transactions.AbstractTransactionVisitor;

import java.util.List;

@Slf4j
@RequestScope
@Service
public class WeightedMeanCalculatorService {

public BuySellMaps visit(List<Transaction> transactions) throws InterruptedException {
BuySellMaps wm = new Transactions().getWeightedMeanSwapMaps(transactions);
// if(log.isDebugEnabled() && wm.getBuyMap().getMap().size() > 1 || wm.getSellMap().getMap().size() > 1) {
// log.debug("swap map:\n{}\n======\nweighted mean: {}", result, new Transactions().getWeightedMean(result));
// }
return wm;
public abstract class WeightedMeanCalculatorService {

private final Coin coin;

protected WeightedMeanCalculatorService(Coin coin) {
this.coin = coin;
}

public BuySellMapsForCoin visit(List<Transaction> transactions) throws InterruptedException {

BuySellMaps result = new BuySellMaps();

for (Transaction transaction : transactions) {
if(Thread.currentThread().isInterrupted()){
break;
}
for (AbstractTransactionVisitor visitor : getVisitors()) {
result.add(visitor.visit(transaction));
}
}
return new BuySellMapsForCoin(coin, result);
}

protected abstract Iterable<? extends AbstractTransactionVisitor> getVisitors();
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ public class ExecuteMessage {

Swap swap;

Send send;

@JsonProperty("assert_limit_order")
AssertLimitOrder assertLimitOrder;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ public void setExecuteMessageString(JsonNode executeMessageString) {
messages = Additional.extract(executeMessageString.toString());
} catch (JsonProcessingException jsonProcessingException) {
var text = executeMessageString.textValue();
// "send" msg
if(text == null){
return;
}
try {
byte[] decodedBytes = Base64.getDecoder().decode(text);
String decodedString = new String(decodedBytes);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.github.kerner1000.terra.json.data;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Data;

import java.util.Base64;

@Data
public class Send {

static ObjectMapper objectMapper = new ObjectMapper();

static {
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
}

Number amount;

String contract;

Swap msg;

@JsonProperty("msg")
public void setMsg(JsonNode msg) throws JsonProcessingException {
byte[] decodedBytes = Base64.getDecoder().decode(msg.textValue());
String decodedString = new String(decodedBytes);
ExecuteMessage swap = objectMapper.readValue(decodedString, ExecuteMessage.class);
this.msg = swap.getSwap();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,9 @@
import com.github.kerner1000.terra.commons.SwapPrices;
import com.github.kerner1000.terra.json.data.Additional;
import com.github.kerner1000.terra.json.data.Swap;
import com.github.kerner1000.terra.json.data.Transaction;
import lombok.extern.slf4j.Slf4j;

import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;
Expand All @@ -28,27 +26,6 @@ public class Transactions {

static final Predicate<Additional> ASTROPORT_FILTER = a -> a != null && a.getContract() != null && a.getContract().stream().anyMatch(c -> c.contains(SwapPairs.Astroport.LUNA_UST));

private final List<AbstractTransactionVisitor> visitors = Arrays.asList(new TerraswapTransactionVisitor(), new AstroportTransactionVisitor(), new MarketTransactionVisitor(), new LoopSwapTransactionVisitor());

public BuySellMaps getWeightedMeanSwapMaps(Collection<? extends Transaction> transactionsList) {

BuySellMaps result = new BuySellMaps();

for (Transaction transaction : transactionsList) {
if(Thread.currentThread().isInterrupted()){
break;
}
for (AbstractTransactionVisitor visitor : visitors) {
result.add(visitor.visit(transaction));
}
}
return result;
}

public SwapPrices getWeightedMean(Collection<? extends Transaction> transactionsList) throws InterruptedException {
return getWeightedMean(getWeightedMeanSwapMaps(transactionsList));
}

public SwapPrices getWeightedMean(BuySellMaps swapResult) {
return new SwapPrices(weightedMean(swapResult.getBuyMap()), weightedMean(swapResult.getSellMap()));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ feign:
default:
loggerLevel: NONE

app.terra.sleep-between-calls: 800
app.terra.sleep-between-calls: 900
app.terra.write-transactions: true

spring:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,9 @@ public void testAstroportUstToLuna() throws IOException {
Transaction transaction = objectMapper.readValue(new File("src/test/resources/example-transaction-astroport-UST-to-LUNA.json"), Transaction.class);
var result = transactionVisitor.visit(transaction);
assertNotNull(result);
assertEquals(1,result.getBuyMap().getMap().size());
assertEquals(0,result.getSellMap().getMap().size());
assertEquals(1, result.getBuyMap().getMap().size());
assertEquals(0, result.getSellMap().getMap().size());
assertEquals(10d, result.getBuyMap().getMap().values().iterator().next());

}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ public class DecodeTest {

@Test
public void test(){
var text = "eyJhc3NlcnRfbGltaXRfb3JkZXIiOnsib2ZmZXJfY29pbiI6eyJkZW5vbSI6InVsdW5hIiwiYW1vdW50IjoiMTAwMDAwMDAifSwiYXNrX2Rlbm9tIjoidXVzZCIsIm1pbmltdW1fcmVjZWl2ZSI6IjE1NDgzNjMxNiJ9fQ==";
var text = "eyJzd2FwIjp7Im1heF9zcHJlYWQiOiIwLjAwNSIsImJlbGllZl9wcmljZSI6IjEuMTc3Njg3MzQ3MDkyMDE5MDcxIn19";
byte[] decodedBytes = Base64.getDecoder().decode(text);
String decodedString = new String(decodedBytes);
System.out.println(decodedString);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.github.kerner1000.terra.json.data;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.*;

class SwapTest {

@BeforeEach
void setUp() {
}

@AfterEach
void tearDown() {
}

@Test
void simpleTest() throws JsonProcessingException {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
ExecuteMessage hans = objectMapper.readValue("{\"swap\":{\"max_spread\":\"0.005\",\"belief_price\":\"1.177687347092019071\"}}", ExecuteMessage.class);
assertNotNull(hans);
}
}
Loading

0 comments on commit ec4a8a9

Please sign in to comment.