garethdmm / gryphon

Powerful, proven, and extensible framework for building trading strategies at any frequency, with a focus on crypto currencies. Battle-tested with billions traded.
http://www.gryphonframework.org
Other
1.05k stars 150 forks source link

Looking for feedback: Strategies and Strategy Ledgers are not intuitive to users #65

Open garethdmm opened 5 years ago

garethdmm commented 5 years ago

Hey folks, I've heard from more than one person that the current behaviour of Strategy ledgers is counter-intuitive to new users. I have some thoughts about how to restructure this but I wanted to get the community opinion.

Here's the issue. The built-in market making strategies have a concept of a 'primary exchange', being the sole exchange which this strategy will place orders on, which is configurable between runs. By default, a strategy only has a single trade history (I call this the 'strategy ledger' in my head, but this might be confusing since we use 'ledger' also for exchanges, and for the total trade history of the firm in general, also looking for feedback about this terminology). This means that if you do a second run of the same strategy with a different primary exchange, it's running on the same strategy ledger and will have the some position, p&l etc. as the previous run.

This is surprising to some users, who think that running e.g. SimpleMarketMaking on two separate exchanges should represent a different trade history and have different metrics.

The reason this happens is because orders are associated with a strategy through their actor field. By default a strategy's actor is just it's name upper-cased. See: https://github.com/garethdmm/gryphon/blob/dbdcdc90c3cb982e28405c6485af4a9393512dce/gryphon/execution/strategies/base.pyx#L86-L92 Creating a separate ledger for each different targeted exchange is pretty simple, you'd just override the actor property and make it parameterized with the primary exchange.

This is intended behaviour. At Tinker, we sometimes ran a single strategy in multiple processes at once, with each process targeting a separate exchange. This gives a bunch of benefits through parallelism but helps with fault tolerance. Writing strategies such that they can be parallelized like this is surprisingly easy.

So here's the questions at hand:

1) Should we change the default strategies so that by default they keep separate ledgers for different target exchanges? 2) Should we somehow clarify in code the use of actor's to create these two different effects?

If yes to 2), I think a simple way to do this would be to have two strategy subclasses users could use. The first could be the current default, something like

class GlobalLedgerStrategy(Strategy)

and the different-ledger-for-each-exchange strategy could do something like this:

class ExchangeLocalLedgerStrategy(Strategy):
    @property
    def actor(self):
        return '%s_%s' % s(elf.__class__.__name__.upper(), self.primary_exchange_name)

Possibly both of these could inheret from something like PrimaryExchangeStrategy, since they both share the property and code of having a configurable target exchange. I'm open to different naming ideas for all of this too.

Thoughts?

bmoscon commented 5 years ago

@garethdmm either sounds fine to me, so long as the behavior is clearly documented somewhere. I have a slight preference for actually leaving it as-is and making it more clear that this is how it works, and why, but option 2 also sounds reasonable and maybe there is a way you could preserve the original behavior and make 2) optional? i.e. by allowing the user to control the value use as the actor name (optional kwarg that if used, overrides default?)