Skip to content

Commit 0ec04d9

Browse files
committed
rest api
1 parent ab84271 commit 0ec04d9

File tree

15 files changed

+2212
-103
lines changed

15 files changed

+2212
-103
lines changed

.flake8

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[flake8]
2+
max-line-length = 100

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,6 @@ dist/
66
__pycache__
77
.DS_Store
88
fix.ipynb
9-
examples
9+
examples/test
10+
.app.py
11+
.env

README.md

Lines changed: 32 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,30 +5,35 @@
55

66
# Python Ctrader Fix API
77

8-
### ToDo
8+
`ejtraderCT` is a Python library to access the Ctrader trading platform's FIX API.
9+
10+
## Features
911

10-
- [ ] Account Information "not possible fix limitation"
1112
- [x] Market Position buy and sell
12-
- [x] Peding orders limit and stop
13+
- [x] Pending orders limit and stop
1314
- [x] Partial close
1415
- [x] Stop loss & Take profit
1516
- [x] Modify Orders
1617
- [x] Modify position
17-
- [x] real time bid & ask
18+
- [x] Real-time bid & ask
19+
- [x] Check connection status
20+
- [ ] Rest API server (in development)
21+
- [ ] Webhook for Tradingviewer (in development)
22+
23+
## Prerequisites
1824

25+
The library has been tested on Python 3.7 to 3.9.
1926

2027
## Installation
21-
#### Tested on python 3.7 to 3.9
22-
```
23-
pip install ejtraderCT -U
24-
```
25-
#### Or install from source
2628

27-
```
28-
git clone https://github.com/ejtraderLabs/ejtraderCT
29-
cd ejtraderCT
30-
python setup.py install
29+
To install the latest version of `ejtraderCT`, you can use pip:
3130

31+
```shell
32+
pip install ejtraderCT -U
33+
```
34+
Or if you want to install from source, you can use:
35+
```shell
36+
pip install git+https://github.com/ejtraderLabs/ejtraderCT.git
3237
```
3338

3439
## Accessing the Ctrader FIX API
@@ -70,13 +75,16 @@ password="12345678" # - The password you configured
7075
api = Ctrader(server,account,password)
7176

7277
```
73-
74-
##### To disconnect and logout from the account
78+
##### Check the connection status
79+
```python
80+
api.isconnected()
81+
```
82+
##### Logout
7583
```python
7684
api.logout()
7785
```
7886

79-
### Real-time quote
87+
#### Real-time quote
8088

8189
##### Subscribe to symbols
8290
```python
@@ -244,11 +252,16 @@ price = "limit or stop entry price"
244252
api.orderModify(id, stoploss, takeprofit, price)
245253

246254
```
247-
## Contributors:
255+
## Contributing
248256

