닌자트레이더 스크립트 C# 코딩하기.
- 닌자트레이더에서 스크립트(C#) 작성 처음 접한 경우 전체 개념 파악 하기 좋은 정보 정리.
- 가장 기본적인 "hello ninja" 코딩하면서 전체적인 활용법 쉽게 파악 가능하게 정리.
사전준비
- 닌자트레이더 개요 이해 , 설치 : https://igotit.tistory.com/6408
닌자 트레이더 . 개요 . 설치 . 둘러보기
닌자 트레이더 개요 . 특징 - 선물(Futures) 중심의 전문 트레이딩 플랫폼.- 닌자 트레이더 는 프로그램 설치만으로 매매 가능한 구조 아니며 외부 선물브로커,데이터공급자 별도 연결해줘야 하고
igotit.tistory.com
스크립트 편집기
닌자트레이더 실행하여, control center 메뉴 : New -> NinjaScript Editor

스크립트 에디터 실행하면 아래 화면처럼 오른쪽에는 카테고리 별로 C# 소스들이 있고 C# 코드 작성 창이 보인다. 아래 화면은 기본 내장된 스크립트 중에서 지표 ADX 클릭해 본것. 화살표 아이콘 클릭하면 컴파일된다. 오른쪽 마지막 아이콘이 Visual Studio 실행하는 아이콘. VS 에서는 편집이나 디버깅 하는 용도로만 사용해야하고 빌드하면 안됨. 항상 닌자 스크립트 에디터에서만 컴파일 해야한다. 닌자트레이더 내장 편집기도 쓸만함.

위 화면의 오른쪽에 보이는 카테고리들은 스크립트 타입이라고 하며, 내가 C# 코드 작성 한다는 말은 이 타입 중 어느 하나에 새로 코드 파일 만들어서 작업한다.
스크립트 타입
| 스크립트 타입 | 베이스 클래스 | 핵심역할 | 실행위치 |
| Indicators | Indicator | 차트에 표시되는 계산 로직 -가격/틱/지표계산 |
Chart |
| Strategies | Strategy | 자동매매 로직 - 주문, 포지션 관리 |
Chart |
| AddOns | AddOnBase | 독립 UI + 기능 확장 - 별도의 창을 갖는 미니프로그램 |
닌자트레이더 실행 레벨. |
| DrawingTools | DrawingTool | 차트 그리기 도구 - 선,박스, 마킹등 시각화 |
Chart |
| MarketAnalyzerColumns | MarketAnalyzerColumn | 스캔용 컬럼 계산 - 여러 종목 동시 스캔 |
Market Analyzer |
| BarsTypes | BarsType | 봉 생성 로직 봉자체를 정의하는로직 |
Chart |
| DataSeries (내부) | — | 시계열 데이터 | -- |
Chart 나 MarketAnalyzer 없이 닌자트레이더 켜두기만 하면 실행가능한 스크립트 형식은 AddOns,
단일 심볼/시세 기반 계산은 Chart 에서 Indicator
주문실행하고 포지션 관리하는 것은 Chart 에서 Strategy
여러 종목 동시 감시, 계산결과 표시용은 MarketAnalyzerColumns . 주의. 여기서의 시세 데이터는 chart 만큼 즉시성 처리 보장 안됨.
AddOn 특징 상세
멀티 심볼 틱 동시 처리용에서는 AddOns 가 유리.
- UI 윈도우 + 독립 스레드 + 전역 시세 관리 가능
- Connection / Instrument / MarketData 직접 구독
- Chart / MA / Strategy와 완전히 분리 가능
[ MarketData ]
↓
[ AddOn Tick Engine ]
↓
[ 공유 메모리 / 캐시 ]
↓ ↓
[ Chart ] [ MarketAnalyzer ]
C# 소스 파일 폴더
C:\Users\본인계정\Documents\NinjaTrader 8\bin\Custom\
* 닌자트레이더 실행파일들 있는 설치 폴더에 만들어지는 것 아님.
이 폴더에 카테고리명들이 보이고 C# 파일들이 있다.
참고 : 처음 닌자 트레이더 설치하면 파일 없으며 메모리상에만 있는 것이 위 editor 창에서 보인다. editor 창에서 compile 버튼 클릭해야 파일들이 만들어짐.
Custom\
├─ Indicators\
├─ Strategies\
├─ AddOns\
├─ MarketAnalyzerColumns\
├─ DrawingTools\
내가 만든 C# 파일 역시 위 폴더 속에 만들어지고 그 외의 경로에 있는 것은 닌자트레이더에서 실행 못함.
한편, 내가 작업하는 C# 소스 파일 중에 닌자트레이더에서 직접 실행하는 게 아닌 내가 재료로 활용하는 파일들은 Custom 하위에 Include 폴더를 만들어서 여기에 배치해두면 된다. Include 외에 다른 이름의 폴더로 해도 되긴 하나 Inlcude 라는 이름으로 하는 게 안전함.
즉,
bin\Custom\Include\
여기에는:
- base class
- helper
- enum
- struct
- util
같은 비-NinjaScript 클래스만 둠
소스파일 구성 구조 예시
bin\Custom\
├─ Strategies\
│ └─ Cy_st.cs
├─ Indicators\
│ └─ Cy_TickLead.cs
└─ Include\
└─ Cy\
├─ Core.cs
├─ Time.cs
├─ Math.cs
└─ Fix.cs
닌자스크립트 . Hello Ninja 만들기
- 가장 간단한 코드 구성으로 닌자트레이더에서 스크립트 만드는 전체 과정을 파악가능하다.
- AddOns 타입으로 만들어본다.
스크립트 에디터 타입 AddOns 마우스 우클릭 메뉴에서 New Add On 클릭한다.

그럼 생성 위한 창이 뜨고

위 화면에서 Next 클릭하여 아래처럼 이름 지정 하고 Next 클릭.

윈도우 생성 종료 이벤트 처리기 추가 선택 가능하다. 일단 2개다 선택하고 Next 클릭.
여기서 말하는 window 란 닌자트레이더에서 생성된 모든 창을 의미한다.

입력 파라메타 추가하란다. 안하고 Next 클릭.

마지막 이다. Finjsh 클릭.

기본코드 자동 생성되었다.

앞에서 선택했던 윈도우 이벤트 핸들러가 추가되어 있다. 여기서 말하는 윈도우란 AddOn 의 윈도를 의미하는 게 아님. 베이스 클래스인 AddOnBase 는 UI 나 윈도우 없이 백그라운드에 로드되는 오브젝트임.
위 코드에서의 윈도우란 닌자트레이더 실행하여 보이는 아래 예시의 모든 윈도우들을 의미한다.
- Control Center
- Chart Window
- Market Analyzer
- Strategy Analyzer
- Accounts 창
- DOM
- Options 창
- 내가 직접 만든 Window
상태변경 이벤트 핸들러 OnStateChange()
기본 생성된 코드에는 SetDefaults, Configure 만 만들어져 있는데 자주 활용되는 Active 등도 있고 이건 타이핑해서 추가 기록하면 된다. Active 는 실행초기 1회 , Terminated 는 닌자트레이더 종료시 1회 발생한다.

시험용으로 Active 시점에 윈도우 1개 만들고, Terminated 시점에 윈도우 제거하는 것을 구현해 보자.
전체 코드.
Hello Ninja 컴파일 하기
위 화면의 화살표 아이콘 클릭하여 컴파일 하면 아래처럼 새로운 Add on 이 있다고 창이 뜬다. Yes 클릭.

Hello Ninja 실행하기
- 앞의 컴파일 과정 완료해도 바로 실행되지 않는다.
- AddOn 실행하려면 닌자트레이더 재시작해야 한다. 닌자트레이더 실행하면 동시에 내가 만든 AddOn 도 실행되고 우리가 코드에 추가했던 윈도우 생성도 정상적으로 만들어진다.
- AddOn 에서 생성한 윈도우는 사용자가 x버튼 클릭하여 닫아도 AddOn 은 계속 실행상태이며 닌자트레이더 종료시 AddOn 도 종료된다.

이 과정까지 닌자스크립트 사용하는 기본 골격은 달성됨.
아래는 좀더 세부적인 작업들 진행해본다.
메뉴 클릭해야 윈도우 보이게 하기.
- 앞에서 제작된 것은 NT 실행 초기 항상 윈도우가 보이고 있는데 , 실행 초기 기본 보이지 않고 내가 추가한 메뉴 클릭하면 윈도우가 보이게 해본다.
앞에서 작성했던 Active 시 윈도우 생성하던 것을 주석처리하고,
else if (State == State.Active)
{
//CreateWindow();
}
OnWindowCreated 와 OnWindowDestroyed 부분을 아래처럼 작성한다.
protected override void OnWindowCreated(Window window)
{
if (window is ControlCenter controlCenter)
{
MenuItem menuItem = new MenuItem
{
Header = "CyAddOn Window"
};
menuItem.Click += MenuItem_Click;//이벤드핸들러 등록
controlCenter.MainMenu.Add(menuItem);
}
}
private void MenuItem_Click(object sender, RoutedEventArgs e)
{
if(window_myaddon == null) // 윈도우 중복 생성 방지.
CreateWindow();
else window_myaddon.Activate();
}
protected override void OnWindowDestroyed(Window window)
{
if (window == window_myaddon)
{
window_myaddon = null;
}
}
컴파일하고, 실행해보면 실행초기에는 AddOn 윈도우는 생성되지 않는다. 대신 Control Center 상단라인에 내가 추가한 메뉴 보인다.

메뉴 클릭하면 윈도우 보인다.

실시간 시세 수신 하기
- 특정 종목 1개 지정하여 시세 수신하도록 해보자.
OnStateChange 에서 아래처럼 종목 구독, 구독해지 추가하고,
protected override void OnStateChange()
{
if (State == State.SetDefaults)
{
Description = @"시험용 AddOn";
Name = "CyAddOnHelloNinja";
}
else if (State == State.Configure)
{
}
else if (State == State.Active)
{
Subscribe();// 구독
}
else if(State == State.Terminated)
{
Unsubscribe(); // 구독해지
window_myaddon?.Close();
}
}
Subscibe (), Unscribe() 를 아래처럼 작성한다.
- 예로 BTCUSD 시세 수신 요청하는것.
private Instrument instrument;
private void Subscribe()
{
instrument = Instrument.GetInstrument("BTCUSD");
if (instrument == null)
{
Print("BTCUSD instrument not found");
return;
}
instrument.MarketDataUpdate += OnMarketDataUpdate;
Print("BTCUSD MarketData subscribed");
}
private void OnMarketDataUpdate(object sender, MarketDataEventArgs e)
{
if (e.MarketDataType != MarketDataType.Last)
return;
Print(
$"BTC TICK | Price={e.Price} " +
$"Volume={e.Volume} " +
$"Time={e.Time:HH:mm:ss.fff}"
);
}
private void Unsubscribe()
{
if (instrument != null)
{
instrument.MarketDataUpdate -= OnMarketDataUpdate;
Print("BTCUSD MarketData unsubscribed");
}
}
위 코드에서 Print() 문에 의한 문자열 출력 위치는 NinjaScript Output 창 이며, 닌자트레이더 메뉴 : New -> NinjaScript Output 창에서 볼 수 있다.
실행하여 닌자스크립트 출력창에 실시간 시세 정상 출력 확인. 챠트에서 보이는 가격과 정확히 일치하는것 확인함.

여기 까지의 전체코드
여러 종목 요청하기
앞의 코드에서 종목 시세 요청하고 수신받는 부분의 코드는 아래가 핵심이다. Subscribe() 에서 종목 지정하고
instrument.MarketDataUpdate += OnMarketDataUpdate; 에서 이벤트핸들러를 등록. 그러면 시세수신 마다 OnMarketDataUpdate 가 호출되며 여기서 받은 데이터 처리한다.
private void Subscribe()
{
instrument = Instrument.GetInstrument("GC FEB26");// BTCUSD 등.
if (instrument == null)
{
Print("Gold instrument not found");
return;
}
instrument.MarketDataUpdate += OnMarketDataUpdate;
Print("BTCUSD MarketData subscribed");
}
private void OnMarketDataUpdate(object sender, MarketDataEventArgs e)
{
if (e.MarketDataType != MarketDataType.Last)
return;
Print(
$"BTC TICK | Price={e.Price} " +
$"Volume={e.Volume} " +
$"Time={e.Time:HH:mm:ss.fff}"
);
CyNinjaX.OnTick(1,e.Ask,e.Bid,e.Time);
}
아래는 여러 종목 요청하는 코드 예
먼저 여러 종목을 관리하기 위한 방법중 하나로 각 심볼들의 고유아이디를 1,2,3 같은 식으로 지정하기 위하여 dictionary 로 아래처럼 만든다.
namespace NinjaTrader.NinjaScript.AddOns
{
public class CyAddOnHelloNinja : NinjaTrader.NinjaScript.AddOnBase
{
private Dictionary<Instrument, int> instrumentIdMap = new Dictionary<Instrument, int>();
private readonly Dictionary<int, string> symbolMap = new()
{
{ 1, "GC FEB26" },
{ 2, "BTCUSD" }
// 필요수량 만큼 추가 가능
};
...
다중 심볼 Subscribe
private void Subscribe()
{
foreach (var kv in symbolMap)
{
int id = kv.Key;
string symbol = kv.Value;
Instrument inst = Instrument.GetInstrument(symbol);
if (inst == null)
{
Print($"{symbol} not found");
continue;
}
instrumentIdMap[inst] = id;
inst.MarketDataUpdate += OnMarketDataUpdate;
Print($"{symbol} subscribed with ID={id}");
}
}
OnMarketDataUpdate
private void OnMarketDataUpdate(object sender, MarketDataEventArgs e)
{
if (e.MarketDataType != MarketDataType.Last)
return;
var inst = sender as Instrument;
if (inst == null)
return;
if (!instrumentIdMap.TryGetValue(inst, out int id))
return;
CyNinjaX.OnTick(
id,
e.Ask,
e.Bid,
e.Time
);
}
Unsubscribe
private void Unsubscribe()
{
foreach (var kv in instrumentIdMap)
{
Instrument inst = kv.Key;
int id = kv.Value;
inst.MarketDataUpdate -= OnMarketDataUpdate;
Print($"{inst.FullName} unsubscribed (ID={id})");
}
}
연결 상태 변경 검출
참고 . 닌자트레이더는 provider 와의 연결 끊긴경우 자동 재연결 처리 됨.
// 연결 상태 업데이트 이벤트 구독. Active 이벤트에서 등록.
Connection.ConnectionStatusUpdate += OnConnectionStatusUpdate;
// 이벤트수신해지. Terminated 에서
// 이벤트 해제
Connection.ConnectionStatusUpdate -= OnConnectionStatusUpdate;
private void OnConnectionStatusUpdate(object sender, ConnectionEventArgs e)
{
// e.Status를 통해 현재 상태 확인 (Connected, Disconnected, Connecting 등)
if (e.Status == ConnectionStatus.Disconnected)
{
// "Connection Closed" 상황 시 실행할 로직
NinjaTrader.Code.Output.Process("연결 끊김: " + e.Connection.Options.Name, PrintTo.OutputTab);
}
else if (e.Status == ConnectionStatus.Connected)
{
NinjaTrader.Code.Output.Process("연결 성공: " + e.Connection.Options.Name, PrintTo.OutputTab);
}
}
주요 상태 값 (ConnectionStatus)
ConnectionStatus.Connected: 연결 완료
ConnectionStatus.Disconnected: 연결 종료 (음성 메시지가 나오는 시점)
ConnectionStatus.Connecting: 연결 시도 중
ConnectionStatus.Disconnecting: 연결 종료 중
Multi Provider 로 설정된 경우 어떤 공급자의 연결 상태 변경인지 확인 방법.
이벤트 핸들러의 인자 ConnectionEventArgs 객체 안에 포함된 Connection 인스턴스의 Options 속성 이용.
- 연결 이름 확인: e.Connection.Options.Name (예: "My Rithmic", "IB")
- 공급자 종류 확인: e.Connection.Options.Provider
private void OnConnectionStatusUpdate(object sender, ConnectionEventArgs e)
{
// 1. 사용자가 설정한 연결 프로필 이름 확인
string connectionName = e.Connection.Options.Name;
// 2. 공급자 기술명 확인 (예: Rithmic, InteractiveBrokers 등)
string providerName = e.Connection.Options.Provider.ToString();
// 3. 로그 출력 예시
NinjaTrader.Code.Output.Process(
string.Format("공급자: {0} ({1}) - 상태: {2}",
connectionName, providerName, e.Status),
PrintTo.OutputTab
);
// 특정 공급자가 끊겼을 때만 로직 실행
if (connectionName == "My Data Feed" && e.Status == ConnectionStatus.Disconnected)
{
// 해당 공급자 전용 처리 로직
}
}
Status vs PriceStatus:
e.Connection 객체 내에는 주문 체결 엔진 상태인 Status와 시세 데이터 피드 상태인 PriceStatus가 별도로 있다.
멀티 공급자 모드 활성화:
이 코드가 의도대로 작동하려면 Tools > Settings 클릭하면 아래화면 처럼 보이고 2번 항목 Multi-provider가 체크되어 있어야 하며, 각 연결마다 고유한 이름을 지정해두는 것이 관리에 용이.

닌자스크립트 C# 코드에서 외부 DLL 임포팅해서 활용하는 경우
DLL 파일을 아래 경로에 둬야 한다.
C:\Users\본인계정\Documents\NinjaTrader 8\bin\Custom\
참고 : C# 에서 DLL 활용법 : https://igotit.tistory.com/6414
C# . VC++ DLL 활용 . DllImport
C# 에서 DLL 활용 DLL 에서 정의된 무인자 함수extern "C" __declspec(dllexport) void __stdcall OnActivated_CyNinjaX();extern "C" __declspec(dllexport) void __stdcall OnTerminated_CyNinjaX(); extern "C" → C++ name mangling을 막아서 C-style
igotit.tistory.com
연관
닌자 트레이더 . 개요 . 설치 . 둘러보기
닌자 트레이더 개요 . 특징 - 선물(Futures ,예 : CME 선물 ) 중심의 전문 트레이딩 플랫폼.- 닌자 트레이더 는 프로그램 설치만으로 매매 가능한 구조 아니며 외부 선물브로커,데이터공급자 별도 연
igotit.tistory.com
첫 등록 : 2026.01.17
최종 수정 : 2026.01.20
단축 주소 : https://igotit.tistory.com/6411
'트레이딩' 카테고리의 다른 글
| 통화 표준 코드 . ISO 4217 (0) | 2026.01.21 |
|---|---|
| 닌자 트레이더 . 개요 . 설치 . 둘러보기 (0) | 2026.01.17 |
| cTrader . 개요 . 설치 . FIX API . Open API (0) | 2026.01.02 |
| 프랍 . WeMasterTrade . 스캘핑 관련 규정 위반 주의 (0) | 2025.09.19 |
| 프랍 WeMasterTrade . 수익 출금용 암호화폐 주소 등록 (4) | 2025.07.29 |
댓글