Dave-Vallance / bt-ccxt-store

Fork of Ed Bartosh's CCXT Store Work
MIT License
423 stars 187 forks source link

Support for starting positions #21

Closed obiben closed 4 years ago

obiben commented 4 years ago

Am I missing something or is there no support for loading current positions from account before starting to execute a strategy?

I'm currently making an attempt to connect backtrader to my (in-house) stock trading platform by implementing a python exchange and the web API at the same time.

Starting positions are one of the last pieces of the puzzle before I can at least start paper trading with it, then it's all up to me to connect the web API to actual trading.

Dave-Vallance commented 4 years ago

No, you are not missing anything.

The concept of a current position can be a tricky one. Especially if you are just swapping coins without leverage. You are never really in a position. You just have balances that you could query at startup.

With leverage, there is a definitive position. However, I have not looked into whether CCXT has a unified endpoint for grabbing a leveraged position size. Actually, just creating a leveraged order can be different from exchange to exchange.

obiben commented 4 years ago

Thanks for the response. I had the creeping suspicion this was indeed the case because this is basically FX trading.

I've gone ahead and made a few additions:

To my exchange:

    def fetch_positions(self, params={}):
        request = {
            'uid': self.uid
        }        

        return self.parse_positions(self.privateGetUserPositions(self.extend(request, params)))

    def parse_positions(self, positions):
        result = {}
        for market, pos in positions.items():
            result[market] = {
                    'size': pos['quantity'],
                    'price': pos['price']
                }

        return result

to ccxtstore:

    @retry
    def fetch_positions(self):
        return self.exchange.fetch_positions()

and finally in ccxtbroker's __init__ function:

        self.positions = collections.defaultdict(Position)

        positions = self.store.fetch_positions()
        for market, pos in positions.items():
            self.positions[market] = Position(size=pos['size'], price=pos['price'])

I still don't understand everything about backtrader, but with this it seems that when I start long, my first transaction will be a sale, and if I start short, it'll be a purchase so I'm all good.

shaoy06 commented 3 years ago

Hi obiben,

I am having the same issue and just saw you have a solution above.

Could you please explain where to insert the following code? thanks! ` def fetch_positions(self, params={}): request = { 'uid': self.uid }

    return self.parse_positions(self.privateGetUserPositions(self.extend(request, params)))

def parse_positions(self, positions):
    result = {}
    for market, pos in positions.items():
        result[market] = {
                'size': pos['quantity'],
                'price': pos['price']
            }

    return result`
obiben commented 3 years ago

This seems like forever ago. self.privateGetUserPositions(self.extend(request, params)) fetches positions for the current user. parse_positions() just seems to swap out the key "quantity" for "size". Pretty sure that's just to be consistent with the terminology in the rest of the project. market in this case was a stock ticker.

shaoy06 commented 3 years ago

This seems like forever ago. self.privateGetUserPositions(self.extend(request, params)) fetches positions for the current user. parse_positions() just seems to swap out the key "quantity" for "size". Pretty sure that's just to be consistent with the terminology in the rest of the project. market in this case was a stock ticker.

Many thanks~