Skip to content

Custom Integration

guillaumedebavelaere edited this page Jun 25, 2019 · 16 revisions

Overview

Custom integration refers to using the TradeItSDK.linkedBrokerManager object as a programmatic workflow upon which you can build your own workflow and screens or use the user's raw balance/positions data in your app. The linkedBrokerManager can be used to link/relink/unlink a user's broker logins. It holds the list of linked brokers in TradeItSDK.linkedBrokerManager.linkedBrokers. Each of these TradeItLinkedBroker objects can be used to authenticate an active session with the broker. Once this has been done, the list of trading accounts associated with the linked broker are stored in linkedBroker.accounts. Each of these TradeItLinkedBrokerAccount objects can be used to trade and retrieve balances and positions. See below for further details and explicit code examples.

Error handling

Any methods which have an error/failure callback will return a TradeItErrorResult object that has an error code errorCode enum property. These codes, and how to handle them, are detailed here: https://www.trade.it/documentation/api#ErrorHandling

Linking a user's broker

Brokers are linked using an OAuth flow to ensure security and privacy. Linked brokers are persisted by the SDK between app launches so should only need to be linked once unless the OAuth token expires or becomes invalidated or the user reinstalls the app. To use a linked broker for TradeIt functionality the linked broker must be authenticated to obtain a valid session.

Getting the list of available brokers

The list of brokers available for use in your app is determined by your API key, and can also change due to intermittent service interruptions so it is important to retrieve a fresh list of available brokers when presenting the choice to users.

