Skip to content

Commit

Permalink
Merge pull request #59 from charvam/ET-894_new_et_csv_format
Browse files Browse the repository at this point in the history
ET-894 Added new Everytrade CSV parser.
  • Loading branch information
charvam authored Jul 28, 2021
2 parents c21ca2c + eaa2db0 commit b152e75
Show file tree
Hide file tree
Showing 7 changed files with 549 additions and 4 deletions.
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
projectVersion=3.6.0
projectVersion=3.7.0
pf4jVersion=3.4.0
xchangeVersion=5.0.4
requiredEverytradeVersion=>=20210427
Expand Down
11 changes: 11 additions & 0 deletions parser-files/etrade_v003_M.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
UID;DATE;SYMBOL;ACTION;QUANTY;PRICE;FEE;FEE_CURRENCY;REBATE;REBATE_CURRENCY
1;27.7.2021 14:43:18;BTC/CZK;BUY;0.066506;210507.3226;;;;
2;27.7.2021 14:43:19;BTC/CZK;BUY;0.066506;210507.3226;140;CZK;;
3;27.7.2021 14:43:20;BTC/CZK;BUY;0.066506;210507.3226;0.001;BTC;;
4;27.7.2021 14:59:21;BTC/EUR;SELL;0.066306;8736.534094;;;;
5;27.7.2021 14:59:22;BTC/EUR;SELL;0.066306;8736.534094;;;5.7;EUR
6;27.7.2021 14:59:23;BTC/EUR;SELL;0.066306;8736.534094;;;0.001;BTC
7;27.7.2021 14:59:24;BTC/CZK;FEE;;;100;CZK;;
8;27.7.2021 14:59:25;BTC/CZK;FEE;;;0.01;BTC;;
9;27.7.2021 14:59:26;BTC/CZK;REBATE;;;;;100;CZK
10;27.7.2021 14:59:27;BTC/CZK;REBATE;;;;;0.01;BTC
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import io.everytrade.server.model.SupportedExchange;
import io.everytrade.server.plugin.api.IPlugin;
import io.everytrade.server.plugin.impl.everytrade.parser.exchange.CoinbaseExchangeSpecificParser;
import io.everytrade.server.plugin.impl.everytrade.parser.exchange.bean.EveryTradeBeanV3;
import io.everytrade.server.plugin.impl.everytrade.parser.exchange.bean.HitBtcBeanV2;
import io.everytrade.server.plugin.impl.everytrade.parser.exchange.bean.PoloniexBeanV2;
import io.everytrade.server.plugin.utils.HeaderTemplateFinder;
Expand Down Expand Up @@ -220,6 +221,13 @@ public class EverytradeCsvMultiParser implements ICsvParser {
SupportedExchange.EVERYTRADE
)
);
EXCHANGE_PARSE_DETAILS.put(
"UID;DATE;SYMBOL;ACTION;QUANTY;PRICE;FEE;FEE_CURRENCY;REBATE;REBATE_CURRENCY",
new ExchangeParseDetail(
() -> new DefaultUnivocityExchangeSpecificParser(EveryTradeBeanV3.class, DELIMITER_SEMICOLON),
SupportedExchange.EVERYTRADE
)
);
EXCHANGE_PARSE_DETAILS.put(
"UID,DATE,SYMBOL,ACTION,QUANTY,PRICE,FEE",
new ExchangeParseDetail(
Expand All @@ -234,6 +242,13 @@ public class EverytradeCsvMultiParser implements ICsvParser {
SupportedExchange.EVERYTRADE
)
);
EXCHANGE_PARSE_DETAILS.put(
"UID,DATE,SYMBOL,ACTION,QUANTY,PRICE,FEE,FEE_CURRENCY,REBATE,REBATE_CURRENCY",
new ExchangeParseDetail(
() -> new DefaultUnivocityExchangeSpecificParser(EveryTradeBeanV3.class, DELIMITER_COMMA),
SupportedExchange.EVERYTRADE
)
);
EXCHANGE_PARSE_DETAILS.put(
"Terminal SN;Server Time;Terminal Time;Local Transaction Id;Remote Transaction Id;Type;Cash Amount;" +
"Cash Currency;Crypto Amount;Crypto Currency;Used Discount;Actual Discount (%);Destination address;" +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,9 +93,6 @@ protected TransactionType detectTransactionType(String value) {
} catch (IllegalArgumentException e) {
throw new DataIgnoredException(UNSUPPORTED_TRANSACTION_TYPE.concat(value));
}
if (!type.equals(TransactionType.BUY) && !type.equals(TransactionType.SELL)) {
throw new DataIgnoredException(UNSUPPORTED_TRANSACTION_TYPE.concat(value));
}
return type;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
package io.everytrade.server.plugin.impl.everytrade.parser.exchange.bean;

import com.univocity.parsers.annotations.Format;
import com.univocity.parsers.annotations.Headers;
import com.univocity.parsers.annotations.Parsed;
import com.univocity.parsers.common.DataValidationException;
import io.everytrade.server.model.Currency;
import io.everytrade.server.model.TransactionType;
import io.everytrade.server.plugin.api.parser.BuySellImportedTransactionBean;
import io.everytrade.server.plugin.api.parser.FeeRebateImportedTransactionBean;
import io.everytrade.server.plugin.api.parser.ImportedTransactionBean;
import io.everytrade.server.plugin.api.parser.TransactionCluster;
import io.everytrade.server.plugin.impl.everytrade.parser.exchange.ExchangeBean;

import java.math.BigDecimal;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;

@Headers(sequence = {
"UID", "DATE", "SYMBOL", "ACTION", "QUANTY", "PRICE", "FEE", "FEE_CURRENCY", "REBATE", "REBATE_CURRENCY"
}, extract = true)
public class EveryTradeBeanV3 extends ExchangeBean {
private String uid;
private Instant date;
private Currency symbolBase;
private Currency symbolQuote;
private TransactionType action;
private BigDecimal quantity;
private BigDecimal price;
private BigDecimal fee;
private Currency feeCurrency;
private BigDecimal rebate;
private Currency rebateCurrency;

@Parsed(field = "UID")
public void setUid(String value) {
uid = value;
}

@Parsed(field = "DATE")
@Format(formats = {"dd.MM.yy HH:mm:ss", "yyyy-MM-dd HH:mm:ss"}, options = {"locale=US", "timezone=UTC"})
public void setDate(Date value) {
date = value.toInstant();
}

@Parsed(field = "SYMBOL")
public void setSymbol(String value) {
String[] symbolParts = value.split("/");
symbolBase = Currency.fromCode(symbolParts[0]);
symbolQuote = Currency.fromCode(symbolParts[1]);
}

@Parsed(field = "ACTION")
public void setAction(String value) {
action = detectTransactionType(value);
}

@Parsed(field = "QUANTY", defaultNullRead = "0")
public void setQuantityBase(BigDecimal value) {
quantity = value;
}

@Parsed(field = "PRICE", defaultNullRead = "0")
public void setPrice(BigDecimal value) {
price = value;
}

@Parsed(field = "FEE", defaultNullRead = "0")
public void setFee(BigDecimal value) {
fee = value;
}

@Parsed(field = "FEE_CURRENCY")
public void setFeeCurrency(String value) {
feeCurrency = value == null ? null : Currency.fromCode(value);
}

@Parsed(field = "REBATE", defaultNullRead = "0")
public void setRebate(BigDecimal value) {
rebate = value;
}

@Parsed(field = "REBATE_CURRENCY")
public void setRebateCurrency(String value) {
rebateCurrency = value == null ? null : Currency.fromCode(value);
}

@Override
public TransactionCluster toTransactionCluster() {
validateCurrencyPair(symbolBase, symbolQuote);
validatePositivity(quantity, price, fee, rebate);
switch (action) {
case BUY:
case SELL:
return createBuySellTransactionCluster();
case FEE:
return new TransactionCluster(createFeeTransactionBean(true), List.of());
case REBATE:
return new TransactionCluster(createRebateTransactionBean(true), List.of());
default:
throw new IllegalStateException(String.format("Unsupported transaction type %s.", action));
}
}

private TransactionCluster createBuySellTransactionCluster() {
if (quantity.compareTo(BigDecimal.ZERO) == 0) {
throw new DataValidationException("Quantity can not be zero.");
}
if (price.compareTo(BigDecimal.ZERO) == 0) {
throw new DataValidationException("Price can not be zero.");
}

final ImportedTransactionBean buySell = new BuySellImportedTransactionBean(
uid, //uuid
date, //executed
symbolBase, //base
symbolQuote, //quote
action, //action
quantity, //base quantity
price //unit price
);

final List<ImportedTransactionBean> related = new ArrayList<>();
if (fee.compareTo(BigDecimal.ZERO) > 0) {
related.add(createFeeTransactionBean(false));
}

if (rebate.compareTo(BigDecimal.ZERO) > 0) {
related.add(createRebateTransactionBean(false));
}

return new TransactionCluster(
buySell,
related
);
}

private FeeRebateImportedTransactionBean createFeeTransactionBean(boolean unrelated) {
final boolean feeCurrencyIsBase = Objects.equals(feeCurrency, symbolBase);
final boolean feeCurrencyIsQuote = Objects.equals(feeCurrency, symbolQuote);
if (!feeCurrencyIsBase && !feeCurrencyIsQuote) {
throw new DataValidationException(String.format(
"Fee currency '%s' differs to base '%s' and to quote '%s'.",
feeCurrency,
symbolBase,
symbolQuote
));
}

return new FeeRebateImportedTransactionBean(
unrelated ? uid : uid + FEE_UID_PART,
date,
symbolBase,
symbolQuote,
TransactionType.FEE,
fee,
feeCurrency
);
}

private FeeRebateImportedTransactionBean createRebateTransactionBean(boolean unrelated) {
final boolean rebateCurrencyIsBase = Objects.equals(rebateCurrency, symbolBase);
final boolean rebateCurrencyIsQuote = Objects.equals(rebateCurrency, symbolQuote);
if (!rebateCurrencyIsBase && !rebateCurrencyIsQuote) {
throw new DataValidationException(String.format(
"Rebate currency '%s' differs to base '%s' and to quote '%s'.",
rebateCurrency,
symbolBase,
symbolQuote
));
}

return new FeeRebateImportedTransactionBean(
unrelated ? uid : uid + FEE_UID_PART,
date,
symbolBase,
symbolQuote,
TransactionType.REBATE,
rebate,
rebateCurrency
);
}
}
Loading

0 comments on commit b152e75

Please sign in to comment.