Skip to content

Commit

Permalink
Merge pull request #8 from joergrs/7_limit_factor
Browse files Browse the repository at this point in the history
New feature to adjust the limit price order based on a factor of the actual pair price.
  • Loading branch information
adocquin authored Nov 6, 2021
2 parents 3130b24 + 677f80f commit 8b1d906
Show file tree
Hide file tree
Showing 8 changed files with 97 additions and 5 deletions.
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,14 @@ api:
# pair: Name of the pair (list of available pairs: https://api.kraken.com/0/public/AssetPairs)
# delay: Delay in days between each buy limit order.
# amount: Amount of the order in quote asset.
# limit_factor (optional): Create the limit order at a price of current price
# multiplied by specified factor (up to 5 digits).
# E.g., limit_factor = 0.95 creates a limit order 5% below market price
dca_pairs:
- pair: "XETHZEUR"
delay: 1
amount: 15
limit_factor: 0.98
- pair: "XXBTZEUR"
delay: 3
amount: 20
Expand All @@ -88,6 +92,9 @@ dca_pairs:
- Available pairs for pair field can be found [here](https://api.kraken.com/0/public/AssetPairs) on *altname*.
- Amount is the amount of quote asset to sell to buy base asset.
- You can specify as many pairs as you want in the dca_pairs list.
- Set a `limit_factor` if you want to place the buy order that is different from the
current market price (up to 5 digits).<br>
E.g., `limit_factor: 0.95` would set the limit price 5% below the market price.

More information on
[Kraken API official documentation](https://support.kraken.com/hc/en-us/articles/360000920306-Ticker-pairs).
Expand Down
1 change: 0 additions & 1 deletion __main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,3 @@
kdca = KrakenDCA(config, ka)
kdca.initialize_pairs_dca()
kdca.handle_pairs_dca()

5 changes: 4 additions & 1 deletion config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,14 @@ api:
# pair: Name of the pair (list of available pairs: https://api.kraken.com/0/public/AssetPairs)
# delay: Delay in days between each buy limit order.
# amount: Amount of the order in quote asset.
# limit_factor (optional): Create the limit order at a price of current price
# multiplied by specified factor (up to 5 digits).
# E.g., limit_factor = 0.95 creates a limit order 5% below market price
dca_pairs:
- pair: "XETHZEUR"
delay: 1
amount: 15
limit_factor: 0.985
- pair: "XXBTZEUR"
delay: 3
amount: 20

22 changes: 21 additions & 1 deletion krakendca/dca.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ class DCA:
delay: int
pair: Pair
amount: float
limit_factor: float
orders_filepath: str

def __init__(
Expand All @@ -28,6 +29,7 @@ def __init__(
pair: Pair,
amount: float,
orders_filepath: str = "orders.csv",
limit_factor: float = 1,
) -> None:
"""
Initialize the DCA object.
Expand All @@ -41,6 +43,7 @@ def __init__(
self.delay = delay
self.pair = pair
self.amount = float(amount)
self.limit_factor = float(limit_factor)
self.orders_filepath = orders_filepath
print(f"Pair: {self.pair.name}, delay: {self.delay}, amount: {self.amount}.")

Expand All @@ -62,12 +65,13 @@ def handle_dca_logic(self) -> None:
# Get current pair ask price.
pair_ask_price = self.pair.get_pair_ask_price(self.ka, self.pair.name)
print(f"Current {self.pair.name} ask price: {pair_ask_price}.")
limit_price = self.get_limit_price(pair_ask_price)
# Create the Order object.
order = Order.buy_limit_order(
current_date,
self.pair.name,
self.amount,
pair_ask_price,
limit_price,
self.pair.lot_decimals,
self.pair.quote_decimals,
)
Expand All @@ -79,6 +83,22 @@ def handle_dca_logic(self) -> None:
else:
print("Already DCA.")

def get_limit_price(self, pair_ask_price: float) -> float:
"""
Calculates wanted limit price from current ask price and limit_factor.
:param pair_ask_price: Pair ask price to adjust li;it price from.
:return: The limit price
"""
if round(self.limit_factor, 5) == 1.0:
limit_price = pair_ask_price
else:
limit_price = round(pair_ask_price * self.limit_factor, 2)
print(
f"Factor adjusted limit price ({self.limit_factor:.4f}): {limit_price}."
)
return limit_price

def get_system_time(self) -> datetime:
"""
Compare system and Kraken time.
Expand Down
3 changes: 2 additions & 1 deletion krakendca/krakendca.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ def initialize_pairs_dca(self):
for dca_pair in self.config.dca_pairs:
pair = Pair.get_pair_from_kraken(self.ka, asset_pairs, dca_pair.get("pair"))
self.dcas_list.append(DCA(
self.ka, dca_pair.get("delay"), pair, dca_pair.get("amount")
self.ka, dca_pair.get("delay"), pair, dca_pair.get("amount"),
limit_factor=dca_pair.get("limit_factor", 1)
))

def handle_pairs_dca(self):
Expand Down
5 changes: 4 additions & 1 deletion tests/fixtures/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,14 @@ api:
# pair: Name of the pair (list of available pairs: https://api.kraken.com/0/public/AssetPairs)
# delay: Delay in days between each buy limit order.
# amount: Amount of the order in quote asset.
# limit_factor (optional): Create the limit order at a price of current price
# multiplied by specified factor (up to 5 digits).
# E.g., limit_factor = 0.95 creates a limit order 5% below market price
dca_pairs:
- pair: "XETHZEUR"
delay: 1
amount: 15
limit_factor: 0.985
- pair: "XXBTZEUR"
delay: 3
amount: 20

50 changes: 50 additions & 0 deletions tests/fixtures/vcr_cassettes/test_limit_factor.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
interactions:
- request:
body: pair=XETHZEUR
headers:
Connection:
- close
Content-Length:
- '13'
Content-Type:
- application/x-www-form-urlencoded
Host:
- api.kraken.com
User-Agent:
- Python-urllib/3.8
method: POST
uri: https://api.kraken.com/0/public/Ticker
response:
body:
string: '{"error":[],"result":{"XETHZEUR":{"a":["3896.01000","54","54.000"],"b":["3896.00000","1","1.000"],"c":["3896.00000","0.01289350"],"v":["13252.90999721","14339.17068685"],"p":["3838.30816","3829.30482"],"t":[20470,22511],"l":["3700.00000","3690.00000"],"h":["3913.02000","3913.02000"],"o":"3729.23000"}}}'
headers:
CF-Cache-Status:
- DYNAMIC
CF-RAY:
- 6a8036490b280746-FRA
Connection:
- close
Content-Type:
- application/json; charset=utf-8
Date:
- Tue, 02 Nov 2021 20:46:24 GMT
Expect-CT:
- max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"
Server:
- cloudflare
Set-Cookie:
- __cf_bm=yvnjJaYTlqqvrgbQUObBpPK_9B7DPalBHlf.kAwetDA-1635885984-0-ATG59S5EJ4tqwg2AtcDhs/509EHUsJWZ3F7YTvUSykyTB928Ps+tANmqYn+/200ttJBUBHiJUpEbQoH9lLixOww=;
path=/; expires=Tue, 02-Nov-21 21:16:24 GMT; domain=.kraken.com; HttpOnly;
Secure; SameSite=None
Transfer-Encoding:
- chunked
cache-control:
- no-cache,max-age=0
referrer-policy:
- no-referrer-when-downgrade
strict-transport-security:
- max-age=15768000
status:
code: 200
message: OK
version: 1
9 changes: 9 additions & 0 deletions tests/test_dca.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ def test_init(self):
assert type(self.dca.pair) == Pair
assert type(self.dca.amount) == float
assert self.dca.amount == 20
assert type(self.dca.limit_factor) == float
assert self.dca.limit_factor == 1
assert self.dca.orders_filepath == self.test_orders_filepath

@freeze_time("2021-04-15 21:33:28.069731")
Expand Down Expand Up @@ -195,3 +197,10 @@ def test_send_buy_limit_order(self, capfd):
"OUHXFN-RTP6W-ART4VP\nDescription: buy 0.01029256 ETHEUR @ limit 1938.11\n"
)
assert captured.out == test_output

@vcr.use_cassette("tests/fixtures/vcr_cassettes/test_limit_factor.yaml")
def test_limit_factor(self):
self.dca.limit_factor = 0.9
assert self.dca.get_limit_price(3896.01) == 3506.41
self.dca.limit_factor = 0.999999
assert self.dca.get_limit_price(3896.01) == 3896.01

0 comments on commit 8b1d906

Please sign in to comment.