@@ -53,6 +53,11 @@ use crate::{
53
53
FastHashMap ,
54
54
} ;
55
55
56
+ pub enum SecuritiesClass {
57
+ Spot ,
58
+ Derivative ,
59
+ }
60
+
56
61
/// Centralized exchange price map organized by exchange.
57
62
///
58
63
///
@@ -166,7 +171,7 @@ impl CexPriceMap {
166
171
let volume_weighted_bid = volume_price. 0 / & cumulative_bbo. 0 ;
167
172
let volume_weighted_ask = volume_price. 1 / & cumulative_bbo. 1 ;
168
173
169
- let fees = exchange. fees ( ) ;
174
+ let fees = exchange. fees ( & pair , & SecuritiesClass :: Spot ) ;
170
175
171
176
let fee_adjusted_maker = (
172
177
& volume_weighted_bid * ( Rational :: ONE - & fees. 0 ) ,
@@ -907,68 +912,203 @@ impl CexExchange {
907
912
///
908
913
/// TODO: Account for special fee pairs & stableswap rates
909
914
/// TODO: Account for futures & spot fee deltas
910
- pub fn fees ( & self ) -> ( Rational , Rational ) {
911
- match self {
912
- CexExchange :: Binance => (
913
- Rational :: from_sci_string ( "0.00012" ) . unwrap ( ) ,
914
- Rational :: from_sci_string ( "0.00024" ) . unwrap ( ) ,
915
- ) ,
916
- CexExchange :: Bitmex => (
917
- Rational :: from_sci_string ( "-0.00025" ) . unwrap ( ) ,
918
- Rational :: from_sci_string ( "0.00075" ) . unwrap ( ) ,
919
- ) ,
920
- CexExchange :: Deribit => {
921
- ( Rational :: from_sci_string ( "0" ) . unwrap ( ) , Rational :: from_sci_string ( "0" ) . unwrap ( ) )
922
- }
923
- CexExchange :: Okex => (
924
- Rational :: from_sci_string ( "-0.00005" ) . unwrap ( ) ,
925
- Rational :: from_sci_string ( "0.00015" ) . unwrap ( ) ,
926
- ) ,
927
- CexExchange :: Coinbase => (
928
- Rational :: from_sci_string ( "0" ) . unwrap ( ) ,
929
- Rational :: from_sci_string ( "0.0005" ) . unwrap ( ) ,
930
- ) ,
931
- CexExchange :: Kraken => (
932
- Rational :: from_sci_string ( "0" ) . unwrap ( ) ,
933
- Rational :: from_sci_string ( "0.001" ) . unwrap ( ) ,
934
- ) ,
935
- CexExchange :: BybitSpot => (
936
- Rational :: from_sci_string ( "0.00005" ) . unwrap ( ) ,
937
- Rational :: from_sci_string ( "0.00015" ) . unwrap ( ) ,
938
- ) ,
939
- CexExchange :: Kucoin => (
940
- Rational :: from_sci_string ( "-0.00005" ) . unwrap ( ) ,
941
- Rational :: from_sci_string ( "0.00025" ) . unwrap ( ) ,
942
- ) ,
943
- CexExchange :: Upbit => (
944
- Rational :: from_sci_string ( "0.0002" ) . unwrap ( ) ,
945
- Rational :: from_sci_string ( "0.0002" ) . unwrap ( ) ,
946
- ) ,
947
- CexExchange :: Huobi => (
948
- Rational :: from_sci_string ( "0.000097" ) . unwrap ( ) ,
949
- Rational :: from_sci_string ( "0.000193" ) . unwrap ( ) ,
950
- ) ,
951
- CexExchange :: GateIo => (
952
- Rational :: from_sci_string ( "0" ) . unwrap ( ) ,
953
- Rational :: from_sci_string ( "0.0002" ) . unwrap ( ) ,
954
- ) ,
955
- CexExchange :: Bitstamp => (
956
- Rational :: from_sci_string ( "0" ) . unwrap ( ) ,
957
- Rational :: from_sci_string ( "0.0003" ) . unwrap ( ) ,
958
- ) ,
959
- CexExchange :: Gemini => (
960
- Rational :: from_sci_string ( "0" ) . unwrap ( ) ,
961
- Rational :: from_sci_string ( "0.0003" ) . unwrap ( ) ,
962
- ) ,
915
+ pub fn fees ( & self , pair : & Pair , trade_type : & SecuritiesClass ) -> ( Rational , Rational ) {
916
+ let ( maker, taker) = match self {
917
+ CexExchange :: Binance => {
918
+ match trade_type {
919
+ SecuritiesClass :: Spot =>
920
+ if Self :: BINANCE_SPOT_PROMO_FEE_TYPE1_PAIRS . iter ( ) . any ( |p| p. eq_ordered ( pair) ) {
921
+ ( "0.0" , "0.0" ) // https://www.binance.com/en/fee/tradingPromote
922
+ } else if Self :: BINANCE_SPOT_PROMO_FEE_TYPE2_PAIRS . iter ( ) . any ( |p| p. eq_ordered ( pair) ) {
923
+ ( "0.0" , "0.00024" ) // https://www.binance.com/en/fee/tradingPromote
924
+
925
+ } else if pair. 0 == USDC_ADDRESS || pair. 1 == USDC_ADDRESS {
926
+ ( "0.00012" , "0.0001425" ) // https://www.binance.com/en/fee/trading
927
+ } else {
928
+ ( "0.00012" , "0.00024" ) // https://www.binance.com/en/fee/trading
929
+ } ,
930
+ SecuritiesClass :: Derivative => ( "0.0003" , "0.0003" ) , // https://www.binance.com/en/fee/optionsTrading
931
+ }
932
+ } ,
933
+ CexExchange :: Bitmex =>
934
+ match trade_type {
935
+ SecuritiesClass :: Spot => ( "0.001" , "0.001" ) , // https://www.bitmex.com/wallet/fees/spot
936
+ SecuritiesClass :: Derivative => ( "-0.000125" , "0.000175" ) , // https://www.bitmex.com/wallet/fees/derivatives
937
+
938
+ }
939
+ CexExchange :: Deribit =>
940
+ match trade_type {
941
+ SecuritiesClass :: Spot => ( "0.0" , "0.0" ) , // https://www.deribit.com/kb/fees
942
+ SecuritiesClass :: Derivative => ( "-0.0001" , "0.0005" ) , // https://www.deribit.com/kb/fees
943
+ }
944
+ CexExchange :: Okex => ( "-0.0001" , "0.00015" ) , // https://tr.okx.com/fees
945
+ CexExchange :: Coinbase =>
946
+ // https://help.coinbase.com/en/exchange/trading-and-funding/exchange-fees
947
+ if USD_STABLES_BY_ADDRESS . iter ( ) . any ( |a| pair. 0 == * a || pair. 1 == * a) ||
948
+ WBTC_ADDRESS == pair. 0 || WBTC_ADDRESS == pair. 1 {
949
+ ( "0.0" , "0.00001" )
950
+ } else {
951
+ ( "0" , "0.0005" )
952
+ } ,
953
+ CexExchange :: Kraken =>
954
+ match trade_type {
955
+ SecuritiesClass :: Spot => ( "0.0" , "0.001" ) , // https://www.kraken.com/features/fee-schedule#spot-crypto
956
+ SecuritiesClass :: Derivative => ( "0.0" , "0.0001" ) , // https://www.kraken.com/features/fee-schedule#futures
957
+ } ,
958
+ CexExchange :: BybitSpot =>
959
+ // https://www.bybit.com/en/help-center/article/Trading-Fee-Structure
960
+ match trade_type {
961
+ SecuritiesClass :: Spot => ( "0.00005" , "0.00015" ) ,
962
+ SecuritiesClass :: Derivative => if USDC_ADDRESS == pair. 0 || USDC_ADDRESS == pair. 1 {
963
+ ( "0.0" , "0.0001" )
964
+ } else {
965
+ ( "0.0" , "0.00025" )
966
+ }
967
+ }
968
+ CexExchange :: Kucoin =>
969
+ // https://www.kucoin.com/vip/privilege
970
+ match trade_type {
971
+ SecuritiesClass :: Spot =>
972
+ if Self :: KUCOIN_CLASS_C_BASE_COINS . iter ( ) . any ( |a| pair. 0 == * a) {
973
+ ( "-0.00005" , "0.00075" )
974
+ } else if Self :: KUCOIN_CLASS_B_BASE_COINS . iter ( ) . any ( |a| pair. 0 == * a) {
975
+ ( "-0.00005" , "0.0005" )
976
+ } else if Self :: KUCOIN_CLASS_A_BASE_COINS . iter ( ) . any ( |a| pair. 0 == * a) {
977
+ ( "-0.00005" , "0.00025" )
978
+ } else if Self :: KUCOIN_TOP_BASE_COINS . iter ( ) . any ( |a| pair. 0 == * a) {
979
+ ( "-0.00005" , "0.00025" )
980
+ } else {
981
+ ( "-0.00005" , "0.00025" )
982
+ } ,
983
+ SecuritiesClass :: Derivative => ( "-0.00008" , "0.00025" ) ,
984
+ } ,
985
+ CexExchange :: Upbit => ( "0.0002" , "0.0002" ) , // https://sg.upbit.com/service_center/guide
986
+ CexExchange :: Huobi =>
987
+ match trade_type {
988
+ SecuritiesClass :: Spot => ( "0.000097" , "0.000193" ) , // https://www.htx.com/zh-cn/support/360000312282
989
+ SecuritiesClass :: Derivative => ( "-0.00005" , "0.0002" ) , // https://www.htx.com/zh-cn/support/360000113122
990
+ }
991
+ CexExchange :: GateIo => ( "0.0" , "0.0002" ) , // https://www.gate.io/fee (curl, search for spot_feelist)
992
+ CexExchange :: Bitstamp => ( "0" , "0.0003" ) , // https://www.bitstamp.net/fee-schedule/
993
+ CexExchange :: Gemini => ( "0" , "0.0003" ) , // https://www.gemini.com/fees/api-fee-schedule#section-gemini-stablecoin-fee-schedule
963
994
CexExchange :: Average => {
964
995
unreachable ! ( "Cannot get fees for cross exchange average quote" )
965
996
}
966
997
CexExchange :: Unknown => unreachable ! ( "Unknown cex exchange" ) ,
967
998
CexExchange :: VWAP | CexExchange :: OptimisticVWAP => {
968
999
unreachable ! ( "Cannot get fees for VWAP" )
969
1000
}
970
- }
1001
+ } ;
1002
+ ( Rational :: from_sci_string ( maker) . unwrap ( ) , Rational :: from_sci_string ( taker) . unwrap ( ) )
971
1003
}
1004
+
1005
+ // https://www.binance.com/en/fee/tradingPromote
1006
+ const BINANCE_SPOT_PROMO_FEE_TYPE1_PAIRS : [ Pair ; 8 ] = [
1007
+ Pair ( WBTC_ADDRESS , FDUSD_ADDRESS ) ,
1008
+ Pair ( FDUSD_ADDRESS , USDT_ADDRESS ) ,
1009
+ Pair ( ETH_ADDRESS , FDUSD_ADDRESS ) ,
1010
+ Pair ( LINK_ADDRESS , FDUSD_ADDRESS ) ,
1011
+ Pair ( AEUR_ADDRESS , USDT_ADDRESS ) ,
1012
+ Pair ( TUSD_ADDRESS , USDT_ADDRESS ) ,
1013
+ Pair ( USDC_ADDRESS , USDT_ADDRESS ) ,
1014
+ Pair ( USDP_ADDRESS , USDT_ADDRESS ) ,
1015
+ ] ;
1016
+
1017
+ // https://www.binance.com/en/fee/tradingPromote
1018
+ const BINANCE_SPOT_PROMO_FEE_TYPE2_PAIRS : [ Pair ; 50 ] = [
1019
+ Pair ( ACE_ADDRESS , FDUSD_ADDRESS ) ,
1020
+ Pair ( ADA_ADDRESS , FDUSD_ADDRESS ) ,
1021
+ Pair ( AEVO_ADDRESS , FDUSD_ADDRESS ) ,
1022
+ Pair ( AI_ADDRESS , FDUSD_ADDRESS ) ,
1023
+ Pair ( ALT_ADDRESS , FDUSD_ADDRESS ) ,
1024
+ Pair ( ARB_ADDRESS , FDUSD_ADDRESS ) ,
1025
+ Pair ( ARKM_ADDRESS , FDUSD_ADDRESS ) ,
1026
+ Pair ( AUCTION_ADDRESS , FDUSD_ADDRESS ) ,
1027
+ Pair ( AXL_ADDRESS , FDUSD_ADDRESS ) ,
1028
+ Pair ( BLZ_ADDRESS , FDUSD_ADDRESS ) ,
1029
+ Pair ( CHZ_ADDRESS , FDUSD_ADDRESS ) ,
1030
+ Pair ( CYBER_ADDRESS , FDUSD_ADDRESS ) ,
1031
+ Pair ( DYDX_ADDRESS , FDUSD_ADDRESS ) ,
1032
+ Pair ( ENA_ADDRESS , FDUSD_ADDRESS ) ,
1033
+ Pair ( ENS_ADDRESS , FDUSD_ADDRESS ) ,
1034
+ Pair ( ETHFI_ADDRESS , FDUSD_ADDRESS ) ,
1035
+ Pair ( FET_ADDRESS , FDUSD_ADDRESS ) ,
1036
+ Pair ( FLOKI_ADDRESS , FDUSD_ADDRESS ) ,
1037
+ Pair ( FTM_ADDRESS , FDUSD_ADDRESS ) ,
1038
+ Pair ( GALA_ADDRESS , FDUSD_ADDRESS ) ,
1039
+ Pair ( GRT_ADDRESS , FDUSD_ADDRESS ) ,
1040
+ Pair ( INJ_ADDRESS , FDUSD_ADDRESS ) ,
1041
+ Pair ( JUP_ADDRESS , FDUSD_ADDRESS ) ,
1042
+ Pair ( LDO_ADDRESS , FDUSD_ADDRESS ) ,
1043
+ Pair ( MATIC_ADDRESS , FDUSD_ADDRESS ) ,
1044
+ Pair ( MEME_ADDRESS , FDUSD_ADDRESS ) ,
1045
+ Pair ( OMNI_ADDRESS , FDUSD_ADDRESS ) ,
1046
+ Pair ( PENDLE_ADDRESS , FDUSD_ADDRESS ) ,
1047
+ Pair ( PEOPLE_ADDRESS , FDUSD_ADDRESS ) ,
1048
+ Pair ( PEPE_ADDRESS , FDUSD_ADDRESS ) ,
1049
+ Pair ( PIXEL_ADDRESS , FDUSD_ADDRESS ) ,
1050
+ Pair ( PORTAL_ADDRESS , FDUSD_ADDRESS ) ,
1051
+ Pair ( REZ_ADDRESS , FDUSD_ADDRESS ) ,
1052
+ Pair ( RNDR_ADDRESS , FDUSD_ADDRESS ) ,
1053
+ Pair ( SAND_ADDRESS , FDUSD_ADDRESS ) ,
1054
+ Pair ( SHIB_ADDRESS , FDUSD_ADDRESS ) ,
1055
+ Pair ( STRK_ADDRESS , FDUSD_ADDRESS ) ,
1056
+ Pair ( SUPER_ADDRESS , FDUSD_ADDRESS ) ,
1057
+ Pair ( UNI_ADDRESS , FDUSD_ADDRESS ) ,
1058
+ Pair ( W_ADDRESS , FDUSD_ADDRESS ) ,
1059
+ Pair ( WLD_ADDRESS , FDUSD_ADDRESS ) ,
1060
+ Pair ( ADA_ADDRESS , TUSD_ADDRESS ) ,
1061
+ Pair ( ARB_ADDRESS , TUSD_ADDRESS ) ,
1062
+ Pair ( ARKM_ADDRESS , TUSD_ADDRESS ) ,
1063
+ Pair ( WBTC_ADDRESS , TUSD_ADDRESS ) ,
1064
+ Pair ( CYBER_ADDRESS , TUSD_ADDRESS ) ,
1065
+ Pair ( ETH_ADDRESS , TUSD_ADDRESS ) ,
1066
+ Pair ( MATIC_ADDRESS , TUSD_ADDRESS ) ,
1067
+ Pair ( MAV_ADDRESS , TUSD_ADDRESS ) ,
1068
+ Pair ( PEPE_ADDRESS , TUSD_ADDRESS ) ,
1069
+ ] ;
1070
+
1071
+ const KUCOIN_TOP_BASE_COINS : [ Address ; 12 ] = [
1072
+ WBTC_ADDRESS ,
1073
+ ETH_ADDRESS ,
1074
+ // XRP_ADDRESS,
1075
+ // SOL_ADDRESS,
1076
+ ADA_ADDRESS ,
1077
+ // DOGE_ADDRESS,
1078
+ // TRX_ADDRESS,
1079
+ // AVAX_ADDRESS,
1080
+ MATIC_ADDRESS ,
1081
+ LINK_ADDRESS ,
1082
+ // DOT_ADDRESS,
1083
+ // LTC_ADDRESS,
1084
+ SHIB_ADDRESS ,
1085
+ // BCH_ADDRESS,
1086
+ // ATOM_ADDRESS,
1087
+ UNI_ADDRESS ,
1088
+ // XMR_ADDRESS,
1089
+ // ETC_ADDRESS,
1090
+ // LUNC_ADDRESS,
1091
+ // TON_ADDRESS,
1092
+ DAI_ADDRESS ,
1093
+ KCS_ADDRESS ,
1094
+ USDT_ADDRESS ,
1095
+ USDC_ADDRESS ,
1096
+ USDP_ADDRESS ,
1097
+ ] ;
1098
+
1099
+ const KUCOIN_CLASS_A_BASE_COINS : [ Address ; 39 ] = [
1100
+ AEVO_ADDRESS , ARB_ADDRESS , ARKM_ADDRESS , AUCTION_ADDRESS , BLZ_ADDRESS , BNB_ADDRESS , CHZ_ADDRESS , CYBER_ADDRESS ,
1101
+ DYDX_ADDRESS , ENA_ADDRESS , ENS_ADDRESS , ETHFI_ADDRESS , FET_ADDRESS , FLOKI_ADDRESS , FTM_ADDRESS , GRT_ADDRESS ,
1102
+ INJ_ADDRESS , JUP_ADDRESS , LDO_ADDRESS , MAV_ADDRESS , MEME_ADDRESS , OMNI_ADDRESS , PAXG_ADDRESS , PENDLE_ADDRESS ,
1103
+ PEOPLE_ADDRESS , PEPE_ADDRESS , PIXEL_ADDRESS , PORTAL_ADDRESS , PYUSD_ADDRESS , REZ_ADDRESS , SAND_ADDRESS , STRK_ADDRESS ,
1104
+ SUPER_ADDRESS , TUSD_ADDRESS , USDD_ADDRESS , USTC_ADDRESS , W_ADDRESS , WBTC_ADDRESS , WLD_ADDRESS ,
1105
+ ] ;
1106
+
1107
+ const KUCOIN_CLASS_B_BASE_COINS : [ Address ; 5 ] = [
1108
+ ACE_ADDRESS , AI_ADDRESS , ALT_ADDRESS , RNDR_ADDRESS , USDE_ADDRESS ,
1109
+ ] ;
1110
+
1111
+ const KUCOIN_CLASS_C_BASE_COINS : [ Address ; 0 ] = [ ] ;
972
1112
}
973
1113
974
1114
#[ cfg( test) ]
0 commit comments