Skip to content

exchanges: Add dynamic function checking to determine exchange functionality #1619

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 15 commits into
base: master
Choose a base branch
from

Conversation

shazbert
Copy link
Collaborator

@shazbert shazbert commented Aug 18, 2024

PR Description

  • Adds AutomaticPreFlightCheck function to determine functionality support between protocols and asset types.
  • This is a POC for eligibility testing. This is backwards compatible and constricted to gateio for initial documentation output.
  • This attempts to standardise what is available across exchange implementations between functionality for a quicker decision on what endpoints to use and dynamically scale up and down depending on actual support. Specifically started with trading endpoints to keep things simple.

Type of change

Please delete options that are not relevant and add an x in [] as item is complete.

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

How has this been tested

Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration and
also consider improving test coverage whilst working on a certain feature or package.

  • go test ./... -race
  • golangci-lint run
  • Test X

Checklist

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation and regenerated documentation via the documentation tool
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally and on Github Actions with my changes
  • Any dependent changes have been merged and published in downstream modules

@shazbert shazbert added help wanted low priority This enhancement or update will be implemented at a later date. labels Aug 18, 2024
@shazbert shazbert requested a review from a team August 18, 2024 04:37
@shazbert shazbert self-assigned this Aug 18, 2024
Copy link

codecov bot commented Aug 18, 2024

Codecov Report

Attention: Patch coverage is 46.61017% with 63 lines in your changes missing coverage. Please review.

Project coverage is 36.39%. Comparing base (225429b) to head (40a5397).
Report is 106 commits behind head on master.

Files with missing lines Patch % Lines
cmd/documentation/documentation.go 0.00% 42 Missing ⚠️
exchanges/preflight.go 83.87% 3 Missing and 7 partials ⚠️
exchanges/protocol/features.go 0.00% 8 Missing ⚠️
engine/engine.go 50.00% 2 Missing and 1 partial ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #1619      +/-   ##
==========================================
+ Coverage   36.36%   36.39%   +0.03%     
==========================================
  Files         422      424       +2     
  Lines      183105   183221     +116     
==========================================
+ Hits        66588    66692     +104     
- Misses     108475   108481       +6     
- Partials     8042     8048       +6     
Files with missing lines Coverage Δ
engine/engine.go 39.71% <50.00%> (+<0.01%) ⬆️
exchanges/protocol/features.go 0.00% <0.00%> (ø)
exchanges/preflight.go 83.87% <83.87%> (ø)
cmd/documentation/documentation.go 0.00% <0.00%> (ø)

... and 16 files with indirect coverage changes

Copy link

This PR is stale because it has been open 30 days with no activity. Please provide an update on the progress of this PR.

@github-actions github-actions bot added the stale label Jan 13, 2025
@shazbert shazbert added review me This pull request is ready for review and removed stale labels Jan 13, 2025
Copy link

This PR is stale because it has been open 30 days with no activity. Please provide an update on the progress of this PR.

@github-actions github-actions bot added the stale label Feb 13, 2025
Copy link
Collaborator

@gloriousCode gloriousCode left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like a worthwhile feature to expand across the exchanges now. I like automation

	var supported bool
	if butts, ok := b.ProtocolCapabilities[protocol.Target{
		Asset:    asset.Spot,
		Protocol: protocol.REST,
	}]; ok {
		supported = butts.AccountBalance
	}

Copy link
Collaborator

@gloriousCode gloriousCode left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nicely done with the revamp. Looks like BTC markets needs a looky and then you're good

Copy link
Collaborator

@gloriousCode gloriousCode left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tHANKS

Copy link
Collaborator

@gloriousCode gloriousCode left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tACK

@gloriousCode gloriousCode added the gcrc GloriousCode Review Complete label Mar 6, 2025
Copy link
Collaborator

@gbjk gbjk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good work 👍

At first I was skeptical about the complexity of using reflect, and how it shouldn't be so hard for us to just do this.
But then I don't see a better way across all exchanges and assets with what we currently have.

Naming was my biggest initial thing.

I definitely thing we shouldn't pollute runtime Base fields with this when it's only need for docs; Correct me if I'm wrong.

Comment on lines +116 to +147
Features []ProtocolFunctionality
}

// ProtocolFunctionality defines a protocol feature set
type ProtocolFunctionality struct {
Protocol string
Assets []AssetFunctionality
}

func (a ProtocolFunctionality) String() string {
return a.Protocol
}

// AssetFunctionality defines an asset feature set
type AssetFunctionality struct {
Asset string
Methods []MethodNameAndOperational
}

func (a AssetFunctionality) String() string {
return a.Asset
}

// MethodNameAndOperational defines a method name and if it is operational
type MethodNameAndOperational struct {
MethodName string
Operational bool
}

// String returns the method name
func (m MethodNameAndOperational) String() string {
return m.MethodName
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🐒

  • I think the naming could use some revision here. MethodNameAndOperational should just be a Method
  • MethodNameAndOperational.MethodName should just be Method.Name
  • Operational feels like another term we've already used, like "Supported" ?
  • Method and Features seems to be overloaded terms, but I think that's okay.
  • Should these really be slices instead of maps; Feels like we're hiding the unique relationship and forcing a lookup usage later
Suggested change
Features []ProtocolFunctionality
}
// ProtocolFunctionality defines a protocol feature set
type ProtocolFunctionality struct {
Protocol string
Assets []AssetFunctionality
}
func (a ProtocolFunctionality) String() string {
return a.Protocol
}
// AssetFunctionality defines an asset feature set
type AssetFunctionality struct {
Asset string
Methods []MethodNameAndOperational
}
func (a AssetFunctionality) String() string {
return a.Asset
}
// MethodNameAndOperational defines a method name and if it is operational
type MethodNameAndOperational struct {
MethodName string
Operational bool
}
// String returns the method name
func (m MethodNameAndOperational) String() string {
return m.MethodName
AvailableMethods ProtocolMethods
}
type ProtocolMethods map[Protocol]AssetMethods
type AssetMethods map[Asset]MethodSupported
type Asset string // Or asset.Item?
type MethodSupported map[Method]bool
type Method string

