Questrade client for iOS.


The process to become a partner developer with Questrade has made it hard to make a very functional experience, so I had to pull it from the AppStore for the time being. You can view the iOS source code here.


After signing up for Questrade and trying their iOS app, I was not satisfied with the slow web-wrapped experience. I wanted a fast mobile client for iOS, so I decided to see if I could make my own. For the initial release, I wanted to deliver an App that was fast, secure and native. With a simple focus on current orders, positions, and balances.


I wanted to push myself on two main fronts while building this. Build a Swift native client API to interact with Questrade, and learn about app distribution automation. While I also gained a deeper understanding of UIKit auto-layout, localization and interface theming. I want to focus on the former two aspects.

Client API

For this project I ended up building a completely native Swift API using powerful Swift features such as Generics and Codable protocols to deliver a lightweight, secure, powerful, and easy to use native API.

// First setup the keychain store for your app
let keychain = AuthKeychainStore(service: "Questrade", account: "Obsidian", data: [:])

// since the init could throw errors you will have to wrap it in a do catch
do {
    // Init iOSQuestAuth class with the keychain store
    let auth = try iOSQuestAuth(keychainStore: keychain)
    // Init QuestAPI with the authorizer
    let api = QuestAPI(authorizor: auth)
    // Optionally set a singleton to access the API
    QuestAPI.shared = api
} catch let err {
    // handle error

Automated Distribution

I learned the basics of fastlane to automate tedious tasks of capturing, uploading, and localizing App Store metadata. I learned how to use fastlane in conjunction with automated Xcode Tests to capture screenshots and publish versions to AppStore Connect using scoped lanes. This was very useful to save time when exporting screenshots for all devices in different localizations, and for pushing quick builds to TestFlight. After spending the time to learn the basics of fastlane I was able to automate processes that are usually very time consuming and tedious.


platform :ios do
    lane :test_beta do

            build_number: latest_testflight_build_number + 1,
            xcodeproj: "Obsidian.xcodeproj"

        commit_version_bump(xcodeproj: "Obsidian.xcodeproj")

            scheme: "Obsidian",
            workspace: "Obsidian.xcworkspace",
            include_bitcode: true,
            output_directory: "./fastlane/app"


UI Test

class ObsidianUITests: XCTestCase {
    let app = XCUIApplication()
    var isLoggedOut = true
    func makeSureAppIsLoggedIn() {
        if isLoggedOut {
            app.images["AppIcon"].press(forDuration: 0.3);
            isLoggedOut = false
    func testPositions() {
        let button = app.tables.children(matching: .cell).element(boundBy: 1).buttons["PositionPriceLabel"]
        let expectation = XCTNSPredicateExpectation(predicate:NSPredicate(format: "exists == true"), object: button)
        wait(for: [expectation], timeout: 1)

        app.otherElements["Graph View"].press(forDuration: 1)
        snapshot("01-SymbolModalGraph", timeWaitingForIdle: 0)
        snapshot("02-Positions", timeWaitingForIdle: 0)


In the end I came away with experience building an open source Questrade API written in Swift, the marketing site, and the published Questrade client app.

Hi I’m Eli!

You can use this form for everything from asking me a question to blackmailing me with a deepfaked porno.