249-
<!-- CONTRIBUTORS:START -->
250-
<!-- CONTRIBUTORS:END -->
257+
We welcome any contribution to `ejtraderCT`. Here are some ways to contribute:
258+
259+
1. Report issues or suggest improvements by opening an [issue](https://github.com/ejtraderLabs/ejtraderCT/issues).
260+
2. Contribute with code to fix issues or add features via a [Pull Request](https://github.com/ejtraderLabs/ejtraderCT/pulls).
261+
262+
Before submitting a pull request, please make sure your codes are well formatted and tested.
251263

252264
## Acknowledgements
253265

254266
I would like to express my gratitude to [@HarukaMa](https://github.com/HarukaMa) for creating the initial project. Their work has been an invaluable starting point for my modifications and improvements.
267+

app.py

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
import os
2+
from typing import List
3+
from pydantic import BaseModel
4+
from fastapi import FastAPI
5+
from ejtraderCT import Ctrader
6+
7+
8+
app = FastAPI()
9+
api = None
10+
11+
12+
class LoginModel(BaseModel):
13+
server: str
14+
account: str
15+
password: str
16+
17+
18+
class SymbolModel(BaseModel):
19+
symbols: List[str]
20+
21+
22+
class OrderModel(BaseModel):
23+
symbol: str
24+
volume: float
25+
stoploss: float
26+
takeprofit: float
27+
price: float = None
28+
29+
30+
class ModifyModel(BaseModel):
31+
id: str
32+
stoploss: float
33+
takeprofit: float
34+
price: float = None
35+
36+
37+
class IdModel(BaseModel):
38+
id: str
39+
40+
41+
@app.post("/login")
42+
async def login():
43+
global api
44+
api = Ctrader(
45+
os.getenv("HOST_NAME"), os.getenv("SENDER_COMPID"), os.getenv("PASSWORD")
46+
)
47+
if api.isconnected():
48+
return {"message": "Logged in"}
49+
else:
50+
return {"error": "Check your credencials"}
51+
52+
53+
@app.get("/quote/{symbol}")
54+
async def quote(symbol: str = None):
55+
if symbol:
56+
quote = api.quote(symbol)
57+
else:
58+
quote = api.quote()
59+
return quote
60+
61+
62+
@app.post("/buy")
63+
async def buy(order: OrderModel):
64+
return {
65+
"Position": api.buy(
66+
order.symbol, order.volume, order.stoploss, order.takeprofit
67+
)
68+
}
69+
70+
71+
@app.post("/sell")
72+
async def sell(order: OrderModel):
73+
return {
74+
"Position": api.sell(
75+
order.symbol, order.volume, order.stoploss, order.takeprofit
76+
)
77+
}
78+
79+
80+
@app.post("/buyLimit")
81+
async def buy_limit(order: OrderModel):
82+
return {
83+
"Order": api.buyLimit(
84+
order.symbol, order.volume, order.stoploss, order.takeprofit, order.price
85+
)
86+
}
87+
88+
89+
@app.post("/sellLimit")
90+
async def sell_limit(order: OrderModel):
91+
return {
92+
"Order": api.sellLimit(
93+
order.symbol, order.volume, order.stoploss, order.takeprofit, order.price
94+
)
95+
}
96+
97+
98+
@app.post("/buyStop")
99+
async def buy_stop(order: OrderModel):
100+
return {
101+
"Order": api.buyStop(
102+
order.symbol, order.volume, order.stoploss, order.takeprofit, order.price
103+
)
104+
}
105+
106+
107+
@app.post("/sellStop")
108+
async def sell_stop(order: OrderModel):
109+
return {
110+
"Order": api.sellStop(
111+
order.symbol, order.volume, order.stoploss, order.takeprofit, order.price
112+
)
113+
}
114+
115+
116+
@app.get("/positions")
117+
async def positions():
118+
return api.positions()
119+
120+
121+
@app.get("/orders")
122+
async def orders():
123+
return api.orders()
124+
125+
126+
@app.post("/orderCancelById")
127+
async def order_cancel_by_id(id_model: IdModel):
128+
api.orderCancelById(id_model.id)
129+
return {"message": "Order cancelled"}
130+
131+
132+
@app.post("/positionCloseById")
133+
async def position_close_by_id(id_model: IdModel):
134+
api.positionCloseById(id_model.id)
135+
return {"message": "Position closed"}
136+
137+
138+
@app.post("/cancel_all")
139+
async def cancel_all():
140+
api.cancel_all()
141+
return {"message": "All orders cancelled"}
142+
143+
144+
@app.post("/close_all")
145+
async def close_all():
146+
api.close_all()
147+
return {"message": "All positions closed"}
148+
149+
150+
@app.post("/positionModify")
151+
async def position_modify(modify: ModifyModel):
152+
api.positionModify(modify.id, modify.stoploss, modify.takeprofit)
153+
return {"message": "Position modified"}
154+
155+
156+
@app.post("/orderModify")
157+
async def order_modify(modify: ModifyModel):
158+
api.orderModify(modify.id, modify.stoploss, modify.takeprofit, modify.price)
159+
return {"message": "Order modified"}
160+
161+
162+
@app.post("/logout")
163+
async def logout():
164+
return {"message": api.logout()}
165+
166+
167+
@app.post("/status")
168+
async def status():
169+
return {"connected": api.isconnected()}

ejtraderCT/api/ctrader.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -356,7 +356,6 @@ def quote(self, symbol=None):
356356
return self.fix.spot_price_list[symbol]
357357
return self.fix.spot_price_list
358358

359-
360359
def order_list_callback(self, data: dict, price_data: dict, client_id: str):
361360
orders = []
362361
for i, kv in enumerate(data.items()):
@@ -423,5 +422,14 @@ def cancel_all(self):
423422
self.fix.cancel_all()
424423

425424
def logout(self):
426-
self.fix.logout()
425+
if self.isconnected():
426+
self.fix.logout()
427+
logout = "Logged out"
428+
else:
429+
logout = "Not logged in"
430+
return logout
431+
432+
433+
def isconnected(self):
434+
return self.fix.logged
427435

0 commit comments

Comments
 (0)