Skip to content

Commit 782f85e

Browse files
authored
Merge pull request #17 from Finterion/feature/poetry-package
Feature/poetry package
2 parents cf8dbbf + a74e9e0 commit 782f85e

File tree

10 files changed

+195
-111
lines changed

10 files changed

+195
-111
lines changed

.github/workflows/publish.yml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
name: Build and publish python package
2+
3+
on:
4+
release:
5+
types: [ published ]
6+
7+
jobs:
8+
publish-service-client-package:
9+
runs-on: ubuntu-latest
10+
permissions:
11+
contents: write
12+
steps:
13+
- name: Publish PyPi package
14+
uses: code-specialist/pypi-poetry-publish@v1
15+
with:
16+
ACCESS_TOKEN: ${{ secrets.REPOSITORY_ACCESS_TOKEN }}
17+
PUBLISH_REGISTRY_PASSWORD: ${{ secrets.PYPI_TOKEN }}

.github/workflows/test.yml

Lines changed: 89 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,99 @@
1-
# This workflow will install Python dependencies, run tests and lint
2-
# with a single version of Python
3-
4-
name: Tests
1+
name: test
52

63
on:
74
push:
85
branches:
96
- '*' # matches every branch that doesn't contain a '/'
107
- '*/*' # matches every branch containing a single '/'
118
- '**' # matches every branch
12-
pull_request:
13-
branches:
14-
- '*' # matches every branch that doesn't contain a '/'
15-
- '*/*' # matches every branch containing a single '/'
16-
- '**' # matches every branch
17-
jobs:
18-
testing:
9+
pull_request:
10+
branches:
11+
- '*' # matches every branch that doesn't contain a '/'
12+
- '*/*' # matches every branch containing a single '/'
13+
- '**' # matches every branch
1914

15+
jobs:
16+
linting:
2017
runs-on: ubuntu-latest
21-
2218
steps:
23-
- uses: actions/checkout@v2
24-
- name: Set up Python 3.9
25-
uses: actions/setup-python@v2
26-
with:
27-
python-version: 3.9
28-
- name: Install dependencies
29-
run: |
30-
python -m pip install --upgrade pip
31-
pip install flake8
32-
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
33-
if [ -f requirements-test.txt ]; then pip install -r requirements-test.txt; fi
34-
- name: Lint with flake8
35-
run: |
36-
# stop the build if there are Python syntax errors or undefined names
37-
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
38-
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
39-
flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
40-
- name: Test
41-
run: |
42-
python -m unittest discover -s tests/
19+
#----------------------------------------------
20+
# check-out repo and set-up python
21+
#----------------------------------------------
22+
- uses: actions/checkout@v4
23+
- uses: actions/setup-python@v5
24+
#----------------------------------------------
25+
# load pip cache if cache exists
26+
#----------------------------------------------
27+
- uses: actions/cache@v3
28+
with:
29+
path: ~/.cache/pip
30+
key: ${{ runner.os }}-pip
31+
restore-keys: ${{ runner.os }}-pip
32+
#----------------------------------------------
33+
# install and run linters
34+
#----------------------------------------------
35+
- run: python -m pip install black flake8 isort
36+
- run: |
37+
flake8 ./finterion
38+
test:
39+
needs: linting
40+
strategy:
41+
fail-fast: true
42+
matrix:
43+
os: [ "ubuntu-latest", "macos-latest" ]
44+
python-version: [ "3.8", "3.9", "3.10", "3.11", "3.12" ]
45+
runs-on: ${{ matrix.os }}
46+
steps:
47+
#----------------------------------------------
48+
# check-out repo and set-up python
49+
#----------------------------------------------
50+
- name: Check out repository
51+
uses: actions/checkout@v4
52+
- name: Set up python ${{ matrix.python-version }}
53+
id: setup-python
54+
uses: actions/setup-python@v5
55+
with:
56+
python-version: ${{ matrix.python-version }}
57+
#----------------------------------------------
58+
# ----- install & configure poetry -----
59+
#----------------------------------------------
60+
- name: Install Poetry
61+
uses: snok/install-poetry@v1
62+
with:
63+
virtualenvs-create: true
64+
virtualenvs-in-project: true
65+
#----------------------------------------------
66+
# load cached venv if cache exists
67+
#----------------------------------------------
68+
- name: Load cached venv
69+
id: cached-poetry-dependencies
70+
uses: actions/cache@v3
71+
with:
72+
path: .venv
73+
key: venv-${{ runner.os }}-${{ steps.setup-python.outputs.python-version }}-${{ hashFiles('**/poetry.lock') }}
74+
#----------------------------------------------
75+
# install dependencies if cache does not exist
76+
#----------------------------------------------
77+
- name: Install dependencies
78+
if: steps.cached-poetry-dependencies.outputs.cache-hit != 'true'
79+
run: poetry install --no-interaction --no-root
80+
#----------------------------------------------
81+
# install your root project, if required
82+
#----------------------------------------------
83+
- name: Install library
84+
run: poetry install --no-interaction
85+
#----------------------------------------------
86+
# add matrix specifics and run test suite
87+
#----------------------------------------------
88+
- name: Run tests
89+
run: |
90+
source .venv/bin/activate
91+
coverage run -m unittest discover -s tests
92+
# #----------------------------------------------
93+
# # upload coverage stats
94+
# #----------------------------------------------
95+
# - name: Upload coverage
96+
# uses: codecov/codecov-action@v3
97+
# with:
98+
# file: ./coverage.xml
99+
# fail_ci_if_error: true

