# Trading system development: write rules a coder can build

URL: https://fincodelabs.com/en/blog/trading-system-development · Publisher: Fincode (Fincode Yazılım ve Teknoloji A.Ş.), Istanbul, Turkey · Category: Trading bots · Published: 2026-11-06 · Updated: 2026-11-06

Trading system development starts with a specification: a printable template, ambiguity tests, failure behavior, acceptance tests and stage gates to live.

**Short answer:** **Trading system development** starts with a written specification that turns rules you already have into statements a programmer can build and a tester can check: market and account, data and time zone, when each condition is evaluated, order handling, size and limits, failure behavior and acceptance tests. Here, strategy development means documenting your own rules; Fincode does not develop or suggest strategies and does not test for profit. Tests show how the software behaves, not future results, and trades can lose money.

Rules usually read clearly until someone has to code them. In the test below, one sentence coded four ways produced four different sets of entries, and each version can claim to follow it. A specification is the document that removes those choices before they turn into orders.

Every value on this page is a placeholder and nothing here suggests what to trade. Fincode sells development from documents like this one, so this guide is not neutral on that point. Which markets and platforms you may use depends on your jurisdiction. For readers in Turkey, Article 99/A of Capital Markets Law No. 6362 treats activity by foreign crypto-asset platforms directed at Turkish residents as unauthorized.

## What does trading system development mean here?

It means documenting your own rules and the system's behavior, not finding a strategy.

**What the search phrases cover on this page**

| Phrase | What it covers here |
| --- | --- |
| Trading system development | Specification, software, tests and go-live for rules you own |
| Algorithmic trading strategy development | Writing your rules down so they can be tested; not how to find or choose them |
| Building an automated trading system | The stage gates and the document each one produces |
| Financial trading system development | The same documents as regulated firms keep them, used as a model |