@@ -485,13 +523,15 @@ func GetContributorList(repo string, verbose bool) ([]Contributor, error) {

// GetDocumentationAttributes returns specific attributes for a file template
func GetDocumentationAttributes(packageName string, contributors []Contributor) Attributes {
name := GetPackageName(packageName, false)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Feels like we have n+ things using public methods.
Could we make a type Package and then have methods on it for Functionaliy, GoDocURL, etc ?

@@ -509,6 +549,48 @@ func GetPackageName(name string, capital bool) string {
return newStrings[i]
}

// GetFunctionality returns a dynamic list of supported functionality for a specific asset type.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// GetFunctionality returns a dynamic list of supported functionality for a specific asset type.
// GetFunctionality returns a list of supported functionality grouped by protocol and asset type

// GenerateSupportedFunctionality analyzes the exchange's supported asset types and protocols, returning a set of dynamically
// discovered features (ProtocolCapabilities) that the exchange supports. This process is based on the exchange's
// specific implementation of wrapper functions.
func GenerateSupportedFunctionality(exch IBotExchange) protocol.FunctionalitySet {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
func GenerateSupportedFunctionality(exch IBotExchange) protocol.FunctionalitySet {
func GetSupportedFunctionality(exch IBotExchange) protocol.FunctionalitySet {

@@ -509,6 +549,48 @@ func GetPackageName(name string, capital bool) string {
return newStrings[i]
}

// GetFunctionality returns a dynamic list of supported functionality for a specific asset type.
func GetFunctionality(name string) []ProtocolFunctionality {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
func GetFunctionality(name string) []ProtocolFunctionality {
func GetFeatures(name string) FeatureMap {

@@ -437,7 +471,11 @@ func GetProjectDirectoryTree(c *Config) ([]string, error) {
// GetTemplateFiles parses and returns all template files in the documentation
// tree
func GetTemplateFiles() (*template.Template, error) {
tmpl := template.New("")
tmpl := template.New("").Funcs(template.FuncMap{
"contains": contains,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Considered using sprig.has ?

tmpl := template.New("")
tmpl := template.New("").Funcs(template.FuncMap{
"contains": contains,
"append": _append,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Considered using sprig.append ?

Comment on lines +10 to +40
{{- /* Collect all unique asset types */ -}}
{{- range $asset := $feature.Assets }}
{{- $assetTypes = append $assetTypes $asset.Asset }}
{{- range $method := $asset.Methods }}
{{- if not (contains $methodNames $method.MethodName) }}
{{- $methodNames = append $methodNames $method.MethodName }}
{{- end }}
{{- end }}
{{- end }}

| Method Name |{{range $asset := $assetTypes}} {{$asset}} |{{end}}
|------------|{{range $asset := $assetTypes}}---|{{end}}

{{- /* Iterate over all unique method names */ -}}
{{- range $methodName := $methodNames }}
| {{$methodName}} |
{{- range $asset := $assetTypes }}
{{- $found := false }}
{{- range $lookup := $feature.Assets }}
{{- if eq $lookup.Asset $asset }}
{{- range $m := $lookup.Methods }}
{{- if eq $m.MethodName $methodName }}
{{- if $m.Operational }} 🟢 {{else}} 🚫 {{end}}
{{- $found = true }}
{{- end }}
{{- end }}
{{- end }}
{{- end }}
{{- if not $found }} 🚫 {{end}} |
{{- end }}
{{- end }}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This feels like a lot of logic in the template, because of the state vars you've had to create, etc.
I feel like you should be able to get the asset types, the methods and their status inside a func and have a much simpler text template here.

return err
}

// Update protocol capabilities with dynamic supported functionality check
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't think this comment is adding anything :)

Suggested change
// Update protocol capabilities with dynamic supported functionality check

Features Features
// ProtocolCapabilities is a map of supported functionality for each asset type and protocol type. This is mapped in
// the supported features check to determine if the method is functional and ready for that asset type.
ProtocolCapabilities protocol.FunctionalitySet
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Took me a while to work out why this bothered me:

  • Capabilities are Features
  • And ProtocolFeatures is just Features re-envisioned, right?

So should we not just change Features itself?
I know it's a lot more work, but if it's the right thing to do...

Alternative thought is: Do we even need to store the FeatureMap? We're not using it often enough to make it a field on Base, IMO. Maybe we derive it when needed

@shazbert shazbert removed the review me This pull request is ready for review label Apr 1, 2025
Copy link

github-actions bot commented May 2, 2025

This PR is stale because it has been open 30 days with no activity. Please provide an update on the progress of this PR.

@github-actions github-actions bot added the stale label May 2, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
gcrc GloriousCode Review Complete low priority This enhancement or update will be implemented at a later date. stale
Projects
Status: In progress
Development

Successfully merging this pull request may close these issues.

3 participants