tuongkha
Could you explain more about _stockGenerators, _snapshotQueue, _snapshotSender in StockList demo code?
In "ExternalFeed.cs" file, StockListDemo code (mark by red color) :
public ExternalFeed() {
_stockGenerators= new Hashtable();
_snapshotQueue= new ArrayList();...
}
public void Start() {
if (_snapshotSender != null) return;
for (int i = 0; i < 30; i++) --> purpose of for statement? Why it loop from 1 to 30?
{
string itemName= "item" + (i + 1);
...
_stockGenerators[itemName]= myProducer;
myProducer.SetFeedListener(_listener);
myProducer.Start();
}
_snapshotSender= new Thread(new ThreadStart(Run)); --> I don't understand
_snapshotSender.Start();
}
private void Run() {
IList snapshots= new ArrayList();
do {
lock (_snapshotQueue) {
if (_snapshotQueue.Count == 0)
Monitor.Wait(_snapshotQueue);
snapshots.Clear();
while (_snapshotQueue.Count > 0) {
ExternalFeedProducer myProducer= (ExternalFeedProducer) _snapshotQueue[0];
snapshots.Add(myProducer);
_snapshotQueue.RemoveAt(0);
} }
foreach (ExternalFeedProducer myProducer in snapshots) {
_listener.OnEvent(myProducer.GetItemName(), myProducer.GetCurrentValues(true), true);
}
} while (true);
}
Dario Crivelli
This sample class "simulates" a broadcast feed, which is one of the most common types of data feed, especially in a trading scenario.
Once you connect to such a feed, you immediately receive the current real-time update flow for all available data (the IExternalFeedListener interface).
Some broacast feed may also allow you to request the current state of a data item. Our sample feed class does support this (the SendCurrentValues method).
In our sample feed class, all available data consists of 30 fake stocks, which is what is needed by the StockList demo front-end. For each of the above stocks/items, we create a specific object, of type ExternalFeedProducer, whose job is to create a thread and generate the updates for the item. We collect all these objects in the _stockGenerators hash table.
In order to manage SendCurrentValues request, the feed does not return the current state to the caller, but it rather sends a redundant event to the IExternalFeedListener interface (i.e. an event which does not carry updated data but just the current state). We do this in a separate thread (we call this thread _snapshotSender; it runs the Run method reported above) and use the _snapshotQueue queue to send the SendCurrentValues requests to that thread.
Hope This Helps
Dario
tuongkha
Hi Dario,
You mean, StockListDemo work-flow :
Step 1: Get feed data (simulate) from "ExternalFeed" class
public ExternalFeedSimulator() {
_stockGenerators= new Hashtable();
_snapshotQueue= new ArrayList();
...
}
Step 2 : Starts generating update events for the stocks. attaching and reading from an external broadcast feed (in step 1).
public void Start()
{
if (_snapshotSender != null) return;
//all available data consists of 30 fake stocks, which is what is needed by the StockList demo front-end.
for (int i = 0; i < 30; i++)
{
....
//For each of the above stocks/items, you create a specific object, of type ExternalFeedProducer, whose job is to create a thread and generate the updates for the item.
ExternalFeedProducer myProducer = new ExternalFeedProducer(itemName,
_openprices, _refprices, _minprices, _maxprices,
_updateTimeMeans, _updateTimeStdDevs, _stockNames);
_stockGenerators[itemName]= myProducer;
myProducer.SetFeedListener(_listener);
myProducer.Start();
}
...
}
private void Run()
{
...
}
Now, I want to call my function every 5 seconds, it starts generating update events for the stocks, attaching and reading from an external broadcast feed (in step 1). How do I do?
Can u help me?
Dario Crivelli
Provided that you still think that the demo architecture fits your needs, in order to send your custom data, you should customize only the "ExternalFeedProducer" class.
Each object instance of this class owns an update thread, which waits for randomly generated times, produced by the "ComputeNextWaitTime" method; you can rewrite the latter to always return 5000 milliseconds.
Then, you should only rewrite the "ComputeNewValues" and "GetCurrentValues" methods. The first one produces new data for the instance-related stock and stores it in the object; the second one collects the stored data in an "IDictionary", suitable for being sent forward.
If, however, you can only read data for all your stocks, from outside, as an atomic operation, then some adjustments would be needed (it is still unclear to me which are your requirements).
Dario
tuongkha
Hi Dario,
I tried follow your instruction, but it has error : Out of memory.
Here my changed
-------
public int ComputeNextWaitTime()
{
lock (this)
{
return 5000;
}
}
public void ComputeNewValues()
{
ISecurityStructReader reader;
reader = new ReadSecurityStruct("C:\\TEMP\\BACKUP14\\SECURITY.DAT");
nStock = 0;
if (reader.Open())
{
arr = reader.Read();
nStock = arr.Count;
_stockSymbol = new string[nStock];
for (int i=0; i< nStock ;i++)
{
Struct_Security item = (Struct_Security)arr;
//_stockNames.Add(item.SecurityName);
_openprices= item.OpenPrice;
_stockSymbol= item.StockSymbol;
...
string itemName= "item" + (i + 1);
ExternalFeedProducer myProducer = new ExternalFeedProducer(itemName, m_openprices, m_refprices, m_minprices, m_maxprices, m_stockSymbol, m_stockNames, m_ceiling, m_floor[i], m_bid1[i], m_bid2[i], m_bid3[i], m_bid1vol[i], m_bid2vol[i], m_bid3vol[i], m_ask1[i], m_ask2[i], m_ask3[i],m_ask1vol[1], m_ask2vol[i], m_ask3vol[i], m_last[i], m_lastVal[i], m_lastVol[i], m_projectOpen[i]);
_stockGenerators[itemName]= myProducer;
myProducer.SetFeedListener(_listener);
myProducer.Start();
}
...
}
}
-----------
My step is correct?
In my case, stock data i get from outside and it is a binary file and has a structure. I read it and store it in array list.
In your code, u stored data in an "IDictionay" because you change only 01 value of item in the same time, but my data has many change in many item (in the same time).
Example :
10:00 AM I have :
stock_symbol[1] = STB , price[1] = 100, volume[1] = 99
stock_symbol[2]= ACB, price[2] = 80, volume[2] = 89
10:01 AM, I have
stock_symbol[1] = STB , price[1] = 101, volume[1] = 90
stock_symbol[2]= ACB, price[2] = 82, volume[2] = 80
How to rewrite "GetCurrentValues" and "ComputeNewValues" to store this? Can u help me?
Dario Crivelli
I assume from the above that the answer to my doubt
If, however, you can only read data for all your stocks, from outside, as an atomic operation, then some adjustments would be needed (it is still unclear to me which are your requirements).
is yes; you can only read updates for several or all stocks alltogether from a file. Then I'm afraid that the demo Data Adapter architecture is not suitable for you as a starting point.
What do you exactly read from your files?
Do you get values for all stocks or only for the modified stocks?
And, for each stock read, do you get values for all fields or only for the modified fields?
Dario
tuongkha
Dear Dario,
Let's me explain : Stock Exchange send data file (binary file) to the Broker company, this file has information for all stocks (stock symbol, stock name, price, volume, ceiling, floor, percent change,...). If some stock has information changed, they send this file again to the Broker company. So every 5-10 seconds, I need read this file again to get values for all stocks, because i don't know which stock modified.
Exactly I need to read from file :
- Get values for all stocks : stock symbol, stock name, stock type (bond or common stock) ceiling price, floor price, open price, split (means stock has divident or not), benifit (means stock has action coporation), prior Close price, last price, last volume, last values, percent change, highest price, lowest price, Best 1 bid, Best 1 bid volume, Best 2 bid, Best 2 bid volume, Best 3 bid, Best 3 bid volume, Best 1 Offer, Best 1 Offer volume, Best 2 Offer, Best 2 Offer volume, Best 3 Offer, Best 3 Offer volume.
for each stock read, I want to get values for all fields :
-------
last price, last volume, last values, percent change, highest price, lowest price, Best 1 bid, Best 1 bid volume, Best 2 bid, Best 2 bid volume, Best 3 bid, Best 3 bid volume, Best 1 Offer, Best 1 Offer volume, Best 2 Offer, Best 2 Offer volume, Best 3 Offer, Best 3 Offer volume
Here struct binary file, it has contain 504 stocks :
--------
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct Struct_Security
{
//221: SECURITY.DAT
//Ma CK dang so (2 bytes)
public short StockNo;
//Ma CK dang chuoi (8 bytes)
[MarshalAs(UnmanagedType.ByValTStr, SizeConst =8)]
public string StockSymbol;
//Loai CK (S:Co phieu, D:Trai phieu, U:Chung chi quy) (1 byte)
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1)]
public string StockType;
//Gia tran (4 bytes)
public int Ceiling;
//Gia san (4 bytes)
public int Floor;
//
public double BigLotValue;
//Ten day du cua CK
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 25)]
public string SecurityName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1)]
public string SectorNo;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1)]
//
public string Designated;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1)]
//CK bi ngung GD (Null: GD binh thuong, S: Bi ngung GD)
public string Suspension;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1)]
public string Delist;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1)]
public string HaltResumeFlag;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1)]
public string Split;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1)]
public string Benefit;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1)]
public string Meeting;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1)]
public string Notice;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1)]
public string ClientIDRequired;
public short CouponRate;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 6)]
public string IssueDate;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 6)]
public string MatureDate;
public int AvrPrice;
public short ParValue;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1)]
public string SDCFlag;
public int PriorClosePrice;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 6)]
public string PriorCloseDate;
public int ProjectOpen;
public int OpenPrice;
public int Last;
public int LastVol;
public double LastVal;
public int Highest;
public int Lowest;
public double Totalshares;
public double TotalValue;
public short AccumulateDeal;
public short BigDeal;
public int BigVol;
public double BigVal;
public short OddDeal;
public int OddVol;
public double OddVal;
//Single
public int Best1Bid;
public int Best1BidVolume;
//Single
public int Best2Bid;
public int Best2BidVolume;
//Single
public int Best3Bid;
public int Best3BidVolume;
//Single
public int Best1Offer;
public int Best1OfferVolume;
//Single
public int Best2Offer;
public int Best2OfferVolume;
//Single
public int Best3Offer;
public int Best3OfferVolume;
public short BoardLost;
public static System.Collections.ArrayList ReaderBlock2Array(BinaryReader br)
{
System.Collections.ArrayList arr = new System.Collections.ArrayList();
br.BaseStream.Position = 0;
while (br.BaseStream.Position < br.BaseStream.Length)
{
byte[] buff = br.ReadBytes(TSSize.Size);
GCHandle handle = GCHandle.Alloc(buff, GCHandleType.Pinned);
Struct_Security s = (Struct_Security)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(Struct_Security));
handle.Free();
arr.Add(s);
}
return arr;
}
}
internal sealed class TSSize
{
public static int _size;
static TSSize()
{
_size = Marshal.SizeOf(typeof(Struct_Security));
}
public static int Size
{
get
{
return _size;
}
}
}
Can u help me?
Dario Crivelli
You should definitely rewrite the ExternalFeedSimulator class and get rid of the included ExternalFeedProducer class.
The Data Adapter should receive all data and detect the changed data in order to send them to Lightstreamer.
However, to keep the Data Adapter simple for demo purpose, the Data Adapter can also forward all data to Lightstreamer, which will be responsible for detecting the changed data and only send them to the client. Please consider that this is not recommended in a production scenario.
The simplest structure might be:
constructor:
create a map to hold all snapshots
(let's create an IDictionary and call it _snaps)
method Start:
start a new thread with the following behaviour:
every 5 seconds:
read the file
for each stock:
create an IDictionary to store all field name/value pairs
associate the IDictionary to the stock name in _snaps
(the previous association, if any, should be garbage collected)
call onEvent on the listener and send the IDictionary
method SendCurrentValues:
get the IDictionary associated to the requested item name in _snap
if found:
call onEvent on the listener and send the IDictionary
else
call onEvent on the listener with an empty IDictionary
tuongkha
Dear Dario,
Thanks for your help, I tried follow by your instruction, but after every 5 second when the data file changed, the Data Adapter didn't receive all data and detect the changed data in order to send them to Lightstreamer. i don't know what are my fault? Can u help me?
Here my changed :
--- "ExternalFeed.cs" file, ExternalFeedSimulator class ----
constructor :
---
private IDictionary _stockGenerators;
public ExternalFeedSimulator {
//create an IDictionary
_stockGenerators= new Hashtable();
ISecurityStructReader reader;
reader = new ReadSecurityStruct("C:\\TEMP\\BACKUP14\\SECURITY.DAT");
nStock = 0;
if (reader.Open())
{
arr = reader.Read();
nStock = arr.Count;
m_stockSymbol = new string[nStock];
m_openprices = new double[nStock];
m_stockNames = new string[nStock];
...
for (int i=0; i< nStock ;i++)
{
Struct_Security item = (Struct_Security)arr;
m_openprices= item.OpenPrice;
...
}
}
reader.Close();
}
public void Start()
{
//Start a new thread
lock (this)
{
if (_snapshotSender != null) return;
_snapshotSender = new Thread(new ThreadStart(Run));
_snapshotSender.Start();
}
}
public void Run()
{
do
{
//every 5 seconds
int waitMillis= ComputeNextWaitTime();
Thread.Sleep(waitMillis);
//read the file ReadBinaryFile();
//for each stock for (int i=0; i<= nStock; i++)
{
//create an IDictionary to store all field name/value pairs associate the IDictionary to the stock name in _snaps
string itemName= "item" + (i + 1);
ExternalFeedProducer myProducer = new ExternalFeedProducer(itemName, m_openprices, m_refprices, m_minprices, m_maxprices, m_stockSymbol, m_stockNames, m_ceiling, m_floor, m_bid1[i], m_bid2[i], m_bid3[i], m_bid1vol[i], m_bid2vol[i], m_bid3vol[i], m_ask1[i], m_ask2[i], m_ask3[i], m_ask1vol[1], m_ask2vol[i], m_ask3vol[i], m_last[i], m_lastVal[i], m_lastVol[i], m_projectOpen[i]);
_stockGenerators[itemName]= myProducer;
//call onEvent on the listener and send the IDictionary
_listener.OnEvent(myProducer.GetItemName(), myProducer.GetCurrentValues(true), true);
}
} while (true);
}
public int ComputeNextWaitTime()
{
lock (this)
{
return 5000;
}
}
public void SendCurrentValues(string itemName)
{
//get the IDictionary associated to the requested item name in _snap
ExternalFeedProducer myProducer= (ExternalFeedProducer) _stockGenerators[itemName];
//call onEvent on the listener with an empty IDictionary, if not found.
if (myProducer == null) return;
//if found, call onEvent on the listener and send the IDictionary
_listener.OnEvent(myProducer.GetItemName(), myProducer.GetCurrentValues(true), true);
}
Dario Crivelli
The code seems correct,
provided that "ReadBinaryFile" populates your "m_" arrays in the same way as the constructor does
and that "GetCurrentValues" generates an IDictionary.
Any unwanted behaviour (for instance, the Data Adapter not receiving all read data) should be inspected with a debugger.
Note that only Lightstreamer Server can check for unchanged data. This means that your Remote Adapter would still forward all updates to Lightstreamer Server.
Dario
tuongkha
Dear Dario,
Here my ReadBinaryFile() method and GetCurrentValues :
--- "ExternalFeed.cs", ExternalFeedSimulator class---
public class ExternalFeedSimulator
{
private double [] m_refprices = null;
private double [] m_openprices = null;
private double [] m_minprices;
private double [] m_maxprices;
...
public ExternalFeedSimulator()
{
_stockGenerators= new Hashtable();
...
}
//Get data stock from outside, read "security.dat" file
public void ReadBinaryFile()
{
ISecurityStructReader reader;
reader = new ReadSecurityStruct("C:\\TEMP\\BACKUP14\\SECURITY.DAT");
nStock = 0;
if (reader.Open())
{
arr = reader.Read();
nStock = arr.Count;
m_stockSymbol = new string[nStock];
m_openprices = new double[nStock];
for (int i=0; i< nStock ;i++)
{
Struct_Security item = (Struct_Security)arr;
m_openprices= item.OpenPrice;
m_stockSymbol= item.StockSymbol;
...
}
}
reader.Close();
}
---- "ExternalFeed.cs" file, ExternalFeedProducer class ---
public void Start() {
lock (this) {
if (_thread != null) return;
_thread = new Thread(new ThreadStart(Run));
_thread.Start();
}
}
private void Run() {
do {
int waitMillis= ComputeNextWaitTime();
Thread.Sleep(waitMillis);
if (_listener != null)
{
_listener.OnEvent(_itemName, GetCurrentValues(false), false);
}
} while (true);
}
//How about this method? Is it correct?
public IDictionary GetCurrentValues(bool fullData) {
lock (this) {
IDictionary eventData = new Hashtable();
eventData["ceiling"] = _ceiling.ToString("#,##0.##");
eventData["floor"] = _floor.ToString("#,##0.##");
...
}
}
How about Start(), Run() method in "ExternalFeedProducer" class? i need remove ? Because it has error in StockListAdapter :
---
Unhandled exception : System.IndexOutOfRangeException : index was outside the bounds of the array at Lightstreamer.Adapters.Data.StockList.ExternalFeedSimulator.Run()
----
Quotes :
"Any unwanted behaviour (for instance, the Data Adapter not receiving all read data) should be inspected with a debugger" --> i don't understand this, u mean if i config in "lightstreamer_log_conf.xml" file and set priority value = "DEBUG" :
<category name="LightstreamerLogger.pump" class="org.apache.log4j.Logger">
<priority value="DEBUG" />
</category>
the Data Adapter not receiving all read data after every 5 seconds?
and How to check or to recognize my Remote Adapter would still forward all updates to Lightstreamer Server?
Can u help me?
Dario Crivelli
To my human eye, the "ReadBinaryFile" and "GetCurrentValues" methods seem correct.
I also confirm that "Start" and "Run" of the "ExternalFeedProducer" class should be removed, as now only the main thread in "ExternalFeedSimulator" is needed.
Hence, if you observe that the Data Adapter does not call onEvent as expected, you should try to setup a code debugger and trace it step by step.
Alternatively, if you want to log the data flow sent by your "ExternalFeedSimulator" class, you have to add custom log lines, for instance in the "onEvent" implementation in "StockList.cs".
Note that, in this method, only the events pertaining to stocks that are currently subscribed to are forwarded to Lightstreamer.
You can have the Remote Server log the update events really sent to Lightstreamer by setting as DEBUG the "Lightstreamer.DotNet.Server.RequestReply" logging category. The configuration of the Remote Server log, in the included deployment example, is in the "DotNetServer.exe.config" file beside the "DotNetServer.exe" executable; the configured log file is "DotNetServer.log".
The Server logging configuration file, "lightstreamer_log_conf.xml", can remain unchanged, for the moment.
Dario
tuongkha
Thanks Dario very much, now it seem ok. but in html file, javascript code, when data stock changed, function updateItem(item, updateInfo) doesn't work.
Last time, i have a question for this issue, and u have to answer the question, but i followed by your instruction, i didn't have successful. I don't know, what are there steps i wrong? Please help me again.
Here my changed
-----"default.html" file --------
<script>
for (var i = 1; i <= 30; i++)
{
var suff = (i % 2 == 1) ? "A" : "B";
document.write('<tr class="lscold'+suff+'">');
document.write('<td> </td>');
document.write('<td class="stockname'+suff+'"><div source="lightstreamer" table="list" item="'+i+'" field="stock_symbol"> - </div></td>');
document.write('<td><div source="lightstreamer" table="list" item="'+i+'" field="ref_price"> - </div></td>');
document.write('<td><div source="lightstreamer" table="list" item="'+i+'" field="ceiling"> - </div></td>');
document.write('<td><div source="lightstreamer" table="list" item="'+i+'" field="floor"> - </div></td>');
document.write('<td><div source="lightstreamer" table="list" item="'+i+'" field="open_price"> - </div></td>');
document.write('<td><div source="lightstreamer" table="list" item="'+i+'" field="max"> - </div></td>');
document.write('<td><div source="lightstreamer" table="list" item="'+i+'" field="min"> - </div></td>');
document.write('<td> </td>');
document.write('<td> </td>');
document.write('<td><div source="lightstreamer" table="list" item="'+i+'" field="close_price"> - </div></td>');
document.write(' <td><div source="lightstreamer" table="list" item="'+i+'" field="close_vol"> - </div></td>');
document.write('<td> </td>');
document.write('<td> </td>');
document.write('<td><div source="lightstreamer" table="list" item="'+i+'" field="bid3"> - </div></td>');
document.write('<td><div source="lightstreamer" table="list" item="'+i+'" field="bid3vol"> - </div></td>');
document.write('<td><div source="lightstreamer" table="list" item="'+i+'" field="bid2"> - </div></td>');
document.write('<td><div source="lightstreamer" table="list" item="'+i+'" field="bid2vol"> - </div></td>');
document.write('<td><div source="lightstreamer" table="list" item="'+i+'" field="bid1"> - </div></td>');
document.write('<td><div source="lightstreamer" table="list" item="'+i+'" field="bid1vol"> - </div></td>');
document.write('<td><div source="lightstreamer" table="list" item="'+i+'" field="last_price"> - </div></td>');
document.write('<td><div source="lightstreamer" table="list" item="'+i+'" field="lastVol"> - </div></td>');
document.write('<td><div source="lightstreamer" table="list" item="'+i+'" field="pct_change"> - </div></td>');
document.write('<td><div source="lightstreamer" table="list" item="'+i+'" field="ask1"> - </div></td>');
document.write('<td><div source="lightstreamer" table="list" item="'+i+'" field="ask1vol"> - </div></td>');
document.write('<td><div source="lightstreamer" table="list" item="'+i+'" field="ask2"> - </div></td>');
document.write('<td><div source="lightstreamer" table="list" item="'+i+'" field="ask2vol"> - </div></td>');
document.write('<td><div source="lightstreamer" table="list" item="'+i+'" field="ask3"> - </div></td>');
document.write('<td><div source="lightstreamer" table="list" item="'+i+'" field="ask3vol"> - </div></td>');
document.write('</tr>');
}
</script>
//////////////////////////Event handlers
var redColor = "#f8b87a";
var greenColor = "lightgreen";
function updateItem(item, updateInfo) {
if (updateInfo == null)
{
return;
}
if (updateInfo.isValueChanged("pct_change")) {
var val = updateInfo.getNewValue("pct_change"); if (val.indexOf("-") > -1) {
updateInfo.addField(216,imgDown);
} else {
updateInfo.addField(216,imgUp);
}
}
var oldLast = updateInfo.getOldValue("last_price");
var newColor;
if (oldLast == null) { //first update for this item
updateInfo.addField(214,greenColor,true); //no fade for snapshot
if (doFade) {
updateInfo.addField(215,"OFF",true);
}
} else if (updateInfo.isValueChanged("last_price")) {
//at least second update
if (oldLast > updateInfo.getNewValue("last_price")) {
updateInfo.addField(214,redColor,true);
} else {
updateInfo.addField(214,greenColor,true);
}
if (doFade) {
updateInfo.addField(215,"ON",true);
}
}
}
function formatValues(item, itemUpdate) {
if (itemUpdate == null) {
return;
}
if (doFade) {
if (itemUpdate.getServerValue(215) == "ON") {
itemUpdate.setHotToColdTime(300);
}
}
itemUpdate.setHotTime(600);
if (itemUpdate.getServerValue(13) == "inactive") {
carryBackUnchanged(itemUpdate);
itemUpdate.setRowAttribute("#808080","#808080","color");
} else {
if (itemUpdate.getFormattedValue(13) != null) {
carryBackUnchanged(itemUpdate);
itemUpdate.setRowAttribute("#000000","#000000","color");
itemUpdate.setAttribute(12,"#000080","#000080","color");
}
//choose the backgroundColor
var backC = (item % 2 == 1) ? "#eeeeee" : "#ddddee";
var backH = itemUpdate.getServerValue(214); itemUpdate.setRowAttribute(backH,backC,"backgroundColor");
//choose the "change" field stylesheet
var newChng;
if ((newChng = itemUpdate.getFormattedValue(3)) != null) {
var hotTxtCol = (newChng.charAt(0) == '-') ? "#dd0000" : "#009900";
itemUpdate.setAttribute(3,"black",hotTxtCol,"color");
itemUpdate.setAttribute(3,"bold","bold","fontWeight");
}
itemUpdate.setAttribute(12,backC,backC,"backgroundColor");
}
//format the timestamp
var time = itemUpdate.getFormattedValue(2);
if (time != null) {
time = formatTime(time);
itemUpdate.setFormattedValue(2,time);
}
//format the "number" fields
for (var i = 1; i <= 11; i++) {
if (i == 2 || i == 4 || i == 7) {
continue; //"string" fields
}
var newValue = itemUpdate.getFormattedValue(i);
if (newValue == null) continue;
var formattedVal = formatDecimal(newValue, 2, true);
if (i == 3) {
if (formattedVal > 0) {
formattedVal = "+" + formattedVal;
}
formattedVal += "%";
}
itemUpdate.setFormattedValue(i,formattedVal);
}
}
////////////////Global var declaration
var group = ["item1", "item2", "item3", "item4","item5", "item6", "item7", "item8","item9", "item10", "item11", "item12","item13", "item14", "item15", "item16", "item17", "item18", "item19", "item20", "item21", "item22", "item23", "item24", "item25", "item26", "item27", "item28", "item29", "item30"];
var schema = ["last_price", "time", "pct_change","bid1", "bid2", "bid3", "bid1vol", "bid2vol", "bid3vol", "ask1","ask2", "ask3", "ask1vol", "ask2vol", "ask3vol", "min", "max","ref_price", "open_price", "stock_name", "stock_symbol", "ceiling", "floor", "lastVal", "lastVol", "close_price", "close_vol"];
var newTable = new OverwriteTable(group, schema,"MERGE");
----------
Now i want to changed, if all of items :
lastVal, lastVol, last_price, bid1, bid2, bid3, ask1, ask2, ask3, bid1vol, bid2vol, bid3vol, ask1vol, ask2vol, ask3vol, pct_change
has values modified, it will be fill by color (if current value < old_value, fill by red color, else fill by green color)
Please help me again.
Dario Crivelli
The sample page you are using as a base point sets the cell highlighting (i.e. "hot") color for all changed fields based on the change of the "last_price" field value. This necessarily involves a two-phase process:
in "updateItem" the change is analyzed and the proper color is stored in an extra field (namely 214);
then, in "formatValues", the color is assigned as the "hot" background color to all the cells in the row (note that only changed cells will be highlighted).
Does this still work for the "last_price" field?
Other code is not relevant for you; the only relevant code is:
function updateItem(item, updateInfo) {
if (updateInfo == null) {
return;
}
var oldLast = updateInfo.getOldValue("last_price");
var newColor;
if (oldLast == null) { //first update for this item
updateInfo.addField(214,greenColor,true);
} else if (updateInfo.isValueChanged("last_price")) {
//at least second update
if (oldLast > updateInfo.getNewValue("last_price")) {
updateInfo.addField(214,redColor,true);
} else {
updateInfo.addField(214,greenColor,true);
}
}
}
function formatValues(item, itemUpdate) {
if (itemUpdate == null) {
return;
}
itemUpdate.setHotTime(600);
//choose the backgroundColor
var backC = (item % 2 == 1) ? "#eeeeee" : "#ddddee";
var backH = itemUpdate.getServerValue(214);
itemUpdate.setRowAttribute(backH,backC,"backgroundColor");
}
You seem to require two changes:
- The change of "last_price" should only affect the "last_price" cell; you can accomplish this by using the "setAttribute" API in place of the "setRowAttribute"; please find the details on these APIs here(the online web client APIs documentation root is http://www.lightstreamer.com/docs/client_web_jsdoc/index.html ).
- The same code should be replicated for all the desired fields; this implies that you have to use more extra fields; you may prefer to name them by names (e.g. "last_price_color" in place of 214).
tuongkha
Dear Dario,
thanks for your help. i found my error. i forgot call updateItem(), formatValues() method.
newTable.setClearOnDisconnected(true); //default is false
newTable.setClearOnRemove(true); //default is false
newTable.onItemUpdate = updateItem;
newTable.onChangingValues = formatValues;
newTable.setPushedHtmlEnabled(true);
in my html.
indrajit
Hi Dario & Tuongkha,
I changed the ExternalFeed.cs file according to my requirements and I can built it successfully, Now I want to implement this file on to lightstremer to get the changes according to my requirements in the browser So, for that what should I do ?
where should I place the ExternalFeed.dll and what are the steps to be followed to get the changes?
Thanks,
Dario Crivelli
The full story is documented in
DOCS-SDKs\sdk_adapter_dotnet\doc\DotNet Adapters.pdf
where a step by step deployment of the Remote StockListDemo is shown. You should just replace the Data Adapter dll.
In a few words, you have to mount special Proxy Adapters, supplied with Lightstreamer on the Server and ensure that the client pages ask for data from those adapters; then launch Lightstreamer Server and the Remote Server.
For any problems in this phase, I revert to
this thread.