The line also matters legally: choosing trades for other people can be a licensed activity, so the rules stay yours. The parts of a finished system are in [trading bot development](https://fincodelabs.com/en/blog/trading-bot-development); this page is the document that comes first.

## Trading system specification template (printable)

Fill every bracket: a bracket you cannot fill is a decision still open.

```
TRADING SYSTEM SPECIFICATION   version [x.y]   owner [name]   date [yyyy-mm-dd]

1 MARKET AND ACCOUNT
  M1 Venue, account type: [venue], [spot / futures / broker account]
  M2 Instruments: [exact symbols]
  M3 Terms read: [API agreement, date]; your jurisdiction: [country]

2 DATA AND TIME
  D1 Source and bar type: [feed], [timeframe], built by [venue / locally]
  D2 Time zone of bars and sessions: [zone]; clock sync: [method]
  D3 Data license for this use: [checked, date]; missing data: [rule]

3 RULES, one testable statement each
  R1 Evaluate at: [bar close / each trade / schedule]
  R2 Entry is true when: [your condition], using [> / >=], on [closed bar / live value]
  R3 Exit is true when: [your condition]
  R4 Entry and exit true together: [which wins]
  R5 New entry while a position is open: [ignore / add up to limit]

4 ORDER HANDLING
  O1 Order type, time in force: [your choice]
  O2 Reference price and price rule: [your rule]
  O3 Not filled after [seconds]: [cancel / replace / leave]
  O4 Partly filled: [your rule for the remainder]
  O5 Rejected: [your rule]

5 SIZE AND LIMITS, your numbers, enforced outside the rule code
  L1 Size rule: [your rule], measured on [balance / marked equity]
  L2 Max order [x], max position [y], max daily loss [z], reset at [hh:mm zone]
  L3 On a breach: [block / stop / close]; who resets: [person]

6 FAILURE BEHAVIOR
  F1 Restart with open position or orders: [resume / halt]
  F2 Data older than [seconds]: [your rule]
  F3 Request times out: at most [n] attempts
  F4 Local records differ from the venue: [your rule]
  F5 Venue down or in maintenance: [your rule]

7 STOPPING AND ALERTS
  S1 Who can stop, how: [person], [command]; who can restart: [person]
  S2 Who is alerted, on which channel: [person], [channel]

8 ACCEPTANCE TESTS, behavior only, never a return or win rate
  T1 traces [rule ID]: given [state], when [event], then [behavior]; environment [name]

9 CHANGES
  [date] [who changed] [who approved] [what changed]
```

Copy it into a document and print it. Bracketed options are prompts, not suggested values, and each ID gives a test something to point at.

## Ambiguity tests: what close above means in code

A rule is ambiguous if two careful programmers can code it differently and both claim to follow it. This script takes the sentence enter when price closes above the level and codes it four ways on synthetic prices. It is an illustration, not a rule to use or a recommendation.

```python
# One sentence, four readings. Synthetic prices only; not a rule to use.
from datetime import datetime, timedelta, timezone

LEVEL = 100.0                 # "enter when price closes above the level"
BARS = [                      # synthetic ticks for each 1-minute bar
    [99.0, 100.4, 99.8],      # bar 0: a tick above, closes below
    [99.9, 100.0],            # bar 1: closes exactly at the level
    [100.2, 100.6],           # bar 2: closes above
    [100.7, 100.3],           # bar 3: closes above again
    [99.7, 99.5],             # bar 4: closes below
    [99.9, 100.5],            # bar 5: closes above
]
closes = [bar[-1] for bar in BARS]

def touch():                  # coder A: any tick crossing the level
    hits, prev = [], BARS[0][0]
    for minute, bar in enumerate(BARS):
        for tick in bar:
            if prev <= LEVEL < tick:
                hits.append(minute)
            prev = tick
    return hits

def every_close():            # coder B: every bar that closes above
    return [m for m, c in enumerate(closes) if c > LEVEL]

def first_close(at_level):    # coder C and D: first close above, > or >=
    above = (lambda c: c >= LEVEL) if at_level else (lambda c: c > LEVEL)
    return [m for m in range(1, len(closes))
            if above(closes[m]) and not above(closes[m - 1])]

for name, hits in [("A tick crosses above", touch()),
                   ("B every close above", every_close()),
                   ("C first close, >", first_close(False)),
                   ("D first close, >=", first_close(True))]:
    print(f"{name:21} entries in bars {hits}")

# "the daily close" depends on the day boundary
utc3 = timezone(timedelta(hours=3))
ticks = [(datetime(2026, 3, 2, 20, 30, tzinfo=timezone.utc), 100.4),
         (datetime(2026, 3, 2, 23, 30, tzinfo=timezone.utc), 99.7)]
day = datetime(2026, 3, 2).date()
for label, tz in [("UTC", timezone.utc), ("UTC+3", utc3)]:
    close = [p for t, p in ticks if t.astimezone(tz).date() == day][-1]
    print(f"2 March close in {label:5}: {close}  above level: {close > LEVEL}")
```

Output (Python 3.11):

```
A tick crosses above  entries in bars [0, 2, 5]
B every close above   entries in bars [2, 3, 5]
C first close, >      entries in bars [2, 5]
D first close, >=     entries in bars [1, 5]
2 March close in UTC  : 99.7  above level: False
2 March close in UTC+3: 100.4  above level: True
```

No reading is right; only you can choose one. The bar that closes exactly at the level fires only for coder D, and the same two ticks give opposite answers depending on the day boundary. Run the same test on your own document: give it to two people and compare what they would code.

**Phrases that split programmers, and what to write instead**

| Phrase | The open question | Write instead |
| --- | --- | --- |
| Closes above [level] | Bar close or any tick? Greater than, or equal too? Every close, or only the first? | At the close of each [timeframe] bar in [zone]: close > [level] and previous close <= [level] |
| At the open | First trade, auction price or next bar? | On the first trade after [hh:mm zone] |
| The daily close | Whose day? | Last trade before [hh:mm zone] |
| [x]% of the account | Balance or marked equity? Are open orders counted? | [x]% of [measure], at [moment] |
| Stop at [y] | Resting on the venue or held by the bot? Which price triggers it? | [Resting / local] stop, triggered by [last / mark] price |
| When the market is calm | Not testable | A number you choose, or delete it |

> **Example rewrite, all placeholders.** R1: evaluate at the close of each [timeframe] bar in [zone]. R2: entry is true when the bar's close > [level] and the previous close <= [level]. O1: send the order on the first trade after that close. Now only reading C fits the sentence, and the values stay yours.

## Write order handling and failure behavior as statements

Say what happens when things go wrong, because that is where a programmer otherwise has to guess.

**Your decision, and what the software owes you regardless**

| Situation | You decide | The software must always |
| --- | --- | --- |
| Partial fill | What happens to the remainder | Use the filled quantity for position and exit, never the requested one |
| Request times out | How many attempts | Look the order up by client order ID before any resend |
| Restart with open orders | Resume or halt | Read orders and balances from the venue before any new order |
| Data goes stale | What to do with open positions | Open nothing new until data recovers |
| Two rules true at once | Which one wins | Decide the same way every time, never by arrival order |
| Limit breached | Block, stop or close | Enforce it outside the rule code, then log and alert |

The middle column is your decision and goes in the document. The right column is what a developer can be held to whatever you decide; limits are covered in [trading bot risk management](https://fincodelabs.com/en/blog/trading-bot-risk-management). The short version in [crypto trading bot developer](https://fincodelabs.com/en/blog/crypto-trading-bot-developer) shows how it fits a hire.

## Acceptance tests: one test per statement, never a profit figure

Give every statement at least one test written as given, when and then, so acceptance becomes a list of behaviors anyone can re-run.

**Trace table: every rule points to a test**

| Rule | Test | Given | When | Then | Result |
| --- | --- | --- | --- | --- | --- |
| R2 | T1 | [state before the bar] | Bar closes [x] | One order intent, logged | [result, date, environment] |
| O4 | T2 | Order for [q] working | [part] fills | Position equals [part]; exit uses it | [result, date, environment] |
| F1 | T3 | Open order, process off | Bot restarts | Reads the venue first; no duplicate | [result, date, environment] |

Refuse any test that names a return or a win rate. Tuning can clear such a line, as [backtesting pitfalls](https://fincodelabs.com/en/blog/backtesting-trading-strategy-pitfalls) shows, and it says nothing about the software. How to build the tests themselves is in [how to test trading bots](https://fincodelabs.com/en/blog/how-to-test-trading-bots).

## Stage gates from written rules to small live size

Each stage ends with a document someone signs, and the next stage waits for it.

**Stage gates and the document each one produces**

| Stage | Document | Gate to leave it | What it cannot show |
| --- | --- | --- | --- |
| 1 Written rules | Specification, signed version | Every rule has an ID, passes the ambiguity test and traces to a test | Whether the rules will work |
| 2 Backtest | Report stating data, fees and slippage assumptions | Entries match a hand check on sample days; the run can be repeated | Future results |
| 3 Testnet or paper | Test report: each case, environment, date, result, log excerpt | All cases pass, restart and partial fill included, checked by someone other than the coder where possible | Real fills and live venue behavior |
| 4 Small live size | Go-live record: version, limits, key permissions, how to roll back | Records reconcile with the venue for [period] before any size change | That the rules will make money |
| 5 Any change | Change record, then the tests it touches | Same gates again, scaled to the change | Anything about the unchanged parts |

The first three are written for regulated firms, not private traders, so use them as models:

- **FINRA Notice 15-09** (26 March 2015) describes testing independent of code development, a test environment segregated from production, a summary of each strategy readable without the code and a pilot of limited size raised only as results are confirmed.
- **RTS 6 Article 5** (as adopted) has a person designated by senior management authorize deployment and any substantial update.
- **The FCA's February 2018 review** groups its findings under definition, development and testing, risk controls, governance and market conduct, and names as good practice checkpoints with a full review at the end of each stage.
- **NautilusTrader's live trading page**, read 5 November 2026, warns that live venues add transport, timing and reconciliation behavior a simulation may not reproduce, which is why no simulated stage replaces stage 4.

## Keep the document and the code in step

Give every change to a rule or limit a new version and a record, or the test report stops describing the running system.

- **The record.** RTS 6 Article 5(7) asks firms to record when a material change was made, by whom, who approved it and what it was; section 9 of the template has those four fields.
- **Parameters.** A changed value in a rule or limit counts as a change, however small.

A filled template is also a brief you can send to any developer and compare quotes against. The [algorithmic trading](https://fincodelabs.com/en/services/algorithmic-trading) page shows how one seller works from such a document, and its [contact page](https://fincodelabs.com/en/contact) takes briefs.

## Frequently asked questions

### Is this the same as trading strategy development?

No. This page teaches how to document rules you already have. It does not cover how to find a strategy or which parameters to use, and Fincode does not develop or suggest strategies.

### Can a developer write the rules for me?

A developer can point out where a rule is ambiguous. Choosing the rules is a different service that can be regulated where you live, and Fincode does not offer it.

### Does passing the acceptance tests mean the system will make money?

No. Tests show how the software behaves, not future results, and trades can lose money. A system can pass every test and still lose.

### Do FINRA or RTS 6 rules apply to my own trading system?

They bind member firms and investment firms, not private traders. Here they are models for what good records look like. Other rules, such as those on market abuse, can apply to anyone.

## Sources

- [FINRA Regulatory Notice 15-09: Guidance on Effective Supervision and Control Practices for Firms Engaging in Algorithmic Trading Strategies (26 March 2015)](https://www.finra.org/rules-guidance/notices/15-09)
- [Commission Delegated Regulation (EU) 2017/589 (RTS 6), Article 5, as adopted](https://www.legislation.gov.uk/eur/2017/589/article/5/adopted)
- [FCA: Algorithmic Trading Compliance in Wholesale Markets (February 2018)](https://www.fca.org.uk/publication/multi-firm-reviews/algorithmic-trading-compliance-wholesale-markets.pdf)
- [NautilusTrader documentation: Live Trading, backtest and live differences](https://nautilustrader.io/docs/latest/concepts/live/)
- [Capital Markets Law No. 6362, consolidated text, Article 99/A (Turkish)](https://www.mevzuat.gov.tr/mevzuatmetin/1.5.6362.pdf)

> This guide is general information about software and markets, not investment, legal or tax advice. Automated trading can lose money, past or backtested performance does not guarantee future results, and the rules that apply depend on your jurisdiction and your exchange's terms. Sources, checks and corrections: see the [editorial policy](https://fincodelabs.com/en/editorial-policy).

---

Published by Fincode (Fincode Yazılım ve Teknoloji A.Ş.), a software company in Istanbul, Turkey: https://fincodelabs.com/en/blog/trading-system-development

Cite as: Fincode, "Trading system development: write rules a coder can build", updated November 6, 2026, https://fincodelabs.com/en/blog/trading-system-development