finterion/__init__.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
from finterion.exceptions import ClientException
2-
from finterion.exceptions import ClientException
3-
from finterion.models import OrderSide, OrderType, Order, Position, Portfolio, \
4-
OrderStatus
5-
from finterion.models import OrderSide, OrderType, Order, Position, Portfolio, \
6-
OrderStatus
2+
from finterion.models import OrderSide, OrderType, Order, Position, \
3+
Portfolio, OrderStatus
74
from finterion.finterion import Finterion
85

96
__all__ = [

finterion/configuration/urls.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,3 @@ def get_retrieve_position_url(base_url, position_id):
2828

2929
def get_retrieve_portfolio_url(base_url):
3030
return f"{base_url}/portfolio"
31-

finterion/finterion.py

Lines changed: 51 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -36,18 +36,21 @@ def get_orders(
3636
target_symbol=None,
3737
symbol=None,
3838
order_type=None,
39-
order_side=None
39+
order_side=None,
40+
query_params: dict = None
4041
):
41-
query_params = {
42-
"itemized": "true",
43-
"environment": self.algorithm["environment"],
44-
}
42+
43+
if query_params is None:
44+
query_params = {}
45+
46+
query_params["itemized"] = "true"
47+
query_params["environment"] = self.algorithm["environment"]
4548

4649
if status is not None:
4750
query_params["status"] = status
4851

4952
if target_symbol is not None:
50-
query_params["target_symbol"] = target_symbol
53+
query_params["TargetSymbol"] = target_symbol
5154

5255
if symbol is not None:
5356
query_params["symbol"] = symbol
@@ -59,14 +62,25 @@ def get_orders(
5962
query_params["side"] = order_side
6063

6164
orders = services.get_orders(
62-
self.api_key, query_params, base_url=self.base_url
65+
api_key=self.api_key,
66+
query_params=query_params,
67+
base_url=self.base_url
6368
)
6469
logger.debug(f"get_orders response {orders}")
6570
return orders["items"]
6671

67-
def get_order(self, order_id):
72+
def get_order(self, order_id, query_params: dict = None):
73+
74+
if query_params is None:
75+
query_params = {}
76+
77+
query_params["environment"] = self.algorithm["environment"]
78+
6879
response = services.get_order(
69-
self.api_key, order_id, base_url=self.base_url
80+
api_key=self.api_key,
81+
order_id=order_id,
82+
base_url=self.base_url,
83+
query_params=query_params
7084
)
7185
logger.info(f"get_order response {response}")
7286
return response
@@ -84,7 +98,9 @@ def create_order(
8498

8599
}
86100
response = services.create_order(
87-
self.api_key, base_url=self.base_url, data=data
101+
api_key=self.api_key,
102+
base_url=self.base_url,
103+
data=data
88104
)
89105
logger.debug(f"create_order response {response}")
90106
return response
@@ -124,18 +140,29 @@ def create_market_order(self, target_symbol, order_side, amount):
124140
logger.debug(f"create_market_order response {response}")
125141
return response
126142

127-
def get_position(self, position_id):
143+
def get_position(self, position_id, query_params: dict = None):
144+
145+
if query_params is None:
146+
query_params = {}
147+
148+
query_params["environment"] = self.algorithm["environment"]
149+
128150
response = services.get_position(
129-
self.api_key, position_id, base_url=self.base_url
151+
api_key=self.api_key,
152+
position_id=position_id,
153+
base_url=self.base_url,
154+
query_params=query_params
130155
)
131156
logger.debug(f"get_position response {response}")
132157
return response
133158

134-
def get_positions(self, symbol=None):
135-
query_params = {
136-
"itemized": "true",
137-
"environment": self.algorithm["environment"],
138-
}
159+
def get_positions(self, symbol=None, query_params: dict = None):
160+
161+
if query_params is None:
162+
query_params = {}
163+
164+
query_params["itemized"] = "true"
165+
query_params["environment"] = self.algorithm["environment"]
139166

140167
if symbol is not None:
141168
query_params["symbol"] = symbol
@@ -146,9 +173,14 @@ def get_positions(self, symbol=None):
146173
logger.debug(f"get_positions response {positions}")
147174
return positions["items"]
148175

149-
def get_portfolio(self):
176+
def get_portfolio(self, query_params: dict = None):
177+
if query_params is None:
178+
query_params = {}
179+
150180
response = services.get_portfolio(
151-
self.api_key, self.base_url
181+
api_key=self.api_key,
182+
query_params=query_params,
183+
base_url=self.base_url
152184
)
153185
logger.debug(f"get_portfolio response {response}")
154186
return response

finterion/models/order.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,4 +101,4 @@ def get_amount_target_symbol(self):
101101
return self.amount_target_symbol
102102

103103
def get_amount_trading_symbol(self):
104-
return self.amount_trading_symbol
104+
return self.amount_trading_symbol

finterion/services.py

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -61,10 +61,14 @@ def get_orders(api_key, query_params, base_url):
6161
return handle_response(response)
6262

6363

64-
def get_order(api_key, order_id, base_url):
64+
def get_order(api_key, order_id, base_url, query_params):
6565
logger.debug("Getting order")
6666
url = get_retrieve_order_url(base_url, order_id)
67-
response = requests.get(url, headers={"XApiKey": api_key})
67+
response = requests.get(
68+
url,
69+
headers={"XApiKey": api_key},
70+
params=query_params
71+
)
6872
return handle_response(response)
6973

7074

@@ -85,15 +89,22 @@ def get_positions(api_key, query_params, base_url):
8589
return handle_response(response)
8690

8791

88-
def get_position(api_key, position_id, base_url):
92+
def get_position(api_key, position_id, base_url, query_params):
93+
8994
logger.debug("Getting position")
9095
url = get_retrieve_position_url(base_url, position_id)
91-
response = requests.get(url, headers={"XApiKey": api_key})
96+
response = requests.get(
97+
url,
98+
headers={"XApiKey": api_key},
99+
params=query_params
100+
)
92101
return handle_response(response)
93102

94103

95-
def get_portfolio(api_key, base_url):
104+
def get_portfolio(api_key, base_url, query_params):
96105
logger.debug("Getting portfolio")
97106
url = get_retrieve_portfolio_url(base_url)
98-
response = requests.get(url, headers={"XApiKey": api_key})
107+
response = requests.get(
108+
url, headers={"XApiKey": api_key}, params=query_params
109+
)
99110
return handle_response(response)

pyproject.toml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
[tool.poetry]
2+
name = "finterion-python-client"
3+
version = "0.7.6"
4+
description = "Official python client for Finterion"
5+
authors = ["marcvanduyn <[email protected]>"]
6+
license = "Apache License 2.0"
7+
readme = "README.md"
8+
9+
[tool.poetry.dependencies]
10+
python = "^3.8"
11+
requests= "^2.26.0"
12+
13+
[tool.poetry.group.test.dependencies]
14+
coverage= "7.4.2"
15+
16+
[build-system]
17+
requires = ["poetry-core"]
18+
build-backend = "poetry.core.masonry.api"

requirements.txt

Lines changed: 0 additions & 1 deletion
This file was deleted.

0 commit comments

Comments
 (0)