TradeItSDK.linkedBrokerManager.getAvailableBrokers(
    onSuccess: { availableBrokers in
        if let firstBroker = availableBrokers.first {
            firstBroker.brokerShortName // Use this string to indicate choice of broker to the SDK/API when linking or requesting the OAuth URL
            firstBroker.brokerLongName // Use this string to display in the UI
        }
    }

Launching OAuth

After initializing TradeItSDK, use the linkedBrokerManager instance to get the URL for the OAuth login popup. The oAuthCallbackUrl should be a deep link back into your app and will be used to pass the OAuthVerifier token back into the app. On success, launch the resulting URL in the system browser or a UIWebView/SFSafariViewController and the user will be presented with an OAuth login page.

TradeItSDK.linkedBrokerManager.getOAuthLoginPopupUrl(
    withBroker: "dummy",
    oAuthCallbackUrl: "yourAppScheme://completeOAuth",
    onSuccess: { url in
        // Do this OR load URL in a UIWebView/SFSafariViewController
        UIApplication.shared.openURL(NSURL(string:url) as! URL)
    }, onFailure: { errorResult in
        AlertManager().showError(errorResult,
                                 onViewController: self)
    }
)

If the user needs to relink an already linked broker in order to update the OAuth token (the OAuth token has expired or become invalidated) then use this method instead of the above:

TradeItSDK.linkedBrokerManager.getOAuthLoginPopupForTokenUpdateUrl(
    forLinkedBroker: linkedBroker, // The linked broker that needs to be relinked
    onSuccess: { url in
        // Do this OR load URL in a UIWebView/SFSafariViewController
        UIApplication.shared.openURL(NSURL(string:url) as! URL)
    }, onFailure: { errorResult in
        AlertManager().showError(
            errorResult,
            onViewController: self
        )
    }
)

OAuth Completion

A successful OAuth login results in the browser redirecting to the provided callback with an appended query string including the oAuthVerifier. Example:

tradeItExampleApp://completeOAuth?oAuthVerifier=123-456-789-000

This should be set up to deep link back into your app. If you already have deep linking in your app, make sure to use a unique host/path for the Trade.it OAuth flow. Deep linking is handled in AppDelegate. Intercept the deep link and extract the OAuth verifier token from the deep link URL and pass it in to the SDK to complete linking:

TradeItSDK.linkedBrokerManager.completeOAuth(
    withOAuthVerifier: oAuthVerifier,
    onSuccess: { linkedBroker in
        print("=====> OAuth successful for \(linkedBroker.brokerName)!")
    },
    onFailure: { errorResult in
        print("=====> ERROR: OAuth failed! \(errorResult.errorCode): \(errorResult.shortMessage): \(errorResult.longMessages?.first)")
    }
)

Authenticating a linked broker

Authenticating a linked broker creates a temporary session (~30 minutes) with the broker that allows for all other actions to be taken, such as trading and retrieving portfolio information.

linkedBroker.authenticateIfNeeded(
    onSuccess: {},
    onSecurityQuestion: { securityQuestion, answerSecurityQuestion, cancelQuestion in
        // Manually prompt the user for an answer and then submit it to finish authenticating
        answerSecurityQuestion("answer")

        // OR use the provided alert manager
        self.alertManager.promptUserToAnswerSecurityQuestion(
            securityQuestion,
            onViewController: self,
            onAnswerSecurityQuestion: answerSecurityQuestion,
            onCancelSecurityQuestion: cancelQuestion)
    }, onFailure: { (errorResult) in
        // handle error
})

Authenticating all accounts

This can be used when the app starts up and none of the linked brokers have a valid session yet. NOTE: This method does not have a callback for authentication errors. If a linked broker could not be authenticated, the linkedBroker.error property will be set.

TradeItSDK.linkedBrokerManager.authenticateAll(onSecurityQuestion: { securityQuestion, answerSecurityQuestion in
    // Manually prompt the user for an answer and then submit it to finish authenticating
    answerSecurityQuestion(/* answer from user */)
    
    // OR use the provided alert manager
    self.alertManager.promptUserToAnswerSecurityQuestion(
        securityQuestion,
        onViewController: self,
        onAnswerSecurityQuestion: answerSecurityQuestion,
        onCancelSecurityQuestion: cancelQuestion)
}, onFinished: {
    // Brokers that did not successfully authenticate will have the TradeItErrorResult error property set: linkedBroker.error?
    print("\(TradeItSDK.linkedBrokerManager.linkedBrokers.map { $0.error == nil }.count) brokers authenticated.")
})

Fetching portfolio and account data

// Account balances - given an authenticated broker account
linkedBrokerAccount.getAccountOverview(onSuccess: {
    print(linkedBrokerAccount.balance)
}, onFailure: { errorResult in
    print(errorResult)
})

// Account positions - given an authenticated broker account
linkedBrokerAccount.getPositions(onSuccess: { positions in
    print(positions.map({ position in
        return position.position
    }))
}, onFailure: { errorResult in
    print(errorResult)
})

Trading

// Trading - given an authenticated broker account
let order = TradeItOrder()
order.linkedBrokerAccount = linkedBrokerAccount
order.symbol = "CMG"
order.action = .buy
order.type = .limit
order.expiration = .goodUntilCanceled
quantity = 100.0
limitPrice = 395.65

order.preview(onSuccess: { previewOrder, placeOrderCallback in
    // Display previewOrder contents to user for review
    // When the user confirms, call the placeOrderCallback to place the trade
    placeOrderCallback({ result in
        // Display result contents to the user
    }, { errorResult in
        // Display errorResult contents to user
    })
}, onFailure: { errorResult in
    // Display errorResult contents to user
})

Manual Initialization

The SDK automatically persists linked brokers locally on the device between usages of your app. However, it is also possible to manually initialize linked brokers and the associated accounts if you have persisted the data elsewhere remotely. This can be used to sync a user's linked accounts between instances of the app on other devices/platforms without the user having to relink.

First, capture and persist the necessary data when a new broker is linked:

class MyViewController: UIViewController, TradeItOAuthDelegate {
    override func viewDidLoad() {
        TradeItSDK.linkedBrokerManager.oAuthDelegate = self
    }

    func didLink(linkedBroker: TradeItLinkedBroker, userId: String, userToken: String) {
        linkedBroker.authenticate(
            onSuccess: {
                // Remotely persist the following data:
                //     userId
                //     userToken
                //     linkedBroker.brokerName
                //     linkedBroker.brokerLongName
                //     linkedBroker.accounts.map { return ($0.accountName, $0.accountNumber, $0.baseCurrency, $0.userCanDisableMargin) }
            },
            onSecurityQuestion: { (securityQuestion, answerSecurityQuestion, cancel) in
                // handle security question
            },
            onFailure: { errorResult in
                // handle failure
            }
        )
    }
}

If you want you can also fetch and store account balances and positions after you authenticate.

Then, later when the app is relaunched, you can sync/load from the remotely persisted data. The SDK loads locally persisted linked brokers from the device when it is configured so make sure any manual intervention is done after configuring the SDK via the call to TradeItSDK.configure().

Sync linked brokers/accounts from remotely persisted data:

let remoteBrokersToSync = [
            LinkedBrokerData( 
                userId: "userId", // persisted data
                userToken: "userToken", // persisted data
                broker: "broker", // persisted data
                brokerLongName: "broker long name", // persisted data
                accounts: [
                   LinkedBrokerAccountData(
                     name: "account name",  // persisted data
                     number: "account number",  // persisted data
                     baseCurrency: "USD",  // persisted data
                     userCanDisableMargin: false // persisted data
                   )
                ]
            )
        ]
        TradeItSDK.linkedBrokerManager.syncLocal(
            withRemoteLinkedBrokers: remoteBrokersToSync,
            onFailure: { errorResult in
                print("=====> Failed to sync linked brokers manually: \(String(describing: errorResult.shortMessage)) - \(String(describing: errorResult.longMessages?.first))")
            },
            onFinished: {
                print("=====> MANUALLY SYNC LINKED BROKERS!")
                TradeItSDK.linkedBrokerManager.linkedBrokers.forEach {
                    // do something
                }
                TradeItSDK.linkedBrokerManager.printLinkedBrokers()
            }
        )